Logo Search packages:      
Sourcecode: xabacus version File versions

Abacus.c

/*-
# X-BASED ABACUS
#
#  Abacus.c
#
###
#
#  Copyright (c) 1994 - 2005  David Albert Bagley, bagleyd@tux.org
#
#                   All Rights Reserved
#
#  Permission to use, copy, modify, and distribute this software and
#  its documentation for any purpose and without fee is hereby granted,
#  provided that the above copyright notice appear in all copies and
#  that both that copyright notice and this permission notice appear in
#  supporting documentation, and that the name of the author not be
#  used in advertising or publicity pertaining to distribution of the
#  software without specific, written prior permission.
#
#  This program is distributed in the hope that it will be "useful",
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
*/

/* Methods file for Abacus */

#if 1
#ifndef SCRIPTFILE
#define SCRIPTFILE "Abacus.les"
#endif
#endif

#if defined(USE_RPLAY) || defined(USE_NAS) || defined(USE_VMSPLAY) || defined(USE_ESOUND) || defined(WINVER) || defined(DEF_PLAY)
#define USE_SOUND
extern void playSound(char * filename);
#endif
#include "AbacusP.h"

#ifdef WINVER
#ifndef INIFILE
#define INIFILE "wabacus.ini"
#endif
#define SECTION "setup"
#else

static Boolean SetValuesAbacus(Widget current, Widget request, Widget renew);
static void QuitAbacus(AbacusWidget w, XEvent * event, char **args, int nArgs);
static void DestroyAbacus(Widget old);
static void ResizeAbacus(AbacusWidget w);
static void InitializeAbacus(Widget request, Widget renew);
static void ExposeAbacus(Widget renew, XEvent * event, Region region);
static void HideAbacus(AbacusWidget w, XEvent * event, char **args, int nArgs);
static void SelectAbacus(AbacusWidget w, XEvent * event, char **args, int nArgs);
static void ReleaseAbacus(AbacusWidget w, XEvent * event, char **args, int nArgs);
static void ClearAbacus(AbacusWidget w, XEvent * event, char **args, int nArgs);
static void ClearAbacusMaybe(AbacusWidget w, XEvent * event, char **args, int nArgs);
static void ClearAbacus2(AbacusWidget w, XEvent * event, char **args, int nArgs);
static void IncrementAbacus(AbacusWidget w, XEvent * event, char **args, int nArgs);
static void DecrementAbacus(AbacusWidget w, XEvent * event, char **args, int nArgs);
static void SpeedAbacus(AbacusWidget w, XEvent * event, char **args, int nArgs);
static void SlowAbacus(AbacusWidget w, XEvent * event, char **args, int nArgs);
static void SoundAbacus(AbacusWidget w, XEvent * event, char **args, int nArgs);
static void FormatAbacus(AbacusWidget w, XEvent * event, char **args, int nArgs);
static void RomanNumeralsAbacus(AbacusWidget w, XEvent * event, char **args, int nArgs);
static void SignAbacus(AbacusWidget w, XEvent * event, char **args, int nArgs);
static void QuarterAbacus(AbacusWidget w, XEvent * event, char **args, int nArgs);
static void QuarterPercentAbacus(AbacusWidget w, XEvent * event, char **args, int nArgs);
static void VerticalAbacus(AbacusWidget w, XEvent * event, char **args, int nArgs);
static void DemoAbacus(AbacusWidget w, XEvent * event, char **args, int nArgs);
static void NextAbacus(AbacusWidget w, XEvent * event, char **args, int nArgs);
static void RepeatAbacus(AbacusWidget w, XEvent * event, char **args, int nArgs);
static void MoreAbacus(AbacusWidget w, XEvent * event, char **args, int nArgs);
static void EnterAbacus(AbacusWidget w, XEvent * event, char **args, int nArgs);
static void LeaveAbacus(AbacusWidget w, XEvent * event, char **args, int nArgs);

static char defaultTranslationsAbacus[] =
"<KeyPress>q: Quit()\n\
 Ctrl<KeyPress>C: Quit()\n\
 <KeyPress>osfCancel: Hide()\n\
 <KeyPress>Escape: Hide()\n\
 <KeyPress>osfEscape: Hide()\n\
 Ctrl<KeyPress>[: Hide()\n\
 <KeyPress>0x1B: Hide()\n\
 <Btn1Down>: Select()\n\
 <Btn1Up>: Release()\n\
 <KeyPress>c: Clear()\n\
 <Btn3Down>: ClearMaybe()\n\
 <Btn3Down>(2+): Clear2()\n\
 <KeyPress>i: Increment()\n\
 <KeyPress>d: Decrement()\n\
 <KeyPress>0x2E: Speed()\n\
 <KeyPress>0x3E: Speed()\n\
 <KeyPress>0x3C: Slow()\n\
 <KeyPress>0x2C: Slow()\n\
 <KeyPress>@: Sound()\n\
 <KeyPress>f: Format()\n\
 <KeyPress>m: RomanNumerals()\n\
 <KeyPress>s: Sign()\n\
 <KeyPress>u: Quarter()\n\
 <KeyPress>p: QuarterPercent()\n\
 <KeyPress>v: Vertical()\n\
 <KeyPress>o: Demo()\n\
 <KeyPress>n: Next()\n\
 <KeyPress>r: Repeat()\n\
 <KeyPress>0x20: More()\n\
 <KeyPress>KP_Space: More()\n\
 <KeyPress>Return: More()\n\
 <EnterWindow>: Enter()\n\
 <LeaveWindow>: Leave()";

static XtActionsRec actionsListAbacus[] =
{
      {(char *) "Quit", (XtActionProc) QuitAbacus},
      {(char *) "Hide", (XtActionProc) HideAbacus},
      {(char *) "Select", (XtActionProc) SelectAbacus},
      {(char *) "Release", (XtActionProc) ReleaseAbacus},
      {(char *) "Clear", (XtActionProc) ClearAbacus},
      {(char *) "ClearMaybe", (XtActionProc) ClearAbacusMaybe},
      {(char *) "Clear2", (XtActionProc) ClearAbacus2},
      {(char *) "Increment", (XtActionProc) IncrementAbacus},
      {(char *) "Decrement", (XtActionProc) DecrementAbacus},
      {(char *) "Speed", (XtActionProc) SpeedAbacus},
      {(char *) "Slow", (XtActionProc) SlowAbacus},
      {(char *) "Sound", (XtActionProc) SoundAbacus},
      {(char *) "Format", (XtActionProc) FormatAbacus},
      {(char *) "RomanNumerals", (XtActionProc) RomanNumeralsAbacus},
      {(char *) "Sign", (XtActionProc) SignAbacus},
      {(char *) "Quarter", (XtActionProc) QuarterAbacus},
      {(char *) "QuarterPercent", (XtActionProc) QuarterPercentAbacus},
      {(char *) "Vertical", (XtActionProc) VerticalAbacus},
      {(char *) "Demo", (XtActionProc) DemoAbacus},
      {(char *) "Next", (XtActionProc) NextAbacus},
      {(char *) "Repeat", (XtActionProc) RepeatAbacus},
      {(char *) "More", (XtActionProc) MoreAbacus},
      {(char *) "Enter", (XtActionProc) EnterAbacus},
      {(char *) "Leave", (XtActionProc) LeaveAbacus}
};

static XtResource resourcesAbacus[] =
{
      {XtNwidth, XtCWidth, XtRDimension, sizeof (Dimension),
       XtOffset(AbacusWidget, core.width),
       XtRString, (caddr_t) "234"},
      {XtNheight, XtCHeight, XtRDimension, sizeof (Dimension),
       XtOffset(AbacusWidget, core.height),
       XtRString, (caddr_t) "123"},
      {XtNrails, XtCRails, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.rails),
       XtRString, (caddr_t) "13"},
      {XtNbase, XtCBase, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.base),
       XtRString, (caddr_t) "10"},
      {XtNdisplayBase, XtCDisplayBase, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.displayBase),
       XtRString, (caddr_t) "10"},
      {XtNformat, XtCFormat, XtRString, sizeof (String),
       XtOffset(AbacusWidget, abacus.format),
       XtRString, (caddr_t) "Other"},
      {XtNvertical, XtCVertical, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.vertical),
       XtRString, (caddr_t) "FALSE"},
      {XtNromanNumerals, XtCRomanNumerals, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.romanNumerals),
       XtRString, (caddr_t) "FALSE"},
      {XtNsign, XtCSign, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.sign),
       XtRString, (caddr_t) "FALSE"},
      {XtNquarter, XtCQuarter, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.quarter),
       XtRString, (caddr_t) "FALSE"},
      {XtNquarterPercent, XtCQuarterPercent, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.quarterPercent),
       XtRString, (caddr_t) "FALSE"},
      {XtNforeground, XtCForeground, XtRPixel, sizeof (Pixel),
       XtOffset(AbacusWidget, abacus.foreground),
       XtRString, (caddr_t) XtDefaultForeground},
      {XtNbackground, XtCBackground, XtRPixel, sizeof (Pixel),
       XtOffset(AbacusWidget, abacus.background),
       XtRString, (caddr_t) XtDefaultBackground},
      {XtNframeColor, XtCForeground, XtRPixel, sizeof (Pixel),
       XtOffset(AbacusWidget, abacus.frameColor),
       XtRString, (caddr_t) "cyan" /*XtDefaultForeground*/},
      {XtNrailColor, XtCForeground, XtRPixel, sizeof (Pixel),
       XtOffset(AbacusWidget, abacus.railColor),
       XtRString, (caddr_t) "gold" /*XtDefaultForeground*/},
      {XtNbeadColor, XtCForeground, XtRPixel, sizeof (Pixel),
       XtOffset(AbacusWidget, abacus.beadColor),
       XtRString, (caddr_t) "DarkRed" /*XtDefaultForeground*/},
      {XtNbeadBorder, XtCForeground, XtRPixel, sizeof (Pixel),
       XtOffset(AbacusWidget, abacus.borderColor),
       XtRString, (caddr_t) "gray25" /*XtDefaultForeground*/},
      {XtNmono, XtCMono, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.mono),
       XtRString, (caddr_t) "FALSE"},
      {XtNreverse, XtCReverse, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.reverse),
       XtRString, (caddr_t) "FALSE"},
      {XtNtopNumber, XtCTopNumber, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.decks[TOP].number),
       XtRString, (caddr_t) "2"},
      {XtNbottomNumber, XtCBottomNumber, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.decks[BOTTOM].number),
       XtRString, (caddr_t) "5"},
      {XtNtopFactor, XtCTopFactor, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.decks[TOP].factor),
       XtRString, (caddr_t) "5"},
      {XtNbottomFactor, XtCBottomFactor, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.decks[BOTTOM].factor),
       XtRString, (caddr_t) "1"},
      {XtNtopSpaces, XtCTopSpaces, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.decks[TOP].spaces),
       XtRString, (caddr_t) "2"},
      {XtNbottomSpaces, XtCBottomSpaces, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.decks[BOTTOM].spaces),
       XtRString, (caddr_t) "3"},
      {XtNtopOrient, XtCTopOrient, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.decks[TOP].orientation),
       XtRString, (caddr_t) "TRUE"},
      {XtNbottomOrient, XtCBottomOrient, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.decks[BOTTOM].orientation),
       XtRString, (caddr_t) "FALSE"},
      {XtNdelay, XtCDelay, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.delay),
       XtRString, (caddr_t) "50"},
      {XtNsound, XtCSound, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.sound),
       XtRString, (caddr_t) "FALSE"},
      {XtNbumpSound, XtCBumpSound, XtRString, sizeof (String),
       XtOffset(AbacusWidget, abacus.bumpSound),
       XtRString, (caddr_t) BUMPSOUND},
      {XtNmoveSound, XtCMoveSound, XtRString, sizeof (String),
       XtOffset(AbacusWidget, abacus.moveSound),
       XtRString, (caddr_t) MOVESOUND},
      {XtNscript, XtCScript, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.script),
       XtRString, (caddr_t) "FALSE"},
      {XtNdemo, XtCDemo, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.demo),
       XtRString, (caddr_t) "FALSE"},
      {XtNaux, XtCAux, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.aux),
       XtRString, (caddr_t) "FALSE"},
      {XtNslot, XtCSlot, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.slot),
       XtRString, (caddr_t) "FALSE"},
      {XtNdiamond, XtCDiamond, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.diamond),
       XtRString, (caddr_t) "FALSE"},

      {XtNdemoPath, XtCDemoPath, XtRString, sizeof (String),
       XtOffset(AbacusWidget, abacusDemo.path),
       XtRString, (caddr_t) DEMOPATH},
      {XtNdemoFont, XtCDemoFont, XtRString, sizeof (Font),
       XtOffset(AbacusWidget, abacusDemo.font),
       XtRString, (caddr_t) "-*-times-*-r-*-*-*-180-*-*-*-*"},
      {XtNdemoForeground, XtCForeground, XtRPixel, sizeof (Pixel),
       XtOffset(AbacusWidget, abacusDemo.foreground),
       XtRString, (caddr_t) XtDefaultForeground},
      {XtNdemoBackground, XtCBackground, XtRPixel, sizeof (Pixel),
       XtOffset(AbacusWidget, abacusDemo.background),
       XtRString, (caddr_t) XtDefaultBackground},

      {XtNdeck, XtCDeck, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.deck),
       XtRString, (caddr_t) "-1"},
      {XtNrail, XtCRail, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.rail),
       XtRString, (caddr_t) "0"},
      {XtNnumber, XtCNumber, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.number),
       XtRString, (caddr_t) "0"},
      {XtNdecimalPosition, XtCDecimalPosition, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.decimalPosition),
       XtRString, (caddr_t) "2"}, /* MAX_FRACTION_DIGITS */
      {XtNmenu, XtCMenu, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.menu),
       XtRString, (caddr_t) "-1"},
      {XtNmode, XtCMode, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.mode),
       XtRString, (caddr_t) "5"},
      {XtNmathBuffer, XtCMathBuffer, XtRString, sizeof (String),
       XtOffset(AbacusWidget, abacus.mathBuffer),
       XtRString, (caddr_t) ""},
      {XtNselectCallback, XtCCallback, XtRCallback, sizeof (caddr_t),
       XtOffset(AbacusWidget, abacus.select),
       XtRCallback, (caddr_t) NULL}
};

AbacusClassRec abacusClassRec =
{
      {
            (WidgetClass) & widgetClassRec,           /* superclass */
            (char *) "Abacus",      /* class name */
            sizeof (AbacusRec),     /* widget size */
            NULL,       /* class initialize */
            NULL,       /* class part initialize */
            FALSE,            /* class inited */
            (XtInitProc) InitializeAbacus,      /* initialize */
            NULL,       /* initialize hook */
            XtInheritRealize, /* realize */
            actionsListAbacus,      /* actions */
            XtNumber(actionsListAbacus),  /* num actions */
            resourcesAbacus,  /* resources */
            XtNumber(resourcesAbacus),    /* num resources */
            NULLQUARK,  /* xrm class */
            TRUE,       /* compress motion */
            TRUE,       /* compress exposure */
            TRUE,       /* compress enterleave */
            TRUE,       /* visible interest */
            (XtWidgetProc) DestroyAbacus, /* destroy */
            (XtWidgetProc) ResizeAbacus,  /* resize */
            (XtExposeProc) ExposeAbacus,  /* expose */
            (XtSetValuesFunc) SetValuesAbacus,  /* set values */
            NULL,       /* set values hook */
            XtInheritSetValuesAlmost,     /* set values almost */
            NULL,       /* get values hook */
            NULL,       /* accept focus */
            XtVersion,  /* version */
            NULL,       /* callback private */
            defaultTranslationsAbacus,    /* tm table */
            NULL,       /* query geometry */
            NULL,       /* display accelerator */
            NULL        /* extension */
      },
      {
            0           /* ignore */
      }
};

WidgetClass abacusWidgetClass = (WidgetClass) & abacusClassRec;

#ifndef HAVE_USLEEP
#if !defined( VMS ) || defined( XVMSUTILS ) || ( __VMS_VER >= 70000000 )
#ifdef USE_XVMSUTILS
#include <X11/unix_time.h>
#endif
#if HAVE_SYS_TIME_H
#include <sys/time.h>
#else
#if HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#endif
#endif
#if defined(SYSV) || defined(SVR4)
#ifdef LESS_THAN_AIX3_2
#include <sys/poll.h>
#else /* !LESS_THAN_AIX3_2 */
#include <poll.h>
#endif /* !LESS_THAN_AIX3_2 */
#endif /* defined(SYSV) || defined(SVR4) */

/* not static in case usleep found in system include */
int
usleep(unsigned int usec)
{
#if (defined (SYSV) || defined(SVR4)) && !defined(__hpux)
#if defined(HAVE_NANOSLEEP)
      {
            struct timespec rqt;

            rqt.tv_nsec = 1000 * (usec % (unsigned int) 1000000);
            rqt.tv_sec = usec / (unsigned int) 1000000;
            return nanosleep(&rqt, NULL);
      }
#else
      (void) poll(

#if defined(__cplusplus) || defined(c_plusplus)
            (pollfd *) /* guess */
#else
            (void *)
#endif
            0, (int) 0, usec / 1000);     /* ms resolution */
#endif
#else
#ifdef VMS
      long timadr[2];

      if (usec != 0) {
            timadr[0] = -usec * 10;
            timadr[1] = -1;

            sys$setimr(4, &timadr, 0, 0, 0);
            sys$waitfr(4);
      }
#else
      struct timeval time_out;

#if 0
      /* (!defined(AIXV3) && !defined(__hpux)) */
      extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);

#endif

      time_out.tv_usec = usec % (unsigned int) 1000000;
      time_out.tv_sec = usec / (unsigned int) 1000000;
      (void) select(0, (void *) 0, (void *) 0, (void *) 0, &time_out);
#endif
#endif
      return 0;
}
#endif

void
SetAbacus(AbacusWidget w, int reason)
{
      abacusCallbackStruct cb;

      cb.reason = reason;
      XtCallCallbacks((Widget) w, (char *) XtNselectCallback, &cb);
}

void
SetAbacusMove(AbacusWidget w, int reason, int aux, int deck,
            int rail, int number)
{
      abacusCallbackStruct cb;

      cb.reason = reason;
      cb.aux = aux;
      cb.deck = deck;
      cb.rail = rail;
      cb.number = number;
      XtCallCallbacks((Widget) w, (char *) XtNselectCallback, &cb);
}

static void
SetAbacusString(AbacusWidget w, int reason, char * string)
{
      abacusCallbackStruct cb;

      cb.reason = reason;
      cb.buffer = string;
      XtCallCallbacks((Widget) w, (char *) XtNselectCallback, &cb);
}
#endif

static void ResizeBead(AbacusWidget w);

#if (!defined(WINVER) || (WINVER <= 0x030a)) /* if X or WINDOWS 3.1 or less */
void
Sleep(unsigned long cMilliseconds)
{
#if (defined(WINVER) && (WINVER <= 0x030a))
      unsigned long time_out = GetTickCount() + cMilliseconds;

      while (time_out > GetTickCount());
#else
      (void) usleep(cMilliseconds * 1000);
#endif
}
#endif

static void
initTimer(AbacusWidget w)
{
#ifdef WINVER
      w->abacus.oldTime = GetTickCount();
#else
      XFlush(XtDisplay(w));
      (void) X_GETTIMEOFDAY(&(w->abacus.oldTime));
#endif
}


static void
useTimer(AbacusWidget w, int delay)
{
      int sleepTime;
#ifdef WINVER
      long  tv = GetTickCount();

      sleepTime = delay - (tv - w->abacus.oldTime);
      w->abacus.oldTime = tv;
      if (sleepTime > 0) {
            Sleep((unsigned int) sleepTime);
      }
#else
      struct timeval tv;

      XFlush(XtDisplay(w));
      (void) X_GETTIMEOFDAY(&tv);
      sleepTime = delay * 1000 - ((tv.tv_sec - w->abacus.oldTime.tv_sec) *
            1000000 + tv.tv_usec - w->abacus.oldTime.tv_usec);
      w->abacus.oldTime.tv_sec = tv.tv_sec;
      w->abacus.oldTime.tv_usec = tv.tv_usec;
      if (sleepTime > 0) {
            (void) usleep((unsigned int) sleepTime);
      }
#endif
}

void
intCat(char ** string, const char * var1, const int var2)
{
      if (!(*string = (char *) malloc(strlen(var1) + 21))) {
            DISPLAY_ERROR("Not enough memory, exiting.");
      }
      (void) sprintf(*string, "%s%d", var1, var2);
}

static void
stringCat(char ** string, const char * var1, const char * var2)
{
      if (!(*string = (char *) malloc(strlen(var1) + strlen(var2) + 1))) {
            DISPLAY_ERROR("Not enough memory, exiting.");
      }
      (void) sprintf(*string, "%s%s", var1, var2);
}

static void
SetModeFromFormat(AbacusWidget w)
{
      if (strncasecmp("chinese", w->abacus.format,
                  MAXLENFORMAT) == 0) {
            w->abacus.mode = CHINESE;
      } else if (strncasecmp("japanese", w->abacus.format,
                  MAXLENFORMAT) == 0) {
            w->abacus.mode = JAPANESE;
      } else if (strncasecmp("korean", w->abacus.format,
                  MAXLENFORMAT) == 0) {
            w->abacus.mode = KOREAN;
      } else if (strncasecmp("roman", w->abacus.format,
                  MAXLENFORMAT) == 0) {
            w->abacus.mode = ROMAN;
      } else if (strncasecmp("italian", w->abacus.format,
                  MAXLENFORMAT) == 0) {
            w->abacus.mode = ROMAN;
      } else if (strncasecmp("russian", w->abacus.format,
                  MAXLENFORMAT) == 0) {
            w->abacus.mode = RUSSIAN;
      } else if (strncasecmp("cn", w->abacus.format, MAXLENFORMAT) == 0) {
            w->abacus.mode = CHINESE;
      } else if (strncasecmp("ja", w->abacus.format, MAXLENFORMAT) == 0) {
            w->abacus.mode = JAPANESE;
      } else if (strncasecmp("jp", w->abacus.format, MAXLENFORMAT) == 0) {
            w->abacus.mode = JAPANESE;
      } else if (strncasecmp("ko", w->abacus.format, MAXLENFORMAT) == 0) {
            w->abacus.mode = KOREAN;
      } else if (strncasecmp("ro", w->abacus.format, MAXLENFORMAT) == 0) {
            w->abacus.mode = ROMAN;
      } else if (strncasecmp("it", w->abacus.format, MAXLENFORMAT) == 0) {
            w->abacus.mode = ROMAN;
      } else if (strncasecmp("ru", w->abacus.format, MAXLENFORMAT) == 0) {
            w->abacus.mode = RUSSIAN;
      } else {
            w->abacus.mode = OTHER;
      }
}

static void
CheckBeads(AbacusWidget w)
{
      char *buf1, *buf2;

      if (w->abacus.base > MAXBASE) {
            intCat(&buf1, "Base must be less than or equal to ", MAXBASE);
            DISPLAY_WARNING(buf1);
            free(buf1);
            w->abacus.base = DEFAULTBASE;
            SetAbacus(w, ABACUS_BASE_DEFAULT);
      } else if (w->abacus.base < MINBASE) {
            intCat(&buf1, "Base must be greater than or equal to ", MINBASE);
            DISPLAY_WARNING(buf1);
            free(buf1);
            w->abacus.base = DEFAULTBASE;
            SetAbacus(w, ABACUS_BASE_DEFAULT);
      } else if (w->abacus.base != DEFAULTBASE && w->abacus.demo) {
            intCat(&buf1, "Base must be equal to ", DEFAULTBASE);
            stringCat(&buf2, buf1, ", for demo");
            free(buf1);
            DISPLAY_WARNING(buf2);
            free(buf2);
            w->abacus.base = DEFAULTBASE;
            SetAbacus(w, ABACUS_BASE_DEFAULT);
#if 0
      } else if (w->abacus.quarter && w->abacus.base % 2 == 1) {
            /* Odd bases produce round-off errors */
            DISPLAY_WARNING("Base can not be odd with quarter set");
            w->abacus.base = DEFAULTBASE;
            SetAbacus(w, ABACUS_BASE_DEFAULT);
      } else if (w->abacus.quarterPercent && w->abacus.base % 2 == 1) {
            /* Odd bases produce round-off errors */
            DISPLAY_WARNING("Base can not be odd with quarter percent set");
            w->abacus.base = DEFAULTBASE;
            SetAbacus(w, ABACUS_BASE_DEFAULT);
#endif
      } else if ((w->abacus.base == 2 || w->abacus.base == 4) &&
                  w->abacus.decks[BOTTOM].spaces < 3 &&
                  w->abacus.quarter) {
            /* Odd bases produce round-off errors but OK */
            /* When base divisible by 4, kind of silly but OK */
            DISPLAY_WARNING("Base can not be 2 or 4 with bottomSpaces < 3 with quarter set");
            w->abacus.base = DEFAULTBASE;
            SetAbacus(w, ABACUS_BASE_DEFAULT);
      } else if ((w->abacus.base == 3 || w->abacus.base == 6 || w->abacus.base == 9) &&
                  w->abacus.decks[BOTTOM].spaces < 2 &&
                  w->abacus.quarter) {
            DISPLAY_WARNING("Base can not 3 or 6 or 9 with bottomSpaces < 2 with quarter set");
            w->abacus.base = DEFAULTBASE;
            SetAbacus(w, ABACUS_BASE_DEFAULT);
      } else if ((w->abacus.base == 2 || w->abacus.base == 4) &&
                  w->abacus.decks[BOTTOM].spaces < 3 &&
                  w->abacus.quarterPercent) {
            DISPLAY_WARNING("Base can not 2 or 4 with bottomSpaces < 3 with quarter percent set");
            w->abacus.base = DEFAULTBASE;
            SetAbacus(w, ABACUS_BASE_DEFAULT);
      } else if ((w->abacus.base == 3 || w->abacus.base == 6 || w->abacus.base == 9) &&
                  w->abacus.decks[BOTTOM].spaces < 2 &&
                  w->abacus.quarterPercent) {
            DISPLAY_WARNING("Base can not 3 or 6 or 9 with bottomSpaces < 2 with quarter percent set");
            w->abacus.base = DEFAULTBASE;
            SetAbacus(w, ABACUS_BASE_DEFAULT);
      }
      if (w->abacus.displayBase > MAXBASE) {
            intCat(&buf1, "Display Base must be less than or equal to ", MAXBASE);
            DISPLAY_WARNING(buf1);
            free(buf1);
            w->abacus.displayBase = DEFAULTBASE;
      } else if (w->abacus.displayBase < MINBASE) {
            intCat(&buf1, "Display Base must be greater than or equal to ",
                  MINBASE);
            DISPLAY_WARNING(buf1);
            free(buf1);
            w->abacus.displayBase = DEFAULTBASE;
      } else if (w->abacus.displayBase != DEFAULTBASE && w->abacus.demo) {
            intCat(&buf1, "Display base must be equal to ", DEFAULTBASE);
            stringCat(&buf2, buf1, ", for demo");
            free(buf1);
            DISPLAY_WARNING(buf2);
            free(buf2);
            w->abacus.displayBase = DEFAULTBASE;
      }
      if (w->abacus.mode == OTHER && w->abacus.demo && !w->abacus.aux) {
            DISPLAY_WARNING("Format must not be \"Other\", for demo");
            w->abacus.mode = CHINESE;
      }
      /* If a particular mode, ignore improper settings */
      if (w->abacus.mode == RUSSIAN) {
            w->abacus.decks[BOTTOM].factor = 1;
            w->abacus.decks[TOP].factor = w->abacus.base;
            w->abacus.decks[BOTTOM].number = w->abacus.base;
            w->abacus.decks[TOP].number = 0;
            w->abacus.decks[BOTTOM].orientation = DEFAULTTOPORIENT;
            w->abacus.decks[TOP].orientation = DEFAULTTOPORIENT;
            if (w->abacus.decks[BOTTOM].spaces < DEFAULTBOTTOMSPACES)
                  w->abacus.decks[BOTTOM].spaces = DEFAULTBOTTOMSPACES;
            w->abacus.decks[TOP].spaces = 0;
            w->abacus.decks[TOP].room = w->abacus.decks[TOP].number +
                  w->abacus.decks[TOP].spaces;
            w->abacus.decks[BOTTOM].room = w->abacus.decks[BOTTOM].number +
                  w->abacus.decks[BOTTOM].spaces;
            w->abacus.slot = False;
            w->abacus.diamond = False;
      } else if (w->abacus.mode == JAPANESE || w->abacus.mode == ROMAN) {
            w->abacus.decks[BOTTOM].factor = 1;
            w->abacus.decks[TOP].factor = baseToBottom(w->abacus.base);
            w->abacus.decks[BOTTOM].number = w->abacus.decks[TOP].factor -
                  1;
            w->abacus.decks[TOP].number = w->abacus.base /
                  w->abacus.decks[TOP].factor - 1;
            w->abacus.decks[BOTTOM].orientation = DEFAULTBOTTOMORIENT;
            w->abacus.decks[TOP].orientation = DEFAULTTOPORIENT;
            if (w->abacus.quarter || w->abacus.quarterPercent ) {
                  if ((w->abacus.base == 2 || w->abacus.base == 4) &&
                              w->abacus.decks[BOTTOM].spaces < 3) {
                        w->abacus.decks[BOTTOM].spaces = 3;
                  } else if ((w->abacus.base == 3 ||
                              w->abacus.base == 6 ||
                              w->abacus.base == 9) &&
                              w->abacus.decks[BOTTOM].spaces < 2) {
                        w->abacus.decks[BOTTOM].spaces = 2;
                  }
            } else
                  w->abacus.decks[BOTTOM].spaces =
                        DEFAULTBOTTOMSPACES - 1;
            w->abacus.decks[TOP].spaces = DEFAULTTOPSPACES - 1;
            w->abacus.decks[TOP].room = w->abacus.decks[TOP].number +
                  w->abacus.decks[TOP].spaces;
            w->abacus.decks[BOTTOM].room = w->abacus.decks[BOTTOM].number +
                  w->abacus.decks[BOTTOM].spaces;
            if (w->abacus.mode == JAPANESE) {
                  w->abacus.slot = False;
                  w->abacus.diamond = True;
            }
            if (w->abacus.mode == ROMAN) {
                  w->abacus.slot = True;
                  w->abacus.diamond = False;
            }
      } else if (w->abacus.mode == KOREAN) {
            w->abacus.decks[BOTTOM].factor = 1;
            w->abacus.decks[TOP].factor = baseToBottom(w->abacus.base);
            w->abacus.decks[BOTTOM].number = w->abacus.decks[TOP].factor;
            w->abacus.decks[TOP].number = w->abacus.base /
                  w->abacus.decks[TOP].factor - 1;
            w->abacus.decks[BOTTOM].orientation = DEFAULTBOTTOMORIENT;
            w->abacus.decks[TOP].orientation = DEFAULTTOPORIENT;
            if (w->abacus.quarter || w->abacus.quarterPercent ) {
                  if ((w->abacus.base == 2 || w->abacus.base == 4) &&
                              w->abacus.decks[BOTTOM].spaces < 3) {
                        w->abacus.decks[BOTTOM].spaces = 3;
                  } else if ((w->abacus.base == 3 ||
                              w->abacus.base == 6 ||
                              w->abacus.base == 9) &&
                              w->abacus.decks[BOTTOM].spaces < 2) {
                        w->abacus.decks[BOTTOM].spaces = 2;
                  }
            } else
                  w->abacus.decks[BOTTOM].spaces = DEFAULTBOTTOMSPACES -
                        1;
            w->abacus.decks[TOP].spaces = DEFAULTTOPSPACES - 1;
            w->abacus.decks[TOP].room = w->abacus.decks[TOP].number +
                  w->abacus.decks[TOP].spaces;
            w->abacus.decks[BOTTOM].room = w->abacus.decks[BOTTOM].number +
                  w->abacus.decks[BOTTOM].spaces;
            w->abacus.slot = False;
            w->abacus.diamond = True;
      } else if (w->abacus.mode == CHINESE) {
            w->abacus.decks[BOTTOM].factor = 1;
            w->abacus.decks[TOP].factor = baseToBottom(w->abacus.base);
            w->abacus.decks[BOTTOM].number = w->abacus.decks[TOP].factor;
            w->abacus.decks[TOP].number = w->abacus.base /
                  w->abacus.decks[TOP].factor;
            w->abacus.decks[BOTTOM].orientation = DEFAULTBOTTOMORIENT;
            w->abacus.decks[TOP].orientation = DEFAULTTOPORIENT;
            if (w->abacus.quarter || w->abacus.quarterPercent ) {
                  if ((w->abacus.base == 2 || w->abacus.base == 4) &&
                              w->abacus.decks[BOTTOM].spaces < 3) {
                        w->abacus.decks[BOTTOM].spaces = 3;
                  } else if ((w->abacus.base == 3 ||
                              w->abacus.base == 6 ||
                              w->abacus.base == 9) &&
                              w->abacus.decks[BOTTOM].spaces < 2) {
                        w->abacus.decks[BOTTOM].spaces = 2;
                  }
            } else
                  w->abacus.decks[BOTTOM].spaces = DEFAULTBOTTOMSPACES;
            w->abacus.decks[TOP].spaces = DEFAULTTOPSPACES;
            w->abacus.decks[TOP].room = w->abacus.decks[TOP].number +
                  w->abacus.decks[TOP].spaces;
            w->abacus.decks[BOTTOM].room = w->abacus.decks[BOTTOM].number +
                  w->abacus.decks[BOTTOM].spaces;
            w->abacus.slot = False;
            w->abacus.diamond = False;
      }
      if (w->abacus.demo && !w->abacus.aux) {   /* Trying to keep these at a minimum... */
            if (w->abacus.rails < MINDEMORAILS) {
                  intCat(&buf1, "Number of rails must be at least ",
                        MINDEMORAILS);
                  stringCat(&buf2, buf1, ", for demo");
                  free(buf1);
                  DISPLAY_WARNING(buf2);
                  free(buf2);
                  w->abacus.rails = MINDEMORAILS;
            }
            if (w->abacus.rails - w->abacus.decimalPosition < MINDEMORAILS) {
                  if (w->abacus.quarterPercent) {
                        w->abacus.quarterPercent = False;
                  }
                  if (w->abacus.quarter) {
                        w->abacus.quarter = False;
                  }
                  w->abacus.decimalPosition = 0;
            }
#if 0
            /* Increment and decrement will get goofed up, if enabled. */
            if (!(w->abacus.rails & 1)) {
                  w->abacus.rails++;
                  DISPLAY_WARNING(
                        "Number of rails must be odd, for demo");
            }
#endif
      } else {
            if (w->abacus.rails < MINRAILS) {
                  intCat(&buf1, "Number of rails must be at least ",
                        MINRAILS);
                  DISPLAY_WARNING(buf1);
                  free(buf1);
                  w->abacus.rails = MINRAILS;
            }
            if (w->abacus.decks[TOP].factor < 1 ||
                        w->abacus.decks[TOP].factor > w->abacus.base) {
                  intCat(&buf1, "Factor of Top Beads out of bounds, use 1..",
                        w->abacus.base);
                  DISPLAY_WARNING(buf1);
                  free(buf1);
                  w->abacus.decks[TOP].factor = 5;
            }
            if (w->abacus.decks[BOTTOM].factor < 1 ||
                        w->abacus.decks[BOTTOM].factor >
                        w->abacus.base) {
                  intCat(&buf1,
                        "Factor of Bottom Beads out of bounds, use 1..",
                        w->abacus.base);
                  DISPLAY_WARNING(buf1);
                  free(buf1);
                  w->abacus.decks[BOTTOM].factor = 1;
            }
      }
      if (w->abacus.decks[TOP].number < 0 ||
                  w->abacus.decks[TOP].number > w->abacus.base) {
            intCat(&buf1, "Number of Top Beads out of bounds, use 1..",
                  w->abacus.base);
            DISPLAY_WARNING(buf1);
            free(buf1);
            w->abacus.decks[TOP].number = 2;
      }
      if (w->abacus.decks[BOTTOM].number < 0 ||
                  w->abacus.decks[BOTTOM].number > w->abacus.base) {
            intCat(&buf1, "Number of Bottom Beads out of bounds, use 1..",
                  w->abacus.base);
            DISPLAY_WARNING(buf1);
            free(buf1);
            w->abacus.decks[BOTTOM].number = 5;
      }
      if (w->abacus.decks[TOP].spaces < 0) {
            DISPLAY_WARNING("Number of Top Spaces must be at least 0");
            w->abacus.decks[TOP].spaces = 2;
      }
      if (w->abacus.decks[BOTTOM].spaces < 0) {
            DISPLAY_WARNING("Number of Bottom Spaces must be at least 0");
            w->abacus.decks[BOTTOM].spaces = 2;
      }
      if (w->abacus.decks[TOP].spaces == 0 && w->abacus.decks[BOTTOM].spaces == 0) {
            DISPLAY_WARNING("Number of Top and Bottom Spaces must be at least 1");
            w->abacus.decks[BOTTOM].spaces = 2;
      }
      if (w->abacus.delay < 0) {
            DISPLAY_WARNING("Delay must be at least 0");
            w->abacus.delay = -w->abacus.delay;
      }
}

static Boolean
CheckMove(AbacusWidget w)
{
      int deck_number, deck_position;
      char *buf1, *buf2;

      if (w->abacus.deck < 0 || w->abacus.deck > 2) {
            intCat(&buf1, "Corrupted deck input value ", w->abacus.deck);
            stringCat(&buf2, buf1, " out of bounds, use 0..2, ignoring");
            free(buf1);
            DISPLAY_WARNING(buf2);
            free(buf2);
            return False;
      }
      if (w->abacus.rail < -w->abacus.decimalPosition || w->abacus.rail >
                        w->abacus.rails - w->abacus.decimalPosition) {
            intCat(&buf1, "Number of rails to small for input value ",
                  w->abacus.rail);
            DISPLAY_WARNING(buf1);
            free(buf1);
            return False;
      }
      if (w->abacus.deck == PLACESETTING) {
            /* moving decimal point */
            if (w->abacus.number + w->abacus.decimalPosition >=
                        w->abacus.rails || w->abacus.number +
                        w->abacus.decimalPosition < 0) {
                  intCat(&buf1, "Corrupted number for input value ",
                        w->abacus.number);
                  stringCat(&buf2, buf1, " out of bounds, use ");
                  free(buf1);
                  intCat(&buf1, buf2, -w->abacus.decimalPosition);
                  free(buf2);
                  stringCat(&buf2, buf1, "..");
                  free(buf1);
                  intCat(&buf1, buf2, w->abacus.rails -
                        w->abacus.decimalPosition);
                  free(buf2);
                  DISPLAY_WARNING(buf1);
                  free(buf1);
                  return False;
            }
            return True;
      }
      deck_number = w->abacus.decks[w->abacus.deck].number;
      deck_position = w->abacus.decks[w->abacus.deck].position[w->abacus.rail
            + w->abacus.decimalPosition];
      if (w->abacus.decks[w->abacus.deck].orientation &&
                  (w->abacus.number < -deck_number + deck_position ||
                  w->abacus.number > deck_position)) {
            intCat(&buf1, "Corrupted number for input value ",
                  w->abacus.number);
            stringCat(&buf2, buf1, " out of bounds, use ");
            free(buf1);
            intCat(&buf1, buf2, -deck_number + deck_position);
            free(buf2);
            stringCat(&buf2, buf1, "..");
            free(buf1);
            intCat(&buf1, buf2, deck_position);
            free(buf2);
            DISPLAY_WARNING(buf1);
            free(buf1);
            return False;
      }
      if (!w->abacus.decks[w->abacus.deck].orientation &&
                  (w->abacus.number < -deck_position ||
                  w->abacus.number > deck_number - deck_position)) {
            intCat(&buf1, "Corrupted number for input value ",
                  w->abacus.number);
            stringCat(&buf2, buf1, " out of bounds, use ");
            free(buf1);
            intCat(&buf1, buf2, -deck_position);
            free(buf2);
            stringCat(&buf2, buf1, "..");
            free(buf1);
            intCat(&buf1, buf2, deck_number - deck_position);
            free(buf2);
            DISPLAY_WARNING(buf1);
            free(buf1);
            return False;
      }
      return True;
}

static void
ResetBeads(AbacusWidget w)
{
      int deck, rail;

      w->abacus.currentDeck = -1;
      w->abacus.numDigits = w->abacus.rails + CARRY + 1;
      for (deck = BOTTOM; deck <= TOP; deck++) {
            if (w->abacus.decks[deck].position)
                  (void) free((void *) w->abacus.decks[deck].position);
            if (!(w->abacus.decks[deck].position = (int *)
                        malloc(sizeof (int) * w->abacus.rails))) {
                  DISPLAY_ERROR("Not enough memory, exiting.");
            }
      }
      if (w->abacus.digits)
            (void) free((void *) w->abacus.digits);
      if (!(w->abacus.digits = (char *)
                  malloc(sizeof (char) * w->abacus.numDigits))) {
            DISPLAY_ERROR("Not enough memory, exiting.");
      }
      for (deck = BOTTOM; deck <= TOP; deck++) {
            w->abacus.decks[deck].room = w->abacus.decks[deck].number +
                  w->abacus.decks[deck].spaces;
            for (rail = 0; rail < w->abacus.rails; rail++)
                  w->abacus.decks[deck].position[rail] =
                        (w->abacus.decks[deck].orientation) ?
                        w->abacus.decks[deck].number : 0;
      }
      if (w->abacus.sign) {
            rail = w->abacus.rails - 1;
            w->abacus.decks[BOTTOM].position[rail] =
                  (w->abacus.decks[BOTTOM].orientation) ? 1 : 0;
      }
      if (w->abacus.quarter) {
            rail = w->abacus.decimalPosition - 1;
            w->abacus.decks[BOTTOM].position[rail] =
                  (w->abacus.decks[BOTTOM].orientation) ? QUARTERS : 0;
      }
      if (w->abacus.quarterPercent) {
            rail = w->abacus.decimalPosition - MAX_FRACTION_DIGITS - 1 -
                  ((w->abacus.quarter) ? 1 : 0);
            w->abacus.decks[BOTTOM].position[rail] =
                  (w->abacus.decks[BOTTOM].orientation) ?
                  QUARTERPERCENTS : 0;
      }
      for (rail = 0; rail < w->abacus.numDigits - 1; rail++)
            w->abacus.digits[rail] = '0';
      w->abacus.digits[w->abacus.numDigits - 1] = '\0';
}

static Boolean
EmptyCounter(AbacusWidget w)
{
      int n = 0;

      while (n < w->abacus.numDigits - 2 && w->abacus.digits[n] == '0')
            n++;
      return (n == w->abacus.numDigits - 2 && w->abacus.digits[n] == '0');
}

static void
SetCounter(AbacusWidget w, int deck, int rail, int number)
{
      int n = 0, s = 0, i;
      int m = 0, o = 0, half;
      char *buffer;

      while (n < w->abacus.numDigits - CARRY - w->abacus.decimalPosition &&
                  w->abacus.digits[n] == '0')
            n++;
      while (m < w->abacus.decimalPosition - 1 &&
                  w->abacus.digits[w->abacus.numDigits - CARRY - m] ==
                  '0')
            m++;
      while (o < w->abacus.numDigits - 1 && w->abacus.digits[o] == '0')
            o++;
      half = w->abacus.numDigits - CARRY - w->abacus.decimalPosition - n + 1;
      s = (w->abacus.sign &&
            ((w->abacus.decks[BOTTOM].position[w->abacus.rails - 1] == 1 &&
            !w->abacus.decks[BOTTOM].orientation) ||
            (w->abacus.decks[BOTTOM].position[w->abacus.rails - 1] == 0 &&
            w->abacus.decks[BOTTOM].orientation)) &&
            o < w->abacus.numDigits - 1) ? 1 : 0;
      if (!(buffer = (char *) malloc(sizeof (char) *
                  (w->abacus.numDigits + 12 + sizeofRoman(w->abacus.base,
                  w->abacus.romanNumerals))))) {
            DISPLAY_ERROR("Not enough memory, exiting.");
      }
      if (s == 1)
            buffer[0] = '-';
      for (i = 0; i < half; i++)
            buffer[s + i] = w->abacus.digits[n + i];
      buffer[s + half] = '.';
      if (w->abacus.quarter) {
            char *stringBuf, *finalBuf;

            if (!(stringBuf = (char *) malloc(sizeof (char) *
                        w->abacus.numDigits + 2))) {
                  DISPLAY_ERROR("Not enough memory, exiting.");
            }
            if (!(finalBuf = (char *) malloc(sizeof (char) *
                        w->abacus.numDigits + 2))) {
                  DISPLAY_ERROR("Not enough memory, exiting.");
            }
            dividePieces(stringBuf, w->abacus.base, QUARTERS,
                  (int) w->abacus.digits[n + half] - '0',
                  w->abacus.decimalPosition + 1);
            for (i = 0; i < w->abacus.decimalPosition - m; i++)
                  buffer[s + half + 1 + i] =
                        w->abacus.digits[n + half + 1 + i];
            if (m == w->abacus.decimalPosition - 1)
                  m--;
            buffer[s + half + w->abacus.decimalPosition - m] = '\0';
            addStrings(finalBuf, buffer, stringBuf, w->abacus.base);
            (void) strcpy(buffer, finalBuf);
            (void) free((void *) stringBuf);
            (void) free((void *) finalBuf);
#if 0
      } else if (w->abacus.quarterPercent) {
            char *stringBuf, *finalBuf;

            if (!(stringBuf = (char *) malloc(sizeof (char) *
                        w->abacus.numDigits + 2))) {
                  DISPLAY_ERROR("Not enough memory, exiting.");
            }
            if (!(finalBuf = (char *) malloc(sizeof (char) *
                        w->abacus.numDigits + 2))) {
                  DISPLAY_ERROR("Not enough memory, exiting.");
            }
            dividePieces(stringBuf, w->abacus.base, QUARTERPERCENTS,
                  (int) w->abacus.digits[n + half] - '0',
                  w->abacus.decimalPosition + 1);
            for (i = 0; i < w->abacus.decimalPosition - m; i++)
                  buffer[s + half + 1 + i] =
                        w->abacus.digits[n + half + 1 + i];
            if (m == w->abacus.decimalPosition - 1)
                  m--;
            buffer[s + half + w->abacus.decimalPosition - m] = '\0';
            addStrings(finalBuf, buffer, stringBuf, w->abacus.base);
            (void) strcpy(buffer, finalBuf);
            (void) free((void *) stringBuf);
            (void) free((void *) finalBuf);
#endif
      } else {
            int offset = w->abacus.decimalPosition - m + 1;

            if (offset < 0)
                  offset = 0;
            for (i = 0; i < offset; i++)
                  buffer[s + half + 1 + i] =
                        w->abacus.digits[n + half + i];
#if 0
            if (offset == 0) {
                  buffer[s + half + 1] = '0';
                  buffer[s + half + 2] = '\0';
            } else
#endif
                  buffer[s + half + offset] = '\0';
      }
      if (w->abacus.script) {
#ifdef SCRIPTFILE
            (void) fprintf(w->abacus.fp, "%d %d %d %d 4\n", PRIMARY, deck,
                  rail - w->abacus.decimalPosition, number);
            (void) fprintf(w->abacus.fp, "Lesson\n\n\nPress Space-bar\n");
#else
            SetAbacusMove(w, ABACUS_SCRIPT, PRIMARY /* FIXME */, deck,
                  rail - w->abacus.decimalPosition, number);
#endif
      }
      if (w->abacus.base != w->abacus.displayBase) {
            char buff[1024];

            convertString(buff, buffer, w->abacus.base,
                  w->abacus.displayBase, w->abacus.decimalPosition);
            (void) free((void *) buffer);
            if (!(buffer = (char *) malloc(sizeof (char) * 1024))) {
                  DISPLAY_ERROR("Not enough memory, exiting.");
            }
            (void) strcpy(buffer, buff);
      }
      if (w->abacus.romanNumerals) {
            char * romanString;

            (void) strcat(buffer, "          ");
            if (!(romanString = (char *) malloc(sizeof (char) *
                        sizeofRoman(w->abacus.displayBase,
                        w->abacus.romanNumerals)))) {
                  DISPLAY_ERROR("Not enough memory, exiting.");
            }
            (void) string2Roman(romanString, buffer, w->abacus.displayBase);
            (void) strcat(buffer, romanString);
            (void) free((void *) romanString);
      }
      SetAbacusString(w, ABACUS_IGNORE, buffer);
      (void) free((void *) buffer);
}

static void
DrawDecimalSeparator(AbacusWidget w, Boolean show)
{
      int x, y;
      GC gc = ((show) ? w->abacus.beadShadeGC[1] : w->abacus.inverseGC);
      Pixmap dr = 0;

      x = 1 - w->abacus.railWidth / 2 + w->abacus.offset.x +
            (w->abacus.rails - w->abacus.decimalPosition) *
            w->abacus.pos.x - (w->abacus.pos.x - 1) / 2;
      y = w->abacus.decks[TOP].room * w->abacus.pos.y + w->abacus.delta.y -
            1 + w->abacus.offset.y;
      if (w->abacus.vertical) {
            y = w->abacus.frameSize.y - 1 - y;
            FILLRECTANGLE(w, dr, gc,
                  y - w->abacus.midHeight, x,
                  w->abacus.midHeight, w->abacus.railWidth + 3);
      } else {
            FILLRECTANGLE(w, dr, gc, x, y, w->abacus.railWidth + 4,
                  w->abacus.midHeight);
      }
}

#ifdef WINVER
#if 0
static void
POLYGON(AbacusWidget w, GC color, GC lineColor,
            const POINT * poly, int n, Boolean origin)
{
      /* CoordModePrevious -> CoordModeOrigin */
      POINT *temp = NULL;
      int pt;

      if (!origin) {
            if (!(temp = (POINT *) malloc(sizeof (POINT) * n))) {
                  DISPLAY_ERROR("Not enough memory, exiting.");
            }
            temp[0] = poly[0];
            for (pt = 1; pt < n; pt++) {
                  temp[pt].x = temp[pt - 1].x + poly[pt].x;
                  temp[pt].y = temp[pt - 1].y + poly[pt].y;
            }
      }
      w->abacus.hPen = CreatePen(PS_SOLID, 1, lineColor);
      w->abacus.hOldPen = (HPEN) SelectObject(w->core.hDC, w->abacus.hPen);
      w->abacus.hBrush = CreateSolidBrush(color);
      w->abacus.hOldBrush = (HBRUSH) SelectObject(w->core.hDC,
            w->abacus.hBrush);
      (void) Polygon(w->core.hDC, (origin) ? poly : temp, n);
      (void) SelectObject(w->core.hDC, w->abacus.hOldBrush);
      (void) DeleteObject(w->abacus.hBrush);
      (void) SelectObject(w->core.hDC, w->abacus.hOldPen);
      (void) DeleteObject(w->abacus.hPen);
      if (!origin) {
            free(temp);
      }
}
#endif

static void
BUFFPOLY(AbacusWidget w, Pixmap dr, GC color, GC lineColor,
            const POINT * poly, int n, Boolean origin)
{
      /* CoordModePrevious -> CoordModeOrigin */
      POINT *temp = NULL;
      int pt;

      if (!origin) {
            if (!(temp = (POINT *) malloc(sizeof (POINT) * n))) {
                  DISPLAY_ERROR("Not enough memory, exiting.");
            }
            temp[0] = poly[0];
            for (pt = 1; pt < n; pt++) {
                  temp[pt].x = temp[pt - 1].x + poly[pt].x;
                  temp[pt].y = temp[pt - 1].y + poly[pt].y;
            }
      }
      w->abacus.hOldBitmap = SelectObject(w->abacus.memDC, dr);
      w->abacus.hPen = CreatePen(PS_SOLID, 1, lineColor);
      w->abacus.hOldPen = (HPEN) SelectObject(w->abacus.memDC,
            w->abacus.hPen);
      w->abacus.hBrush = CreateSolidBrush(color);
      w->abacus.hOldBrush = (HBRUSH) SelectObject(w->abacus.memDC,
            w->abacus.hBrush);
      (void) Polygon(w->abacus.memDC, (origin) ? poly : temp, n);
      (void) SelectObject(w->abacus.memDC, w->abacus.hOldBrush);
      (void) DeleteObject(w->abacus.hBrush);
      (void) SelectObject(w->abacus.memDC, w->abacus.hOldPen);
      (void) DeleteObject(w->abacus.hPen);
      (void) SelectObject(w->abacus.memDC, w->abacus.hOldBitmap);
      if (!origin) {
            free(temp);
      }
}
#else
#define POLYGON(w,c,lc,l,n,o) XFillPolygon(XtDisplay(w), XtWindow(w), c, \
  l, n, Convex, (o) ? CoordModeOrigin : CoordModePrevious); \
  XDrawLines(XtDisplay(w), XtWindow(w), lc, \
  l, (n)+1,(o) ? CoordModeOrigin : CoordModePrevious)
#define BUFFPOLY(w,dr,c,lc,l,n,o) XFillPolygon(XtDisplay(w), dr, c, \
  l, n, Convex, (o) ? CoordModeOrigin : CoordModePrevious); \
  XDrawLines(XtDisplay(w), dr, lc, \
  l, (n)+1,(o) ? CoordModeOrigin : CoordModePrevious)
#endif

static void
DrawGroupSeparator(AbacusWidget w, int separatorPosition, Boolean show)
{
      GC gc = ((show) ? w->abacus.beadShadeGC[1] : w->abacus.inverseGC);
      int x, y;
      Pixmap dr = 0;

      x = 1 - w->abacus.railWidth / 2 + w->abacus.offset.x +
            (w->abacus.rails - w->abacus.decimalPosition -
            separatorPosition) *
            w->abacus.pos.x - (w->abacus.pos.x - 1) / 2;
      y = w->abacus.decks[TOP].room * w->abacus.pos.y + w->abacus.delta.y -
            1 + w->abacus.offset.y;
      FILLRECTANGLE(w, dr, gc, x + 1, y + 1, w->abacus.railWidth + 2,
            w->abacus.midHeight - 2);
      FILLRECTANGLE(w, dr, gc, x, y + (w->abacus.midHeight - 1) / 2,
            1, (w->abacus.midHeight - 1) % 2 + 1);
      FILLRECTANGLE(w, dr, gc, x + w->abacus.railWidth + 3,
            y + (w->abacus.midHeight - 1) / 2,
            1, (w->abacus.midHeight - 1) % 2 + 1);
      FILLRECTANGLE(w, dr, gc, x + (w->abacus.railWidth + 1) / 2 + 1, y,
            (w->abacus.railWidth + 1) % 2 + 1, 1);
      FILLRECTANGLE(w, dr, gc, x + (w->abacus.railWidth + 1) / 2 + 1,
            y + w->abacus.midHeight - 1,
            (w->abacus.railWidth + 1) % 2 + 1, 1);
}

static void
DrawAllGroupSeparators(AbacusWidget w, Boolean show)
{
      int separator;

      for (separator = 1; separator <= ((w->abacus.rails -
                  ((w->abacus.sign) ? 1 : 0) -
                  w->abacus.decimalPosition - 1) / GROUPING_SIZE);
                  separator++)
            DrawGroupSeparator(w, GROUPING_SIZE * separator, show);
}

static void
EraseFrame(const AbacusWidget w, Pixmap dr)
{
      FILLRECTANGLE(w, dr, w->abacus.inverseGC,
            0, 0, w->core.width, w->core.height);
}

static void
DrawFrame(const AbacusWidget w, Pixmap dr, Boolean show, Boolean focus)
{
      int deck, x, y, yOffset;
      GC gc = (show) ? ((focus) ? w->abacus.frameGC : w->abacus.borderGC) :
            w->abacus.inverseGC;

      x = w->abacus.rails * w->abacus.pos.x + w->abacus.delta.x - 1;
      if (w->abacus.vertical) {
            /* Left */
            FILLRECTANGLE(w, dr, gc,
                  0, 0, w->abacus.frameSize.y, w->abacus.offset.x + 1);
            /* Right */
            FILLRECTANGLE(w, dr, gc, 0, x + w->abacus.offset.x,
                  w->abacus.frameSize.y,
                  w->abacus.frameSize.x - (x + w->abacus.offset.x));
      } else {
            /* Left */
            FILLRECTANGLE(w, dr, gc,
                  0, 0, w->abacus.offset.x + 1, w->abacus.frameSize.y);
            /* Right */
            FILLRECTANGLE(w, dr, gc, x + w->abacus.offset.x, 0,
                  w->abacus.frameSize.x - (x + w->abacus.offset.x),
                  w->abacus.frameSize.y);
      }
      for (deck = UP; deck >= DOWN; deck--) {
            yOffset = (deck == UP) ? 0 : w->abacus.decks[TOP].height;
            y = w->abacus.decks[deck].room * w->abacus.pos.y +
                  w->abacus.delta.y - 1;
            if (deck == UP) {
                if (w->abacus.vertical) {
                  /* Top */
                  FILLRECTANGLE(w, dr, gc,
                        yOffset - 1,
                        w->abacus.offset.x + 1,
                        w->abacus.offset.y + 1,
                        x - 1);
                  /* Middle */
                  FILLRECTANGLE(w, dr, gc,
                        w->abacus.frameSize.y - 1 - (y + yOffset + w->abacus.offset.y) - w->abacus.midHeight,
                        w->abacus.offset.x + 1,
                        w->abacus.midHeight,
                        x - 1);
                } else {
                  /* Top */
                  FILLRECTANGLE(w, dr, gc,
                        w->abacus.offset.x + 1,
                        yOffset - 1,
                        x - 1,
                        w->abacus.offset.y + 1);
                  /* Middle */
                  FILLRECTANGLE(w, dr, gc,
                        w->abacus.offset.x + 1,
                        y + yOffset + w->abacus.offset.y,
                        x - 1,
                        w->abacus.midHeight);
                }
                DrawDecimalSeparator(w, show);
                DrawAllGroupSeparators(w, show);
            } else {
                if (w->abacus.vertical) {
                  /* Bottom */
                  FILLRECTANGLE(w, dr, gc,
                        y + yOffset + w->abacus.offset.y,
                        w->abacus.offset.x + 1,
                        w->abacus.frameSize.y - (y + yOffset + w->abacus.offset.y),
                        x - 1);
                } else {
                  /* Bottom */
                  FILLRECTANGLE(w, dr, gc,
                        w->abacus.offset.x + 1,
                        y + yOffset + w->abacus.offset.y + w->abacus.midHeight - 3,
                        x - 1,
                        w->abacus.frameSize.y - (y + yOffset + w->abacus.offset.y + w->abacus.midHeight - 3));
                }
            }
      }
}

static void
FillRectClipY(AbacusWidget w, Pixmap dr, GC gc, int dx, int dy, int sx, int sy,
            int oy, int woy, int wsy)
{
      int noy = oy, nsy = sy;

      if (oy + sy < woy || oy > woy + wsy || wsy <= 0)
            return;
      if (noy < woy) {
            noy = woy;
            nsy = sy - woy + oy;
      }
      if (noy + nsy > woy + wsy) {
            nsy = wsy + woy - noy;
      }
      FILLRECTANGLE(w, dr, gc, dx, dy + noy, sx, nsy);
}

static void
DrawRail(AbacusWidget w, const int deck, const int rail, const int j,
             const int offset, const int size)
{
      int dx, dy, yOffset;
      Pixmap dr = 0;

      yOffset = (deck == UP) ? 0 :
            w->abacus.decks[TOP].height + w->abacus.midHeight - 3;
      dx = (w->abacus.rails - rail - 1) * w->abacus.pos.x +
            w->abacus.delta.x + w->abacus.offset.x;
      dy = (j - 1) * w->abacus.pos.y + w->abacus.delta.y +
            yOffset + w->abacus.offset.y - 2;
      if (w->abacus.vertical) {
            FILLRECTANGLE(w, dr, w->abacus.inverseGC,
              dy + 1, dx,
              size - 2, w->abacus.beadSize.x + 2);
      } else {
            FillRectClipY(w, dr, w->abacus.inverseGC,
              dx, dy,
              w->abacus.beadSize.x + 2, w->abacus.beadSize.y + 3,
              0, offset, size);
            if (w->abacus.slot && j == 1) {
              FillRectClipY(w, dr, w->abacus.borderGC,
                dx + w->abacus.beadSize.x / 2 - w->abacus.railWidth / 2,
                dy,
                w->abacus.railWidth,
                5 * w->abacus.beadSize.y / 8 + 4,
                3 * w->abacus.beadSize.y / 8, offset, size);
              /* round off the top of rail */
              FillRectClipY(w, dr, w->abacus.inverseGC,
                dx + w->abacus.beadSize.x / 2 - w->abacus.railWidth / 2,
                dy,
                1, 1, 3 * w->abacus.beadSize.y / 8, offset, size);
              FillRectClipY(w, dr, w->abacus.inverseGC,
                dx + w->abacus.beadSize.x / 2 + (w->abacus.railWidth - 1) / 2,
                dy,
                1, 1, 3 * w->abacus.beadSize.y / 8, offset, size);
            } else if (w->abacus.slot &&
                j == w->abacus.decks[deck].room) {
              FillRectClipY(w, dr, w->abacus.borderGC,
                dx + w->abacus.beadSize.x / 2 - w->abacus.railWidth / 2,
                dy,
                w->abacus.railWidth,
                5 * w->abacus.beadSize.y / 8 + 3, 0, offset, size);
              /* round off the bottom of rail */
              FillRectClipY(w, dr, w->abacus.inverseGC,
                dx + w->abacus.beadSize.x / 2 - w->abacus.railWidth / 2,
                dy,
                1, 1, 2 + 5 * w->abacus.beadSize.y / 8, offset, size);
              FillRectClipY(w, dr, w->abacus.inverseGC,
                dx + w->abacus.beadSize.x / 2 + (w->abacus.railWidth - 1) / 2,
                dy,
                1, 1, 2 + 5 * w->abacus.beadSize.y / 8, offset, size);
            } else {
              FillRectClipY(w, dr, (w->abacus.slot) ?
                w->abacus.borderGC : w->abacus.railGC,
                dx + w->abacus.beadSize.x / 2 - w->abacus.railWidth / 2,
                dy, w->abacus.railWidth, w->abacus.beadSize.y + 3,
                0, offset, size);
            }
      }
}

static void
DrawBead(AbacusWidget w, const int deck, const int rail, const int bead,
            const int j, const Boolean show, const Boolean moving,
            const int pressedOffset,
            const int offsetX, const int offsetY)
{
      int dx, dy, yOffset, special = 0;
      Pixmap dr = 0;

      yOffset = (deck == UP) ? 0 :
            w->abacus.decks[TOP].height + w->abacus.midHeight - 3;
      dx = (w->abacus.rails - rail - 1) * w->abacus.pos.x +
            w->abacus.delta.x + w->abacus.offset.x + offsetX;
      dy = (j - 1) * w->abacus.pos.y + w->abacus.delta.y +
            yOffset + w->abacus.offset.y - 1 + offsetY;
      if (show) {
            if ((rail == w->abacus.rails - 1) && w->abacus.sign) {
                  special++;
            } else if (w->abacus.quarter &&
                  (rail == w->abacus.decimalPosition - 1)) {
              if (w->abacus.decks[(deck == TOP) ? BOTTOM : TOP].spaces == 0) {
                  if (bead == QUARTERS / 2 || bead == QUARTERS / 2 + 1) {
                    special++;
                  }
              } else {
                  special++;
              }
            } else if (w->abacus.quarterPercent &&
                  (rail == w->abacus.decimalPosition -
                  MAX_FRACTION_DIGITS - 1 -
                  ((w->abacus.quarter) ? 1 : 0))) {
              if (w->abacus.decks[(deck == TOP) ? BOTTOM : TOP].spaces == 0) {
                  if (bead == QUARTERPERCENTS / 2 ||
                              bead == QUARTERPERCENTS / 2 + 1) {
                    special++;
                  }
              } else {
                  special++;
              }
            } else if (!((rail == w->abacus.rails - 1) && w->abacus.sign) &&
              w->abacus.decks[(deck == TOP) ? BOTTOM : TOP].spaces == 0) {
#if 0
                ( (j - 1 == w->abacus.base / 2 +
                ((w->abacus.decks[deck].position[rail] <
                w->abacus.base / 2 + 1) ? w->abacus.decks[deck].spaces : 0)) ||
                ((j == w->abacus.base / 2 +
                ((w->abacus.decks[deck].position[rail] <
                w->abacus.base / 2) ? w->abacus.decks[deck].spaces : 0)) &&
                (w->abacus.base % 2 == 0)) ))
#else
              if ((((bead == w->abacus.base / 2) && ((w->abacus.base & 1) == 0)) ||
                  bead == w->abacus.base / 2 + 1) && w->abacus.base > 2)
#endif
              {
              /* If you slow this down you can see the errors */
                  special++;
              }
            }
            dx += pressedOffset;
            dy += pressedOffset;
#if 0
      if (w->abacus.vertical) {
            if (pressedOffset == 0) {
                /* Draw the rail around bead */
                if (!w->abacus.slot || j != 1) {
                  FILLRECTANGLE(w, dr, (w->abacus.slot) ?
                        w->abacus.borderGC : w->abacus.railGC,
                        w->abacus.frameSize.y - dy - 2,
                        dx + w->abacus.beadSize.x / 2 - w->abacus.railWidth / 2,
                        3, w->abacus.railWidth);
                }
                if (!w->abacus.slot || j != w->abacus.decks[deck].room) {
                  FILLRECTANGLE(w, dr, (w->abacus.slot) ?
                        w->abacus.borderGC : w->abacus.railGC,
                        w->abacus.frameSize.y - 4 - dy - w->abacus.beadSize.y,
                        dx + w->abacus.beadSize.x / 2 - w->abacus.railWidth / 2,
                        3, w->abacus.railWidth);
                }
            }
      } else
#endif
      {
            if (!moving && pressedOffset == 0) {
                /* Draw the rail around bead, do not draw too much */
                FILLRECTANGLE(w, dr, w->abacus.inverseGC,
                        dx,
                        dy + w->abacus.beadSize.y + 1,
                        w->abacus.beadSize.x, 1);
                if (!w->abacus.slot || j != 1) {
                  FILLRECTANGLE(w, dr, (w->abacus.slot) ?
                        w->abacus.borderGC : w->abacus.railGC,
                        dx + w->abacus.beadSize.x / 2 - w->abacus.railWidth / 2,
                        dy - 1, w->abacus.railWidth, 3);
                }
                if (!w->abacus.slot || j != w->abacus.decks[deck].room) {
                  FILLRECTANGLE(w, dr, (w->abacus.slot) ?
                        w->abacus.borderGC : w->abacus.railGC,
                        dx + w->abacus.beadSize.x / 2 - w->abacus.railWidth / 2,
                        dy + w->abacus.beadSize.y - 1, w->abacus.railWidth, 3);
                }
            } else {
                /* Normally I would let this go but it does not look right */
                FILLRECTANGLE(w, dr, w->abacus.inverseGC,
                        dx - pressedOffset,
                        dy - pressedOffset,
                        w->abacus.beadSize.x, 1);
                FILLRECTANGLE(w, dr, w->abacus.inverseGC,
                        dx - pressedOffset,
                        dy - pressedOffset,
                        1, w->abacus.beadSize.y);
                if (!w->abacus.slot || j != 1) {
                  FILLRECTANGLE(w, dr, (w->abacus.slot) ?
                        w->abacus.borderGC : w->abacus.railGC,
                        dx + w->abacus.beadSize.x / 2 - w->abacus.railWidth / 2 - pressedOffset,
                        dy - pressedOffset, w->abacus.railWidth, 1);
                }
            }
#ifdef WINVER
            w->abacus.hOldBitmap = (HBITMAP) SelectObject(w->abacus.memDC,
                  w->abacus.bufferBead[pressedOffset][special]);
            BitBlt(w->core.hDC,
                  dx, dy,
                  w->abacus.beadSize.x + 1, w->abacus.pos.y - 1,
                  w->abacus.memDC,
                  0, 0,
                  SRCCOPY);
            SelectObject(w->abacus.memDC, w->abacus.hOldBitmap);
#else
            XSetGraphicsExposures(XtDisplay(w), w->abacus.frameGC, False);
            XCopyArea(XtDisplay(w),
                  w->abacus.bufferBead[pressedOffset][special],
                  XtWindow(w),
                  w->abacus.frameGC,
                  0, 0,
                  w->abacus.beadSize.x + 1, w->abacus.pos.y - 1,
                  dx, dy);
#endif
      }
      } else {
          DrawRail(w, deck, rail, j, pressedOffset, w->abacus.beadSize.y + 3);
      }

}

static void
DrawBufferedBead(AbacusWidget w, const int pressedOffset, const int special)
{
      int shadeFill, shadeLine, shadeDot;
      Pixmap *dr;

      dr = &(w->abacus.bufferBead[pressedOffset][special]);
      if (pressedOffset == 1) {
#ifdef INSIDEOUT
            if (w->abacus.diamond) {
                  shadeDot = 2;
                  shadeLine = shadeFill = 1;
            } else {
#endif
            shadeFill = 2;
            shadeLine = shadeDot = 1;
#ifdef INSIDEOUT
            }
#endif
      } else {
            shadeFill = 1;
            shadeLine = 2;
            shadeDot = 0;
      }
      if (special == 1) {
            shadeFill++;
            shadeLine++;
            shadeDot++;
      }
      if (w->abacus.vertical) {
            FILLRECTANGLE(w, *dr, w->abacus.inverseGC,
                  0, 0, w->abacus.pos.y - 1, w->abacus.beadSize.x + 1);
      } else {
            FILLRECTANGLE(w, *dr, w->abacus.inverseGC,
                  0, 0, w->abacus.beadSize.x + 1, w->abacus.pos.y - 1);
            if (w->abacus.diamond) {
                  Point tempList[5];
                  int railWid = MIN(w->abacus.beadSize.x - 5,
                        w->abacus.railWidth);

                  tempList[0].x = w->abacus.beadSize.x / 2 +
                        (railWid - 1) / 2 + 2;
                  tempList[0].y = w->abacus.beadSize.y;
                  tempList[1].x = w->abacus.beadSize.x / 2 -
                        railWid / 2 - 2;
                  tempList[1].y = w->abacus.beadSize.y;
                  tempList[2].x = 0;
                  tempList[2].y = w->abacus.beadSize.y / 2;
                  tempList[3].x = w->abacus.beadSize.x;
                  tempList[3].y = w->abacus.beadSize.y / 2;
                  tempList[4].x = w->abacus.beadSize.x / 2 +
                        (railWid - 1) / 2 + 2;
                  tempList[4].y = w->abacus.beadSize.y;
                  BUFFPOLY(w, *dr, w->abacus.beadShadeGC[shadeFill],
                        w->abacus.beadShadeGC[shadeFill],
                        tempList, 4, True);
                  tempList[0].x = w->abacus.beadSize.x / 2 -
                        railWid / 2 - 2;
                  tempList[0].y = 0;
                  tempList[1].x = w->abacus.beadSize.x / 2 +
                        (railWid - 1) / 2 + 2;
                  tempList[1].y = 0;
                  tempList[2].x = w->abacus.beadSize.x;
                  tempList[2].y = w->abacus.beadSize.y / 2;
                  tempList[3].x = 0;
                  tempList[3].y = w->abacus.beadSize.y / 2;
                  tempList[4].x = w->abacus.beadSize.x / 2 -
                        railWid / 2 - 2;
                  tempList[4].y = 0;
                  BUFFPOLY(w, *dr, w->abacus.beadShadeGC[shadeDot],
                        w->abacus.beadShadeGC[shadeDot],
                        tempList, 4, True);
            } else {
                if (w->abacus.beadSize.x > w->abacus.beadSize.y) {
                  DRAWCIRCLE(w, *dr, w->abacus.beadShadeGC[shadeLine],
                        w->abacus.beadSize.y - 1,
                        w->abacus.beadSize.x / 2 -
                        (w->abacus.beadSize.x - w->abacus.beadSize.y) / 2,
                        (w->abacus.beadSize.y - 1) / 2);
                  DRAWCIRCLE(w, *dr, w->abacus.beadShadeGC[shadeLine],
                        w->abacus.beadSize.y - 1,
                        w->abacus.beadSize.x / 2 +
                        (w->abacus.beadSize.x - w->abacus.beadSize.y) / 2,
                        (w->abacus.beadSize.y - 1) / 2);
                  DRAWRECTANGLE(w, *dr, w->abacus.beadShadeGC[shadeLine],
                        w->abacus.beadSize.x / 2 -
                        (w->abacus.beadSize.x - w->abacus.beadSize.y) / 2, 0,
                        w->abacus.beadSize.x - w->abacus.beadSize.y, w->abacus.beadSize.y);
                  FILLCIRCLE(w, *dr, w->abacus.beadShadeGC[shadeFill],
                        w->abacus.beadSize.y - 1,
                        w->abacus.beadSize.x / 2 -
                        (w->abacus.beadSize.x - w->abacus.beadSize.y) / 2,
                        (w->abacus.beadSize.y - 1) / 2);
                  FILLCIRCLE(w, *dr, w->abacus.beadShadeGC[shadeFill],
                        w->abacus.beadSize.y - 1,
                        w->abacus.beadSize.x / 2 +
                     (w->abacus.beadSize.x - w->abacus.beadSize.y) / 2,
                        (w->abacus.beadSize.y - 1) / 2);
                  FILLRECTANGLE(w, *dr, w->abacus.beadShadeGC[shadeFill],
                        w->abacus.beadSize.x / 2 -
                      (w->abacus.beadSize.x - w->abacus.beadSize.y) / 2, 0,
                        w->abacus.beadSize.x - w->abacus.beadSize.y,
                        w->abacus.beadSize.y);
#ifdef INSIDEOUT
                   if (pressedOffset == 0) {
#endif
                        FILLCIRCLE(w, *dr, w->abacus.beadShadeGC[shadeDot],
                              w->abacus.beadSize.y / 6,
                              -w->abacus.beadSize.y / 5 +
                              w->abacus.beadSize.x / 2 -
                     (w->abacus.beadSize.x - w->abacus.beadSize.y) / 2,
                              -w->abacus.beadSize.y  / 5 +
                              (w->abacus.beadSize.y - 1) / 2);
#ifdef INSIDEOUT
                      } else {
                        FILLCIRCLE(w, *dr, w->abacus.beadShadeGC[shadeDot],
                              w->abacus.beadSize.y / 6,
                              w->abacus.beadSize.y / 5 +
                              w->abacus.beadSize.x / 2 +
                     (w->abacus.beadSize.x - w->abacus.beadSize.y) / 2,
                              w->abacus.beadSize.y  / 5 +
                              (w->abacus.beadSize.y - 1) / 2);
                      }
#endif
                  } else if (w->abacus.beadSize.x < w->abacus.beadSize.y) {
                      DRAWCIRCLE(w, *dr, w->abacus.beadShadeGC[shadeLine],
                        w->abacus.beadSize.x - 1,
                        (w->abacus.beadSize.x - 1) / 2,
                        w->abacus.beadSize.y / 2 - 1 -
                    (w->abacus.beadSize.y - w->abacus.beadSize.x) / 2);
                      DRAWCIRCLE(w, *dr, w->abacus.beadShadeGC[shadeLine],
                        w->abacus.beadSize.x - 1,
                        (w->abacus.beadSize.x - 1) / 2 ,
                        w->abacus.beadSize.y / 2 + 1 +
                    (w->abacus.beadSize.y - w->abacus.beadSize.x) / 2);
                      DRAWRECTANGLE(w, *dr, w->abacus.beadShadeGC[shadeLine],
                        0, w->abacus.beadSize.y / 2 - 1 -
                     (w->abacus.beadSize.y - w->abacus.beadSize.x) / 2,
                        w->abacus.beadSize.x, w->abacus.beadSize.y - w->abacus.beadSize.x + 2);
                       FILLCIRCLE(w, *dr, w->abacus.beadShadeGC[shadeFill],
                        w->abacus.beadSize.x - 1,
                        (w->abacus.beadSize.x - 1) / 2,
                        w->abacus.beadSize.y / 2 - 1 -
                    (w->abacus.beadSize.y - w->abacus.beadSize.x) / 2);
                       FILLCIRCLE(w, *dr, w->abacus.beadShadeGC[shadeFill],
                        w->abacus.beadSize.x - 1,
                        (w->abacus.beadSize.x - 1) / 2,
                        w->abacus.beadSize.y / 2 + 1 +
                    (w->abacus.beadSize.y - w->abacus.beadSize.x) / 2);
                      FILLRECTANGLE(w, *dr, w->abacus.beadShadeGC[shadeFill],
                        0, w->abacus.beadSize.y / 2 -
                     (w->abacus.beadSize.y - w->abacus.beadSize.x) / 2,
                        w->abacus.beadSize.x, w->abacus.beadSize.y - w->abacus.beadSize.x + 2);
#ifdef INSIDEOUT
                      if (pressedOffset == 0) {
#endif
                        FILLCIRCLE(w, *dr, w->abacus.beadShadeGC[shadeDot],
                              w->abacus.beadSize.x / 6,
                        -w->abacus.beadSize.x / 5 +
                        (w->abacus.beadSize.x - 1) / 2,
                        -w->abacus.beadSize.x / 5 +
                         w->abacus.beadSize.y / 2 -
                     (w->abacus.beadSize.y - w->abacus.beadSize.x) / 2);
#ifdef INSIDEOUT
                      } else {
                        FILLCIRCLE(w, *dr, w->abacus.beadShadeGC[shadeDot],
                              w->abacus.beadSize.x / 6,
                        w->abacus.beadSize.x / 5 +
                        (w->abacus.beadSize.x - 1) / 2,
                        w->abacus.beadSize.x / 5 +
                        w->abacus.beadSize.y / 2 +
                     (w->abacus.beadSize.y - w->abacus.beadSize.x) / 2);
                      }
#endif
                  } else {
                      DRAWCIRCLE(w, *dr, w->abacus.beadShadeGC[shadeLine],
                        w->abacus.beadSize.y - 1,
                        (w->abacus.beadSize.x - 1) / 2,
                        (w->abacus.beadSize.y - 1) / 2);
                      FILLCIRCLE(w, *dr, w->abacus.beadShadeGC[shadeFill],
                        w->abacus.beadSize.y - 1,
                        (w->abacus.beadSize.x - 1) / 2,
                        (w->abacus.beadSize.y - 1) / 2);
                      if (pressedOffset == 0) {
                        FILLCIRCLE(w, *dr, w->abacus.beadShadeGC[shadeDot],
                              w->abacus.beadSize.x / 6,
                        -w->abacus.beadSize.x / 5 +
                        (w->abacus.beadSize.x - 1) / 2,
                        -w->abacus.beadSize.x / 5 +
                         (w->abacus.beadSize.y - 1) / 2);
                      } else {
                        FILLCIRCLE(w, *dr, w->abacus.beadShadeGC[shadeDot],
                              w->abacus.beadSize.x / 6,
                        w->abacus.beadSize.x / 5 +
                        (w->abacus.beadSize.x - 1) / 2,
                        w->abacus.beadSize.x / 5 +
                         (w->abacus.beadSize.y - 1) / 2);
                      }
                  }
            }
      }

}

static void
DrawAllBufferedBeads(AbacusWidget w)
{
      int pressedOffset, shade;

      for (pressedOffset = 0; pressedOffset < 2; pressedOffset++) {
            for (shade = 0; shade < 2; shade++) {
                  DrawBufferedBead(w, pressedOffset, shade);
            }
      }
}

static void
AnimateSlide(AbacusWidget w, int deck, int rail, int bead, int j, int spaces,
            int dir, int delay)
{
      int space, inc, aBead, numBeads;
      int gapJ;
      int posOff, beadOff;

      if (dir == UP)
            numBeads = bead - w->abacus.decks[deck].position[rail];
      else
            numBeads = w->abacus.decks[deck].position[rail] - bead + 1;
#if 0
printf("deck %d, rail %d, bead %d, j %d, spaces %d, dir %d, numBeads %d\n",
deck, rail, bead, j, spaces, dir, numBeads);
if (inc== 0) {
printf("    aBead %d, posOff %d, b %d, p %d\n", aBead, posOff,
            bead + ((dir == UP) ? -aBead : aBead), j);
}
#endif
      for (space = 0; space < spaces; space++) {
        gapJ = w->abacus.pos.y / w->abacus.numSlices;
        if (gapJ == 0)
          gapJ++;
        initTimer(w);
        for (inc = 0; inc < w->abacus.pos.y + gapJ; inc += gapJ) {
          if (inc > w->abacus.pos.y) {
            gapJ = w->abacus.pos.y + gapJ - inc;
            inc = w->abacus.pos.y;
          }
          for (aBead = numBeads - 1; aBead >= 0; aBead--) {
            beadOff = NEWPOS(dir, aBead);
            posOff = NEWPOS(dir, (aBead + space));
            /* actual bead, bead position */
            DrawBead(w, deck, rail, bead + beadOff, j,
            True, True, FALSE, 0,
            NEWPOS(dir, inc) + posOff * w->abacus.pos.y);
            /* Erase old slivers */
            if (dir == UP) {
            DrawRail(w, deck, rail, j + posOff,
              w->abacus.pos.y - inc, gapJ);
            } else {
            DrawRail(w, deck, rail, j + posOff,
              inc - gapJ + 1, gapJ);
            }
          }
          useTimer(w, delay);
        }
      }
}

static void
AddBead(AbacusWidget w, const int d, const int p)
{
      int position = w->abacus.numDigits - 2 - p;
      int digit = char2Int(w->abacus.digits[position]);

      digit += d;
      w->abacus.digits[position] = int2Char(digit % w->abacus.base);
      if (digit >= w->abacus.base) {
            if ((w->abacus.quarter && (p + 1 == w->abacus.decimalPosition - 1)) ||
                (w->abacus.quarterPercent && (p + 1 == w->abacus.decimalPosition -
            MAX_FRACTION_DIGITS - 1 - ((w->abacus.quarter) ? 1 : 0))))
                  AddBead(w, digit / w->abacus.base, p + 2);
            else
                  AddBead(w, digit / w->abacus.base, p + 1);
      }
}

static void
SubBead(AbacusWidget w, const int d, const int p)
{
      int position = w->abacus.numDigits - 2 - p;
      int digit = char2Int(w->abacus.digits[position]);

      digit -= d;
      w->abacus.digits[position] = int2Char(((digit + w->abacus.base) % w->abacus.base));
      if (digit < 0) {
            if ((w->abacus.quarter && (p + 1 == w->abacus.decimalPosition - 1)) ||
                (w->abacus.quarterPercent && (p + 1 == w->abacus.decimalPosition -
            MAX_FRACTION_DIGITS - 1 - ((w->abacus.quarter) ? 1 : 0))))
                  SubBead(w, 1 + (-1 - digit) / w->abacus.base, p + 2);
            else
                  SubBead(w, 1 + (-1 - digit) / w->abacus.base, p + 1);
      }
}

static void
MoveUp(AbacusWidget w, const int deck, const int rail, const int j,
            const int factor, const int spaces,
            const int fast, const int delay)
{
      if (j > w->abacus.decks[deck].position[rail] + spaces) {
            int temp = w->abacus.decks[deck].position[rail];

            if (fast == INSTANT || delay == 0) {
                  int l;

                  initTimer(w);
                  for (l = 0; l < spaces; l++) {
                        int k;

                        for (k = temp + spaces + 1; k <= j; k++) {
                              DrawBead(w, deck, rail,
                                    k - spaces, k - l,
                                    False, False, FALSE, 0, 0);
                              DrawBead(w, deck, rail,
                                    k - spaces, k - l - 1,
                                    True, False, FALSE, 0, 0);
                        }
                        if (l + 1 != spaces) {
                              useTimer(w, delay);
                        }
                  }
            } else {
                  AnimateSlide(w, deck, rail, j - spaces, j, spaces, UP,
                        delay / w->abacus.numSlices);
            }
#ifdef USE_SOUND
            if (w->abacus.sound) {
                  playSound((char *) BUMPSOUND);
            }
#endif
            w->abacus.decks[deck].position[rail] = j - spaces;
            if (w->abacus.decks[deck].orientation) {
                  SubBead(w, factor * (j - spaces - temp), rail);
                  SetCounter(w, deck, rail, -(j - spaces - temp));
            } else {    /* w->abacus.decks[deck].orientation == DOWN */
                  AddBead(w, factor * (j - spaces - temp), rail);
                  SetCounter(w, deck, rail, j - spaces - temp);
            }
      }
}

static void
MoveDown(AbacusWidget w, const int deck, const int rail, const int j,
            const int factor, const int spaces,
            const int fast, const int delay)
{
      if (j <= w->abacus.decks[deck].position[rail]) {
            int temp = w->abacus.decks[deck].position[rail];

            if (fast == INSTANT || delay == 0) {
                  int l;

                  initTimer(w);
                  for (l = 0; l < spaces; l++) {
                        int k;

                        for (k = temp; k >= j; k--) {
                              DrawBead(w, deck, rail, k, k + l,
                                    False, False, FALSE, 0, 0);
                              DrawBead(w, deck, rail, k, k + l + 1,
                                    True, False, FALSE, 0, 0);
                        }
                        if (l + 1 != spaces) {
                              useTimer(w, delay);
                        }
                  }
            } else {
                  AnimateSlide(w, deck, rail, j, j, spaces, DOWN,
                        delay / w->abacus.numSlices);
            }
#ifdef USE_SOUND
            if (w->abacus.sound) {
                  playSound((char *) BUMPSOUND);
            }
#endif
            w->abacus.decks[deck].position[rail] = j - 1;
            if (w->abacus.decks[deck].orientation) {
                  AddBead(w, factor * (temp - j + 1), rail);
                  SetCounter(w, deck, rail, temp - j + 1);
            } else {    /* w->abacus.decks[deck].orientation == DOWN */
                  SubBead(w, factor * (temp - j + 1), rail);
                  SetCounter(w, deck, rail, -(temp - j + 1));
            }
      }
}

static void
MoveBeadsUp(AbacusWidget w, const int deck, const int rail, const int j,
            const Boolean fast)
{
      int factor = 1, quarters, quarterPercents, spaces;

      if (w->abacus.sign && (rail == w->abacus.rails - 1)) {
            factor = 0;
            spaces = w->abacus.decks[deck].room - 1;
            MoveUp(w, deck, rail, j, factor, spaces, NORMAL,
                  (fast) ? 0 : w->abacus.delay *
                  w->abacus.decks[BOTTOM].spaces /
                  (w->abacus.decks[BOTTOM].room - 1));
      } else if (w->abacus.quarter && (rail == w->abacus.decimalPosition - 1)) {
            if (w->abacus.decks[BOTTOM].number ==
                        w->abacus.decks[TOP].factor - 1) {
                  quarters = QUARTERS - 1;
            } else {
                  quarters = QUARTERS;
            }
            spaces = w->abacus.decks[deck].room - quarters;
            MoveUp(w, deck, rail, j, factor, spaces, NORMAL,
                  (fast) ? 0 : w->abacus.delay *
                  w->abacus.decks[BOTTOM].spaces /
                  (w->abacus.decks[BOTTOM].room - QUARTERS));
      } else if (w->abacus.quarterPercent && (rail == w->abacus.decimalPosition - MAX_FRACTION_DIGITS - 1 - ((w->abacus.quarter) ? 1 : 0))) {
            if (w->abacus.decks[BOTTOM].number ==
                        w->abacus.decks[TOP].factor - 1) {
                  quarterPercents = QUARTERPERCENTS - 1;
            } else {
                  quarterPercents = QUARTERPERCENTS;
            }
            spaces = w->abacus.decks[deck].room - quarterPercents;
            MoveUp(w, deck, rail, j, factor, spaces, NORMAL,
                  (fast) ? 0 : w->abacus.delay *
                  w->abacus.decks[BOTTOM].spaces /
                  (w->abacus.decks[BOTTOM].room - QUARTERPERCENTS));
      } else if (j > w->abacus.decks[deck].position[rail] + w->abacus.decks[deck].spaces) {
            factor = w->abacus.decks[deck].factor;
            spaces = w->abacus.decks[deck].spaces;
            MoveUp(w, deck, rail, j, factor, spaces, NORMAL,
                  (fast) ? 0 : w->abacus.delay);
      }
}

static void
MoveBeadsDown(AbacusWidget w, const int deck, const int rail, const int j,
            const Boolean fast)
{
      int factor = 1, quarters, quarterPercents, spaces;

      if ((rail == w->abacus.rails - 1) && w->abacus.sign) {
            factor = 0;
            spaces = w->abacus.decks[deck].room - 1;
            MoveDown(w, deck, rail, j, factor, spaces, NORMAL,
                  (fast) ? 0 : w->abacus.delay *
                  w->abacus.decks[BOTTOM].spaces /
                  (w->abacus.decks[BOTTOM].room - 1));
      } else if (w->abacus.quarter && (rail == w->abacus.decimalPosition - 1)) {
            if (w->abacus.decks[BOTTOM].number ==
                        w->abacus.decks[TOP].factor - 1) {
                  quarters = QUARTERS - 1;
            } else {
                  quarters = QUARTERS;
            }
            spaces = w->abacus.decks[deck].room - quarters;
            MoveDown(w, deck, rail, j, factor, spaces, NORMAL,
                  (fast) ? 0 : w->abacus.delay *
                  w->abacus.decks[BOTTOM].spaces /
                  (w->abacus.decks[BOTTOM].room - QUARTERS));
      } else if (w->abacus.quarterPercent && (rail == w->abacus.decimalPosition -
                  MAX_FRACTION_DIGITS - 1 - ((w->abacus.quarter) ? 1 : 0))) {
            if (w->abacus.decks[BOTTOM].number ==
                        w->abacus.decks[TOP].factor - 1) {
                  quarterPercents = QUARTERPERCENTS - 1;
            } else {
                  quarterPercents = QUARTERPERCENTS;
            }
            spaces = w->abacus.decks[deck].room - quarterPercents;
            MoveDown(w, deck, rail, j, factor, spaces, NORMAL,
                  (fast) ? 0 : w->abacus.delay *
                  w->abacus.decks[BOTTOM].spaces /
                  (w->abacus.decks[BOTTOM].room - QUARTERPERCENTS));
      } else if (j <= w->abacus.decks[deck].position[rail]) {
            factor = w->abacus.decks[deck].factor;
            spaces = w->abacus.decks[deck].spaces;
            MoveDown(w, deck, rail, j, factor, spaces, NORMAL,
                  (fast) ? 0 : w->abacus.delay);
      }
}

static Boolean
PositionToBead(AbacusWidget w, int x, int y, int *deck, int *rail, int *j)
{
      int quarters, quarterPercents;

      if (w->abacus.vertical) {
            int temp = x;

            x = y;
            y = w->abacus.frameSize.y - 1 - temp;
      }
      x -= w->abacus.offset.x;
      y -= w->abacus.offset.y;
      if (y > w->abacus.decks[TOP].height) {
            y = y - w->abacus.decks[TOP].height;
            *deck = BOTTOM;
      } else {
            *deck = TOP;
      }
      if (w->abacus.decks[*deck].number == 0) {
            return False;
      }
      *rail = w->abacus.rails - 1 - (x - w->abacus.delta.x / 2) /
            w->abacus.pos.x;
      *j = (y - w->abacus.delta.y / 2) / w->abacus.pos.y + 1;
      if (*rail < 0)
            *rail = 0;
      else if (*rail >= w->abacus.rails)
            *rail = w->abacus.rails - 1;
      if (*j < 1)
            *j = 1;
      else if (*j > w->abacus.decks[*deck].room)
            *j = w->abacus.decks[*deck].room;
      if (*rail == w->abacus.rails - 1 && w->abacus.sign) {
            if (*deck == TOP)
                  return False;
            return ((*j == 1 &&
                   w->abacus.decks[*deck].position[*rail] == 1) ||
                  (*j == w->abacus.decks[*deck].room &&
                   w->abacus.decks[*deck].position[*rail] == 0));
      }
      if (w->abacus.quarter && (*rail == w->abacus.decimalPosition - 1)) {
            if (*deck == TOP)
                  return False;
            if (w->abacus.decks[BOTTOM].number ==
                        w->abacus.decks[TOP].factor - 1) {
                  quarters = QUARTERS - 1;
            } else {
                  quarters = QUARTERS;
            }
            return ((*j > w->abacus.decks[*deck].position[*rail] +
                  w->abacus.decks[*deck].room - quarters) ||
                  (*j <= w->abacus.decks[*deck].position[*rail]));
      }
      if (w->abacus.quarterPercent && (*rail == w->abacus.decimalPosition -
          MAX_FRACTION_DIGITS - 1 - ((w->abacus.quarter) ? 1 : 0))) {
            if (*deck == TOP)
                  return False;
            if (w->abacus.decks[BOTTOM].number ==
                        w->abacus.decks[TOP].factor - 1) {
                  quarterPercents = QUARTERPERCENTS - 1;
            } else {
                  quarterPercents = QUARTERPERCENTS;
            }
            return ((*j > w->abacus.decks[*deck].position[*rail] +
                  w->abacus.decks[*deck].room - quarterPercents) ||
                  (*j <= w->abacus.decks[*deck].position[*rail]));
      }
      return ((*j > w->abacus.decks[*deck].position[*rail] +
             w->abacus.decks[*deck].spaces) ||
            (*j <= w->abacus.decks[*deck].position[*rail]));
}

static void
MoveBeadsByPos(AbacusWidget w, const int deck, const int rail, const int pos,
            const Boolean fast)
{
      if (w->abacus.sign && (rail == w->abacus.rails - 1)) {
            if (deck == TOP)
                  return;
      }
      if (w->abacus.quarter && (rail == w->abacus.decimalPosition - 1)) {
            if (deck == TOP)
                  return;
      }
      if (w->abacus.quarterPercent && (rail == w->abacus.decimalPosition -
          MAX_FRACTION_DIGITS - 1 - ((w->abacus.quarter) ? 1 : 0))) {
            if (deck == TOP)
                  return;
      }
      if (pos <= w->abacus.decks[deck].position[rail]) {
            MoveBeadsDown(w, deck, rail, pos, fast);
      } else {
            MoveBeadsUp(w, deck, rail, pos, fast);
      }
}

static void
ShiftBar(AbacusWidget w, int decimalPosition)
{
      int rail;
      int quarters = 0, quarterPercents = 0;
      int quarterRail = w->abacus.decimalPosition - 1;
      int quarterPercentRail = w->abacus.decimalPosition -
            MAX_FRACTION_DIGITS - 1 - ((w->abacus.quarter) ? 1 : 0);
      int oldQuarterRail = decimalPosition - 1;
      int oldQuarterPercentRail = decimalPosition -
            MAX_FRACTION_DIGITS - 1 - ((w->abacus.quarter) ? 1 : 0);
      char q;

      if (w->abacus.quarter)
            quarters = w->abacus.decks[0].position[oldQuarterRail];
      if (w->abacus.quarterPercent)
            quarterPercents =
                  w->abacus.decks[0].position[oldQuarterPercentRail];
      if (w->abacus.decimalPosition > decimalPosition)
            for (rail = oldQuarterRail; rail < quarterRail; rail++) {
                  w->abacus.decks[0].position[rail] =
                        w->abacus.decks[0].position[rail + 1];
                  w->abacus.decks[1].position[rail] =
                        w->abacus.decks[1].position[rail + 1];
            }
      else if (w->abacus.decimalPosition < decimalPosition)
            for (rail = oldQuarterRail; rail > quarterRail; rail--) {
                  w->abacus.decks[0].position[rail] =
                        w->abacus.decks[0].position[rail - 1];
                  w->abacus.decks[1].position[rail] =
                        w->abacus.decks[1].position[rail - 1];
            }
      if (w->abacus.quarter) {
            w->abacus.decks[0].position[quarterRail] = quarters;
            w->abacus.decks[1].position[quarterRail] = 0;
      }
      if (w->abacus.quarterPercent) {
            w->abacus.decks[0].position[quarterPercentRail] =
                  quarterPercents;
            w->abacus.decks[1].position[quarterPercentRail] = 0;
      }
      q = w->abacus.digits[w->abacus.rails + CARRY - decimalPosition];
      if (w->abacus.decimalPosition > decimalPosition)
            for (rail = w->abacus.rails + CARRY - decimalPosition;
      rail > w->abacus.rails + CARRY - w->abacus.decimalPosition; rail--) {
                  w->abacus.digits[rail] = w->abacus.digits[rail - 1];
            }
      else if (w->abacus.decimalPosition < decimalPosition)
            for (rail = w->abacus.rails + CARRY - decimalPosition;
      rail < w->abacus.rails + CARRY - w->abacus.decimalPosition; rail++) {
                  w->abacus.digits[rail] = w->abacus.digits[rail + 1];
            }
      w->abacus.digits[w->abacus.rails + CARRY - w->abacus.decimalPosition] =
            q;
}

static void
ClearAllBeads(AbacusWidget w)
{
      int rail, deck;

      for (rail = 0; rail < w->abacus.rails; rail++) {
            for (deck = DOWN; deck <= UP; deck++) {
                  if (w->abacus.sign && (rail == w->abacus.rails - 1)) {
                        if (deck == TOP)
                              continue;
                  }
                  if (w->abacus.quarter && (rail == w->abacus.decimalPosition - 1)) {
                        if (deck == TOP)
                              continue;
                  }
                  if (w->abacus.quarterPercent && (rail == w->abacus.decimalPosition -
                      MAX_FRACTION_DIGITS - 1 - ((w->abacus.quarter) ? 1 : 0))) {
                        if (deck == TOP)
                              continue;
                  }
                  if (w->abacus.decks[deck].orientation)
                        MoveBeadsUp(w, deck, rail,
                              w->abacus.decks[deck].room, True);
                  else  /* w->abacus.decks[deck].orientation == DOWN */
                        MoveBeadsDown(w, deck, rail, 1, True);
            }
      }
}

static void
DrawAllBeads(AbacusWidget w)
{
      int deck, rail, j, spaces, quarters, quarterPercents;

      deck = BOTTOM;
      if (w->abacus.sign) {
            rail = w->abacus.rails - 1;
            DrawBead(w, deck, rail, 1, 1,
                  (1 == w->abacus.decks[deck].position[rail]),
                  False, FALSE, 0, 0);
            for (j = 2; j < w->abacus.decks[deck].room; j++)
                  DrawBead(w, deck, rail, 0, j, False,
                        False, FALSE, 0, 0);
            DrawBead(w, deck, rail, 1, w->abacus.decks[deck].room,
                  (0 == w->abacus.decks[deck].position[rail]),
                  False, FALSE, 0, 0);
      }
      if (w->abacus.quarter) {
            rail = w->abacus.decimalPosition - 1;
            if (w->abacus.decks[BOTTOM].number ==
                        w->abacus.decks[TOP].factor - 1) {
                  quarters = QUARTERS - 1;
            } else {
                  quarters = QUARTERS;
            }
            spaces = w->abacus.decks[deck].room - quarters;
            for (j = 1; j <= w->abacus.decks[deck].position[rail]; j++)
                  DrawBead(w, deck, rail, j, j, True, False, FALSE,
                        0, 0);
            for (j = w->abacus.decks[deck].position[rail] + 1;
                 j < spaces + w->abacus.decks[deck].position[rail] + 1; j++)
                  DrawBead(w, deck, rail, 0, j, False, False, FALSE,
                        0, 0);
            for (j = spaces + w->abacus.decks[deck].position[rail] + 1;
                 j <= w->abacus.decks[deck].room; j++)
                  DrawBead(w, deck, rail, j - spaces, j,
                        True, False, FALSE, 0, 0);
      }
      if (w->abacus.quarterPercent) {
            rail = w->abacus.decimalPosition - MAX_FRACTION_DIGITS - 1 -
                  ((w->abacus.quarter) ? 1 : 0);
            if (w->abacus.decks[BOTTOM].number ==
                w->abacus.decks[TOP].factor - 1) {
                  quarterPercents = QUARTERPERCENTS - 1;
            } else {
                  quarterPercents = QUARTERPERCENTS;
            }
            spaces = w->abacus.decks[deck].room - quarterPercents;
            for (j = 1; j <= w->abacus.decks[deck].position[rail]; j++)
                  DrawBead(w, deck, rail, j, j, True, False, FALSE,
                        0, 0);
            for (j = w->abacus.decks[deck].position[rail] + 1;
                 j < spaces + w->abacus.decks[deck].position[rail] + 1; j++)
                  DrawBead(w, deck, rail, 0, j, False, False, FALSE,
                        0, 0);
            for (j = spaces + w->abacus.decks[deck].position[rail] + 1;
                 j <= w->abacus.decks[deck].room; j++)
                  DrawBead(w, deck, rail, j - spaces, j,
                        True, False, FALSE, 0, 0);
      }
      for (rail = 0; rail < w->abacus.rails - ((w->abacus.sign) ? 1 : 0);
                  rail++) {
            if ((w->abacus.quarter && (rail == w->abacus.decimalPosition - 1)) ||
               (w->abacus.quarterPercent && (rail == w->abacus.decimalPosition - MAX_FRACTION_DIGITS - 1 - ((w->abacus.quarter) ? 1 : 0)))) {
                  continue;
            }
            for (deck = DOWN; deck <= UP; deck++) {
                  for (j = 1; j <= w->abacus.decks[deck].position[rail]; j++)
                        DrawBead(w, deck, rail, j, j,
                              True, False, FALSE, 0, 0);
                  for (j = w->abacus.decks[deck].position[rail] + 1;
                       j < w->abacus.decks[deck].spaces + w->abacus.decks[deck].position[rail] + 1; j++)
                        DrawBead(w, deck, rail, 0, j,
                              False, False, FALSE, 0, 0);
                  for (j = w->abacus.decks[deck].spaces + w->abacus.decks[deck].position[rail] + 1;
                       j <= w->abacus.decks[deck].room; j++)
                        DrawBead(w, deck, rail,
                              j - w->abacus.decks[deck].spaces, j,
                              True, False, FALSE, 0, 0);
            }
      }
      SetCounter(w, 0, w->abacus.decimalPosition, 0);
}

static void
SetDecimal(AbacusWidget w, int rail)
{
      int j;

      if (w->abacus.script) {
#ifdef SCRIPTFILE
            (void) fprintf(w->abacus.fp, "%d %d %d %d 4\n", PRIMARY, 2,
                  0, rail - w->abacus.decimalPosition);
            (void) fprintf(w->abacus.fp, "Lesson\n\n\nPress Space-bar\n");
#else
            SetAbacusMove(w, ABACUS_SCRIPT, PRIMARY /* FIXME */, 2,
                  0, rail - w->abacus.decimalPosition);
#endif
      }
      if (w->abacus.sign && rail >= w->abacus.rails - 1)
            rail = w->abacus.rails - 2;
      if (w->abacus.quarterPercent && rail <= MAX_FRACTION_DIGITS)
            return;
      if (w->abacus.quarter || w->abacus.quarterPercent) {
            EraseFrame(w, 0);
      }
      DrawFrame(w, 0, False, True);
      j = w->abacus.decimalPosition;
      w->abacus.decimalPosition = rail;
      DrawFrame(w, 0, True, True);
      if (w->abacus.quarter || w->abacus.quarterPercent) {
            ShiftBar(w, j);
            DrawAllBeads(w);
      }
      SetCounter(w, 0, w->abacus.decimalPosition, 0);
#ifdef USE_SOUND
      if (w->abacus.sound) {
            playSound((char *) MOVESOUND);
      }
#endif
}

static void
MoveBeadsByValue(AbacusWidget w, const int deck, const int rail,
            const int number, const Boolean fast)
{
      if (deck > 1) {
            SetDecimal(w, number + w->abacus.decimalPosition);
            return;
      }
      if ((w->abacus.decks[deck].orientation && number < 0) ||
                  (!w->abacus.decks[deck].orientation && number > 0)) {
            int spaces = w->abacus.decks[deck].spaces;
            if (w->abacus.quarter &&
                        rail == w->abacus.decimalPosition - 1) {
                  if (w->abacus.decks[BOTTOM].number ==
                              w->abacus.decks[TOP].factor - 1) {
                        spaces = w->abacus.decks[deck].room - QUARTERS + 1;
                  } else {
                        spaces = w->abacus.decks[deck].room - QUARTERS;
                  }
            }
            if (w->abacus.quarterPercent &&
                        rail == w->abacus.decimalPosition -
                MAX_FRACTION_DIGITS - ((w->abacus.quarter) ? 1 : 0)) {
                  if (w->abacus.decks[BOTTOM].number ==
                              w->abacus.decks[TOP].factor - 1) {
                        spaces = w->abacus.decks[deck].room - QUARTERPERCENTS + 1;
                  } else {
                        spaces = w->abacus.decks[deck].room - QUARTERPERCENTS;
                  }
            }
            MoveBeadsUp(w, deck, rail, spaces +
                  w->abacus.decks[deck].position[rail] +
                  ((number >= 0) ? number : -number),
                  fast);
      } else if ((!w->abacus.decks[deck].orientation && number < 0) ||
               (w->abacus.decks[deck].orientation && number > 0)) {
            MoveBeadsDown(w, deck, rail,
                  w->abacus.decks[deck].position[rail] + 1 -
                  ((number >= 0) ? number : -number),
                  fast);
      }
      if (w->abacus.sign && (rail == w->abacus.rails - 1)) {
            if (deck == TOP)
                  return;

            if (number <= w->abacus.decks[deck].position[rail]) {
                  MoveBeadsDown(w, deck, rail, 1, fast);
            } else {
                  MoveBeadsUp(w, deck, rail,
                        w->abacus.decks[BOTTOM].room, fast);
            }
            return;
      }
}

static Boolean
SetBeadsForValue(AbacusWidget w, char * expression, Boolean minusSign,
      int quarters, int quarterPercents)
{
      int i, val = -1, topUnits, bottomUnits;
      int percentPosition = w->abacus.decimalPosition -
              MAX_FRACTION_DIGITS - ((w->abacus.quarter) ? 1 : 0);
#ifdef DEBUG
(void) printf("SetBeadsForValue: expression %s, minusSign %d, quarters %d, quarterPercents %d\n", expression, minusSign, quarters, quarterPercents);
#endif
      for (i = 0; i < (int) strlen(expression) - CARRY; i++) {
            char a = expression[i + CARRY];

            val = char2Int(a);
            if (w->abacus.quarter &&
                w->abacus.rails - i != w->abacus.decimalPosition) {
                  if (val >= w->abacus.base)
                        return False;
                  if (quarters == QUARTERS && w->abacus.rails - i ==
                              w->abacus.decimalPosition + 1) {
                        val++;
                  }
            } else if (w->abacus.quarterPercent &&
                w->abacus.rails - i != percentPosition) {
                  if (val >= w->abacus.base)
                        return False;
                  if (quarterPercents == QUARTERPERCENTS &&
                     w->abacus.rails - i == percentPosition + 1) {
                        val++;
                  }
            }
            if (w->abacus.quarter && quarters == QUARTERS &&
                  w->abacus.rails - i == w->abacus.decimalPosition) {
                  MoveBeadsByValue(w, BOTTOM,
                        w->abacus.decimalPosition - 1, 0, True);
                  quarters = 0;
            } else if (w->abacus.quarterPercent &&
                  quarterPercents == QUARTERPERCENTS &&
                  w->abacus.rails - i == percentPosition) {
                  MoveBeadsByValue(w, BOTTOM,
                        percentPosition - 1, 0, True);
                  quarterPercents = 0;
            } else {
                  topUnits = val / w->abacus.decks[TOP].factor;
                  bottomUnits = (val % w->abacus.decks[TOP].factor) /
                        w->abacus.decks[BOTTOM].factor;
                  if (topUnits > w->abacus.decks[TOP].number) {
                        return False;
                  }
                  MoveBeadsByValue(w, TOP, w->abacus.rails - i - 1,
                        topUnits, True);
                  MoveBeadsByValue(w, BOTTOM, w->abacus.rails - i - 1,
                        bottomUnits, True);
            }
      }
      MoveBeadsByValue(w, BOTTOM, w->abacus.rails - 1,
            (w->abacus.decks[BOTTOM].orientation) ?
            ((minusSign) ? 1 : 0) :
            ((minusSign) ? w->abacus.decks[BOTTOM].room -
            w->abacus.decks[BOTTOM].spaces : 0), True);
#if 0
      /* These are already in expression, so do not do again */
      MoveBeadsByValue(w, BOTTOM, w->abacus.decimalPosition - 1,
            quarters, True);
      MoveBeadsByValue(w, BOTTOM, w->abacus.decimalPosition -
            MAX_FRACTION_DIGITS - 1 - ((w->abacus.quarter) ? 1 : 0),
            quarterPercents, True);
#endif
      return True;
}

void
ClearRails(AbacusWidget w)
{
      ClearAllBeads(w);
      if (w->abacus.demo) {
            SetAbacus(w, ABACUS_CLEAR);
      }
      if (!EmptyCounter(w)) {
            DISPLAY_WARNING("corruption");
      }
      SetCounter(w, 0, w->abacus.decimalPosition, 0); /* needed when 0 */
}

static void
CheckDecimal(AbacusWidget w)
{
      if (w->abacus.decimalPosition >= w->abacus.rails -
                  ((w->abacus.sign) ? 1 : 0) +
                  ((w->abacus.quarter) ? 1 : 0) +
                  ((w->abacus.quarterPercent) ? 1 : 0)) {
            DrawFrame(w, 0, False, True);
            w->abacus.decimalPosition = w->abacus.rails - 1 -
                  ((w->abacus.sign) ? 1 : 0) +
                  ((w->abacus.quarter) ? 1 : 0) +
                  ((w->abacus.quarterPercent) ? 1 : 0);
            DrawFrame(w, 0, True, True);
            SetCounter(w, 0, w->abacus.decimalPosition, 0);
      }
}

/* via increment/decrement or by sign and quarters */
static Boolean
ShiftRails(AbacusWidget w, int shift, int loc, Boolean special)
{
      int deck, rail, local_rails = 0, i, inc;
      int signValue = 0, quarterValue = 0, quarterPercentValue = 0;
      DeckPart local_decks[MAXDECKS];
      int oldRails = w->abacus.rails, newRails = w->abacus.rails + shift;
      Boolean oldSign = w->abacus.sign;
      Boolean oldQuarter = w->abacus.quarter;
      Boolean oldQuarterPercent = w->abacus.quarterPercent;

      if (shift == 0 || newRails < MINRAILS ||
                  (w->abacus.demo && newRails < MINDEMORAILS) ||
                        (special && loc < 0))
            return False;

      if (special) {
            if (loc == oldRails - 1) {
                  oldSign = !oldSign;
            } else if (loc == w->abacus.decimalPosition - 1) {
                  oldQuarter = !oldQuarter;
            } else if (loc == w->abacus.decimalPosition -
          MAX_FRACTION_DIGITS - ((oldQuarter) ? 1 : 0) - 1) {
                  oldQuarterPercent = !oldQuarterPercent;
            }
      }
      inc = (shift > 0) ? shift : 0;
      /* Alloc space to save the rails */
      local_rails = oldRails;
      for (deck = BOTTOM; deck <= TOP; deck++) {
            if (!(local_decks[deck].position = (int *)
                        calloc((unsigned int) (local_rails + inc),
                        sizeof (int)))) {
                  DISPLAY_ERROR("Not enough memory, exiting.");
            }
            if (w->abacus.decks[deck].orientation) {
                  i = 0;
                  for (rail = 0; rail < local_rails + inc; rail++) {
                        if (deck == BOTTOM && w->abacus.quarter &&
                            rail == w->abacus.decimalPosition - 1) {
                              quarterValue = QUARTERS;
                        } else if (deck == BOTTOM &&
                              w->abacus.quarterPercent &&
                              (w->abacus.decimalPosition -
                              MAX_FRACTION_DIGITS - 1 -
                              ((w->abacus.quarter) ? 1 : 0) > 0)) {
                              quarterPercentValue = QUARTERPERCENTS;
                        } else {
                              local_decks[deck].position[i++] =
                                    w->abacus.decks[deck].number;
                        }
                  }
            }
            i = 0;
            for (rail = 0; rail < local_rails; rail++) {
                  if (oldSign && (rail == oldRails - 1)) {
                        if (deck != TOP && oldSign == w->abacus.sign)
                              signValue = ((w->abacus.decks[deck].position[rail] == 1 &&
                                    !w->abacus.decks[deck].orientation) ||
                                    (w->abacus.decks[deck].position[rail] == 0 &&
                                    w->abacus.decks[deck].orientation)) ? 1 : 0;
                  } else if (oldQuarter &&
                              (rail == w->abacus.decimalPosition -
                              1)) {
                        if (deck != TOP)
                              quarterValue = w->abacus.decks[deck].position[rail];
                  } else if (oldQuarterPercent &&
                              (rail == w->abacus.decimalPosition -
                              MAX_FRACTION_DIGITS - 1 -
                              ((w->abacus.quarter) ? 1 : 0))) {
                        if (deck != TOP)
                              quarterPercentValue = w->abacus.decks[deck].position[rail];
                  } else {
                        local_decks[deck].position[i++] =
                              w->abacus.decks[deck].position[rail];
                  }
            }
      }
      w->abacus.rails += shift;
      inc = 0;
      if (loc <= w->abacus.decimalPosition &&
                  w->abacus.decimalPosition + shift >= 0) {
            w->abacus.decimalPosition += shift;
            if (!special) /* want to destroy fractional values if forced */
                  inc += shift;
      }
#ifdef DEBUG
(void) printf("ShiftRails decimalPosition w%d, rails w%d, shift %d, loc %d inc%d\n",
  w->abacus.decimalPosition, w->abacus.rails, shift, loc, inc);
#endif
      ResetBeads(w);
      ResizeAbacus(w);
      ResizeBead(w);
      DrawAllBufferedBeads(w);
      EraseFrame(w, 0);
      DrawFrame(w, 0, True, True);
      DrawAllBeads(w);
      for (deck = BOTTOM; deck <= TOP; deck++) {
            i = -inc;
            for (rail = inc; rail < w->abacus.rails; rail++) {
                  if (w->abacus.sign && (rail == w->abacus.rails - 1)) {
                        if (deck == TOP)
                              continue;
                        if (w->abacus.decks[deck].orientation)
                              MoveBeadsByPos(w, deck, rail,
                                    (signValue == 1) ?
                                    1 : w->abacus.decks[deck].room,
                                    True);
                        else {
                              MoveBeadsByPos(w, deck, rail,
                                    (signValue == 1) ?
                                    w->abacus.decks[deck].room : 1,
                                    True);
                        }
                  } else if (w->abacus.quarter &&
                              (rail == w->abacus.decimalPosition -
                              1)) {
                        i = -1;
                        if (deck == TOP)
                              continue;
                        if (w->abacus.decks[deck].orientation)
                              MoveBeadsByValue(w, deck, rail,
                                    QUARTERS - quarterValue,
                                    True);
                        else {
                              MoveBeadsByValue(w, deck, rail,
                                    quarterValue,
                                    True);
                        }
                  } else if (w->abacus.quarterPercent &&
                              (rail == w->abacus.decimalPosition -
                              MAX_FRACTION_DIGITS - 1 -
                              ((w->abacus.quarter) ? 1 : 0))) {
                        if (deck == TOP)
                              continue;
                        if (w->abacus.decks[deck].orientation)
                              MoveBeadsByValue(w, deck, rail,
                                    QUARTERPERCENTS - quarterPercentValue,
                                    True);
                        else
                              MoveBeadsByValue(w, deck, rail,
                                    quarterPercentValue,
                                    True);
                  } else {
                        if (w->abacus.decks[deck].orientation)
                              MoveBeadsByValue(w, deck, rail,
                                    w->abacus.decks[deck].number -
                                    local_decks[deck].position[rail + i],
                                    True);
                        else
                              MoveBeadsByValue(w, deck, rail,
                                    local_decks[deck].position[rail + i],
                                    True);
                  }
            }
      }
      for (deck = BOTTOM; deck <= TOP; deck++) {
            if (local_decks[deck].position)
                  (void) free((void *) local_decks[deck].position);
      }
      return True;
}

#ifndef WINVER
/* via slider */
static void
ShiftedRails(AbacusWidget c, AbacusWidget w)
{
      int deck, rail, local_rails = 0, i, inc;
      int shift = w->abacus.rails - c->abacus.rails;
      int oldRails = c->abacus.rails, newRails = w->abacus.rails;
      int oldDecimalPosition = c->abacus.decimalPosition;
      Boolean oldSign = c->abacus.sign;
      Boolean oldQuarter = c->abacus.quarter;
      Boolean oldQuarterPercent = c->abacus.quarterPercent;
      int signValue = 0, quarterValue = 0, quarterPercentValue = 0;
      DeckPart local_decks[MAXDECKS];
      int loc;

      if (shift == 0 || newRails <
            ((w->abacus.sign) ? 1: 0) + ((w->abacus.quarter) ? 1 : 0) +
            ((w->abacus.quarterPercent) ? MAX_FRACTION_DIGITS + 1 : 0) +
            ((w->abacus.demo) ? MINDEMORAILS : MINRAILS)) {
            return;
      }
      inc = (shift > 0) ? shift : 0;
      /* Alloc space to save the rails */
      local_rails = c->abacus.rails;
      for (deck = BOTTOM; deck <= TOP; deck++) {
            if (!(local_decks[deck].position = (int *)
                        calloc((unsigned int) (local_rails + inc),
                        sizeof (int)))) {
                  DISPLAY_ERROR("Not enough memory, exiting.");
            }
            if (w->abacus.decks[deck].orientation) {
                  i = 0;
                  for (rail = 0; rail < local_rails + inc; rail++) {
                        if (deck == BOTTOM && oldQuarter &&
                            rail == oldDecimalPosition - 1) {
                              quarterValue = QUARTERS;
                        } else if (deck == BOTTOM &&
                              oldQuarterPercent &&
                              (oldDecimalPosition -
                              MAX_FRACTION_DIGITS - 1 -
                              ((oldQuarter) ? 1 : 0) > 0)) {
                              quarterPercentValue = QUARTERPERCENTS;
                        } else {
                              local_decks[deck].position[i++] =
                                    c->abacus.decks[deck].number;
                        }
                  }
            }
            i = 0;
            for (rail = 0; rail < local_rails; rail++) {
                  if (oldSign && (rail == oldRails - 1)) {
                        if (deck != TOP)
                              signValue = ((c->abacus.decks[deck].position[rail] == 1 &&
                                    !c->abacus.decks[deck].orientation) ||
                                    (c->abacus.decks[deck].position[rail] == 0 &&
                                    c->abacus.decks[deck].orientation)) ? 1 : 0;
                  } else if (oldQuarter &&
                              (rail == oldDecimalPosition -
                              1)) {
                        if (deck != TOP)
                              quarterValue = c->abacus.decks[deck].position[rail];
                  } else if (oldQuarterPercent &&
                              (rail == oldDecimalPosition -
                              MAX_FRACTION_DIGITS - 1 -
                              ((oldQuarter) ? 1 : 0))) {
                        if (deck != TOP)
                              quarterPercentValue = c->abacus.decks[deck].position[rail];
                  } else {
                        local_decks[deck].position[i++] = c->abacus.decks[deck].position[rail];
                  }
            }
      }

#ifdef DELETE_FROM_RIGHT
      if (shift > 0 || w->abacus.decimalPosition <=
            ((w->abacus.quarter) ? MAX_FRACTION_DIGITS + 1 +
            ((w->abacus.quarterPercent) ? 1 : 0): 0))
#else
      if (shift > 0 || oldDecimalPosition > 1)
#endif
            loc = w->abacus.rails - 1;
      else
            loc = 0;
      w->abacus.decimalPosition = oldDecimalPosition;
      if (loc < w->abacus.decimalPosition) {
            loc = w->abacus.decimalPosition - w->abacus.rails + 1;
            w->abacus.decimalPosition = w->abacus.rails - 1;
      } else
            loc = 0;

      ResetBeads(w);
      ResizeAbacus(w);
      ResizeBead(w);
      DrawAllBufferedBeads(w);
      EraseFrame(w, 0);
      DrawFrame(w, 0, True, True);
      DrawAllBeads(w);

      for (deck = BOTTOM; deck <= TOP; deck++) {
            i = loc;
            for (rail = 0; rail < w->abacus.rails; rail++) {
                  if (w->abacus.sign && (rail == w->abacus.rails - 1)) {
                        if (deck == TOP)
                              continue;
                        if (w->abacus.decks[deck].orientation)
                              MoveBeadsByPos(w, deck, rail, (signValue == 1) ?
                                    1 : w->abacus.decks[deck].room,
                                    True);
                        else {
                              MoveBeadsByPos(w, deck, rail, (signValue == 1) ?
                                    w->abacus.decks[deck].room : 1,
                                    True);
                        }
                  } else if (w->abacus.quarter &&
                              (rail == w->abacus.decimalPosition -
                              1)) {
                        i = -1;
                        if (deck == TOP)
                              continue;
                        if (w->abacus.decks[deck].orientation)
                              MoveBeadsByValue(w, deck, rail,
                                    QUARTERS - quarterValue,
                                    True);
                        else {
                              MoveBeadsByValue(w, deck, rail,
                                    quarterValue,
                                    True);
                        }
                  } else if (w->abacus.quarterPercent &&
                              (rail == w->abacus.decimalPosition -
                              MAX_FRACTION_DIGITS - 1 -
                              ((w->abacus.quarter) ? 1 : 0))) {
                        if (deck == TOP)
                              continue;
                        if (w->abacus.decks[deck].orientation)
                              MoveBeadsByValue(w, deck, rail,
                                    QUARTERPERCENTS - quarterPercentValue,
                                    True);
                        else
                              MoveBeadsByValue(w, deck, rail,
                                    quarterPercentValue,
                                    True);
                  } else {
                        if (w->abacus.decks[deck].orientation)
                              MoveBeadsByValue(w, deck, rail,
                                    w->abacus.decks[deck].number -
                                    local_decks[deck].position[rail + i],
                                    True);
                        else
                              MoveBeadsByValue(w, deck, rail,
                                    local_decks[deck].position[rail + i],
                                    True);
                  }
            }
      }
      for (deck = BOTTOM; deck <= TOP; deck++) {
            if (local_decks[deck].position)
                  (void) free((void *) local_decks[deck].position);
      }
}
#endif

static Boolean
InsertSpecialRail(AbacusWidget w, int loc)
{
      if (ShiftRails(w, 1, loc, True)) {
            SetAbacus(w, ABACUS_INC);
            return True;
      }
      return False;
}

static Boolean
DeleteSpecialRail(AbacusWidget w, int loc)
{
      if (w->abacus.rails <= 1 + ((w->abacus.sign) ? 1 : 0) +
                  ((w->abacus.quarter) ? 1 : 0) +
                  ((w->abacus.quarterPercent) ? 1 : 0))
            return False;
      if (ShiftRails(w, -1, loc, True)) {
            SetAbacus(w, ABACUS_DEC);
            CheckDecimal(w);
            return True;
      }
      return False;
}

static void
IncrementRails(AbacusWidget w)
{
      if (ShiftRails(w, 1, w->abacus.rails - 1, False)) {
            SetAbacus(w, ABACUS_INC);
      }
}

static void
DecrementRails(AbacusWidget w)
{
      if (w->abacus.rails <= 1 + ((w->abacus.sign) ? 1 : 0) +
                  ((w->abacus.quarter) ? 1 : 0) +
                  ((w->abacus.quarterPercent) ? MAX_FRACTION_DIGITS + 1 :
                  0))
            return;
#ifdef DELETE_FROM_RIGHT
      if (w->abacus.decimalPosition <= ((w->abacus.quarter) ? MAX_FRACTION_DIGITS + 1 + ((w->abacus.quarterPercent) ? 1 : 0): 0))
#else
      if (w->abacus.decimalPosition > 1)
#endif
      {

            if (ShiftRails(w, -1, w->abacus.rails - 1, False)) {
                  SetAbacus(w, ABACUS_DEC);
            }
      } else {
            if (ShiftRails(w, -1, 0, False)) {
                  SetAbacus(w, ABACUS_DEC);
            }
      }
      CheckDecimal(w);
}

static void
SpeedBead(AbacusWidget w)
{
      w->abacus.delay -= 10;
      if (w->abacus.delay < 0)
            w->abacus.delay = 0;
}

static void
SlowBead(AbacusWidget w)
{
      w->abacus.delay += 10;
}

static void
SoundBead(AbacusWidget w)
{
      w->abacus.sound = !w->abacus.sound;
}

static void
ReformatRails(AbacusWidget w, Boolean minusSign,
            int quarters, int quarterPercents)
{
      char * buffer;

      if (!(buffer = (char *) malloc(sizeof (char) *
                  (strlen(w->abacus.digits) + 1)))) {
            DISPLAY_ERROR("Not enough memory, exiting.");
      }
      (void) strcpy(buffer, w->abacus.digits);
      ResetBeads(w);
      ResizeAbacus(w);
      ResizeBead(w);
      DrawAllBufferedBeads(w);
      EraseFrame(w, 0);
      DrawFrame(w, 0, True, True);
      DrawAllBeads(w);
      minusSign = (w->abacus.sign && minusSign);
      if (w->abacus.quarter && w->abacus.decimalPosition < 1)
            w->abacus.quarter = False;
      quarters = ((w->abacus.quarter) ? quarters : 0);
      quarterPercents = ((w->abacus.quarterPercent) ? quarterPercents : 0);
      if (!SetBeadsForValue(w, buffer, minusSign,
                  quarters, quarterPercents)) {
            ResetBeads(w);
      }
      free(buffer);
}

static void
FormatRails(AbacusWidget w)
{
      Boolean minusSign = False;
      Boolean orient = w->abacus.decks[BOTTOM].orientation;
      int quarters = 0, quarterPercents = 0, value;

      if (w->abacus.sign) {
            value = w->abacus.decks[BOTTOM].position[w->abacus.rails - 1];
            minusSign = ((value == 1 && !orient) || (value == 0 && orient));
      }
      if (w->abacus.quarter) {
            value = w->abacus.decks[BOTTOM].position[w->abacus.decimalPosition - 1];
            quarters = ((orient) ? QUARTERS - value : value);
      }
      if (w->abacus.quarterPercent) {
            value = w->abacus.decks[BOTTOM].position[w->abacus.decimalPosition -
            MAX_FRACTION_DIGITS - 1 - ((w->abacus.quarter) ? 1 : 0)];
            quarterPercents = ((orient) ? QUARTERPERCENTS - value : value);
      }
      if (w->abacus.mode < CHINESE || w->abacus.mode > MAXMODES)
            w->abacus.mode = CHINESE;
      else
            w->abacus.mode = (w->abacus.mode + 1) % MAXFORMATS;
      if (w->abacus.demo && w->abacus.mode == OTHER) {
            w->abacus.mode = CHINESE;
      }
      CheckBeads(w);
      ReformatRails(w, minusSign, quarters, quarterPercents);
      SetAbacus(w, ABACUS_FORMAT);
}

static void
RomanNumeralsRails(AbacusWidget w)
{
      w->abacus.romanNumerals = !w->abacus.romanNumerals;
      SetCounter(w, 0, w->abacus.decimalPosition, 0);
}

static void
SignRails(AbacusWidget w)
{
      Boolean oldSign = w->abacus.sign;

      w->abacus.sign = !w->abacus.sign;
      if (w->abacus.sign) {
            if (!InsertSpecialRail(w, w->abacus.rails - 1))
                  w->abacus.sign = oldSign;
      } else {
            if (!DeleteSpecialRail(w, w->abacus.rails - 1))
                  w->abacus.sign = oldSign;
      }
      if (w->abacus.sign != oldSign) {
            SetAbacus(w, ABACUS_SIGN);
      }
}

static void
QuarterRails(AbacusWidget w)
{
      Boolean oldQuarter = w->abacus.quarter;

      if (w->abacus.decimalPosition < MAX_FRACTION_DIGITS) {
            return;
      }
      if (((w->abacus.base == 2 || w->abacus.base == 4) &&
                  w->abacus.decks[BOTTOM].spaces < 3) ||
                  ((w->abacus.base == 3 || w->abacus.base == 6 ||
                  w->abacus.base == 9) &&
                  w->abacus.decks[BOTTOM].spaces < 2)) {
            /* Odd bases produce round-off errors but OK */
            /* When base divisible by 4, kind of silly but OK */
            /* 4, 6, & 9 enough room in Russian but not others */
            return;
      }
      w->abacus.quarter = !w->abacus.quarter;
      if (w->abacus.quarter) {
            if (!InsertSpecialRail(w, w->abacus.decimalPosition - 1))
                  w->abacus.quarter = oldQuarter;
      } else {
            if (!DeleteSpecialRail(w, w->abacus.decimalPosition - 1))
                  w->abacus.quarter = oldQuarter;
      }
      if (w->abacus.quarter != oldQuarter) {
            SetAbacus(w, ABACUS_QUARTER);
      }
}

static void
QuarterPercentRails(AbacusWidget w)
{
#if QUARTER_PERCENT
      Boolean oldQuarterPercent = w->abacus.quarterPercent;

      if (w->abacus.decimalPosition < MAX_FRACTION_DIGITS) {
            return;
      }
      if (((w->abacus.base == 2 || w->abacus.base == 4) &&
                  w->abacus.decks[BOTTOM].spaces < 3) ||
                  ((w->abacus.base == 3 || w->abacus.base == 6 ||
                  w->abacus.base == 9) &&
                  w->abacus.decks[BOTTOM].spaces < 2)) {
            /* Odd bases produce round-off errors but OK */
            /* When base divisible by 4, kind of silly but OK */
            /* 4, 6, & 9 enough room in Russian but not others */
            return;
      }
      w->abacus.quarterPercent = !w->abacus.quarterPercent;
      if (w->abacus.quarterPercent) {
            if (!InsertSpecialRail(w, w->abacus.decimalPosition - MAX_FRACTION_DIGITS - 1))
                  w->abacus.quarterPercent = oldQuarterPercent;
      } else {
            if (!DeleteSpecialRail(w, w->abacus.decimalPosition - MAX_FRACTION_DIGITS - 1))
                  w->abacus.quarterPercent = oldQuarterPercent;
      }
      if (w->abacus.quarterPercent != oldQuarterPercent) {
            SetAbacus(w, ABACUS_QUARTERPERCENT);
      }
#endif
}

static void
VerticalRails(AbacusWidget w)
{
#ifdef VERTICAL
      EraseFrame(w, 0);
      w->abacus.vertical = !w->abacus.vertical;
      DrawFrame(w, 0, True, True);
      DrawAllBeads(w);
#endif
}

#define FACTOR 0.7

#ifdef WINVER
#define MAXINTENSITY 0xFF
static int
brighter(const int light)
{
      int i = (int) ((1 - FACTOR) * MAXINTENSITY);
      int temp = light;

      if (temp < i)
            temp = i;
      return MIN(temp / FACTOR, MAXINTENSITY);
}

static int
darker(const int light)
{
      return (int) (light * FACTOR);
}

static void
SetValuesAbacus(AbacusWidget w)
{
      struct tagColor {
            int   red, green, blue;
      } color;
      char  szBuf[80];

      w->abacus.decks[TOP].factor =
            GetPrivateProfileInt(SECTION, "topFactor", 5, INIFILE);
      w->abacus.decks[BOTTOM].factor =
            GetPrivateProfileInt(SECTION, "bottomFactor", 1, INIFILE);
      w->abacus.decks[TOP].orientation = (BOOL)
            GetPrivateProfileInt(SECTION, "topOrient", 1, INIFILE);
      w->abacus.decks[BOTTOM].orientation = (BOOL)
            GetPrivateProfileInt(SECTION, "bottomOrient", 0, INIFILE);
      w->abacus.decks[TOP].number =
            GetPrivateProfileInt(SECTION, "topNumber", 2, INIFILE);
      w->abacus.decks[BOTTOM].number =
            GetPrivateProfileInt(SECTION, "bottomNumber", 5, INIFILE);
      w->abacus.decks[TOP].spaces =
            GetPrivateProfileInt(SECTION, "topSpaces", 2, INIFILE);
      w->abacus.decks[BOTTOM].spaces =
            GetPrivateProfileInt(SECTION, "bottomSpaces", 3, INIFILE);
      w->abacus.rails = GetPrivateProfileInt(SECTION, "rails", 13, INIFILE);
      w->abacus.slot = (BOOL) GetPrivateProfileInt(SECTION,
            "slot", FALSE, INIFILE);
      w->abacus.diamond = (BOOL) GetPrivateProfileInt(SECTION,
            "diamond", FALSE, INIFILE);
      (void) GetPrivateProfileString(SECTION, "format", "Other",
            szBuf, sizeof (szBuf), INIFILE);
      (void) strcpy(w->abacus.format, szBuf);
      w->abacus.format[80] = 0;
      w->abacus.base = GetPrivateProfileInt(SECTION, "base", 10, INIFILE);
      w->abacus.displayBase = GetPrivateProfileInt(SECTION, "displayBase",
             10, INIFILE);
      w->abacus.romanNumerals = (BOOL) GetPrivateProfileInt(SECTION,
            "romanNumerals", FALSE, INIFILE);
      w->abacus.quarter = (BOOL) GetPrivateProfileInt(SECTION,
            "quarter", FALSE, INIFILE);
      w->abacus.quarterPercent = (BOOL) GetPrivateProfileInt(SECTION,
            "quarterPercent", FALSE, INIFILE);
      w->abacus.vertical = (BOOL) GetPrivateProfileInt(SECTION, "vertical",
            FALSE, INIFILE);
      w->abacus.mono = (BOOL) GetPrivateProfileInt(SECTION, "mono",
            DEFAULTMONO, INIFILE);
      w->abacus.reverse = (BOOL) GetPrivateProfileInt(SECTION, "reverse",
            DEFAULTREVERSE, INIFILE);
      /* DarkRed */
      (void) GetPrivateProfileString(SECTION, "beadColor", "139 0 0",
            szBuf, sizeof (szBuf), INIFILE);
      (void) sscanf(szBuf, "%d %d %d",
            &(color.red), &(color.green), &(color.blue));
      w->abacus.beadShadeGC[1] = RGB(color.red, color.green, color.blue);
      w->abacus.beadShadeGC[0] = RGB(brighter(color.red),
            brighter(color.green), brighter(color.blue));
      w->abacus.beadShadeGC[2] = RGB(darker(color.red),
            darker(color.green), darker(color.blue));
      w->abacus.beadShadeGC[3] = RGB(darker(darker(color.red)),
            darker(darker(color.green)), darker(darker(color.blue)));
      w->abacus.beadShadeGC[4] = RGB(darker(darker(darker(color.red))),
            darker(darker(darker(color.green))),
            darker(darker(darker(color.blue))));
      /* gray25 */
      (void) GetPrivateProfileString(SECTION, "beadBorder", "64 64 64",
            szBuf, sizeof (szBuf), INIFILE);
      (void) sscanf(szBuf, "%d %d %d",
            &(color.red), &(color.green), &(color.blue));
      w->abacus.borderGC = RGB(color.red, color.green, color.blue);
      /* gold */
      (void) GetPrivateProfileString(SECTION, "railColor", "255 215 0",
            szBuf, sizeof (szBuf), INIFILE);
      (void) sscanf(szBuf, "%d %d %d",
            &(color.red), &(color.green), &(color.blue));
      w->abacus.railGC = RGB(color.red, color.green, color.blue);
      /* cyan */
      (void) GetPrivateProfileString(SECTION, "frameColor", "0 255 255",
            szBuf, sizeof (szBuf), INIFILE);
      (void) sscanf(szBuf, "%d %d %d",
            &(color.red), &(color.green), &(color.blue));
      w->abacus.frameGC = RGB(color.red, color.green, color.blue);
#if 0
      /* black */
      (void) GetPrivateProfileString(SECTION, "foreground", "0 0 0",
            szBuf, sizeof (szBuf), INIFILE);
      (void) sscanf(szBuf, "%d %d %d",
            &(color.red), &(color.green), &(color.blue));
      w->abacus.foregroundGC = RGB(color.red, color.green, color.blue);
#endif
      /* #AEB2C3 */
      (void) GetPrivateProfileString(SECTION, "background", "174 178 195",
            szBuf, sizeof (szBuf), INIFILE);
      (void) sscanf(szBuf, "%d %d %d",
            &(color.red), &(color.green), &(color.blue));
      w->abacus.inverseGC = RGB(color.red, color.green, color.blue);
      w->abacus.delay = GetPrivateProfileInt(SECTION, "delay", 50, INIFILE);
      w->abacus.sound = (BOOL)
            GetPrivateProfileInt(SECTION, "sound", 0, INIFILE);
      (void) GetPrivateProfileString(SECTION, "bumpSound", BUMPSOUND,
            szBuf, sizeof (szBuf), INIFILE);
      (void) strcpy(w->abacus.bumpSound, szBuf);
      (void) GetPrivateProfileString(SECTION, "moveSound", MOVESOUND,
            szBuf, sizeof (szBuf), INIFILE);
      (void) strcpy(w->abacus.moveSound, szBuf);
      w->abacus.script = (BOOL)
            GetPrivateProfileInt(SECTION, "script", 0, INIFILE);
      w->abacus.demo = (BOOL)
            GetPrivateProfileInt(SECTION, "demo", 0, INIFILE);
      (void) GetPrivateProfileString(SECTION, "textColor", "0 255 0",
            szBuf, sizeof (szBuf), INIFILE);
      (void) sscanf(szBuf, "%d %d %d",
            &(color.red), &(color.green), &(color.blue));
      /* Bright Green */
      w->abacusDemo.foregroundGC = RGB(color.red, color.green, color.blue);
      (void) GetPrivateProfileString(SECTION, "demoPath", DEMOPATH,
            szBuf, sizeof (szBuf), INIFILE);
      (void) strcpy(w->abacusDemo.path, szBuf);
      w->abacusDemo.path[80] = 0;
}

void
DestroyAbacus(AbacusWidget w, HBRUSH brush)
{
#ifdef SCRIPTFILE
      if (w->abacus.script) {
            char buf[512];

            (void) fclose(w->abacus.fp);
            (void) sprintf(buf, "Saved to %s.", SCRIPTFILE);
            DISPLAY_INFO(buf);
      }
#endif
      (void) DeleteObject(brush);
      PostQuitMessage(0);
}

void
SetAbacusMove(AbacusWidget w, int reason, int aux, int deck,
            int rail, int number)
{
      if (aux != PRIMARY)
            return;
      w->abacus.deck = deck;
      w->abacus.rail = rail;
      w->abacus.number = number;
      if (CheckMove(w)) {
            MoveBeadsByValue(w, deck, rail
                  + w->abacus.decimalPosition, w->abacus.number,
                  False);
      }
}

#else
#define MAXINTENSITY 0xFFFF

static Pixel
brighter(AbacusWidget w, Pixel pixel)
{
      XColor color;
      int i = (int) ((1 - FACTOR) * MAXINTENSITY);

      color.pixel = pixel;
      XQueryColor(XtDisplay(w), w->abacus.colormap, &color);
      if (color.red < i)
            color.red = i;
      if (color.green < i)
            color.green = i;
      if (color.blue < i)
            color.blue = i;
      color.red = (unsigned short) MIN(color.red / FACTOR, MAXINTENSITY);
      color.green = (unsigned short) MIN(color.green / FACTOR, MAXINTENSITY);
      color.blue = (unsigned short) MIN(color.blue / FACTOR, MAXINTENSITY);
      if (XAllocColor(XtDisplay(w), w->abacus.colormap, &color))
            return color.pixel;
      return pixel;
}

static Pixel
darker(AbacusWidget w, Pixel pixel)
{
      XColor color;

      color.pixel = pixel;
      XQueryColor(XtDisplay(w), w->abacus.colormap, &color);
      color.red = (unsigned short) (color.red * FACTOR);
      color.green = (unsigned short) (color.green * FACTOR);
      color.blue = (unsigned short) (color.blue * FACTOR);
      if (XAllocColor(XtDisplay(w), w->abacus.colormap, &color))
            return color.pixel;
      return pixel;
}

static void
SetAllColors(AbacusWidget w)
{
      XGCValues values;
      XtGCMask valueMask;

      valueMask = GCForeground | GCBackground;
      if (w->abacus.reverse) {
            values.foreground = w->abacus.foreground;
            values.background = w->abacus.background;
      } else {
            values.foreground = w->abacus.background;
            values.background = w->abacus.foreground;
      }
      if (w->abacus.inverseGC)
            XtReleaseGC((Widget) w, w->abacus.inverseGC);
      w->abacus.inverseGC = XtGetGC((Widget) w, valueMask, &values);
      if (w->abacus.mono) {
            if (w->abacus.reverse) {
                  values.foreground = w->abacus.background;
                  values.background = w->abacus.foreground;
            } else {
                  values.foreground = w->abacus.foreground;
                  values.background = w->abacus.background;
            }
      } else {
                  values.foreground = w->abacus.frameColor;
                  values.background = w->abacus.borderColor;
      }
      if (w->abacus.frameGC)
            XtReleaseGC((Widget) w, w->abacus.frameGC);
      w->abacus.frameGC = XtGetGC((Widget) w, valueMask, &values);
      if (w->abacus.mono) {
            if (w->abacus.reverse) {
                  values.foreground = w->abacus.background;
                  values.background = w->abacus.foreground;
            } else {
                  values.foreground = w->abacus.foreground;
                  values.background = w->abacus.background;
            }
      } else {
            values.foreground = w->abacus.railColor;
            values.background = w->abacus.borderColor;
      }
      if (w->abacus.railGC)
            XtReleaseGC((Widget) w, w->abacus.railGC);
      w->abacus.railGC = XtGetGC((Widget) w, valueMask, &values);
      if (w->abacus.mono) {
            if (w->abacus.reverse) {
                  values.foreground = w->abacus.background;
                  values.background = w->abacus.foreground;
            } else {
                  values.foreground = w->abacus.foreground;
                  values.background = w->abacus.background;
            }
      } else {
            values.foreground = w->abacus.beadColor;
            values.background = w->abacus.borderColor;
      }
      if (!w->abacus.mono && (BlackPixelOfScreen(XtScreen(w)) ==
                  w->abacus.beadColor)) {
            w->abacus.beadColor = brighter(w, values.foreground);
            values.foreground = w->abacus.beadColor;
      }
      if (w->abacus.beadShadeGC[1])
            XtReleaseGC((Widget) w, w->abacus.beadShadeGC[1]);
      w->abacus.beadShadeGC[1] = XtGetGC((Widget) w, valueMask, &values);
      if (!w->abacus.mono) {
            values.foreground = brighter(w, w->abacus.beadColor);
      }
      if (w->abacus.beadShadeGC[0])
            XtReleaseGC((Widget) w, w->abacus.beadShadeGC[0]);
      w->abacus.beadShadeGC[0] = XtGetGC((Widget) w, valueMask, &values);
      if (!w->abacus.mono) {
            values.foreground = darker(w, w->abacus.beadColor);
      }
      if (w->abacus.beadShadeGC[2])
            XtReleaseGC((Widget) w, w->abacus.beadShadeGC[2]);
      w->abacus.beadShadeGC[2] = XtGetGC((Widget) w, valueMask, &values);
      if (!w->abacus.mono) {
            values.foreground = darker(w, values.foreground);
      }
      if (w->abacus.beadShadeGC[3])
            XtReleaseGC((Widget) w, w->abacus.beadShadeGC[3]);
      w->abacus.beadShadeGC[3] = XtGetGC((Widget) w, valueMask, &values);
      if (!w->abacus.mono) {
            values.foreground = darker(w, values.foreground);
      }
      if (w->abacus.beadShadeGC[4])
            XtReleaseGC((Widget) w, w->abacus.beadShadeGC[4]);
      w->abacus.beadShadeGC[4] = XtGetGC((Widget) w, valueMask, &values);
      if (w->abacus.mono) {
            if (w->abacus.reverse) {
                  values.foreground = w->abacus.foreground;
                  values.background = w->abacus.background;
            } else {
                  values.foreground = w->abacus.background;
                  values.background = w->abacus.foreground;
            }
      } else {
            values.foreground = w->abacus.borderColor;
            values.background = w->abacus.beadColor;
      }
      if (w->abacus.borderGC)
            XtReleaseGC((Widget) w, w->abacus.borderGC);
      w->abacus.borderGC = XtGetGC((Widget) w, valueMask, &values);
}

static Boolean
SetValuesAbacus(Widget current, Widget request, Widget renew)
{
      AbacusWidget c = (AbacusWidget) current, w = (AbacusWidget) renew;
      Boolean redraw = False;
      Boolean redrawBeads = False;
      Boolean sign = False, orient = w->abacus.decks[BOTTOM].orientation;
      int quarter = 0, quarterPercent = 0, value;

      if (w->abacus.demo && ((w->abacus.mode != c->abacus.mode) ||
                  (w->abacus.demo != c->abacus.demo))) {
            ClearAllBeads(w);
            if (!EmptyCounter(w)) {
                  DISPLAY_WARNING("corruption");
            }
            SetCounter(w, 0, w->abacus.decimalPosition, 0); /* needed when 0 */
      }
      if (strncasecmp(w->abacus.format, c->abacus.format,
                  MAXLENFORMAT) != 0) {
            SetModeFromFormat(w);
            SetAbacus(w, ABACUS_FORMAT);
            if (w->abacus.demo)
                  ClearRails(w);
      }
      if (w->abacus.quarter && w->abacus.decimalPosition < 1) {
            w->abacus.quarter = False;
            c->abacus.quarter = False;
            SetAbacus(w, ABACUS_QUARTER);
      }
      CheckBeads(w);
      if (w->abacus.sign) {
            value = w->abacus.decks[BOTTOM].position[w->abacus.rails - 1];
            sign = ((value == 1 && !orient) || (value == 0 && orient));
      }
      if (w->abacus.quarter) {
            value = w->abacus.decks[BOTTOM].position[w->abacus.decimalPosition -
                  1];
            quarter = ((orient) ? QUARTERS - value : value);
      }
      if (w->abacus.quarterPercent) {
            value = w->abacus.decks[BOTTOM].position[w->abacus.decimalPosition -
            MAX_FRACTION_DIGITS - 1 - ((w->abacus.quarter) ? 1 : 0)];
            quarterPercent = ((orient) ? QUARTERPERCENTS - value : value);
      }
      CheckBeads(w);
      if (w->core.background_pixel != c->core.background_pixel ||
                  w->abacus.foreground != c->abacus.foreground ||
                  w->abacus.borderColor != c->abacus.borderColor ||
                  w->abacus.beadColor != c->abacus.beadColor ||
                  w->abacus.railColor != c->abacus.railColor ||
                  w->abacus.reverse != c->abacus.reverse ||
                  w->abacus.mono != c->abacus.mono) {
            SetAllColors(w);
            redrawBeads = True;
      }
      if (w->abacus.rails != c->abacus.rails) {
            ShiftedRails(c, w);
      }
      if (w->abacus.sign != c->abacus.sign) {
            if (w->abacus.sign) {
                  if (!InsertSpecialRail(w, w->abacus.rails - 1)) {
                        w->abacus.sign = !w->abacus.sign;
                        SetAbacus(w, ABACUS_SIGN);
                  }
            } else {
                  if (!DeleteSpecialRail(w, w->abacus.rails - 1)) {
                        w->abacus.sign = !w->abacus.sign;
                        SetAbacus(w, ABACUS_SIGN);
                  }
            }
      }
      if (w->abacus.quarter != c->abacus.quarter) {
            if (w->abacus.quarter) {
                  if (!InsertSpecialRail(w,
                              w->abacus.decimalPosition - 1)) {
                        w->abacus.quarter = !w->abacus.quarter;
                        SetAbacus(w, ABACUS_QUARTER);
                  }
            } else {
                  if (!DeleteSpecialRail(w,
                              w->abacus.decimalPosition - 1)) {
                        w->abacus.quarter = !w->abacus.quarter;
                        SetAbacus(w, ABACUS_QUARTER);
                  }
            }
      }
      if (w->abacus.quarterPercent != c->abacus.quarterPercent) {
            if (w->abacus.quarterPercent) {
                  if (!InsertSpecialRail(w, w->abacus.decimalPosition -
                              MAX_FRACTION_DIGITS - 1 -
                              ((w->abacus.quarter) ? 1 : 0))) {
                        w->abacus.quarterPercent =
                              !w->abacus.quarterPercent;
                        SetAbacus(w, ABACUS_QUARTERPERCENT);
                  }
            } else {
                  if (!DeleteSpecialRail(w, w->abacus.decimalPosition -
                              MAX_FRACTION_DIGITS - 1 -
                              ((w->abacus.quarter) ? 1 : 0))) {
                        w->abacus.quarterPercent =
                              !w->abacus.quarterPercent;
                        SetAbacus(w, ABACUS_QUARTERPERCENT);
                  }
            }
      }
      if (w->abacus.vertical != c->abacus.vertical) {
            ResizeAbacus(w);
            ResizeBead(w);
            DrawAllBufferedBeads(w);
            redraw = True;
      }
      if (w->abacus.displayBase != c->abacus.displayBase) {
            SetCounter(w, 0, w->abacus.decimalPosition, 0);
      }
      if (w->abacus.decks[BOTTOM].number != c->abacus.decks[BOTTOM].number ||
                  w->abacus.decks[TOP].number !=
                  c->abacus.decks[TOP].number ||
                  w->abacus.decks[BOTTOM].factor !=
                  c->abacus.decks[BOTTOM].factor ||
                  w->abacus.decks[TOP].factor !=
                  c->abacus.decks[TOP].factor ||
                  w->abacus.decks[BOTTOM].spaces !=
                  c->abacus.decks[BOTTOM].spaces ||
                  w->abacus.decks[TOP].spaces !=
                  c->abacus.decks[TOP].spaces ||
                  w->abacus.diamond != c->abacus.diamond ||
                  w->abacus.slot != c->abacus.slot ||
                  w->abacus.decimalPosition !=
                  c->abacus.decimalPosition ||
                  w->abacus.base != c->abacus.base) {
            ReformatRails(w, sign, quarter, quarterPercent);
            redraw = False;
      }
      if (w->abacus.decks[BOTTOM].orientation !=
                  c->abacus.decks[BOTTOM].orientation ||
                  w->abacus.decks[TOP].orientation !=
                  c->abacus.decks[TOP].orientation) {
            redraw = True;
      }
      if (w->abacus.pos.x != c->abacus.pos.x ||
                  w->abacus.pos.y != c->abacus.pos.y)
            redrawBeads = True;
      if (redrawBeads && !redraw && XtIsRealized(renew) &&
                  renew->core.visible) {
            EraseFrame(c, 0);
            DrawFrame(w, 0, True, True);
            DrawAllBeads(w);
      }
      if (w->abacus.menu != -1) {
            int menu = w->abacus.menu;

            w->abacus.menu = -1;
            switch (menu) {
            case 1:
                  ClearRails(w);
                  break;
            case 2:
                  IncrementRails(w);
                  break;
            case 3:
                  DecrementRails(w);
                  break;
            case 4:
                  FormatRails(w);
                  break;
            case 5:
                  RomanNumeralsRails(w);
                  break;
            case 6:
                  SignRails(w);
                  break;
            case 7:
                  QuarterRails(w);
                  break;
            case 8:
                  SpeedBead(w);
                  break;
            case 9:
                  SlowBead(w);
                  break;
            case 10:
                  SoundBead(w);
                  break;
            /* Reorder the following when working */
            case 11:
                  QuarterPercentRails(w);
                  break;
            case 12:
                  VerticalRails(w);
                  break;
            default:
                  break;
            }
      }
      if (w->abacus.deck == ABACUS_CLEAR) {
            w->abacus.deck = ABACUS_IGNORE;
            ClearAllBeads(w);
      } else if (w->abacus.deck == ABACUS_CALC) {
            w->abacus.deck = ABACUS_IGNORE;
            calculate(w, w->abacus.mathBuffer);
      } else if (w->abacus.deck != ABACUS_IGNORE) {
            if (CheckMove(w)) {
                  MoveBeadsByValue(w, w->abacus.deck, w->abacus.rail
                        + w->abacus.decimalPosition, w->abacus.number,
                        False);
            }
            w->abacus.deck = ABACUS_IGNORE;
      }
      return (redraw);
}

static void
QuitAbacus(AbacusWidget w
#ifndef WINVER
, XEvent * event, char **args, int nArgs
#endif
)
{
#ifdef WINVER
      if (w->abacus.freeDC) {
            int sel, shade;

            for (sel = 0; sel < 2; sel++)
                  for (shade = 0; shade < 2; shade++) {
                        if (w->abacus.bufferBead[sel][shade] != NULL) {
                              DeleteObject(w->abacus.bufferBead[sel][shade]);
                              w->abacus.bufferBead[sel][shade] = NULL;
                        }
                  }
            DeleteDC(w->abacus.memDC);
            w->abacus.memDC = NULL;
      }
#else
      XtCloseDisplay(XtDisplay(w));
#endif
      exit(0);
}

static void
DestroyAbacus(Widget old)
{
      AbacusWidget w = (AbacusWidget) old;
      int i;

#ifdef SCRIPTFILE
      if (w->abacus.script) {
            char buf[512];

            (void) fclose(w->abacus.fp);
            (void) sprintf(buf, "Saved to %s.", SCRIPTFILE);
            DISPLAY_INFO(buf);
      }
#endif
      for (i = 0; i < 5; i++)
            XtReleaseGC(old, w->abacus.beadShadeGC[i]);
      XtReleaseGC(old, w->abacus.borderGC);
      XtReleaseGC(old, w->abacus.railGC);
      XtReleaseGC(old, w->abacus.frameGC);
      XtReleaseGC(old, w->abacus.inverseGC);
      XtRemoveCallbacks(old, XtNselectCallback, w->abacus.select);
}
#endif

static void
ResizeBead(AbacusWidget w)
{
      int sel, shade;

#ifdef WINVER
      if (w->abacus.memDC == NULL) {
            w->abacus.memDC = CreateCompatibleDC(w->core.hDC);
            if (w->abacus.memDC == NULL) {
                  DISPLAY_ERROR("Not enough memory, exiting.");
            }
      }
#else
      Display *display = XtDisplay(w);
      Window window = XtWindow(w);
      XWindowAttributes xgwa;

      (void) XGetWindowAttributes(display, window, &xgwa);
      if (w->abacus.colormap == None) {
            w->abacus.mono = (xgwa.depth < 2 || w->abacus.mono);
            w->abacus.colormap = xgwa.colormap;
      }
#endif
      for (sel = 0; sel < 2; sel++)
            for (shade = 0; shade < 2; shade++) {
#ifdef WINVER
                  if (w->abacus.bufferBead[sel][shade] != NULL) {
                        DeleteObject(w->abacus.bufferBead[sel][shade]);
                        w->abacus.bufferBead[sel][shade] = NULL;
                  }
                  if ((w->abacus.bufferBead[sel][shade] = CreateCompatibleBitmap(w->core.hDC,
                      w->abacus.beadSize.x + 1, w->abacus.pos.y - 1)) == NULL) {
                    DISPLAY_ERROR("Not enough memory, exiting.");
                  }
#else
                  if (w->abacus.bufferBead[sel][shade] != None) {
                        XFreePixmap(display, w->abacus.bufferBead[sel][shade]);
                        w->abacus.bufferBead[sel][shade] = None;
                  }
                  if ((w->abacus.bufferBead[sel][shade] = XCreatePixmap(display, window,
                      w->abacus.beadSize.x + 1, w->abacus.pos.y - 1,
                      xgwa.depth)) == None) {
                    DISPLAY_ERROR("Not enough memory, exiting.");
                  }
#endif
            }
#ifndef WINVER
      SetAllColors(w);
#endif
}

#ifndef WINVER
static
#endif
void
ResizeAbacus(AbacusWidget w)
{
      int height;
#ifdef WINVER
      RECT rect;

      /* Determine size of client area */
      (void) GetClientRect(w->core.hWnd, &rect);
      w->core.width = rect.right;
      w->core.height = rect.bottom;
      if (w->abacus.demo) {
            w->abacusDemo.fontHeight = 16;
            w->core.height -= LINES * 16; /* fontHeight? */
            w->abacusDemo.framed = True;
      }
#endif

      w->abacus.delta.x = 8;
      w->abacus.delta.y = 2;
      w->abacus.midHeight = 6;
      w->abacus.frameSize.x = ((w->abacus.vertical) ? w->core.height :
            w->core.width);
      w->abacus.frameSize.y = ((w->abacus.vertical) ? w->core.width :
            w->core.height);
      w->abacus.pos.x = MAX(((int) w->abacus.frameSize.x -
            w->abacus.delta.x) / w->abacus.rails, w->abacus.delta.x);
      w->abacus.pos.y = MAX(((int) w->abacus.frameSize.y - 2 *
            w->abacus.delta.y - w->abacus.midHeight) /
            (w->abacus.decks[TOP].room + w->abacus.decks[BOTTOM].room),
            w->abacus.delta.y);
      w->abacus.width = w->abacus.pos.x * w->abacus.rails +
            w->abacus.delta.x + 2;
      w->abacus.decks[TOP].height = w->abacus.pos.y *
            w->abacus.decks[TOP].room + w->abacus.delta.y + 2;
      w->abacus.decks[BOTTOM].height = w->abacus.pos.y *
            w->abacus.decks[BOTTOM].room + w->abacus.delta.y + 2;
      height = w->abacus.decks[TOP].height + w->abacus.decks[BOTTOM].height;
      w->abacus.offset.x = ((int) w->abacus.frameSize.x - w->abacus.width +
            2) / 2;
      w->abacus.offset.y = ((int) w->abacus.frameSize.y - height -
            w->abacus.midHeight + 5) / 2 + 1;
      w->abacus.midBarY = w->abacus.decks[TOP].room * w->abacus.pos.y +
            w->abacus.delta.y - 1 + w->abacus.offset.y;
      if (w->abacus.slot)
            w->abacus.railWidth = w->abacus.pos.x / 8 + 1;
      else
            w->abacus.railWidth = w->abacus.pos.x / 40 + 1;
      w->abacus.beadSize.x = w->abacus.pos.x - w->abacus.delta.x;
      w->abacus.beadSize.y = w->abacus.pos.y - w->abacus.delta.y;
}

#ifndef WINVER
static
#endif
void
InitializeAbacus(
#ifdef WINVER
AbacusWidget w, HBRUSH brush
#else
Widget request, Widget renew
#endif
)
{
      int deck;
#ifdef WINVER
      SetValuesAbacus(w);
      brush = CreateSolidBrush(w->abacus.inverseGC);
      SETBACK(w->core.hWnd, brush);
      w->abacus.bufferBead[0][0] = NULL;
      w->abacus.bufferBead[0][1] = NULL;
      w->abacus.bufferBead[1][0] = NULL;
      w->abacus.bufferBead[1][1] = NULL;
#else
      AbacusWidget w = (AbacusWidget) renew;
      int i;

      w->abacus.bufferBead[0][0] = None;
      w->abacus.bufferBead[0][1] = None;
      w->abacus.bufferBead[1][0] = None;
      w->abacus.bufferBead[1][1] = None;
      w->abacus.colormap = None;
      for (i = 0; i < 5; i++)
            w->abacus.beadShadeGC[i] = NULL;
      w->abacus.borderGC = NULL;
      w->abacus.railGC = NULL;
      w->abacus.frameGC = NULL;
      w->abacus.inverseGC = NULL;
#endif
      w->abacus.focus = False;
      w->abacus.numSlices = ((w->abacus.delay < 5 * MAXSLICES) ?
            w->abacus.delay / 5 + 1 : MAXSLICES);
#ifndef QUARTER_PERCENT
      w->abacus.quarterPercent = False;
#endif
#ifndef VERTICAL
      w->abacus.vertical = False;
#endif
      for (deck = 0; deck < MAXDECKS; deck++)
            w->abacus.decks[deck].position = NULL;
      w->abacus.digits = NULL;
      w->abacus.decimalPosition = MAX_FRACTION_DIGITS;
      if (w->abacus.quarter)
            w->abacus.decimalPosition++;
      if (w->abacus.quarterPercent)
            w->abacus.decimalPosition++;
      /* w->abacus.decimalPosition = w->abacus.rails / 2 */
      SetModeFromFormat(w);
      CheckBeads(w);
      ResetBeads(w);
      ResizeAbacus(w);
#ifdef SCRIPTFILE
      if (w->abacus.script) {
            if ((w->abacus.fp = fopen(SCRIPTFILE, "w")) == NULL) {
                  char buf[512];

                  (void) sprintf(buf, "Can not write to %s.",
                        SCRIPTFILE);
                  DISPLAY_WARNING(buf);
            }
      }
#endif
}

#ifndef WINVER
static
#endif
void
ExposeAbacus(
#ifdef WINVER
AbacusWidget w
#else
Widget renew, XEvent * event, Region region
#endif
)
{
#ifndef WINVER
      AbacusWidget w = (AbacusWidget) renew;

      if (!w->core.visible)
            return;
#endif
      ResizeBead(w);
      DrawAllBufferedBeads(w);
      EraseFrame(w, 0);
      DrawFrame(w, 0, True, w->abacus.focus);
      DrawAllBeads(w);
}

#ifndef WINVER
static
#endif
void
HideAbacus(AbacusWidget w
#ifndef WINVER
, XEvent * event, char **args, int nArgs
#endif
)
{
      SetAbacus(w, ABACUS_HIDE);
}

#ifndef WINVER
static
#endif
void
SelectAbacus(AbacusWidget w
#ifdef WINVER
, const int x, const int y
#else
, XEvent * event, char **args, int nArgs
#endif
)
{
      int deck, rail, j, bead;
#ifndef WINVER
      int x = event->xbutton.x, y = event->xbutton.y;
#endif

      if (w->abacus.demo) {
            ClearAllBeads(w);
            SetAbacus(w, ABACUS_CLEAR);
            w->abacus.currentDeck = -1;
      } else if ((!w->abacus.vertical && (y >= w->abacus.midBarY) &&
                  (y <= w->abacus.midBarY + w->abacus.midHeight))) {
            rail = w->abacus.rails -
                  (x + 1 + w->abacus.railWidth / 2 -
                  w->abacus.delta.x - w->abacus.offset.x) /
                  w->abacus.pos.x - 1;
            SetDecimal(w, rail);
      } else if ((w->abacus.vertical && (x <= w->abacus.frameSize.y - 1 - w->abacus.midBarY) &&
            (x >= w->abacus.frameSize.y - 1 - w->abacus.midBarY - w->abacus.midHeight))) {
            rail = w->abacus.rails -
                  (y - w->abacus.beadSize.x / 2 -
                  w->abacus.delta.x - w->abacus.offset.x) /
                  w->abacus.pos.x - 1;
            SetDecimal(w, rail);
      } else if (PositionToBead(w, x, y, &deck, &rail, &j)) {
            w->abacus.currentDeck = deck;
            w->abacus.currentRail = rail;
            w->abacus.currentPosition = j;
            bead = j;
            if (bead > w->abacus.decks[deck].position[rail])
                  bead -= w->abacus.decks[deck].spaces;
            DrawBead(w, deck, rail, bead, j, True, False, TRUE, 0, 0);
      } else
            w->abacus.currentDeck = -1;
}

#ifndef WINVER
static
#endif
void
ReleaseAbacus(AbacusWidget w
#ifndef WINVER
, XEvent * event, char **args, int nArgs
#endif
)
{
      int bead;

      if (w->abacus.currentDeck < 0)
            return;
      bead = w->abacus.currentPosition;
      if (bead > w->abacus.decks[w->abacus.currentDeck].position[w->abacus.currentRail])
            bead -= w->abacus.decks[w->abacus.currentDeck].spaces;
      DrawBead(w, w->abacus.currentDeck, w->abacus.currentRail,
            bead, w->abacus.currentPosition, False, False, TRUE, 0, 0);
      DrawBead(w, w->abacus.currentDeck, w->abacus.currentRail,
            bead, w->abacus.currentPosition, True, False, FALSE, 0, 0);
      MoveBeadsByPos(w, w->abacus.currentDeck, w->abacus.currentRail,
            w->abacus.currentPosition, False);
      w->abacus.currentDeck = -1;
}

#ifndef WINVER
static
#endif
void
ClearAbacus(AbacusWidget w
#ifndef WINVER
, XEvent * event, char **args, int nArgs
#endif
)
{
      ClearRails(w);
}

#ifndef WINVER
static
void
ClearAbacusMaybe(AbacusWidget w
, XEvent * event, char **args, int nArgs
)
{
#ifdef HAVE_MOTIF
      if (!EmptyCounter(w) && !w->abacus.aux) {
            /* Check if one really wants to destroy calculations. */
            SetAbacus(w, ABACUS_CLEAR_QUERY);
      }
#endif
}

static
void
ClearAbacus2(AbacusWidget w
, XEvent * event, char **args, int nArgs
)
{
#ifndef HAVE_MOTIF
      ClearRails(w);
#endif
}
#endif

#ifndef WINVER
static
#endif
void
IncrementAbacus(AbacusWidget w
#ifndef WINVER
, XEvent * event, char **args, int nArgs
#endif
)
{
      IncrementRails(w);
}

#ifndef WINVER
static
#endif
void
DecrementAbacus(AbacusWidget w
#ifndef WINVER
, XEvent * event, char **args, int nArgs
#endif
)
{
      DecrementRails(w);
}

#ifndef WINVER
static
#endif
void
SpeedAbacus(AbacusWidget w
#ifndef WINVER
, XEvent * event, char **args, int nArgs
#endif
)
{
      SpeedBead(w);
}

#ifndef WINVER
static
#endif
void
SlowAbacus(AbacusWidget w
#ifndef WINVER
, XEvent * event, char **args, int nArgs
#endif
)
{
      SlowBead(w);
}

#ifndef WINVER
static
#endif
void
SoundAbacus(AbacusWidget w
#ifndef WINVER
, XEvent * event, char **args, int nArgs
#endif
)
{
      SoundBead(w);
}

#ifndef WINVER
static
#endif
void
FormatAbacus(AbacusWidget w
#ifndef WINVER
, XEvent * event, char **args, int nArgs
#endif
)
{
      FormatRails(w);
}

#ifndef WINVER
static
#endif
void
RomanNumeralsAbacus(AbacusWidget w
#ifndef WINVER
, XEvent * event, char **args, int nArgs
#endif
)
{
      RomanNumeralsRails(w);
}

#ifndef WINVER
static
#endif
void
SignAbacus(AbacusWidget w
#ifndef WINVER
, XEvent * event, char **args, int nArgs
#endif
)
{
      SignRails(w);
}

#ifndef WINVER
static
#endif
void
QuarterAbacus(AbacusWidget w
#ifndef WINVER
, XEvent * event, char **args, int nArgs
#endif
)
{
      QuarterRails(w);
}

#ifndef WINVER
static
#endif
void
QuarterPercentAbacus(AbacusWidget w
#ifndef WINVER
, XEvent * event, char **args, int nArgs
#endif
)
{
      QuarterPercentRails(w);
}

#ifndef WINVER
static
#endif
void
VerticalAbacus(AbacusWidget w
#ifndef WINVER
, XEvent * event, char **args, int nArgs
#endif
)
{
      VerticalRails(w);
}

#ifndef WINVER
static
void
DemoAbacus(AbacusWidget w
, XEvent * event, char **args, int nArgs
)
{
      SetAbacus(w, ABACUS_DEMO);
}

static
void
NextAbacus(AbacusWidget w
, XEvent * event, char **args, int nArgs
)
{
      if (w->abacus.demo) {
            SetAbacus(w, ABACUS_NEXT);
      }
}

static
void
RepeatAbacus(AbacusWidget w
, XEvent * event, char **args, int nArgs
)
{
      if (w->abacus.demo) {
            SetAbacus(w, ABACUS_REPEAT);
      }
}

static
void
MoreAbacus(AbacusWidget w
, XEvent * event, char **args, int nArgs
)
{
      if (w->abacus.demo) {
            SetAbacus(w, ABACUS_MORE);
      }
}
#endif

#ifndef WINVER
static
#endif
void
EnterAbacus(AbacusWidget w
#ifndef WINVER
, XEvent * event, char **args, int nArgs
#endif
)
{
      w->abacus.focus = True;
      DrawFrame(w, 0, True, w->abacus.focus);
}

#ifndef WINVER
static
#endif
void
LeaveAbacus(AbacusWidget w
#ifndef WINVER
, XEvent * event, char **args, int nArgs
#endif
)
{
      w->abacus.focus = False;
      DrawFrame(w, 0, True, w->abacus.focus);
}

#ifdef OLDANDINTHEWAY
/* This routine will do a XFillArc for a circle */
DiskXI(Display * display, Window window, GC gc, int diameter,
            int ctrX, int ctrY)
{
      int x, y, p, d;

      x = 0;
      y = diameter >> 1;
      p = diameter & 1;
      d = 1 - 2 * y + p;
      while (x < y) {
            DiskPointsXI(display, window, gc, ctrX, ctrY, x, y, p);
            if (d < 0)
                  d = d + (4 * x) + 6;
            else {
                  d = d + (4 * (x - y)) + 10;
                  y--;
            }
            x++;
      }
      if (x == y)
            DiskPointsXI(display, window, gc, ctrX, ctrY, x, y, p);
}                       /* DiskXI */

DiskPointsXI(Display * display, Window window, GC gc, int ctrX, int ctrY,
            int x, int y, int p)
{
      XFillRectangle(display, window, gc,
            ctrX - x, ctrY - y, 2 * x + p + 1, 1);
      XFillRectangle(display, window, gc,
            ctrX - x, ctrY + y + p, 2 * x + p + 1, 1);
      XFillRectangle(display, window, gc,
            ctrX - y, ctrY - x, 2 * y + p + 1, 1);
      XFillRectangle(display, window, gc,
            ctrX - y, ctrY + x + p, 2 * y + p + 1, 1);
      /*XDrawLine(display, window, gc, ctrX - x, ctrY - y, ctrX + x + p, ctrY - y);
      XDrawLine(display, window, gc,
            ctrX - x, ctrY + y + p, ctrX + x + p, ctrY + y + p);
      XDrawLine(display, window, gc, ctrX - y, ctrY - x, ctrX + y + p, ctrY - x);
      XDrawLine(display, window, gc,
            ctrX - y, ctrY + x + p, ctrX + y + p, ctrY + x + p); */
}                       /* DiskPointsXI */

#endif

Generated by  Doxygen 1.6.0   Back to index