Logo Search packages:      
Sourcecode: xabacus version File versions  Download package

Abacus.c

/*
 * @(#)Abacus.c
 *
 * Copyright 1994 - 2010  David A. 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 */

#include "file.h"
#include "rngs.h"
#include "sound.h"
#include "AbacusP.h"
static Boolean deleteSpecialRail(AbacusWidget w,
      Boolean sign, Boolean piece, Boolean piecePercent);

#ifdef WINVER
#ifndef SCRIPTFILE
#define SCRIPTFILE "Abacus.les"
#endif

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

#if defined( USE_SOUND ) && defined( USE_NAS )
Display *dsp;
#endif

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 complementAbacus(AbacusWidget w,
      XEvent *event, char **args, int nArgs);
static void clearWithQueryAbacus(AbacusWidget w,
      XEvent *event, char **args, int nArgs);
static void clearWithDoubleClickAbacus(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 speedUpAbacus(AbacusWidget w,
      XEvent *event, char **args, int nArgs);
static void slowDownAbacus(AbacusWidget w,
      XEvent *event, char **args, int nArgs);
static void toggleSoundAbacus(AbacusWidget w,
      XEvent *event, char **args, int nArgs);
static void changeFormatAbacus(AbacusWidget w,
      XEvent *event, char **args, int nArgs);
static void changeMuseumAbacus(AbacusWidget w,
      XEvent *event, char **args, int nArgs);
static void toggleRomanNumeralsAbacus(AbacusWidget w,
      XEvent *event, char **args, int nArgs);
static void toggleGroupingAbacus(AbacusWidget w,
      XEvent *event, char **args, int nArgs);
static void toggleNegativeSignAbacus(AbacusWidget w,
      XEvent *event, char **args, int nArgs);
static void toggleQuartersAbacus(AbacusWidget w,
      XEvent *event, char **args, int nArgs);
static void toggleQuarterPercentsAbacus(AbacusWidget w,
      XEvent *event, char **args, int nArgs);
static void toggleTwelfthsAbacus(AbacusWidget w,
      XEvent *event, char **args, int nArgs);
static void toggleSubdecksAbacus(AbacusWidget w,
      XEvent *event, char **args, int nArgs);
static void toggleEighthsAbacus(AbacusWidget w,
      XEvent *event, char **args, int nArgs);
static void toggleAnomalyAbacus(AbacusWidget w,
      XEvent *event, char **args, int nArgs);
static void toggleWatchAbacus(AbacusWidget w,
      XEvent *event, char **args, int nArgs);
static void toggleDemoAbacus(AbacusWidget w,
      XEvent *event, char **args, int nArgs);
static void showNextAbacus(AbacusWidget w,
      XEvent *event, char **args, int nArgs);
static void showRepeatAbacus(AbacusWidget w,
      XEvent *event, char **args, int nArgs);
static void showMoreAbacus(AbacusWidget w,
      XEvent *event, char **args, int nArgs);
static void toggleTeachAbacus(AbacusWidget w,
      XEvent *event, char **args, int nArgs);
static void toggleRightToLeftAddAbacus(AbacusWidget w,
      XEvent *event, char **args, int nArgs);
static void toggleRightToLeftMultAbacus(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 translations[] =
"<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\
 <KeyPress>0x2E: Speed()\n\
 <KeyPress>0x3E: Speed()\n\
 <KeyPress>0x3C: Slow()\n\
 <KeyPress>0x2C: Slow()\n\
 Shift<KeyPress>2: Sound()\n\
 <Btn1Down>: Select()\n\
 <Btn1Up>: Release()\n\
 <KeyPress>c: Clear()\n\
 <Btn3Down>: ClearWithQuery()\n\
 <Btn3Down>(2+): ClearWithDoubleClick()\n\
 <KeyPress>~: Complement()\n\
 <KeyPress>`: Complement()\n\
 <KeyPress>i: Increment()\n\
 <KeyPress>d: Decrement()\n\
 <KeyPress>f: Format()\n\
 <KeyPress>e: Museum()\n\
 <KeyPress>m: RomanNumerals()\n\
 <KeyPress>g: Group()\n\
 <KeyPress>s: Sign()\n\
 <KeyPress>u: Quarter()\n\
 <KeyPress>p: QuarterPercent()\n\
 <KeyPress>t: Twelfth()\n\
 <KeyPress>b: Subdeck()\n\
 <KeyPress>h: Eighth()\n\
 <KeyPress>l: Anomaly()\n\
 <KeyPress>w: Watch()\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\
 <KeyPress>$: Teach()\n\
 <KeyPress>+: RightToLeftAdd()\n\
 <KeyPress>*: RightToLeftMult()\n\
 <EnterWindow>: Enter()\n\
 <LeaveWindow>: Leave()";

static XtActionsRec actionsList[] =
{
      {(char *) "Quit", (XtActionProc) quitAbacus},
      {(char *) "Hide", (XtActionProc) hideAbacus},
      {(char *) "Select", (XtActionProc) selectAbacus},
      {(char *) "Release", (XtActionProc) releaseAbacus},
      {(char *) "Clear", (XtActionProc) clearAbacus},
      {(char *) "ClearWithQuery", (XtActionProc) clearWithQueryAbacus},
      {(char *) "ClearWithDoubleClick", (XtActionProc) clearWithDoubleClickAbacus},
      {(char *) "Complement", (XtActionProc) complementAbacus},
      {(char *) "Increment", (XtActionProc) incrementAbacus},
      {(char *) "Decrement", (XtActionProc) decrementAbacus},
      {(char *) "Speed", (XtActionProc) speedUpAbacus},
      {(char *) "Slow", (XtActionProc) slowDownAbacus},
      {(char *) "Sound", (XtActionProc) toggleSoundAbacus},
      {(char *) "Format", (XtActionProc) changeFormatAbacus},
      {(char *) "Museum", (XtActionProc) changeMuseumAbacus},
      {(char *) "RomanNumerals", (XtActionProc) toggleRomanNumeralsAbacus},
      {(char *) "Group", (XtActionProc) toggleGroupingAbacus},
      {(char *) "Sign", (XtActionProc) toggleNegativeSignAbacus},
      {(char *) "Quarter", (XtActionProc) toggleQuartersAbacus},
      {(char *) "QuarterPercent", (XtActionProc) toggleQuarterPercentsAbacus},
      {(char *) "Twelfth", (XtActionProc) toggleTwelfthsAbacus},
      {(char *) "Subdeck", (XtActionProc) toggleSubdecksAbacus},
      {(char *) "Eighth", (XtActionProc) toggleEighthsAbacus},
      {(char *) "Anomaly", (XtActionProc) toggleAnomalyAbacus},
      {(char *) "Watch", (XtActionProc) toggleWatchAbacus},
      {(char *) "Demo", (XtActionProc) toggleDemoAbacus},
      {(char *) "Next", (XtActionProc) showNextAbacus},
      {(char *) "Repeat", (XtActionProc) showRepeatAbacus},
      {(char *) "More", (XtActionProc) showMoreAbacus},
      {(char *) "Teach", (XtActionProc) toggleTeachAbacus},
      {(char *) "RightToLeftAdd", (XtActionProc) toggleRightToLeftAddAbacus},
      {(char *) "RightToLeftMult", (XtActionProc) toggleRightToLeftMultAbacus},
      {(char *) "Enter", (XtActionProc) enterAbacus},
      {(char *) "Leave", (XtActionProc) leaveAbacus}
};

static XtResource resources[] =
{
      {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"},
      {XtNmono, XtCMono, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.mono),
       XtRString, (caddr_t) "FALSE"},
      {XtNreverseVideo, XtCReverseVideo, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.reverse),
       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) "#AEB2C3" /*XtDefaultBackground*/},
      {XtNborderColor, XtCForeground, XtRPixel, sizeof (Pixel),
       XtOffset(AbacusWidget, abacus.borderColor),
       XtRString, (caddr_t) "gray25" /*XtDefaultForeground*/},
      {XtNframeColor, XtCColor, XtRPixel, sizeof (Pixel),
       XtOffset(AbacusWidget, abacus.frameColor),
       XtRString, (caddr_t) "wheat4" /*XtDefaultForeground*/},
      {XtNprimaryBeadColor, XtCForeground, XtRPixel, sizeof (Pixel),
       XtOffset(AbacusWidget, abacus.beadColor[0]),
       XtRString, (caddr_t) "DarkRed" /*XtDefaultForeground*/},
      {XtNleftAuxBeadColor, XtCForeground, XtRPixel, sizeof (Pixel),
       XtOffset(AbacusWidget, abacus.leftAuxColor),
       XtRString, (caddr_t) "LimeGreen" /*XtDefaultForeground*/},
      {XtNrightAuxBeadColor, XtCForeground, XtRPixel, sizeof (Pixel),
       XtOffset(AbacusWidget, abacus.rightAuxColor),
       XtRString, (caddr_t) "gainsboro" /*XtDefaultForeground*/},
      {XtNsecondaryBeadColor, XtCForeground, XtRPixel, sizeof (Pixel),
       XtOffset(AbacusWidget, abacus.beadColor[1]),
       XtRString, (caddr_t) "wheat4" /*XtDefaultForeground*/},
      {XtNhighlightBeadColor, XtCForeground, XtRPixel, sizeof (Pixel),
       XtOffset(AbacusWidget, abacus.beadColor[2]),
       XtRString, (caddr_t) "magenta" /*XtDefaultForeground*/},
      {XtNprimaryRailColor, XtCForeground, XtRPixel, sizeof (Pixel),
       XtOffset(AbacusWidget, abacus.railColor[0]),
       XtRString, (caddr_t) "gold" /*XtDefaultForeground*/},
      {XtNsecondaryRailColor, XtCForeground, XtRPixel, sizeof (Pixel),
       XtOffset(AbacusWidget, abacus.railColor[1]),
       XtRString, (caddr_t) "LightSteelBlue1" /*XtDefaultForeground*/},
      {XtNhighlightRailColor, XtCForeground, XtRPixel, sizeof (Pixel),
       XtOffset(AbacusWidget, abacus.railColor[2]),
       XtRString, (caddr_t) "Purple" /*XtDefaultForeground*/},
      {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},
      {XtNsound, XtCSound, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.sound),
       XtRString, (caddr_t) "FALSE"},
      {XtNdelay, XtCDelay, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.delay),
       XtRString, (caddr_t) "50"},
      {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"},
      {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},
      {XtNteach, XtCTeach, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.teach),
       XtRString, (caddr_t) "FALSE"},
      {XtNteachBuffer, XtCTeachBuffer, XtRString, sizeof (String),
       XtOffset(AbacusWidget, abacus.teachBuffer),
       XtRString, (caddr_t) ""},
      {XtNrightToLeftAdd, XtCRightToLeftAdd, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.rightToLeftAdd),
       XtRString, (caddr_t) "FALSE"},
      {XtNrightToLeftMult, XtCRightToLeftMult, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.rightToLeftMult),
       XtRString, (caddr_t) "FALSE"},
      {XtNlee, XtCLee, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.lee),
       XtRString, (caddr_t) "TRUE"},
      {XtNrails, XtCRails, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.rails),
       XtRString, (caddr_t) "13"},
      {XtNleftAuxRails, XtCLeftAuxRails, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.leftAuxRails),
       XtRString, (caddr_t) "9"},
      {XtNrightAuxRails, XtCRightAuxRails, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.rightAuxRails),
       XtRString, (caddr_t) "9"},
      {XtNvertical, XtCVertical, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.vertical),
       XtRString, (caddr_t) "FALSE"},
      {XtNcolorScheme, XtCColorScheme, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.colorScheme),
       XtRString, (caddr_t) "0"},
      {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"},
      {XtNrailIndex, XtCRailIndex, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.railIndex),
       XtRString, (caddr_t) "0"},
      {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"},
      {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"},
      {XtNtopPiece, XtCTopPiece, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.decks[TOP].piece),
       XtRString, (caddr_t) "0"},
      {XtNbottomPiece, XtCBottomPiece, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.decks[BOTTOM].piece),
       XtRString, (caddr_t) "0"},
      {XtNtopPiecePercent, XtCTopPiecePercent, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.decks[TOP].piecePercent),
       XtRString, (caddr_t) "0"},
      {XtNbottomPiecePercent, XtCBottomPiecePercent, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.decks[BOTTOM].piecePercent),
       XtRString, (caddr_t) "0"},
      {XtNshiftPercent, XtCShiftPercent, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.shiftPercent),
       XtRString, (caddr_t) "2"},
      {XtNsubdeck, XtCSubdeck, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.subdeck),
       XtRString, (caddr_t) "0"},
      {XtNsubbead, XtCSubbead, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.subbead),
       XtRString, (caddr_t) "4"},
      {XtNsign, XtCSign, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.sign),
       XtRString, (caddr_t) "FALSE"},
      {XtNdecimalPosition, XtCDecimalPosition, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.decimalPosition),
       XtRString, (caddr_t) "2"}, /* same as shiftPercent */
      {XtNgroup, XtCGroup, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.group),
       XtRString, (caddr_t) "FALSE"},
      {XtNgroupSize, XtCGroupSize, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.groupSize),
       XtRString, (caddr_t) "3"},
      {XtNdecimalComma, XtCDecimalComma, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.decimalComma),
       XtRString, (caddr_t) "FALSE"},
      {XtNbase, XtCBase, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.base),
       XtRString, (caddr_t) "10"},
      {XtNsubbase, XtCSubbase, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.subbase),
       XtRString, (caddr_t) "12"},
      {XtNanomaly, XtCAnomaly, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.anomaly),
       XtRString, (caddr_t) "0"},
      {XtNshiftAnomaly, XtCShiftAnomaly, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.shiftAnomaly),
       XtRString, (caddr_t) "2"},
      {XtNanomalySq, XtCAnomalySq, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.anomalySq),
       XtRString, (caddr_t) "0"},
      {XtNshiftAnomalySq, XtCShiftAnomalySq, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.shiftAnomalySq),
       XtRString, (caddr_t) "2"},
      {XtNdisplayBase, XtCDisplayBase, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.displayBase),
       XtRString, (caddr_t) "10"},
      {XtNpressOffset, XtCPressOffset, XtRBoolean, sizeof (int),
       XtOffset(AbacusWidget, abacus.pressOffsetY),
       XtRString, (caddr_t) "0"},
      {XtNromanNumerals, XtCRomanNumerals, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.romanNumerals),
       XtRString, (caddr_t) "FALSE"},
      {XtNlatin, XtCLatin, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.latin),
       XtRString, (caddr_t) "FALSE"},
      {XtNancientRoman, XtCAncientRoman, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.ancientRoman),
       XtRString, (caddr_t) "FALSE"},
      {XtNmodernRoman, XtCModernRoman, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.modernRoman),
       XtRString, (caddr_t) "FALSE"},
      {XtNmode, XtCMode, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.mode),
       XtRString, (caddr_t) "0"}, /* CHINESE */
      {XtNformat, XtCFormat, XtRString, sizeof (String),
       XtOffset(AbacusWidget, abacus.format),
       XtRString, (caddr_t) "Chinese"},
      {XtNmuseum, XtCMuseum, XtRString, sizeof (String),
       XtOffset(AbacusWidget, abacus.museum),
       XtRString, (caddr_t) "--"},
      {XtNversionOnly, XtCBoolean, XtRBoolean, sizeof (Boolean),
       XtOffset(AbacusWidget, abacus.versionOnly),
       XtRString, (caddr_t) "FALSE"},
      {XtNmenu, XtCMenu, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.menu),
       XtRString, (caddr_t) "999"}, /* ACTION_IGNORE */
      {XtNaux, XtCAux, XtRBoolean, sizeof (int),
       XtOffset(AbacusWidget, abacus.aux),
       XtRString, (caddr_t) "0"},
      {XtNdeck, XtCDeck, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.deck),
       XtRString, (caddr_t) "-1"}, /* IGNORE_DECK */
      {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"},
      {XtNmathBuffer, XtCMathBuffer, XtRString, sizeof (String),
       XtOffset(AbacusWidget, abacus.mathBuffer),
       XtRString, (caddr_t) ""},
      {XtNpixmapSize, XtCPixmapSize, XtRInt, sizeof (int),
       XtOffset(AbacusWidget, abacus.pixmapSize),
       XtRString, (caddr_t) "64"},
      {XtNleftAuxAbacus, XtCLeftAuxAbacus, XtRPointer, sizeof (caddr_t),
       XtOffset(AbacusWidget, abacus.leftAux),
       XtRCallback, (caddr_t) NULL},
      {XtNrightAuxAbacus, XtCRightAuxAbacus, XtRPointer, sizeof (caddr_t),
       XtOffset(AbacusWidget, abacus.rightAux),
       XtRCallback, (caddr_t) NULL},
      {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 */
            actionsList,      /* actions */
            XtNumber(actionsList),  /* num actions */
            resources,  /* resources */
            XtNumber(resources),    /* 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 */
            translations,     /* tm table */
            NULL,       /* query geometry */
            NULL,       /* display accelerator */
            NULL        /* extension */
      },
      {
            0           /* ignore */
      }
};

WidgetClass abacusWidgetClass = (WidgetClass) & abacusClassRec;

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);
}

void
setAbacusText(AbacusWidget w, int reason, char * text, int line)
{
        abacusCallbackStruct cb;

        cb.reason = reason;
        cb.line = line;
        cb.teachBuffer = text;
        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);

static char
decimalChar(AbacusWidget w)
{
      return ((w->abacus.decimalComma) ? ',' : '.');
}

static char
groupChar(AbacusWidget w)
{
      return ((w->abacus.decimalComma) ? '.' : ',');
}

static void
setSubmodeFromMuseum(AbacusWidget w)
{
      if (strncasecmp("it", w->abacus.museum,
                  COUNTRY_SIZE) == 0) {
            w->abacus.submode = IT;
      } else if (strncasecmp("uk", w->abacus.museum,
                  COUNTRY_SIZE) == 0) {
            w->abacus.submode = UK;
      } else if (strncasecmp("fr", w->abacus.museum,
                  COUNTRY_SIZE) == 0) {
            w->abacus.submode = FR;
      } else {
            w->abacus.submode = NRAND(MAX_MUSEUMS);
      }
}

static Boolean
submodeSlotsSeparate(int submode)
{
      return (submode == UK);
}

static void
setModeFromFormat(AbacusWidget w)
{
      if (strncasecmp("chinese", w->abacus.format,
                  MAX_FORMAT_LENGTH) == 0) {
            w->abacus.mode = CHINESE;
      } else if (strncasecmp("japanese", w->abacus.format,
                  MAX_FORMAT_LENGTH) == 0) {
            w->abacus.mode = JAPANESE;
      } else if (strncasecmp("korean", w->abacus.format,
                  MAX_FORMAT_LENGTH) == 0) {
            w->abacus.mode = KOREAN;
      } else if (strncasecmp("roman", w->abacus.format,
                  MAX_FORMAT_LENGTH) == 0) {
            w->abacus.mode = ROMAN;
      } else if (strncasecmp("italian", w->abacus.format,
                  MAX_FORMAT_LENGTH) == 0) {
            w->abacus.mode = ROMAN;
      } else if (strncasecmp("russian", w->abacus.format,
                  MAX_FORMAT_LENGTH) == 0) {
            w->abacus.mode = RUSSIAN;
      } else if (strncasecmp("danish", w->abacus.format,
                  MAX_FORMAT_LENGTH) == 0) {
            w->abacus.mode = DANISH;
      } else if (strncasecmp("cn", w->abacus.format, MAX_FORMAT_LENGTH) == 0) {
            w->abacus.mode = CHINESE;
      } else if (strncasecmp("zh", w->abacus.format, MAX_FORMAT_LENGTH) == 0) {
            w->abacus.mode = CHINESE;
      } else if (strncasecmp("jp", w->abacus.format, MAX_FORMAT_LENGTH) == 0) {
            w->abacus.mode = JAPANESE;
      } else if (strncasecmp("ja", w->abacus.format, MAX_FORMAT_LENGTH) == 0) {
            w->abacus.mode = JAPANESE;
      } else if (strncasecmp("ko", w->abacus.format, MAX_FORMAT_LENGTH) == 0) {
            w->abacus.mode = KOREAN;
      } else if (strncasecmp("ro", w->abacus.format, MAX_FORMAT_LENGTH) == 0) {
            w->abacus.mode = ROMAN;
      } else if (strncasecmp("it", w->abacus.format, MAX_FORMAT_LENGTH) == 0) {
            w->abacus.mode = ROMAN;
      } else if (strncasecmp("ru", w->abacus.format, MAX_FORMAT_LENGTH) == 0) {
            w->abacus.mode = RUSSIAN;
      } else if (strncasecmp("dk", w->abacus.format, MAX_FORMAT_LENGTH) == 0) {
            w->abacus.mode = DANISH;
      } else if (strncasecmp("da", w->abacus.format, MAX_FORMAT_LENGTH) == 0) {
            w->abacus.mode = DANISH;
      } else {
            w->abacus.mode = GENERIC;
      }
}

/* This is setup for Roman abacus of 3 subdecks
 * deck == 0 => 1/12 * pieceFactor
 * deck == 1 => 1/4 * pieceFactor
 * deck == 2 => 1/2 * pieceFactor
 * For other subdecks its more whimsical. */
static int
convertRomanFactor(AbacusWidget w, int deck)
{
      int b = w->abacus.decks[BOTTOM].piece;

      if (w->abacus.decks[TOP].piece != 0)
            b *= w->abacus.decks[TOP].piece;
      if (w->abacus.subbase == EIGHTHS) {
            if (deck <= 1)
                  return 1;
            else
                  return deck * b / (w->abacus.subdeck + 2);
      }
      if (deck == 0)
            return 1;
      else
            return deck * b / (w->abacus.subdeck + 1);
}

static int
checkBottomSpace(AbacusWidget w)
{
      return w->abacus.decks[BOTTOM].spaces +
            convertBaseToBottom(w->abacus.base) - 1;
}

Boolean checkPiece(AbacusWidget w)
{
      return (w->abacus.decks[BOTTOM].piece != 0);
}

Boolean checkPiecePercent(AbacusWidget w)
{
      return (w->abacus.decks[BOTTOM].piece != 0 &&
                  w->abacus.decks[BOTTOM].piecePercent != 0);
}

Boolean
checkSubdeck(AbacusWidget w, int position)
{
      return (w->abacus.decks[BOTTOM].piece != 0 &&
            w->abacus.decks[BOTTOM].piecePercent == 0 &&
            w->abacus.slot && w->abacus.subdeck != 0 &&
            w->abacus.decks[BOTTOM].room >= w->abacus.subbead +
            w->abacus.subdeck * SUBDECK_SPACE &&
            w->abacus.decimalPosition == position);
}

static Boolean
checkAnomaly(AbacusWidget w)
{
      /* Record carries from anomalies to add in later */
      return (w->abacus.anomaly != 0);
}

static int
numberPieces(AbacusWidget w, int deck)
{
      int pieces = 0;

      if (deck == BOTTOM) {
            pieces = w->abacus.decks[BOTTOM].piece;
            if (w->abacus.decks[TOP].number == 0 &&
                        w->abacus.decks[TOP].piece != 0)
                  pieces *= w->abacus.decks[TOP].piece;
            if (w->abacus.decks[BOTTOM].number ==
                        w->abacus.decks[TOP].factor - 1)
                  pieces -= 1;
      } else {
            if (w->abacus.decks[TOP].number != 0 &&
                        w->abacus.decks[TOP].piece != 0) {
                  pieces = w->abacus.decks[TOP].piece;
                  if ((w->abacus.decks[TOP].number + 1) *
                              w->abacus.decks[TOP].factor ==
                              w->abacus.base)
                        pieces -= 1;
            }
      }
      return pieces;
}

static int
numberPiecePercents(AbacusWidget w, int deck)
{
      int piecePercents = 0;

      if (deck == BOTTOM) {
            piecePercents = w->abacus.decks[BOTTOM].piecePercent;
            if (w->abacus.decks[TOP].number == 0 &&
                        w->abacus.decks[TOP].piecePercent != 0)
                  piecePercents *= w->abacus.decks[TOP].piecePercent;
            if (w->abacus.decks[BOTTOM].number ==
                        w->abacus.decks[TOP].factor - 1)
                  piecePercents -= 1;
      } else {
            if (w->abacus.decks[TOP].number != 0 &&
                        w->abacus.decks[TOP].piecePercent != 0) {
                  piecePercents = w->abacus.decks[TOP].piecePercent;
                  if ((w->abacus.decks[TOP].number + 1) *
                              w->abacus.decks[TOP].factor ==
                              w->abacus.base)
                        piecePercents -= 1;
            }
      }
      return piecePercents;
}

static int valuePiece(AbacusWidget w) {
      int sum = 0, localBase = 1;
      int factor = 1, rail = w->abacus.decimalPosition - 1;

      if (w->abacus.decks[BOTTOM].piece != 0) {
            int deck;

            for (deck = BOTTOM; deck <= TOP; deck++) {
                  int piecePosition = w->abacus.decks[deck].position[rail];

                  localBase = w->abacus.decks[BOTTOM].piece;
                  if (deck == TOP) {
                        if (w->abacus.decks[TOP].piece == 0) {
                              break;
                        } else {
                              factor = w->abacus.decks[BOTTOM].piece;
                              localBase *= w->abacus.decks[TOP].piece;
                        }
                  }
                  if (w->abacus.decks[deck].orientation) {
                        sum += (numberPieces(w, deck) - piecePosition) *
                              factor;
                  } else {
                        sum += piecePosition * factor;
                  }
            }
      }
      return sum % localBase;
}

#if 0
static int valuePiecePercent(AbacusWidget w) {
      int sum = 0, localBase = 1;
      int factor = 1, rail = w->abacus.decimalPosition - w->abacus.shiftPercent - 1 -
            ((w->abacus.decks[BOTTOM].piece == 0) ? 0 : 1);

      if (w->abacus.decks[BOTTOM].piece != 0 &&
                  w->abacus.decks[BOTTOM].piecePercent != 0) {
            int deck;

            for (deck = BOTTOM; deck <= TOP; deck++) {
                  int piecePercentPosition = w->abacus.decks[deck].position[rail];

                  localBase = w->abacus.decks[BOTTOM].piecePercent;
                  if (deck == TOP) {
                        if (w->abacus.decks[TOP].piecePercent == 0) {
                              break;
                        } else {
                              factor = w->abacus.decks[BOTTOM].piecePercent;
                              localBase *= w->abacus.decks[TOP].piecePercent;
                        }
                  }
                  if (w->abacus.decks[deck].orientation) {
                        sum += (numberPiecePercents(w, deck) -
                              piecePercentPosition) * factor;
                  } else {
                        sum += piecePercentPosition * factor;
                  }
            }
      }
      return sum % localBase;
}
#endif

static int valueSubdeck(AbacusWidget w) {
      int sum = 0;

      if (checkSubdeck(w, 3)) {
            int deck;

            for (deck = 0; deck < w->abacus.subdeck; deck++) {
                  if (w->abacus.decks[BOTTOM].orientation) {
                        sum += (w->abacus.subdecks[deck].number -
                              w->abacus.subdecks[deck].position) *
                              convertRomanFactor(w, deck);
                  } else {
                        sum += w->abacus.subdecks[deck].position *
                              convertRomanFactor(w, deck);
                  }
            }
      }
      return sum;
}

static void
setSpace(AbacusWidget w, int deck)
{
      int room, number;

      room = w->abacus.decks[deck].number + w->abacus.decks[deck].spaces;
      if (w->abacus.decks[BOTTOM].piece != 0) {
            number = numberPieces(w, deck);
            if (room <= number)
                  room = number + 1;
            if (w->abacus.decks[BOTTOM].piecePercent != 0) {
                  number = numberPiecePercents(w, deck);
                  if (room <= number)
                        room = number + 1;
            }
            if (deck == BOTTOM && checkSubdeck(w, 3)) {
                  number = w->abacus.subbead + w->abacus.subdeck *
                        w->abacus.subdecks[deck].spaces - 1;
                  if (room <= number)
                        room = number + 1;
            }
      }
      if (w->abacus.decks[deck].number != 0) {
            if (room > w->abacus.decks[deck].number +
                        w->abacus.decks[deck].spaces)
                  w->abacus.decks[deck].spaces = room -
                        w->abacus.decks[deck].number;
            w->abacus.decks[deck].room = w->abacus.decks[deck].number +
                  w->abacus.decks[deck].spaces;
      }
}

static int numberSubbeads(AbacusWidget w, int subdecks)
{
      if (w->abacus.subdeck != 0)
            return w->abacus.subbead / w->abacus.subdeck +
                  ((w->abacus.subbead % w->abacus.subdeck -
                  subdecks <= 0) ? 0 : 1);
      return 0;
}

static int numberSubbeadsOffset(AbacusWidget w, int subdecks)
{
      int deck, offset = 0;
      int space = 1;

      if (subdecks < 0)
            return w->abacus.subbead + w->abacus.subdeck *
                  w->abacus.subdecks[0].spaces;
      for (deck = 0; deck < w->abacus.subdeck - 1 - subdecks; deck++) {
            offset += numberSubbeads(w, w->abacus.subdeck - 1 - deck) +
                  space;
      }
      return offset;
}

static int positionSubdeck(AbacusWidget w, int j)
{
      int b1, b2, subj, d;

      subj = j;
      b1 = b2 = 0;
      for (d = w->abacus.subdeck - 1; d >= 0; d--) {
            b1 = b2;
            b2 = numberSubbeadsOffset(w, d - 1);
            if (subj <= b2) {
                  subj = subj - b1;
                  break;
            }
      }
      return subj;
}

static int subdeckPosition(AbacusWidget w, int j)
{
      int subj, d;

      subj = j;
      for (d = w->abacus.subdeck - 1; d >= 0; d--) {
            if (subj <= numberSubbeadsOffset(w, d - 1)) {
                  break;
            }
      }
      return d;
}

#if 0
static int numberSubdeck(AbacusWidget w, int subbeads)
{
      int deck, offset = 0;
      int space = 1;

      for (deck = 0; deck < w->abacus.subdeck; deck++) {
            offset += numberSubbeads(w, deck) + space;
            if (offset >= subbeads)
                  return deck;
      }
      return w->abacus.subdeck;
}
#endif

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

      if (w->abacus.aux != PRIMARY && w->abacus.vertical) {
            /* not allowed by default, but user can change later */
            w->abacus.vertical = False;
      }
      if (w->abacus.railIndex != 0)
            w->abacus.railIndex = 1;
      if (w->abacus.shiftPercent <= 0) {
            w->abacus.shiftPercent = DEFAULT_SHIFT_PERCENT;
      }
      if (w->abacus.decimalPosition < 0) {
            w->abacus.decimalPosition = 0;
      }
      if (w->abacus.decimalPosition >= w->abacus.rails) {
            w->abacus.decimalPosition = w->abacus.rails - 1;
      }
      if (w->abacus.shiftPercent >= w->abacus.rails) {
            w->abacus.shiftPercent = 2;
      }
      if (w->abacus.decks[BOTTOM].piece > MAX_BASE) {
            intCat(&buf1, "Bottom Piece must be less than or equal to ", MAX_BASE);
            DISPLAY_WARNING(buf1);
            free(buf1);
            w->abacus.decks[BOTTOM].piece = 0;
      } else if (w->abacus.decks[BOTTOM].piece != 0 &&
                  w->abacus.decks[BOTTOM].piece < MIN_BASE) {
            intCat(&buf1, "Bottom Piece must be greater than or equal to ", MIN_BASE);
            stringCat(&buf2, buf1, ", or 0");
            free(buf1);
            DISPLAY_WARNING(buf2);
            free(buf2);
            w->abacus.decks[BOTTOM].piece = 0;
      }
      if (w->abacus.decks[TOP].piece != 0 &&
                  w->abacus.decks[TOP].piece < MIN_BASE) {
            intCat(&buf1, "Top Piece must be greater than or equal to ", MIN_BASE);
            stringCat(&buf2, buf1, ", or 0");
            free(buf1);
            DISPLAY_WARNING(buf2);
            free(buf2);
            w->abacus.decks[TOP].piece = 0;
      }
      if (w->abacus.decks[BOTTOM].piecePercent > MAX_BASE) {
            intCat(&buf1, "Bottom Piece Percent must be less than or equal to ", MAX_BASE);
            DISPLAY_WARNING(buf1);
            free(buf1);
            w->abacus.decks[BOTTOM].piecePercent = 0;
      } else if (w->abacus.decks[BOTTOM].piecePercent != 0 &&
                  w->abacus.decks[BOTTOM].piecePercent < MIN_BASE) {
            intCat(&buf1, "Bottom Piece Percent must be greater than or equal to ", MIN_BASE);
            stringCat(&buf2, buf1, ", or 0");
            free(buf1);
            DISPLAY_WARNING(buf2);
            free(buf2);
            w->abacus.decks[BOTTOM].piecePercent = 0;
      }
      if (w->abacus.decks[TOP].piecePercent != 0 &&
                  w->abacus.decks[TOP].piecePercent < MIN_BASE) {
            intCat(&buf1, "Top Piece Percent must be greater than or equal to ", MIN_BASE);
            stringCat(&buf2, buf1, ", or 0");
            free(buf1);
            DISPLAY_WARNING(buf2);
            free(buf2);
            w->abacus.decks[TOP].piecePercent = 0;
      }
      if (w->abacus.base > MAX_BASE) {
            intCat(&buf1, "Base must be less than or equal to ", MAX_BASE);
            DISPLAY_WARNING(buf1);
            free(buf1);
            w->abacus.base = DEFAULT_BASE;
            setAbacus(w, ACTION_BASE_DEFAULT);
      } else if (w->abacus.base < MIN_BASE) {
            intCat(&buf1, "Base must be greater than or equal to ", MIN_BASE);
            DISPLAY_WARNING(buf1);
            free(buf1);
            w->abacus.base = DEFAULT_BASE;
            setAbacus(w, ACTION_BASE_DEFAULT);
      } else if (w->abacus.base != DEFAULT_BASE && w->abacus.demo) {
            intCat(&buf1, "Base must be equal to ", DEFAULT_BASE);
            stringCat(&buf2, buf1, ", for demo");
            free(buf1);
            DISPLAY_WARNING(buf2);
            free(buf2);
            w->abacus.base = DEFAULT_BASE;
            setAbacus(w, ACTION_BASE_DEFAULT);
      }
      if (w->abacus.decks[BOTTOM].piece != 0 &&
                  (checkBottomSpace(w) < w->abacus.decks[BOTTOM].piece)) {
            /*DISPLAY_WARNING("Bottom Spaces must be large enough with base when piece set");*/
            w->abacus.decks[BOTTOM].spaces -=
                  (checkBottomSpace(w) - w->abacus.decks[BOTTOM].piece);
      }
      if (w->abacus.decks[BOTTOM].piecePercent > 1 &&
                  (checkBottomSpace(w) < w->abacus.decks[BOTTOM].piecePercent)) {
            /*DISPLAY_WARNING("Bottom Spaces must be large enough with base when piece percent set");*/
            w->abacus.decks[BOTTOM].spaces -=
                  (checkBottomSpace(w) - w->abacus.decks[BOTTOM].piecePercent);
      }
      if (w->abacus.anomaly < 0) {
            DISPLAY_WARNING("Anomaly must be greater than or equal to 0");
            w->abacus.anomaly = 0;
      }
      if (w->abacus.anomaly >= w->abacus.base) {
            intCat(&buf1, "Anomaly must be less than ", w->abacus.base);
            DISPLAY_WARNING(buf1);
            free(buf1);
            w->abacus.anomaly = 0;
      }
      if (w->abacus.shiftAnomaly <= 0) {
            DISPLAY_WARNING("Shift Anomaly must be greater than 0");
            w->abacus.shiftAnomaly = DEFAULT_SHIFT_ANOMALY;
      }
      if (w->abacus.anomalySq < 0) {
            DISPLAY_WARNING("Anomaly Squared must be greater than or equal to 0");
            w->abacus.anomalySq = 0;
      }
      if (w->abacus.anomalySq >= w->abacus.base) {
            intCat(&buf1, "Anomaly Squared must be less than ", w->abacus.base);
            DISPLAY_WARNING(buf1);
            free(buf1);
            w->abacus.anomalySq = 0;
      }
      if (w->abacus.shiftAnomalySq <= 0) {
            DISPLAY_WARNING("Shift Anomaly Squared must be greater than 0");
            w->abacus.shiftAnomalySq = DEFAULT_SHIFT_ANOMALY;
      }
      if (w->abacus.displayBase > MAX_BASE) {
            intCat(&buf1, "Display Base must be less than or equal to ", MAX_BASE);
            DISPLAY_WARNING(buf1);
            free(buf1);
            w->abacus.displayBase = DEFAULT_BASE;
      } else if (w->abacus.displayBase < MIN_BASE) {
            intCat(&buf1, "Display Base must be greater than or equal to ",
                  MIN_BASE);
            DISPLAY_WARNING(buf1);
            free(buf1);
            w->abacus.displayBase = DEFAULT_BASE;
      } else if (w->abacus.displayBase != DEFAULT_BASE && w->abacus.demo) {
            intCat(&buf1, "Display Base must be equal to ", DEFAULT_BASE);
            stringCat(&buf2, buf1, ", for demo");
            free(buf1);
            DISPLAY_WARNING(buf2);
            free(buf2);
            w->abacus.displayBase = DEFAULT_BASE;
      }
      if (w->abacus.mode == GENERIC && w->abacus.demo &&
                  w->abacus.aux == PRIMARY) {
            /*DISPLAY_WARNING("Format must not be \"Generic\", for demo");*/
            w->abacus.mode = CHINESE;
      }
      /* If a particular mode, ignore improper settings */
      if (w->abacus.mode == DANISH) {
            w->abacus.colorScheme = COLOR_HALF;
            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 = DEFAULT_BOTTOM_ORIENT;
            w->abacus.decks[TOP].orientation = DEFAULT_TOP_ORIENT;
            w->abacus.decks[BOTTOM].spaces = 4 * DEFAULT_BOTTOM_SPACES;
            w->abacus.decks[TOP].spaces = 0;
            w->abacus.vertical = True;
            w->abacus.slot = False;
            w->abacus.diamond = False;
            w->abacus.railIndex = 1;
            setSpace(w, BOTTOM);
            setSpace(w, TOP);
      } else if (w->abacus.mode == RUSSIAN) {
            w->abacus.colorScheme = COLOR_MIDDLE | COLOR_FIRST;
            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 = DEFAULT_TOP_ORIENT;
            w->abacus.decks[TOP].orientation = DEFAULT_TOP_ORIENT;
            w->abacus.decks[BOTTOM].spaces = DEFAULT_BOTTOM_SPACES;
            w->abacus.decks[TOP].spaces = 0;
            w->abacus.vertical = True;
            w->abacus.slot = False;
            w->abacus.diamond = False;
            w->abacus.railIndex = 1;
            setSpace(w, BOTTOM);
            setSpace(w, TOP);
      } else if (w->abacus.mode == JAPANESE || w->abacus.mode == ROMAN) {
            w->abacus.colorScheme = 0;
            w->abacus.decks[BOTTOM].factor = 1;
            w->abacus.decks[TOP].factor = convertBaseToBottom(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 = DEFAULT_BOTTOM_ORIENT;
            w->abacus.decks[TOP].orientation = DEFAULT_TOP_ORIENT;
            if (w->abacus.subdeck < 0)
                  w->abacus.subdeck = DEFAULT_SUBDECKS;
            w->abacus.vertical = False;
            if (w->abacus.mode == JAPANESE) {
                  w->abacus.slot = False;
                  w->abacus.diamond = True;
                  w->abacus.decks[BOTTOM].spaces = DEFAULT_BOTTOM_SPACES - 1;
                  w->abacus.decks[TOP].spaces = DEFAULT_TOP_SPACES - 1;
            } else if (w->abacus.mode == ROMAN) {
                  w->abacus.slot = True;
                  w->abacus.diamond = False;
                  w->abacus.decks[BOTTOM].spaces = DEFAULT_BOTTOM_SPACES + 1;
                  w->abacus.decks[TOP].spaces = DEFAULT_TOP_SPACES + 1;
            }
            w->abacus.railIndex = 0;
            setSpace(w, BOTTOM);
            setSpace(w, TOP);
      } else if (w->abacus.mode == KOREAN) {
            w->abacus.colorScheme = 0;
            w->abacus.decks[BOTTOM].factor = 1;
            w->abacus.decks[TOP].factor = convertBaseToBottom(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 = DEFAULT_BOTTOM_ORIENT;
            w->abacus.decks[TOP].orientation = DEFAULT_TOP_ORIENT;
            w->abacus.decks[BOTTOM].spaces = DEFAULT_BOTTOM_SPACES - 1;
            w->abacus.decks[TOP].spaces = DEFAULT_TOP_SPACES - 1;
            w->abacus.vertical = False;
            w->abacus.slot = False;
            w->abacus.diamond = True;
            w->abacus.railIndex = 0;
            setSpace(w, BOTTOM);
            setSpace(w, TOP);
      } else if (w->abacus.mode == CHINESE) {
            w->abacus.colorScheme = 0;
            w->abacus.decks[BOTTOM].factor = 1;
            w->abacus.decks[TOP].factor = convertBaseToBottom(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 = DEFAULT_BOTTOM_ORIENT;
            w->abacus.decks[TOP].orientation = DEFAULT_TOP_ORIENT;
            w->abacus.decks[BOTTOM].spaces = DEFAULT_BOTTOM_SPACES;
            w->abacus.decks[TOP].spaces = DEFAULT_TOP_SPACES;
            w->abacus.vertical = False;
            w->abacus.slot = False;
            w->abacus.diamond = False;
            w->abacus.railIndex = 0;
            setSpace(w, BOTTOM);
            setSpace(w, TOP);
      }
      if (w->abacus.demo && w->abacus.aux == PRIMARY) {
            /* Trying to keep these at a minimum... */
            if (w->abacus.rails < MIN_DEMO_RAILS) {
                  intCat(&buf1, "Number of rails must be at least ",
                        MIN_DEMO_RAILS);
                  stringCat(&buf2, buf1, ", for demo");
                  free(buf1);
                  DISPLAY_WARNING(buf2);
                  free(buf2);
                  w->abacus.rails = MIN_DEMO_RAILS;
            }
            if (w->abacus.rails - w->abacus.decimalPosition <
                        MIN_DEMO_RAILS) {
                  if (w->abacus.decks[BOTTOM].piecePercent != 0) {
                        w->abacus.decks[BOTTOM].piecePercent = 0;
                  }
                  if (w->abacus.decks[BOTTOM].piece != 0) {
                        w->abacus.decks[BOTTOM].piece = 0;
                  }
                  w->abacus.decimalPosition = 0;
            }
      } else {
            if (w->abacus.rails < MIN_RAILS) {
                  intCat(&buf1, "Number of rails must be at least ",
                        MIN_RAILS);
                  DISPLAY_WARNING(buf1);
                  free(buf1);
                  w->abacus.rails = MIN_RAILS;
            }
            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 plus Bottom Spaces must be at least 1");
            w->abacus.decks[BOTTOM].spaces = 2;
      }
      if (w->abacus.groupSize < 2) {
            DISPLAY_WARNING("Group Size must be at least 2");
            w->abacus.groupSize = DEFAULT_GROUP_SIZE;
      }
      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 too small for input, needs rail ",
                  w->abacus.rail);
            DISPLAY_WARNING(buf1);
            free(buf1);
            return False;
      }
      if (w->abacus.deck == PLACE_SETTING) {
            /* 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
resetSubdecks(AbacusWidget w)
{

      int deck, ndecks;

      if (w->abacus.subdecks)
            free(w->abacus.subdecks);
      ndecks = (w->abacus.subdeck <= 0) ? DEFAULT_SUBDECKS :
            w->abacus.subdeck;
      if (!(w->abacus.subdecks = (SubdeckPart *) malloc(
                  sizeof (SubdeckPart) * ndecks))) {
            DISPLAY_ERROR("Not enough memory (resetSubdecks), exiting.");
      }
      for (deck = 0; deck < ndecks; deck++) {
            w->abacus.subdecks[deck].number =
                  numberSubbeads(w, deck);
            w->abacus.subdecks[deck].spaces = SUBDECK_SPACE;
            w->abacus.subdecks[deck].room =
                  w->abacus.subdecks[deck].number +
                  w->abacus.subdecks[deck].spaces;
            w->abacus.subdecks[deck].position =
                  (w->abacus.decks[BOTTOM].orientation) ?
                  w->abacus.subdecks[deck].number : 0;
      }
}

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

      w->abacus.currentDeck = IGNORE_DECK;
      w->abacus.numDigits = w->abacus.rails + CARRY + 1;
      for (deck = BOTTOM; deck <= TOP; deck++) {
            if (w->abacus.decks[deck].position)
                  free(w->abacus.decks[deck].position);
            if (!(w->abacus.decks[deck].position = (int *)
                        malloc(sizeof (int) * w->abacus.rails))) {
                  DISPLAY_ERROR("Not enough memory (resetBeads), exiting.");
            }
      }
      if (w->abacus.digits)
            free(w->abacus.digits);
      if (!(w->abacus.digits = (char *)
                  malloc(sizeof (char) * w->abacus.numDigits))) {
            DISPLAY_ERROR("Not enough memory (resetBeads1), 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.decks[BOTTOM].piece != 0) {
            rail = w->abacus.decimalPosition - 1;
            w->abacus.decks[BOTTOM].position[rail] =
                  (w->abacus.decks[BOTTOM].orientation) ?
                  numberPieces(w, BOTTOM) : 0;
            if (w->abacus.decks[TOP].number != 0 &&
                        w->abacus.decks[TOP].piece != 0) {
                  w->abacus.decks[TOP].position[rail] =
                        (w->abacus.decks[TOP].orientation) ?
                        numberPieces(w, TOP) : 0;
            }
      }
      if (w->abacus.decks[BOTTOM].piece != 0 &&
                  w->abacus.decks[BOTTOM].piecePercent != 0) {
            rail = w->abacus.decimalPosition - w->abacus.shiftPercent - 1 -
                  ((w->abacus.decks[BOTTOM].piece == 0) ? 0 : 1);
            w->abacus.decks[BOTTOM].position[rail] =
                  (w->abacus.decks[BOTTOM].orientation) ?
                  numberPiecePercents(w, BOTTOM) : 0;
            if (w->abacus.decks[TOP].number != 0 &&
                        w->abacus.decks[TOP].piecePercent != 0) {
                  w->abacus.decks[TOP].position[rail] =
                        (w->abacus.decks[TOP].orientation) ?
                        numberPiecePercents(w, TOP) : 0;
            }
      }
      resetSubdecks(w);
      for (rail = 0; rail < w->abacus.numDigits - 1; rail++)
            w->abacus.digits[rail] = '0';
      w->abacus.digits[w->abacus.numDigits - 1] = '\0';
}

#ifdef HAVE_MOTIF
static Boolean
isEmptyCounter(AbacusWidget w)
{
      int n = 0;

      while (n < w->abacus.numDigits - 1) {
            if (w->abacus.digits[n] != '0') {
                  return False;
            }
            n++;
      }
      return True;
}
#endif

static Boolean
emptyCounter(AbacusWidget w)
{
      int n = 0;
      Boolean good = True;

      while (n < w->abacus.numDigits - 1) {
            if (w->abacus.digits[n] != '0') {
                  good = False;
                  w->abacus.digits[n] = '0';
            }
            n++;
      }
      return good;
}

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;
      Boolean anomalyActive;

      /* n digits above decimal *
       * m digits below decimal */
      while (n < w->abacus.numDigits - 2 - 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 - 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)) ||
            (w->abacus.decks[TOP].number != 0 &&
            w->abacus.decks[TOP].piecePercent != 0 &&
            ((w->abacus.decks[TOP].position[w->abacus.rails - 1] == 1 &&
            !w->abacus.decks[TOP].orientation) ||
            (w->abacus.decks[TOP].position[w->abacus.rails - 1] == 0 &&
            w->abacus.decks[TOP].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, w->abacus.ancientRoman))))) {
            DISPLAY_ERROR("Not enough memory (setCounter), exiting.");
      }
      if (s == 1)
            buffer[0] = '-';
      for (i = 0; i < half; i++)
            buffer[s + i] = w->abacus.digits[n + i];
      buffer[s + half] = decimalChar(w);
      buffer[s + half + 1] = '\0';
      if (w->abacus.decks[BOTTOM].piece != 0) {
            char *stringBuf, *finalBuf, *midBuf;
            int pieces = w->abacus.decks[BOTTOM].piece;
            int precision;

            if (!(stringBuf = (char *) malloc(sizeof (char) *
                        w->abacus.numDigits + 2))) {
                  DISPLAY_ERROR("Not enough memory (setCounter1), exiting.");
            }
            if (!(midBuf = (char *) malloc(sizeof (char) *
                        w->abacus.numDigits + 2))) {
                  DISPLAY_ERROR("Not enough memory (setCounter2), exiting.");
            }
            if (!(finalBuf = (char *) malloc(sizeof (char) *
                        w->abacus.numDigits + 2))) {
                  DISPLAY_ERROR("Not enough memory (setCounter3), exiting.");
            }
            precision = ((w->abacus.decks[BOTTOM].piecePercent == 0) ?
                  1 : 2) * w->abacus.shiftPercent + 2;
            if ((precision <= 2 * w->abacus.shiftPercent + 2) &&
                        checkSubdeck(w, 3)) {
                  precision = 2 * w->abacus.shiftPercent + 2;
            }
            if (precision <= w->abacus.decimalPosition)
                  precision = w->abacus.decimalPosition +
                        ((w->abacus.decks[BOTTOM].piecePercent == 0) ? 1 : 0);
            if (w->abacus.decks[TOP].piece != 0)
                  pieces *= w->abacus.decks[TOP].piece;
            /* get piece part */
            dividePieces(midBuf, w->abacus.base, pieces,
                  char2Int(w->abacus.digits[n + half]),
                  precision, decimalChar(w));
            if (w->abacus.decks[BOTTOM].piecePercent != 0) {
                  int piecePercents =
                        w->abacus.decks[BOTTOM].piecePercent;

                  if (w->abacus.decks[TOP].piecePercent != 0)
                        piecePercents *=
                              w->abacus.decks[TOP].piecePercent;
                  /* get piecePercent part */
                  dividePieces(stringBuf, w->abacus.base, piecePercents,
                        char2Int(w->abacus.digits[n + half + w->abacus.shiftPercent + 1]),
                        precision, decimalChar(w));
                  /* shift to proper piece percent place */
                  shiftDecimal(finalBuf, stringBuf,
                        w->abacus.shiftPercent, 0, decimalChar(w));
                  /* get piece + piecePercent */
                  addStrings(stringBuf, finalBuf, midBuf, w->abacus.base,
                        decimalChar(w));
                  /* shift out piece part */
                  /*shiftDecimal(midBuf, buffer, -1, decimalChar(w)); */
                  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';
                  /* shift out piecePercent part */
                  shiftDecimal(midBuf, buffer, -1, w->abacus.shiftPercent,
                        decimalChar(w));
                  /* get pieces + piece percent + normal */
                  addStrings(finalBuf, stringBuf, midBuf, w->abacus.base,
                        decimalChar(w));
            } else if (checkSubdeck(w, 3)) {
                  int pieceFractions =
                        w->abacus.decks[BOTTOM].piece;

                  if (w->abacus.decks[TOP].piece != 0)
                        pieceFractions *=
                              w->abacus.decks[TOP].piece;
                  /* get pieceFraction part */
                  dividePieces(finalBuf, w->abacus.base,
                        pieceFractions * w->abacus.subbase,
                        char2Int(w->abacus.digits[n + half + 1]),
                        precision, decimalChar(w));
                  /* get piece + pieceFraction */
                  addStrings(stringBuf, finalBuf, midBuf, w->abacus.base,
                        decimalChar(w));
                  /* No fixing because no digits after Roman fraction */
                  /* get pieces + piece percent + normal */
                  addStrings(finalBuf, stringBuf, buffer, w->abacus.base,
                        decimalChar(w));
            } else {
                  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, midBuf, w->abacus.base,
                        decimalChar(w));
            }
            (void) strcpy(buffer, finalBuf);
            free(stringBuf);
            free(midBuf);
            free(finalBuf);
      }
      if (w->abacus.decks[BOTTOM].piece == 0 &&
                  w->abacus.decks[BOTTOM].piecePercent == 0) {
            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 WINVER
            (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 to Continue\n");
#else
            setAbacusMove(w, ACTION_SCRIPT,
                  w->abacus.aux, deck,
                  rail - w->abacus.decimalPosition, number);
#endif
      }
      anomalyActive = checkAnomaly(w);
      if (w->abacus.base != w->abacus.displayBase || anomalyActive) {
            char buff[1024];

            if (anomalyActive) {
                convertString(buff, buffer, w->abacus.base,
                  w->abacus.displayBase, w->abacus.decimalPosition,
                  w->abacus.anomaly, w->abacus.shiftAnomaly,
                  w->abacus.carryAnomaly,
                  w->abacus.anomalySq, w->abacus.shiftAnomalySq,
                  w->abacus.carryAnomalySq, decimalChar(w));
            } else {
                convertString(buff, buffer, w->abacus.base,
                  w->abacus.displayBase, w->abacus.decimalPosition,
                  0, w->abacus.shiftAnomaly, False,
                  0, w->abacus.shiftAnomalySq, False,
                  decimalChar(w));
            }
            free(buffer);
            if (!(buffer = (char *) malloc(sizeof (char) * 1024))) {
                  DISPLAY_ERROR("Not enough memory (setCounter4), exiting.");
            }
            (void) strcpy(buffer, buff);
      }
      if (w->abacus.romanNumerals) {
            int pieces = w->abacus.decks[BOTTOM].piece;
            char *romanString;

            (void) strcat(buffer, "          ");
            if (w->abacus.decks[TOP].piece != 0)
                  pieces *= w->abacus.decks[TOP].piece;
            if (!(romanString = (char *) malloc(sizeof (char) *
                        sizeofRoman(w->abacus.displayBase,
                        w->abacus.romanNumerals,
                        w->abacus.ancientRoman)))) {
                  DISPLAY_ERROR("Not enough memory (setCounter5), exiting.");
            }
            (void) string2Roman(romanString, buffer, w->abacus.displayBase,
                  pieces, valuePiece(w), valueSubdeck(w),
                  w->abacus.subbase, decimalChar(w),
                  w->abacus.ancientRoman, w->abacus.latin);
            (void) strcat(buffer, romanString);
            free(romanString);
      }
      if (w->abacus.group) {
            char *groupString;

            if (!(groupString = (char *) malloc(sizeof (char) *
                        3 * strlen(buffer) / 2))) {
                  DISPLAY_ERROR("Not enough memory (setCounter6), exiting.");
            }
            string2Group(groupString, buffer, w->abacus.groupSize,
                  decimalChar(w), groupChar(w));
            free(buffer);
            setAbacusString(w, ACTION_IGNORE, groupString);
            free(groupString);
      } else {
            setAbacusString(w, ACTION_IGNORE, buffer);
            free(buffer);
      }
}

/* Note On Draws:
 * There is some overlap i.e. it draws some extra pixels.
 * This is to synchronize Java, X and Windows.
 */
static void
drawDecimalSeparator(AbacusWidget w, int rail, Boolean show)
{
      int x, y;
      GC gc = ((show) ? w->abacus.symbolGC : w->abacus.inverseGC);
      Pixmap dr = 0;

      x = 1 - w->abacus.railWidth / 2 + w->abacus.offset.x +
            rail * 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 - w->abacus.midHeight - y;
      }
      VFILLRECTANGLE(w, dr, gc, x, y,
            w->abacus.railWidth + 4, w->abacus.midHeight);
}

static void
drawGroupSeparator(AbacusWidget w, int rail, Boolean show)
{
      GC gc = ((show) ? w->abacus.symbolGC : w->abacus.inverseGC);
      int x, y;
      Pixmap dr = 0;

      x = 1 - w->abacus.railWidth / 2 + w->abacus.offset.x +
            rail * 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 - w->abacus.midHeight - y;
      }
      VFILLRECTANGLE(w, dr, gc,
            x + 1, y + 1,
            w->abacus.railWidth + 2, w->abacus.midHeight - 2);
      VFILLRECTANGLE(w, dr, gc,
            x, y + (w->abacus.midHeight - 1) / 2,
            w->abacus.railWidth + 4,
            (w->abacus.midHeight - 1) % 2 + 1);
      VFILLRECTANGLE(w, dr, gc,
            x + (w->abacus.railWidth + 1) / 2 + 1, y,
            (w->abacus.railWidth + 1) % 2 + 1,
            w->abacus.midHeight);
}

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) / w->abacus.groupSize);
                  separator++)
            drawGroupSeparator(w, w->abacus.rails -
                  w->abacus.decimalPosition -
                  w->abacus.groupSize * separator, show);
}

#define SYMBOLGC(s) (s)?((w->abacus.mono && w->abacus.slot)?w->abacus.beadShadeGC[4]:w->abacus.symbolGC):w->abacus.inverseGC

static void
drawRomanI(AbacusWidget w, int rail, Boolean show)
{
      GC gc = SYMBOLGC(show);
      int x, y;
      Pixmap dr = 0;

      x = 2 + w->abacus.offset.x +
            rail * 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 - w->abacus.midHeight - y;
      }
      VFILLRECTANGLE(w, dr, gc, x, y, 2, w->abacus.midHeight);
}

static void
drawRomanX(AbacusWidget w, int rail, Boolean show)
{
      int x, y, ht;
      GC gc = SYMBOLGC(show);
      Pixmap dr = 0;

      x = 2 + w->abacus.offset.x +
            rail * 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;
      ht = w->abacus.midHeight - 1;
      if (w->abacus.vertical) {
            y = w->abacus.frameSize.y - w->abacus.midHeight - y;
      }
      VDRAWLINE(w, dr, gc, x - 3, y, x + 3, y + ht);
      VDRAWLINE(w, dr, gc, x + 3, y, x - 3, y + ht);
      VDRAWLINE(w, dr, gc, x + 2, y + ht, x - 2, y);
      VDRAWLINE(w, dr, gc, x - 2, y + ht, x + 2, y);
      VDRAWLINE(w, dr, gc, x + 3, y + ht, x - 3, y);
      VDRAWLINE(w, dr, gc, x - 3, y + ht, x + 3, y);
      VDRAWLINE(w, dr, gc, x - 2, y, x + 2, y + ht);
      VDRAWLINE(w, dr, gc, x + 2, y, x - 2, y + ht);
}

static void
drawRomanC(AbacusWidget w, int rail, Boolean show)
{
      int x, y;
      GC gc = SYMBOLGC(show);
      Pixmap dr = 0;

      x = 2 + w->abacus.offset.x +
            rail * 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 - w->abacus.midHeight - y;
      }
      VFILLRECTANGLE(w, dr, gc, x - 2, y, 5, 1);
      VFILLRECTANGLE(w, dr, gc, x - 2, y + w->abacus.midHeight - 1, 5, 1);
      VFILLRECTANGLE(w, dr, gc, x - 3, y + 1, 2, w->abacus.midHeight - 2);
      VDRAWLINE(w, dr, gc, x + 3, y + 1, x + 2, y);
      VDRAWLINE(w, dr, gc, x + 3, y + w->abacus.midHeight - 2,
            x + 2, y + w->abacus.midHeight - 1);
}

static void
drawRomanM(AbacusWidget w, int rail, Boolean show)
{
      GC gc = SYMBOLGC(show);
      int x, y;
      Pixmap dr = 0;

      x = 2 + w->abacus.offset.x +
            rail * 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 - w->abacus.midHeight - y;
      }
      if (w->abacus.modernRoman) {
            VFILLRECTANGLE(w, dr, gc, x - 3, y, 2, w->abacus.midHeight);
            VFILLRECTANGLE(w, dr, gc, x + 3, y, 2, w->abacus.midHeight);
            VDRAWLINE(w, dr, gc, x - 2, y, x, y + 2);
            VDRAWLINE(w, dr, gc, x + 3, y, x + 1, y + 2);
            VDRAWLINE(w, dr, gc, x - 3, y, x - 1, y + 1);
            VDRAWLINE(w, dr, gc, x + 4, y, x + 2, y + 1);
      } else {
            VFILLRECTANGLE(w, dr, gc, x, y, 2, w->abacus.midHeight);
            VFILLRECTANGLE(w, dr, gc,
                  x - 5, y + 3, 2, w->abacus.midHeight - 4);
            VFILLRECTANGLE(w, dr, gc,
                  x - 4, y + 2, 3, 1);
            VFILLRECTANGLE(w, dr, gc,
                  x - 4, y + w->abacus.midHeight - 1, 3, 1);
            VFILLRECTANGLE(w, dr, gc,
                  x + 5, y + 3, 2, w->abacus.midHeight - 4);
            VFILLRECTANGLE(w, dr, gc,
                  x + 3, y + 2, 3, 1);
            VFILLRECTANGLE(w, dr, gc,
                  x + 3, y + w->abacus.midHeight - 1, 3, 1);
      }
}

static void
drawRomanx(AbacusWidget w, int rail, Boolean show)
{
      GC gc = SYMBOLGC(show);
      int x, y, ht;
      Pixmap dr = 0;

      x = 2 + w->abacus.offset.x +
            rail * 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;
      ht = w->abacus.midHeight - 1;
      if (w->abacus.vertical) {
            y = w->abacus.frameSize.y - w->abacus.midHeight - y;
      }
      if (w->abacus.modernRoman) {
            VDRAWLINE(w, dr, gc, x - 1, y + 2, x + 2, y + ht);
            VDRAWLINE(w, dr, gc, x + 2, y + 2, x - 1, y + ht);
            VDRAWLINE(w, dr, gc, x - 2, y + 2, x + 3, y + ht);
            VDRAWLINE(w, dr, gc, x + 3, y + 2, x - 2, y + ht);
            VFILLRECTANGLE(w, dr, gc, x - 3, y, 8, 1);
      } else {
            VFILLRECTANGLE(w, dr, gc, x, y, 2, w->abacus.midHeight);
            VFILLRECTANGLE(w, dr, gc, x - 3, y + 3,
                  1, w->abacus.midHeight - 4);
            VDRAWLINE(w, dr, gc, x - 2, y + 2, x - 3, y + 3);
            VDRAWLINE(w, dr, gc, x - 2, y + w->abacus.midHeight - 1,
                  x - 3, y + w->abacus.midHeight - 2);
            VFILLRECTANGLE(w, dr, gc, x + 4, y + 3,
                  1, w->abacus.midHeight - 4);
            VDRAWLINE(w, dr, gc, x + 3, y + 2, x + 4, y + 3);
            VDRAWLINE(w, dr, gc, x + 3, y + w->abacus.midHeight - 1,
                  x + 4, y + w->abacus.midHeight - 2);
            VFILLRECTANGLE(w, dr, gc, x - 5, y + 2,
                  1, w->abacus.midHeight - 3);
            VDRAWLINE(w, dr, gc, x - 3, y, x - 5, y + 2);
            VDRAWLINE(w, dr, gc, x - 4, y + w->abacus.midHeight - 1,
                  x - 5, y + w->abacus.midHeight - 2);
            VFILLRECTANGLE(w, dr, gc, x + 6, y + 2,
                  1, w->abacus.midHeight - 3);
            VDRAWLINE(w, dr, gc, x + 4, y, x + 6, y + 2);
            VDRAWLINE(w, dr, gc, x + 5, y + w->abacus.midHeight - 1,
                  x + 6, y + w->abacus.midHeight - 2);
      }
}

static void
drawRomanc(AbacusWidget w, int rail, Boolean show)
{
      GC gc = SYMBOLGC(show);
      int x, y;
      Pixmap dr = 0;

      x = 2 + w->abacus.offset.x +
            rail * 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 - w->abacus.midHeight - y;
      }
      if (w->abacus.modernRoman) {
            VFILLRECTANGLE(w, dr, gc, x - 2, y + 2, 6, 1);
            VFILLRECTANGLE(w, dr, gc, x - 2, y + w->abacus.midHeight - 1,
                  6, 1);
            VFILLRECTANGLE(w, dr, gc, x - 3, y + 3, 2, 2);
            VFILLRECTANGLE(w, dr, gc, x - 3, y, 8, 1);
      } else {
            VFILLRECTANGLE(w, dr, gc, x, y, 2, w->abacus.midHeight);
            VDRAWLINE(w, dr, gc, x - 2, y + 3, x - 3, y + 4);
            VDRAWLINE(w, dr, gc, x - 3, y + 4, x - 2, y + 3);
            VDRAWLINE(w, dr, gc, x - 2, y + w->abacus.midHeight - 1,
                  x - 3, y + w->abacus.midHeight - 2);
            VDRAWLINE(w, dr, gc, x + 3, y + 3, x + 4, y + 4);
            VDRAWLINE(w, dr, gc, x + 4, y + 4, x + 3, y + 3);
            VDRAWLINE(w, dr, gc, x + 3, y + w->abacus.midHeight - 1,
                  x + 4, y + w->abacus.midHeight - 2);
            VFILLRECTANGLE(w, dr, gc, x - 3, y + 1, 2, 1);
            VDRAWLINE(w, dr, gc, x - 4, y + 2,
                  x - 5, y + 3);
            VFILLRECTANGLE(w, dr, gc, x - 5, y + 3, 1, 2);
            VDRAWLINE(w, dr, gc, x - 4, y + w->abacus.midHeight - 1,
                  x - 5, y + w->abacus.midHeight - 2);
            VFILLRECTANGLE(w, dr, gc, x + 3, y + 1, 2, 1);
            VDRAWLINE(w, dr, gc, x + 5, y + 2,
                  x + 6, y + 3);
            VFILLRECTANGLE(w, dr, gc, x + 6, y + 3, 1, 2);
            VDRAWLINE(w, dr, gc, x + 5, y + w->abacus.midHeight - 1,
                  x + 6, y + w->abacus.midHeight - 2);
            VFILLRECTANGLE(w, dr, gc, x - 7, y + 2,
                  1, w->abacus.midHeight - 3);
            VDRAWLINE(w, dr, gc, x - 5, y, x - 7, y + 2);
            VDRAWLINE(w, dr, gc, x - 6, y + w->abacus.midHeight - 1,
                  x - 7, y + w->abacus.midHeight - 2);
            VFILLRECTANGLE(w, dr, gc, x + 8,
                  y + 2, 1, w->abacus.midHeight - 3);
            VDRAWLINE(w, dr, gc, x + 6, y, x + 8, y + 2);
            VDRAWLINE(w, dr, gc, x + 7, y + w->abacus.midHeight - 1,
                  x + 8, y + w->abacus.midHeight - 2);
      }
}

static void
drawRomanm(AbacusWidget w, int rail, Boolean show)
{
      int x, y, ht;
      GC gc = SYMBOLGC(show);
      Pixmap dr = 0;

      x = 2 + w->abacus.offset.x +
            rail * 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;
      ht = w->abacus.midHeight - 1;
      if (w->abacus.vertical) {
            y = w->abacus.frameSize.y - w->abacus.midHeight - y;
      }
      if (w->abacus.modernRoman) {
            VFILLRECTANGLE(w, dr, gc, x - 3, y + 2,
                  2, w->abacus.midHeight - 2);
            VFILLRECTANGLE(w, dr, gc, x + 3, y + 2,
                  2, w->abacus.midHeight - 2);
            VDRAWLINE(w, dr, gc, x - 2, y + 2, x, y + 4);
            VDRAWLINE(w, dr, gc, x + 3, y + 2, x + 1, y + 4);
            VDRAWLINE(w, dr, gc, x - 3, y + 2, x - 1, y + 3);
            VDRAWLINE(w, dr, gc, x + 4, y + 2, x + 2, y + 3);
            VFILLRECTANGLE(w, dr, gc, x - 3, y, 8, 1);
      } else {
            VDRAWLINE(w, dr, gc, x - 1, y + 2, x + 2, y + ht);
            VDRAWLINE(w, dr, gc, x + 2, y + 2, x - 1, y + ht);
            VDRAWLINE(w, dr, gc, x - 2, y + 2, x + 3, y + ht);
            VDRAWLINE(w, dr, gc, x + 3, y + 2, x - 2, y + ht);
            VDRAWLINE(w, dr, gc, x - 1, y + ht, x + 2, y + 2);
            VDRAWLINE(w, dr, gc, x + 2, y + ht, x - 1, y + 2);
            VDRAWLINE(w, dr, gc, x - 2, y + ht, x + 3, y + 2);
            VDRAWLINE(w, dr, gc, x + 3, y + ht, x - 2, y + 2);
            VFILLRECTANGLE(w, dr, gc, x - 4, y, 1, w->abacus.midHeight);
            VFILLRECTANGLE(w, dr, gc, x + 5, y, 1, w->abacus.midHeight);
            VFILLRECTANGLE(w, dr, gc, x - 3, y, 8, 1);
      }
}

static void
drawRomanHalf(AbacusWidget w, int rail, Boolean show)
{
      int x, y;
      GC gc = SYMBOLGC(show);
      Pixmap dr = 0;

      x = 4 + w->abacus.offset.x +
            rail * w->abacus.pos.x - (w->abacus.pos.x - 1) / 2 -
            w->abacus.beadSize.x / 2;
      y = w->abacus.decks[TOP].room * w->abacus.pos.y + w->abacus.delta.y -
            1 + w->abacus.offset.y +
            numberSubbeadsOffset(w, w->abacus.subdeck - 1) *
            w->abacus.pos.y + w->abacus.pos.y / 2;
      if (w->abacus.vertical) {
            y = w->abacus.frameSize.y - w->abacus.midHeight - y;
      }
      if (w->abacus.submode == IT) {
            VFILLRECTANGLE(w, dr, gc, x - 1, y, 4, 1);
            VFILLRECTANGLE(w, dr, gc, x - 1, y + w->abacus.midHeight - 1,
                  4, 1);
            VDRAWLINE(w, dr, gc, x - 2, y + 1, x - 1, y);
            VDRAWLINE(w, dr, gc, x - 2, y + w->abacus.midHeight - 2,
                  x - 1, y + w->abacus.midHeight - 1);
            VDRAWLINE(w, dr, gc, x + 3, y + 1, x + 2, y);
            VDRAWLINE(w, dr, gc, x + 3, y + w->abacus.midHeight - 2,
                  x + 2, y + w->abacus.midHeight - 1);
            VDRAWLINE(w, dr, gc, x - 2, y + 1,
                  x + 3, y + w->abacus.midHeight - 2);
      } else if (w->abacus.submode == UK) {
            VFILLRECTANGLE(w, dr, gc, x, y, 2, 1);
            VFILLRECTANGLE(w, dr, gc, x - 2, y + w->abacus.midHeight - 1,
                  6, 1);
            VDRAWLINE(w, dr, gc, x - 1, y + 1, x, y);
            VDRAWLINE(w, dr, gc, x + 2, y + 1, x + 1, y);
            VDRAWLINE(w, dr, gc, x - 1, y + 1, x + 1, y + 3);
            VDRAWLINE(w, dr, gc, x + 1, y + w->abacus.midHeight - 3,
                  x - 1, y + w->abacus.midHeight - 1);
      } else if (w->abacus.submode == FR) {
            VFILLRECTANGLE(w, dr, gc, x - 1, y + 2, 3, 1);
            VFILLRECTANGLE(w, dr, gc, x - 1, y + w->abacus.midHeight - 1,
                  5, 1);
            VDRAWLINE(w, dr, gc, x + 1, y, x - 1, y + 2);
            VDRAWLINE(w, dr, gc, x + 1, y + w->abacus.midHeight - 3,
                  x - 1, y + w->abacus.midHeight - 1);
      }
}

static void
drawRomanQuarter(AbacusWidget w, int rail, Boolean show)
{
      int x, y;
      GC gc = SYMBOLGC(show);
      Pixmap dr = 0;

      x = 4 + w->abacus.offset.x +
            rail * w->abacus.pos.x - (w->abacus.pos.x - 1) / 2 -
            w->abacus.beadSize.x / 2;
      y = w->abacus.decks[TOP].room * w->abacus.pos.y + w->abacus.delta.y -
            1 + w->abacus.offset.y +
            numberSubbeadsOffset(w, w->abacus.subdeck - 2) *
            w->abacus.pos.y + w->abacus.pos.y / 2;
      if (w->abacus.vertical) {
            y = w->abacus.frameSize.y - w->abacus.midHeight - y;
      }
      if (w->abacus.submode == IT) {
            VFILLRECTANGLE(w, dr, gc, x - 1, y, 5, 1);
            VFILLRECTANGLE(w, dr, gc, x - 1, y + w->abacus.midHeight - 1,
                  5, 1);
            VFILLRECTANGLE(w, dr, gc, x + 3, y + 1,
                  2, w->abacus.midHeight - 2);
            VDRAWLINE(w, dr, gc, x - 1, y, x - 2, y + 1);
            VDRAWLINE(w, dr, gc, x - 1, y + w->abacus.midHeight - 1,
                  x - 2, y + w->abacus.midHeight - 2);
      } else if (w->abacus.submode == UK) {
            VFILLRECTANGLE(w, dr, gc, x + 1, y + 2, 1, 2);
            VDRAWLINE(w, dr, gc, x - 1, y, x + 1, y + 2);
            VDRAWLINE(w, dr, gc, x - 1, y + w->abacus.midHeight - 1,
                  x + 1, y + w->abacus.midHeight - 3);
      } else if (w->abacus.submode == FR) {
            VFILLRECTANGLE(w, dr, gc, x, y, 2, 1);
            VFILLRECTANGLE(w, dr, gc, x + 1, y + 1, 1, 3);
            VDRAWLINE(w, dr, gc, x - 1, y + 1, x + 1, y);
            VDRAWLINE(w, dr, gc, x - 1, y + w->abacus.midHeight - 1,
                  x + 1, y + w->abacus.midHeight - 3);
      }
}

static void
drawRomanTwelfth(AbacusWidget w, int rail, Boolean show)
{
      int x, y;
      GC gc = SYMBOLGC(show);
      Pixmap dr = 0;

      x = 4 + w->abacus.offset.x +
            rail * w->abacus.pos.x - (w->abacus.pos.x - 1) / 2 -
            w->abacus.beadSize.x / 2;
      y = w->abacus.decks[TOP].room * w->abacus.pos.y + w->abacus.delta.y -
            1 + w->abacus.offset.y +
            numberSubbeadsOffset(w, w->abacus.subdeck - 3) *
            w->abacus.pos.y + w->abacus.pos.y / 2;
      if (w->abacus.vertical) {
            y = w->abacus.frameSize.y - w->abacus.midHeight - y;
      }
      if (w->abacus.submode == IT) {
            VFILLRECTANGLE(w, dr, gc, x - 3, y, 6, 1);
            VFILLRECTANGLE(w, dr, gc, x - 2, y + w->abacus.midHeight - 1,
                  6, 1);
            VDRAWLINE(w, dr, gc, x + 2, y,
                  x - 2, y + w->abacus.midHeight - 1);
            VDRAWLINE(w, dr, gc, x - 3, y + w->abacus.midHeight - 1,
                  x + 3, y);
            VDRAWLINE(w, dr, gc, x + 3, y,
                  x - 3, y + w->abacus.midHeight - 1);
      } else if (w->abacus.submode == UK) {
            VFILLRECTANGLE(w, dr, gc, x - 2, y + w->abacus.midHeight - 1,
                  5, 1);
            VFILLRECTANGLE(w, dr, gc, x - 1, y, 3, 1);
            VFILLRECTANGLE(w, dr, gc, x + 2, y + 1, 1, 2);
            VDRAWLINE(w, dr, gc, x - 2, y + 1, x - 1, y);
            VDRAWLINE(w, dr, gc, x + 2, y + 1, x + 1, y);
            VDRAWLINE(w, dr, gc, x + 2, y + 2,
                  x - 2, y + w->abacus.midHeight - 1);
      } else if (w->abacus.submode == FR) {
            VFILLRECTANGLE(w, dr, gc, x - 1, y + w->abacus.midHeight - 1,
                  6, 1);
            VFILLRECTANGLE(w, dr, gc, x, y, 3, 1);
            VDRAWLINE(w, dr, gc, x - 1, y + 1, x, y);
            VDRAWLINE(w, dr, gc, x + 3, y + 1, x + 2, y);
            VDRAWLINE(w, dr, gc, x + 3, y + 1,
                  x - 1, y + w->abacus.midHeight - 1);
      }
}

static void
drawNegative(AbacusWidget w, int rail, Boolean show)
{
      int x, y;
      GC gc = SYMBOLGC(show);
      Pixmap dr = 0;

      x = 1 - w->abacus.railWidth / 2 + w->abacus.offset.x +
            rail * 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 - w->abacus.midHeight - y;
      }
      VFILLRECTANGLE(w, dr, gc, x, y + 2,
            w->abacus.railWidth + 4, 2);
}

static void
drawPiece(AbacusWidget w, int rail, Boolean show)
{
      int x, y;
      GC gc = SYMBOLGC(show);
      Pixmap dr = 0;

      x = 1 - w->abacus.railWidth / 2 + w->abacus.offset.x +
            rail * 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 - w->abacus.midHeight - y;
      }
      VFILLRECTANGLE(w, dr, gc, x, y + 2, w->abacus.railWidth + 4, 2);
      VFILLRECTANGLE(w, dr, gc, x + 2, y,
            w->abacus.railWidth, w->abacus.midHeight);
}

static void
drawRomanPiece(AbacusWidget w, int rail, Boolean show)
{
      int x, y, woffset = 0, hoffset = 1;
      GC gc = SYMBOLGC(show);
      Pixmap dr = 0;

      x = 2 + w->abacus.offset.x +
            rail * 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 - w->abacus.midHeight - y;
      }
      if (!w->abacus.slot) {
            woffset = ((w->abacus.railWidth & 1) == 1) ? 1 : 0;
            hoffset = ((w->abacus.railWidth & 1) == 1) ? 0 : 1;
      }
      VFILLRECTANGLE(w, dr, gc,
            x - 1 + woffset , y, 3 + hoffset, 1);
      VFILLRECTANGLE(w, dr, gc,
            x - 1 + woffset, y + w->abacus.midHeight - 1, 3 + hoffset, 1);
      VFILLRECTANGLE(w, dr, gc,
            x - 2 + woffset, y + 1, 2, w->abacus.midHeight - 2);
      VFILLRECTANGLE(w, dr, gc,
            x + 1 + woffset + hoffset, y + 1, 2, w->abacus.midHeight - 2);
}

static void
drawAnomaly(AbacusWidget w, int rail, Boolean show)
{
      int x, y;
      GC gc = SYMBOLGC(show);
      Pixmap dr = 0;

      x = 1 - w->abacus.railWidth / 2 + w->abacus.offset.x +
            rail * 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 - w->abacus.midHeight - y;
      }
      if (w->abacus.railWidth - 4 > 0) {
            VDRAWLINE(w, dr, gc, x, y, x + 1, y + 1);
            VDRAWLINE(w, dr, gc,
                  x + w->abacus.railWidth + 3, y + w->abacus.midHeight - 1,
                  x + w->abacus.railWidth + 2, y + w->abacus.midHeight - 2);
            VDRAWLINE(w, dr, gc,
                  x, y + w->abacus.midHeight - 1,
                  x + 1, y + w->abacus.midHeight - 2);
            VDRAWLINE(w, dr, gc,
                  x + w->abacus.railWidth + 3, y,
                  x + w->abacus.railWidth + 2, y + 1);
            VFILLRECTANGLE(w, dr, gc,
                  x + 1, y + 1, 2, 1);
            VFILLRECTANGLE(w, dr, gc,
                  x + w->abacus.railWidth + 1, y + w->abacus.midHeight - 2, 2, 1);
            VFILLRECTANGLE(w, dr, gc,
                  x + 1, y + w->abacus.midHeight - 2, 2, 1);
            VFILLRECTANGLE(w, dr, gc,
                  x + w->abacus.railWidth + 1, y + 1, 2, 1);
            VFILLRECTANGLE(w, dr, gc,
                  x + 3, y + 2, w->abacus.railWidth - 2, 2);
      } else {
            VDRAWLINE(w, dr, gc, x, y, x + 2, y + 2);
            VDRAWLINE(w, dr, gc,
                  x + w->abacus.railWidth + 3, y + w->abacus.midHeight - 1,
                  x + w->abacus.railWidth + 1, y + w->abacus.midHeight - 3);
            VDRAWLINE(w, dr, gc,
                  x, y + w->abacus.midHeight - 1,
                  x + 2, y + w->abacus.midHeight - 3);
            VDRAWLINE(w, dr, gc,
                  x + w->abacus.railWidth + 3, y,
                  x + w->abacus.railWidth + 1, y + 2);
            VFILLRECTANGLE(w, dr, gc,
                  x + 2, y + 2, w->abacus.railWidth, 2);
      }
}

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, yPrime;
      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;
      /* Top/Left */
      VFILLRECTANGLE(w, dr, gc,
            0, 0, w->abacus.offset.x + 1, w->abacus.frameSize.y);
      /* Bottom/Right */
      VFILLRECTANGLE(w, dr, gc,
            x + w->abacus.offset.x, 0,
            w->abacus.frameSize.x - (x + w->abacus.offset.x),
            w->abacus.frameSize.y);
      for (deck = TOP; deck >= BOTTOM; deck--) {
            yOffset = (deck == TOP) ? 0 : w->abacus.decks[TOP].height;
            y = w->abacus.decks[deck].room * w->abacus.pos.y +
                  w->abacus.delta.y - 1;
            yPrime = y + yOffset + w->abacus.offset.y;
            if (w->abacus.vertical) {
                  yPrime = w->abacus.frameSize.y -
                        w->abacus.midHeight - yPrime;
                  yOffset = w->abacus.frameSize.y - w->abacus.offset.y -
                        yOffset;
            }
            if (deck == TOP) {
                  Boolean anomalyActive = checkAnomaly(w);

                  /* Right/Top */
                  VFILLRECTANGLE(w, dr, gc,
                        w->abacus.offset.x + 1,
                        yOffset,
                        x - 1,
                        w->abacus.offset.y);
                  if (!w->abacus.slot) {
                        /* Middle */
                        VFILLRECTANGLE(w, dr, gc,
                              w->abacus.offset.x + 1,
                              yPrime,
                              x - 1,
                              w->abacus.midHeight + ((w->abacus.vertical &&
                              w->abacus.decks[TOP].number == 0) ? 1 : 0));
                  }
                  if (w->abacus.slot && !anomalyActive) {
                        int pRails = w->abacus.rails -
                              w->abacus.decimalPosition -
                              ((w->abacus.sign) ? 1 : 0);

                        drawRomanI(w, w->abacus.rails -
                              w->abacus.decimalPosition, show);
                        if (pRails - 1)
                        drawRomanX(w, w->abacus.rails -
                              w->abacus.decimalPosition - 1, show);
                        if (pRails - 2)
                        drawRomanC(w, w->abacus.rails -
                              w->abacus.decimalPosition - 2, show);
                        if (pRails - 3)
                        drawRomanM(w, w->abacus.rails -
                              w->abacus.decimalPosition - 3, show);
                        if (pRails - 4)
                        drawRomanx(w, w->abacus.rails -
                              w->abacus.decimalPosition - 4, show);
                        if (pRails - 5)
                        drawRomanc(w, w->abacus.rails -
                              w->abacus.decimalPosition - 5, show);
                        if (pRails - 6)
                        drawRomanm(w, w->abacus.rails -
                              w->abacus.decimalPosition - 6, show);
                        if (checkSubdeck(w, 3)) {
                              drawRomanHalf(w,
                                w->abacus.rails -
                                w->abacus.decimalPosition + 3,
                                show);
                              if (w->abacus.subdeck > 1)
                                drawRomanQuarter(w,
                                  w->abacus.rails -
                                  w->abacus.decimalPosition + 3,
                                  show);
                              if (w->abacus.subdeck > 2)
                                drawRomanTwelfth(w,
                                  w->abacus.rails -
                                  w->abacus.decimalPosition + 3,
                                  show);
                        }
                  } else {
                        drawDecimalSeparator(w, w->abacus.rails -
                              w->abacus.decimalPosition, show);
                        if (!anomalyActive)
                              drawAllGroupSeparators(w, show);
                  }
                  if (w->abacus.sign)
                        drawNegative(w, 1, show);
                  if (w->abacus.slot) {
                  if (w->abacus.decks[BOTTOM].piece != 0)
                        drawRomanPiece(w, w->abacus.rails -
                              w->abacus.decimalPosition + 1, show);
                  if (w->abacus.decks[BOTTOM].piecePercent != 0)
                        drawRomanPiece(w, w->abacus.rails -
                              w->abacus.decimalPosition + 1 +
                              ((w->abacus.decks[BOTTOM].piece == 0) ? 0 : 1) +
                              w->abacus.shiftPercent, show);
                  } else {
                        if (w->abacus.decks[BOTTOM].piece != 0)
                              drawPiece(w, w->abacus.rails -
                                    w->abacus.decimalPosition + 1, show);
                        if (w->abacus.decks[BOTTOM].piecePercent != 0)
                              drawPiece(w, w->abacus.rails -
                                    w->abacus.decimalPosition + 1 +
                                    ((w->abacus.decks[BOTTOM].piece == 0) ? 0 : 1) +
                                    w->abacus.shiftPercent, show);
                  }
                  if (anomalyActive)
                        drawAnomaly(w, w->abacus.rails -
                              w->abacus.decimalPosition -
                              w->abacus.shiftAnomaly, show);
                  if (anomalyActive && w->abacus.anomalySq != 0)
                        drawAnomaly(w, w->abacus.rails -
                              w->abacus.decimalPosition -
                              w->abacus.shiftAnomaly -
                              w->abacus.shiftAnomalySq, show);
            } else {
                  if (w->abacus.vertical) {
                        /* Left */
                        FILLRECTANGLE(w, dr, gc,
                              0,
                              w->abacus.offset.x + 1,
                              yPrime + 3,
                              x - 1);
                  } else {
                        /* Bottom */
                        FILLRECTANGLE(w, dr, gc,
                              w->abacus.offset.x + 1,
                              yPrime + w->abacus.midHeight - 3,
                              x - 1,
                              w->abacus.frameSize.y -
                              (yPrime + w->abacus.midHeight - 3));
                  }
            }
      }
}

static void
fillRectClipX(AbacusWidget w, Pixmap dr, GC gc, int dx, int dy, int sx, int sy,
            int ox, int wox, int wsx)
{
      int nox = ox, nsx = sx;

      if (ox + sx < wox || ox > wox + wsx || wsx <= 0)
            return;
      if (nox < wox) {
            nox = wox;
            nsx = sx - wox + ox;
      }
      if (nox + nsx > wox + wsx) {
            nsx = wsx + wox - nox;
      }
      FILLRECTANGLE(w, dr, gc, dx + nox, dy, nsx, sy);
}

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 offsetX, const int size)
{
      int dx, dy, yOffset, subj = 0, d = -1, room;
      Pixmap dr = 0;

      yOffset = (deck == TOP) ? 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 - 1;
      if (w->abacus.vertical)
            dy = w->abacus.frameSize.y - w->abacus.beadSize.y -
                  dy - 1;
      dy -= w->abacus.pressOffsetY;
      room = w->abacus.decks[deck].room;
      if (checkSubdeck(w, 3) && rail == w->abacus.decimalPosition - 2) {
            if (submodeSlotsSeparate(w->abacus.submode)) {
                  d = subdeckPosition(w, j);
                  subj = positionSubdeck(w, j);
            } else {
                  room = 0;
                  for (d = 0; d < w->abacus.subdeck; d++)
                        room += w->abacus.subdecks[d].room;
                  d = -1;
            }
      }
      vfillRectClip(w, dr, w->abacus.inverseGC,
            dx, dy,
            w->abacus.beadSize.x + 2,
            w->abacus.beadSize.y + 1 + 2 * w->abacus.pressOffsetY,
            0, offsetX, size);
      if (w->abacus.slot && (j == 1 || (d != -1 && subj == 1))) {
            vfillRectClip(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, offsetX, size);
            /* round off the top of rail */
            vfillRectClip(w, dr, w->abacus.inverseGC,
                  dx + w->abacus.beadSize.x / 2 -
                  w->abacus.railWidth / 2 - 1, dy,
                  2, 1, 3 * w->abacus.beadSize.y / 8, offsetX, size);
            vfillRectClip(w, dr, w->abacus.inverseGC,
                  dx + w->abacus.beadSize.x / 2 +
                  (w->abacus.railWidth - 1) / 2, dy,
                  2, 1, 3 * w->abacus.beadSize.y / 8, offsetX, size);
      } else if (w->abacus.slot && (j == room ||
                  (d != -1 && subj == w->abacus.subdecks[d].room))) {
            vfillRectClip(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, offsetX, size);
            /* round off the bottom of rail */
            vfillRectClip(w, dr, w->abacus.inverseGC,
                  dx + w->abacus.beadSize.x / 2 -
                  w->abacus.railWidth / 2 - 1, dy,
                  2, 1, 2 + 5 * w->abacus.beadSize.y / 8, offsetX, size);
            vfillRectClip(w, dr, w->abacus.inverseGC,
                  dx + w->abacus.beadSize.x / 2 +
                  (w->abacus.railWidth - 1) / 2, dy,
                  2, 1, 2 + 5 * w->abacus.beadSize.y / 8, offsetX, size);
      } else {
            vfillRectClip(w, dr, (w->abacus.slot) ?  w->abacus.borderGC :
                  w->abacus.railGC[w->abacus.railIndex],
                  dx + w->abacus.beadSize.x / 2 -
                  w->abacus.railWidth / 2, dy,
                  w->abacus.railWidth,
                  w->abacus.beadSize.y + 1 + 2 * w->abacus.pressOffsetY,
                  0, offsetX, 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 pressed,
            const int offsetX, const int offsetY)
{
      int dx, dy, yOffset, special = 0, pieces, piecePercents;
      int color = 0;
      int d = -1, subj = 0, room, sx, sy;
      Pixmap dr = 0;

      yOffset = (deck == TOP) ? 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 - 2 + w->abacus.pressOffsetY +
            offsetY;
      room = w->abacus.decks[deck].room;
      if (checkSubdeck(w, 3) && rail == w->abacus.decimalPosition - 2) {
            if (submodeSlotsSeparate(w->abacus.submode)) {
                  d = subdeckPosition(w, j);
                  subj = positionSubdeck(w, j);
            } else {
                  room = 0;
                  for (d = 0; d < w->abacus.subdeck; d++)
                        room += w->abacus.subdecks[d].room;
                  d = -1;
            }
      }
      if (show) {
            if ((rail == w->abacus.rails - 1) && w->abacus.sign) {
                  special++;
            } else if (w->abacus.decks[BOTTOM].piece != 0 &&
                  (rail == w->abacus.decimalPosition - 1)) {
                pieces = numberPieces(w, deck);
                if ((w->abacus.colorScheme & COLOR_MIDDLE) != 0) {
                  if ((((bead == pieces / 2) && ((pieces & 1) == 0)) ||
                              bead == pieces / 2 + 1) && pieces > 2)
                        special++;
                } else if ((w->abacus.colorScheme & COLOR_HALF) != 0) {
                  if ((pieces & 1) != 0) {
                        if (bead == pieces / 2 + 1)
                              color++;
                  } else if (bead > pieces / 2) {
                        if (w->abacus.decks[deck].orientation)
                              color++;
                  } else {
                        if (!w->abacus.decks[deck].orientation)
                              color++;
                  }
                } else {
                  special++;
                }
            } else if (w->abacus.decks[BOTTOM].piecePercent != 0 &&
                  (rail == w->abacus.decimalPosition -
                  w->abacus.shiftPercent - 1 -
                  ((w->abacus.decks[BOTTOM].piece != 0) ? 1 : 0))) {
                piecePercents = numberPiecePercents(w, deck);
                if ((w->abacus.colorScheme & COLOR_MIDDLE) != 0) {
                  if ((((bead == piecePercents / 2) &&
                              ((piecePercents & 1) == 0)) ||
                              bead == piecePercents / 2 + 1) &&
                              piecePercents > 2)
                        special++;
                } else if ((w->abacus.colorScheme & COLOR_HALF) != 0) {
                  if ((piecePercents & 1) != 0) {
                        if (bead == piecePercents / 2 + 1)
                              color++;
                  } else if (bead > piecePercents / 2) {
                        if (w->abacus.decks[deck].orientation)
                              color++;
                  } else {
                        if (!w->abacus.decks[deck].orientation)
                              color++;
                  }
                } else {
                  special++;
                }
            } else if (checkSubdeck(w, 3) &&
                        (rail == w->abacus.decimalPosition - 2)) {
                  if (((w->abacus.subdeck - subdeckPosition(w, j)) % 2) == 0)
                        special++;
            } else if (!((rail == w->abacus.rails - 1) &&
                        w->abacus.sign) &&
                        (w->abacus.colorScheme & COLOR_MIDDLE) != 0) {
                  if ((((bead == w->abacus.decks[deck].number / 2) &&
                              ((w->abacus.decks[deck].number & 1) == 0)) ||
                              bead == w->abacus.decks[deck].number / 2 + 1) &&
                              w->abacus.decks[deck].number > 2) {
                        special++;
                  }
                  if ((w->abacus.colorScheme & COLOR_FIRST) != 0 &&
                              deck == BOTTOM &&
                              rail - w->abacus.decimalPosition > 0 &&
                              (rail - w->abacus.decimalPosition) %
                              w->abacus.groupSize == 0) {
                        if (bead == w->abacus.decks[deck].number &&
                            w->abacus.decks[deck].orientation)
                              special++;
                        else if (bead == 1 &&
                            !w->abacus.decks[deck].orientation)
                              special++;
                  }
            } else if (!((rail == w->abacus.rails - 1) &&
                        w->abacus.sign) &&
                        (w->abacus.colorScheme & COLOR_HALF) != 0) {
                  if ((w->abacus.decks[deck].number & 1) != 0) {
                        if (bead == w->abacus.decks[deck].number / 2 + 1)
                              color++;
                  } else if (bead > w->abacus.decks[deck].number / 2) {
                        if (w->abacus.decks[deck].orientation)
                              color++;
                  } else {
                        if (!w->abacus.decks[deck].orientation)
                              color++;
                  }
            }
            if (w->abacus.vertical)
                  dy = w->abacus.frameSize.y - w->abacus.beadSize.y -
                        dy - 3 + 2 * w->abacus.pressOffsetY;
            dx += pressed * w->abacus.pressOffsetX;
            dy += pressed * w->abacus.pressOffsetY;
            if (!moving && pressed == 0) {
                  VFILLRECTANGLE(w, dr, w->abacus.inverseGC,
                        dx,
                        dy + w->abacus.beadSize.y +
                        w->abacus.pressOffsetY,
                        w->abacus.beadSize.x, 1);
                  if (w->abacus.pressOffsetY != 0) {
                  /* Draw the rail around bead */
                      if (!w->abacus.slot || (j != 1 && (d == -1 ||
                              subj != 1))) {
                        VFILLRECTANGLE(w, dr, (w->abacus.slot) ?
                              w->abacus.borderGC : w->abacus.railGC[w->abacus.railIndex],
                              dx + w->abacus.beadSize.x / 2 -
                              w->abacus.railWidth / 2,
                              dy - 1 + ((w->abacus.vertical) ?
                              w->abacus.beadSize.y : 0),
                              w->abacus.railWidth, 3);
                      }
                      if (!w->abacus.slot || (j != room && (d == -1 ||
                              subj != w->abacus.subdecks[d].room))) {
                        VFILLRECTANGLE(w, dr, (w->abacus.slot) ?
                              w->abacus.borderGC : w->abacus.railGC[w->abacus.railIndex],
                              dx + w->abacus.beadSize.x / 2 -
                              w->abacus.railWidth / 2,
                              dy - 1 + ((w->abacus.vertical) ?
                              0 : w->abacus.beadSize.y),
                              w->abacus.railWidth, 3);
                      }
                  }
            } else {
                  /* Tweak */
                  VFILLRECTANGLE(w, dr, w->abacus.inverseGC,
                        dx - w->abacus.pressOffsetX * pressed,
                        dy - 2 * w->abacus.pressOffsetY * pressed + 1,
                        1, w->abacus.beadSize.y);
                  if (w->abacus.pressOffsetY != 0) {
                      VFILLRECTANGLE(w, dr, w->abacus.inverseGC,
                        dx - w->abacus.pressOffsetX * pressed,
                        dy - w->abacus.pressOffsetY * pressed,
                        w->abacus.beadSize.x, 1);
                      if (!w->abacus.slot || (j != 1 && (d == -1 ||
                                    subj != 1))) {
                        VFILLRECTANGLE(w, dr, (w->abacus.slot) ?
                              w->abacus.borderGC : w->abacus.railGC[w->abacus.railIndex],
                              dx + w->abacus.beadSize.x / 2 -
                              w->abacus.railWidth / 2 -
                              w->abacus.pressOffsetX * pressed,
                              dy - w->abacus.pressOffsetY * pressed,
                              w->abacus.railWidth, 1);
                      }
                  }
            }
            if (w->abacus.vertical) {
                  sx = w->abacus.pos.y - w->abacus.pressOffsetY;
                  sy = w->abacus.beadSize.x + 1;
                  yOffset = dx;
                  dx = dy + 1 - w->abacus.pressOffsetY;
                  dy = yOffset;
            } else {
                  sx = w->abacus.beadSize.x + 1;
                  sy = w->abacus.pos.y - w->abacus.pressOffsetY;
                  dy = dy + 1 - w->abacus.pressOffsetY;
            }
#ifdef WINVER
            w->core.hOldBitmap = (HBITMAP) SelectObject(w->core.memDC,
                  w->abacus.bufferBead[color][pressed][special]);
            BitBlt(w->core.hDC,
                  dx, dy,
                  sx, sy,
                  w->core.memDC,
                  0, 0,
                  SRCCOPY);
            (void) SelectObject(w->core.memDC, w->core.hOldBitmap);
#else
            VOID XSetGraphicsExposures(XtDisplay(w), w->abacus.frameGC,
                  False);
            VOID XCopyArea(XtDisplay(w),
                  w->abacus.bufferBead[color][pressed][special],
                  XtWindow(w),
                  w->abacus.frameGC,
                  0, 0,
                  sx, sy,
                  dx, dy);
#endif
      } else {
            drawRail(w, deck, rail, j, ((w->abacus.pressOffsetY == 0) ?
                  0 : pressed),
                  w->abacus.beadSize.y +
                  1 + 2 * w->abacus.pressOffsetY);
      }
}

static void
drawBufferedBead(AbacusWidget w, const int color, const int pressed,
            const int special)
{
      int shadeFill, shadeLine, shadeDot;
      int railWid = MIN(w->abacus.beadSize.x - 5, w->abacus.railWidth);
      Pixmap *dr;

      dr = &(w->abacus.bufferBead[color][pressed][special]);
      if (w->abacus.mono) {
            shadeFill = 4;
            shadeLine = 4;
            shadeDot = 4;
            if (pressed == 1) {
                  shadeLine = 0;
            }
      } else {
            if (pressed == 1) {
#ifdef INSIDEOUT
                  if (w->abacus.diamond) {
                        shadeDot = 2;
                        shadeLine = shadeFill = 1;
                  } else {
#endif
                  shadeFill = 2;
                  shadeLine = 1;
                  shadeDot = 1;
#ifdef INSIDEOUT
                  }
#endif
            } else {
                  shadeFill = 1;
                  shadeLine = 2;
                  shadeDot = 0;
            }
            if (special == 1) {
                  shadeFill++;
                  shadeLine++;
                  shadeDot++;
            }
            shadeFill += 4 * color;
            shadeLine += 4 * color;
            shadeDot += 4 * color;
      }
      VFILLRECTANGLE(w, *dr, w->abacus.inverseGC,
                  0, 0, w->abacus.beadSize.x + 1,
                  w->abacus.pos.y);
      if (w->abacus.diamond) {
            Point tempList[5];

            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 - 1;
            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;
            VPOLYGON(w, *dr, w->abacus.beadShadeGC[shadeFill],
                  w->abacus.beadShadeGC[shadeFill],
                  tempList, 4, True, 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 - 1;
            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;
            VPOLYGON(w, *dr, w->abacus.beadShadeGC[shadeDot],
                  w->abacus.beadShadeGC[shadeDot],
                  tempList, 4, True, True);
      } else {
            /*VFILLRECTANGLE(w, *dr,
                  w->abacus.beadShadeGC[shadeLine],
                  w->abacus.beadSize.x / 2 -
                  w->abacus.railWidth / 2 - 1, 0,
                  w->abacus.railWidth + 1,
                  w->abacus.beadSize.y + 1);*/
            if (w->abacus.beadSize.x >= w->abacus.beadSize.y +
                        railWid + 2) {
                  VDRAWCIRCLE(w, *dr, w->abacus.beadShadeGC[shadeLine],
                        w->abacus.beadSize.y,
                        w->abacus.beadSize.x / 2 -
                        (w->abacus.beadSize.x -
                        w->abacus.beadSize.y) / 2,
                        w->abacus.beadSize.y / 2);
                  VDRAWCIRCLE(w, *dr, w->abacus.beadShadeGC[shadeLine],
                        w->abacus.beadSize.y,
                        w->abacus.beadSize.x / 2 +
                        (w->abacus.beadSize.x -
                        w->abacus.beadSize.y) / 2,
                        w->abacus.beadSize.y / 2);
                  VFILLCIRCLE(w, *dr, w->abacus.beadShadeGC[shadeFill],
                        w->abacus.beadSize.y,
                        w->abacus.beadSize.x / 2 -
                        (w->abacus.beadSize.x -
                        w->abacus.beadSize.y) / 2,
                        w->abacus.beadSize.y / 2);
                  VFILLCIRCLE(w, *dr, w->abacus.beadShadeGC[shadeFill],
                        w->abacus.beadSize.y,
                        w->abacus.beadSize.x / 2 +
                        (w->abacus.beadSize.x -
                        w->abacus.beadSize.y) / 2,
                        w->abacus.beadSize.y / 2);
                  VDRAWRECTANGLE(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);
                  VFILLRECTANGLE(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 + 1,
                        w->abacus.beadSize.y);
#ifdef INSIDEOUT
                  if (pressed == 0) {
#endif
                        VFILLCIRCLE(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 {
                        VFILLCIRCLE(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 {
      /*(w->abacus.beadSize.x < w->abacus.beadSize.y + railWid + 2)*/
                  int beadDiameter = w->abacus.beadSize.x - railWid - 2;
                  int beadOffset = w->abacus.beadSize.y - beadDiameter;

                  VDRAWCIRCLE(w, *dr, w->abacus.beadShadeGC[shadeLine],
                        beadDiameter,
                        w->abacus.beadSize.x / 2 -
                        (w->abacus.beadSize.x - beadDiameter) / 2,
                        beadDiameter / 2);
                  VDRAWCIRCLE(w, *dr, w->abacus.beadShadeGC[shadeLine],
                        beadDiameter,
                        w->abacus.beadSize.x / 2 +
                        (w->abacus.beadSize.x - beadDiameter) / 2,
                        beadDiameter / 2);
                  VDRAWCIRCLE(w, *dr, w->abacus.beadShadeGC[shadeLine],
                        beadDiameter,
                        w->abacus.beadSize.x / 2 -
                        (w->abacus.beadSize.x - beadDiameter) / 2,
                        beadDiameter / 2 + beadOffset);
                  VDRAWCIRCLE(w, *dr, w->abacus.beadShadeGC[shadeLine],
                        beadDiameter,
                        w->abacus.beadSize.x / 2 +
                        (w->abacus.beadSize.x - beadDiameter) / 2,
                        beadDiameter / 2 + beadOffset);
                  VFILLCIRCLE(w, *dr, w->abacus.beadShadeGC[shadeFill],
                        beadDiameter,
                        w->abacus.beadSize.x / 2 -
                        (w->abacus.beadSize.x - beadDiameter) / 2,
                        beadDiameter / 2);
                  VFILLCIRCLE(w, *dr, w->abacus.beadShadeGC[shadeFill],
                        beadDiameter,
                        w->abacus.beadSize.x / 2 +
                        (w->abacus.beadSize.x - beadDiameter) / 2,
                        beadDiameter / 2);
                  VFILLCIRCLE(w, *dr, w->abacus.beadShadeGC[shadeFill],
                        beadDiameter,
                        w->abacus.beadSize.x / 2 -
                        (w->abacus.beadSize.x - beadDiameter) / 2,
                        beadDiameter / 2 + beadOffset);
                  VFILLCIRCLE(w, *dr, w->abacus.beadShadeGC[shadeFill],
                        beadDiameter,
                        w->abacus.beadSize.x / 2 +
                        (w->abacus.beadSize.x - beadDiameter) / 2,
                        beadDiameter / 2 + beadOffset);
                  VDRAWRECTANGLE(w, *dr,
                        w->abacus.beadShadeGC[shadeLine],
                        w->abacus.beadSize.x / 2 -
                        (w->abacus.beadSize.x - beadDiameter) / 2, 0,
                        w->abacus.beadSize.x - beadDiameter,
                        w->abacus.beadSize.y);
                  VDRAWRECTANGLE(w, *dr,
                        w->abacus.beadShadeGC[shadeLine],
                        w->abacus.beadSize.x / 2 -
                        (w->abacus.beadSize.x - beadDiameter) / 2 -
                        beadDiameter / 2,
                        beadDiameter / 2,
                        w->abacus.beadSize.x, beadOffset);
                  VFILLRECTANGLE(w, *dr,
                        w->abacus.beadShadeGC[shadeFill],
                        w->abacus.beadSize.x / 2 -
                        (w->abacus.beadSize.x - beadDiameter) / 2, 0,
                        w->abacus.beadSize.x - beadDiameter + 1,
                        w->abacus.beadSize.y);
                  VFILLRECTANGLE(w, *dr,
                        w->abacus.beadShadeGC[shadeFill],
                        w->abacus.beadSize.x / 2 -
                        (w->abacus.beadSize.x - beadDiameter) / 2 -
                        beadDiameter / 2,
                        beadDiameter / 2,
                        w->abacus.beadSize.x + 1, beadOffset + 1);
#ifdef INSIDEOUT
                  if (pressed == 0) {
#endif
                        VFILLCIRCLE(w, *dr,
                              w->abacus.beadShadeGC[shadeDot],
                              beadDiameter / 6,
                              -beadDiameter / 5 +
                              w->abacus.beadSize.x / 2 -
                              (w->abacus.beadSize.x -
                              beadDiameter) / 2,
                              -beadDiameter / 5 +
                              (beadDiameter - 1) / 2);
#ifdef INSIDEOUT
                  } else {
                        VFILLCIRCLE(w, *dr,
                              w->abacus.beadShadeGC[shadeDot],
                              beadDiameter / 6,
                              beadDiameter / 5 +
                              w->abacus.beadSize.x / 2 +
                              (w->abacus.beadSize.x -
                              beadDiameter) / 2,
                              beadDiameter / 5 +
                              (beadDiameter - 1) / 2);
                   }
#endif
            }
      }
}

static void
drawAllBufferedBeads(AbacusWidget w)
{
      int color, pressed, shade;

      for (color = 0; color < 3; color++)
            for (pressed = 0; pressed < 2; pressed++)
                  for (shade = 0; shade < 2; shade++)
                        drawBufferedBead(w, color, pressed, shade);
}

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

      if (dir == UP)
            numBeads = bead - position;
      else
            numBeads = position - bead + 1;
      for (space = 0; space < spaces; space++) {
            gapJ = w->abacus.pos.y / w->abacus.numSlices;
            if (gapJ == 0)
                  gapJ++;
            FLUSH(w);
            initTimer(w->abacus.oldTime);
            for (inc = 1; 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 ((w->abacus.vertical && dir == DOWN) ||
                                    (!w->abacus.vertical &&
                                    dir == UP)) {
                              drawRail(w, deck, rail, j + posOff,
                                    w->abacus.pos.y - inc,
                                    gapJ);
                        } else {
                              drawRail(w, deck, rail, j + posOff,
                                    inc - gapJ +
                                    w->abacus.pressOffsetY,
                                    gapJ);
                        }
                  }
                  FLUSH(w);
                  useTimer(&(w->abacus.oldTime), 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]);
      int b = w->abacus.base;

      digit += d;
      if ((w->abacus.decks[BOTTOM].piece != 0 &&
                  (p == w->abacus.decimalPosition - 1)) ||
                  (checkSubdeck(w, 3) &&
                  (p == w->abacus.decimalPosition - 2))) {
            b = w->abacus.decks[BOTTOM].piece;
            if (w->abacus.decks[TOP].piece != 0)
                  b *= w->abacus.decks[TOP].piece;
      } else if (w->abacus.decks[BOTTOM].piecePercent != 0 &&
                  (p == w->abacus.decimalPosition -
                   w->abacus.shiftPercent - 1 -
                   ((w->abacus.decks[BOTTOM].piece == 0) ? 0 : 1))) {
            b = w->abacus.decks[BOTTOM].piecePercent;
            if (w->abacus.decks[TOP].piecePercent != 0)
                  b *= w->abacus.decks[TOP].piecePercent;
      }
      w->abacus.digits[position] = int2Char(digit % b);
      if (digit >= b) {
            if (checkSubdeck(w, 3) &&
                        (p + 1 == w->abacus.decimalPosition - 1))
                  addBead(w, digit / b, p + 1);
            else if ((w->abacus.decks[BOTTOM].piece != 0 &&
                        (p + 1 == w->abacus.decimalPosition - 1)) ||
                        (w->abacus.decks[BOTTOM].piecePercent != 0 &&
                        (p + 1 == w->abacus.decimalPosition -
                        w->abacus.shiftPercent - 1 -
                        ((w->abacus.decks[BOTTOM].piece == 0) ? 0 : 1))))
                  addBead(w, digit / b, p + 2);
            else {
                  addBead(w, digit / b, p + 1);
                  if (w->abacus.anomaly != 0) {
                    if (p + 1 == w->abacus.shiftAnomaly +
                          w->abacus.decimalPosition) {
                        w->abacus.carryAnomaly = True;
                    } else if (w->abacus.anomalySq != 0 &&
                          p + 1 == w->abacus.shiftAnomaly +
                          w->abacus.shiftAnomalySq +
                          w->abacus.decimalPosition) {
                        w->abacus.carryAnomalySq = True;
                    }
                  }
            }
      }
}

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]);
      int b = w->abacus.base;

      digit -= d;
      if ((w->abacus.decks[BOTTOM].piece != 0 &&
                  (p == w->abacus.decimalPosition - 1)) ||
                  (checkSubdeck(w, 3) &&
                  (p == w->abacus.decimalPosition - 2))) {
            b = w->abacus.decks[BOTTOM].piece;
            if (w->abacus.decks[TOP].piece != 0)
                  b *= w->abacus.decks[TOP].piece;
      } else if (w->abacus.decks[BOTTOM].piecePercent != 0 &&
                  (p == w->abacus.decimalPosition -
                  w->abacus.shiftPercent - 1 -
                  ((w->abacus.decks[BOTTOM].piece == 0) ? 0 : 1))) {
            b = w->abacus.decks[BOTTOM].piecePercent;
            if (w->abacus.decks[TOP].piecePercent != 0)
                  b *= w->abacus.decks[TOP].piecePercent;
      }
      w->abacus.digits[position] = int2Char(((digit + b) % b));
      if (digit < 0) {
            if (checkSubdeck(w, 3) &&
                        (p + 1 == w->abacus.decimalPosition - 1))
                  subBead(w, 1 - (1 + digit) / b, p + 1);
            else if ((w->abacus.decks[BOTTOM].piece != 0 &&
                        (p + 1 == w->abacus.decimalPosition - 1)) ||
                        (w->abacus.decks[BOTTOM].piecePercent != 0 &&
                        (p + 1 == w->abacus.decimalPosition -
                        w->abacus.shiftPercent - 1 -
                        ((w->abacus.decks[BOTTOM].piece == 0) ? 0 : 1))))
                  subBead(w, 1 - (1 + digit) / b, p + 2);
            else {
                  subBead(w, 1 - (1 + digit) / b, p + 1);
                  if (w->abacus.anomaly != 0) {
                    if (p + 1 == w->abacus.shiftAnomaly +
                          w->abacus.decimalPosition) {
                        w->abacus.carryAnomaly = False;
                    } else if (w->abacus.anomalySq != 0 &&
                          p + 1 == w->abacus.shiftAnomaly +
                          w->abacus.shiftAnomalySq +
                          w->abacus.decimalPosition) {
                        w->abacus.carryAnomalySq = False;
                    }
                  }
            }
      }
}

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)
{
      int pos, rdeck, rj, rpos;

      if (j > MAX_BASE + spaces) {
            char buf[512];

            (void) sprintf(buf, "corruption (moveUp) %d > %d.",
                  j, MAX_BASE + spaces);
            return;
      }
      if (checkSubdeck(w, 3) && rail == w->abacus.decimalPosition - 2) {
            pos = w->abacus.subdecks[deck].position;
            rdeck = BOTTOM;
            rj = j + numberSubbeadsOffset(w, deck);
            rpos = pos + numberSubbeadsOffset(w, deck);
      } else {
            pos = w->abacus.decks[deck].position[rail];
            rdeck = deck;
            rj = j;
            rpos = pos;
      }
      if (j > pos + spaces) {
            int temp = rpos;

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

                  FLUSH(w);
                  initTimer(w->abacus.oldTime);
                  for (l = 0; l < spaces; l++) {
                        int k;

                        for (k = temp + spaces + 1; k <= rj; k++) {
                              drawBead(w, rdeck, rail,
                                    k - spaces, k - l,
                                    False, False, FALSE, 0, 0);
                              drawBead(w, rdeck, rail,
                                    k - spaces, k - l - 1,
                                    True, False, FALSE, 0, 0);
                        }
                        if (l + 1 != spaces) {
                              FLUSH(w);
                              useTimer(&(w->abacus.oldTime), delay);
                        }
                  }
            } else {
                  animateSlide(w, rdeck, rail, rj - spaces, rpos, rj,
                        spaces, UP, delay / w->abacus.numSlices);
            }
#ifdef USE_SOUND
            if (w->abacus.sound) {
                  playSound((char *) BUMPSOUND);
            }
#endif
            if (checkSubdeck(w, 3) && rail == w->abacus.decimalPosition - 2) {
                  w->abacus.subdecks[deck].position = j - spaces;
            } else {
                  w->abacus.decks[deck].position[rail] = j - spaces;
            }
            if (w->abacus.decks[rdeck].orientation) {
                  subBead(w, factor * (rj - spaces - temp), rail);
                  setCounter(w, deck, rail, -(rj - spaces - temp));
            } else {    /* w->abacus.decks[rdeck].orientation == DOWN */
                  addBead(w, factor * (rj - spaces - temp), rail);
                  setCounter(w, deck, rail, rj - 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)
{
      int pos, rdeck, rj, rpos;

      if (-j > MAX_BASE) {
            char buf[512];

            (void) sprintf(buf, "corruption (moveDown) %d > %d.",
                  -j, MAX_BASE);
            return;
      }
      if (checkSubdeck(w, 3) && rail == w->abacus.decimalPosition - 2) {
            pos = w->abacus.subdecks[deck].position;
            rdeck = BOTTOM;
            rj = j + numberSubbeadsOffset(w, deck);
            rpos = pos + numberSubbeadsOffset(w, deck);
      } else {
            pos = w->abacus.decks[deck].position[rail];
            rdeck = deck;
            rj = j;
            rpos = pos;
      }
      if (j <= pos) {
            int temp = rpos;

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

                  FLUSH(w);
                  initTimer(w->abacus.oldTime);
                  for (l = 0; l < spaces; l++) {
                        int k;

                        for (k = temp; k >= rj; k--) {
                              drawBead(w, rdeck, rail, k, k + l,
                                    False, False, FALSE, 0, 0);
                              drawBead(w, rdeck, rail, k, k + l + 1,
                                    True, False, FALSE, 0, 0);
                        }
                        if (l + 1 != spaces) {
                              FLUSH(w);
                              useTimer(&(w->abacus.oldTime), delay);
                        }
                  }
            } else {
                  animateSlide(w, rdeck, rail, rj, rpos, rj,
                        spaces, DOWN, delay / w->abacus.numSlices);
            }
#ifdef USE_SOUND
            if (w->abacus.sound) {
                  playSound((char *) BUMPSOUND);
            }
#endif
            if (checkSubdeck(w, 3) && rail == w->abacus.decimalPosition - 2) {
                  w->abacus.subdecks[deck].position = j - 1;
            } else {
                  w->abacus.decks[deck].position[rail] = j - 1;
            }
            if (w->abacus.decks[rdeck].orientation) {
                  addBead(w, factor * (temp - rj + 1), rail);
                  setCounter(w, deck, rail, temp - rj + 1);
            } else {    /* w->abacus.decks[rdeck].orientation == DOWN */
                  subBead(w, factor * (temp - rj + 1), rail);
                  setCounter(w, deck, rail, -(temp - rj + 1));
            }
      }
}

static void
moveBeadsUp(AbacusWidget w, const int deck, const int rail, const int j,
            const Boolean fast)
{
      int factor = 1, pieces, piecePercents, spaces;

#ifdef DEBUG
      (void) printf("moveBeadsUp: deck %d, rail %d, j %d\n",
                  deck, rail, j);
#endif
      if (w->abacus.sign && (rail == w->abacus.rails - 1)) {
            if (deck == BOTTOM) {
                  factor = 0;
                  spaces = w->abacus.decks[deck].room - 1;
                  if (spaces > 0)
                        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.decks[BOTTOM].piece != 0 &&
                  (rail == w->abacus.decimalPosition - 1)) {
            pieces = numberPieces(w, deck);
            if (deck == TOP)
                  factor *= w->abacus.decks[BOTTOM].piece;
            spaces = w->abacus.decks[deck].room - pieces;
            if (spaces > 0)
                  moveUp(w, deck, rail, j, factor, spaces, NORMAL,
                        (fast) ? 0 : w->abacus.delay *
                        w->abacus.decks[deck].spaces /
                        (w->abacus.decks[deck].room - pieces));
      } else if (w->abacus.decks[BOTTOM].piecePercent != 0 &&
                  (rail == w->abacus.decimalPosition -
                  w->abacus.shiftPercent - 1 -
                  ((w->abacus.decks[BOTTOM].piece == 0) ? 0 : 1))) {
            piecePercents = numberPiecePercents(w, deck);
            if (deck == TOP)
                  factor *= w->abacus.decks[BOTTOM].piecePercent;
            spaces = w->abacus.decks[deck].room - piecePercents;
            if (spaces > 0)
                  moveUp(w, deck, rail, j, factor, spaces, NORMAL,
                        (fast) ? 0 : w->abacus.delay *
                        w->abacus.decks[deck].spaces /
                        (w->abacus.decks[deck].room - piecePercents));
      } else if (checkSubdeck(w, 3) && (rail == w->abacus.decimalPosition - 2 ||
                  rail == w->abacus.decimalPosition - 3)) {
            if (rail == w->abacus.decimalPosition - 2) {
                  moveUp(w, deck, rail, j, convertRomanFactor(w, deck),
                        w->abacus.subdecks[deck].spaces, NORMAL,
                        (fast) ? 0 : w->abacus.delay *
                        w->abacus.subdecks[deck].spaces);
            }
      } 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, pieces, piecePercents, spaces;

#ifdef DEBUG
      (void) printf("moveBeadsDown: deck %d, rail %d, j %d\n",
                  deck, rail, j);
#endif
      if ((rail == w->abacus.rails - 1) && w->abacus.sign) {
            if (deck == BOTTOM) {
                  factor = 0;
                  spaces = w->abacus.decks[deck].room - 1;
                  if (spaces > 0)
                        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.decks[BOTTOM].piece != 0 &&
                  (rail == w->abacus.decimalPosition - 1)) {
            pieces = numberPieces(w, deck);
            if (deck == TOP)
                  factor *= w->abacus.decks[BOTTOM].piece;
            spaces = w->abacus.decks[deck].room - pieces;
            if (spaces > 0)
                  moveDown(w, deck, rail, j, factor, spaces, NORMAL,
                        (fast) ? 0 : w->abacus.delay *
                        w->abacus.decks[deck].spaces /
                        (w->abacus.decks[deck].room - pieces));
      } else if (w->abacus.decks[BOTTOM].piecePercent != 0 &&
                  (rail == w->abacus.decimalPosition -
                  w->abacus.shiftPercent - 1 -
                  ((w->abacus.decks[BOTTOM].piece == 0) ? 0 : 1))) {
            piecePercents = numberPiecePercents(w, deck);
            if (deck == TOP)
                  factor *= w->abacus.decks[BOTTOM].piecePercent;
            spaces = w->abacus.decks[deck].room - piecePercents;
            if (spaces > 0)
                  moveDown(w, deck, rail, j, factor, spaces, NORMAL,
                        (fast) ? 0 : w->abacus.delay *
                        w->abacus.decks[deck].spaces /
                        (w->abacus.decks[deck].room - piecePercents));
      } else if (checkSubdeck(w, 3) && (rail == w->abacus.decimalPosition - 2 ||
                  rail == w->abacus.decimalPosition - 3)) {
            if (rail == w->abacus.decimalPosition - 2) {
                  moveDown(w, deck, rail, j, convertRomanFactor(w, deck),
                        w->abacus.subdecks[deck].spaces, NORMAL,
                        (fast) ? 0 : w->abacus.delay *
                        w->abacus.subdecks[deck].spaces);
            }
      } 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 positionX, int positionY,
            int *deck, int *rail, int *j)
{
      int pieces, piecePercents;
      int x = positionX, y = positionY;

      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 - 3;
            *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.decks[BOTTOM].piece != 0 &&
                  (*rail == w->abacus.decimalPosition - 1)) {
            pieces = numberPieces(w, *deck);
            if (*deck == TOP && pieces == 0)
                  return False;
            return ((*j > w->abacus.decks[*deck].position[*rail] +
                  w->abacus.decks[*deck].room - pieces) ||
                  (*j <= w->abacus.decks[*deck].position[*rail]));
      }
      if (w->abacus.decks[BOTTOM].piecePercent != 0 &&
                  (*rail == w->abacus.decimalPosition -
                  w->abacus.shiftPercent - 1 -
                  ((w->abacus.decks[BOTTOM].piece == 0) ? 0 : 1))) {
            piecePercents = numberPiecePercents(w, *deck);
            if (*deck == TOP && piecePercents == 0)
                  return False;
            return ((*j > w->abacus.decks[*deck].position[*rail] +
                  w->abacus.decks[*deck].room - piecePercents) ||
                  (*j <= w->abacus.decks[*deck].position[*rail]));
      }
      if (checkSubdeck(w, 3) && *rail == w->abacus.decimalPosition - 3) {
            return False;
      } else if (checkSubdeck(w, 3) && *rail == w->abacus.decimalPosition - 2) {
            int d, beads;

            if (*deck == TOP)
                  return False;
            d = subdeckPosition(w, *j);
            *j = positionSubdeck(w, *j);
            *deck = d;
            beads = numberSubbeads(w, d);
            return ((*j > w->abacus.subdecks[*deck].position +
                  w->abacus.subdecks[*deck].room - beads) ||
                  (*j <= w->abacus.subdecks[*deck].position));
      }
      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)
{
      int bead;

      if (w->abacus.sign && (rail == w->abacus.rails - 1) && deck == TOP)
            return;
      if (w->abacus.decks[BOTTOM].piece != 0 &&
                  (rail == w->abacus.decimalPosition - 1) &&
                  deck == TOP && (w->abacus.decks[TOP].number == 0 &&
                  w->abacus.decks[TOP].piece == 0))
            return;
      if (w->abacus.decks[BOTTOM].piecePercent != 0 &&
                  (rail == w->abacus.decimalPosition -
                  w->abacus.shiftPercent - 1 -
                  ((w->abacus.decks[BOTTOM].piece == 0) ? 0 : 1)) &&
                  deck == TOP && (w->abacus.decks[TOP].number == 0 ||
                  w->abacus.decks[TOP].piecePercent == 0))
            return;
      if (checkSubdeck(w, 3) && rail == w->abacus.decimalPosition - 3)
            return;
      if (checkSubdeck(w, 3) && rail == w->abacus.decimalPosition - 2)
            bead = w->abacus.subdecks[deck].position;
      else
            bead = w->abacus.decks[deck].position[rail];
      if (pos <= bead) {
            moveBeadsDown(w, deck, rail, pos, fast);
      } else {
            moveBeadsUp(w, deck, rail, pos, fast);
      }
}

static void
shiftBar(AbacusWidget w, int oldDecimalPosition)
{
      int deck, rail;
      int pieces[MAX_DECKS], piecePercents[MAX_DECKS];
      int pieceRail = w->abacus.decimalPosition - 1;
      int piecePercentRail = w->abacus.decimalPosition -
            w->abacus.shiftPercent - 1 -
            ((w->abacus.decks[BOTTOM].piece == 0) ? 0 : 1);
      int oldPieceRail = oldDecimalPosition - 1;
      int oldPiecePercentRail = oldDecimalPosition -
            w->abacus.shiftPercent - 1 -
            ((w->abacus.decks[BOTTOM].piece == 0) ? 0 : 1);
      char p = '0', pp = '0';

      pieces[TOP] = 0;
      pieces[BOTTOM] = 0;
      piecePercents[TOP] = 0;
      piecePercents[BOTTOM] = 0;
      if (w->abacus.decks[BOTTOM].piece != 0) {
            int digit = w->abacus.rails + CARRY - oldDecimalPosition;

            pieces[BOTTOM] =
                  w->abacus.decks[BOTTOM].position[oldPieceRail];
            if (w->abacus.decks[TOP].piece != 0 ||
                        w->abacus.decks[TOP].number == 0)
                  pieces[TOP] =
                        w->abacus.decks[TOP].position[oldPieceRail];
            p = w->abacus.digits[digit];
            w->abacus.digits[digit] = '0';
      }
      if (w->abacus.decks[BOTTOM].piecePercent != 0) {
            int digit = w->abacus.rails + CARRY -
                  oldDecimalPosition + w->abacus.shiftPercent +
                  ((w->abacus.decks[BOTTOM].piece == 0) ? 0 : 1);

            piecePercents[BOTTOM] =
                  w->abacus.decks[BOTTOM].position[oldPiecePercentRail];
            if (w->abacus.decks[TOP].piecePercent != 0 ||
                        w->abacus.decks[TOP].number == 0)
                  piecePercents[TOP] =
                        w->abacus.decks[TOP].position[oldPiecePercentRail];
            pp = w->abacus.digits[digit];
            w->abacus.digits[digit] = '0';
      }
      /* shift around */
      if (oldDecimalPosition < w->abacus.decimalPosition) {
            for (rail = oldPieceRail; rail < pieceRail; rail++) {
                  for (deck = BOTTOM; deck <= TOP; deck++) {
                        w->abacus.decks[deck].position[rail] =
                              w->abacus.decks[deck].position[rail + 1];
                        if (w->abacus.decks[BOTTOM].piecePercent != 0)
                              w->abacus.decks[deck].position[rail - w->abacus.shiftPercent - 1] =
                                    w->abacus.decks[deck].position[rail - w->abacus.shiftPercent];
                  }
            }
            for (rail = w->abacus.rails + CARRY - oldDecimalPosition;
                        rail > w->abacus.rails + CARRY -
                        w->abacus.decimalPosition; rail--) {
                  w->abacus.digits[rail] = w->abacus.digits[rail - 1];
                  if (w->abacus.decks[BOTTOM].piecePercent != 0)
                        w->abacus.digits[rail + w->abacus.shiftPercent + 1] =
                              w->abacus.digits[rail + w->abacus.shiftPercent];
            }
      } else if (oldDecimalPosition > w->abacus.decimalPosition) {
            for (rail = oldPieceRail; rail > pieceRail; rail--) {
                  for (deck = BOTTOM; deck <= TOP; deck++) {
                        w->abacus.decks[deck].position[rail] =
                              w->abacus.decks[deck].position[rail - 1];
                        if (w->abacus.decks[BOTTOM].piecePercent != 0)
                              w->abacus.decks[deck].position[rail - w->abacus.shiftPercent - 1] =
                                    w->abacus.decks[deck].position[rail - w->abacus.shiftPercent - 2];
                  }
            }
            for (rail = w->abacus.rails + CARRY - oldDecimalPosition;
                        rail < w->abacus.rails + CARRY -
                        w->abacus.decimalPosition; rail++) {
                  w->abacus.digits[rail] = w->abacus.digits[rail + 1];
                  if (w->abacus.decks[BOTTOM].piecePercent != 0)
                        w->abacus.digits[rail + w->abacus.shiftPercent + 1] =
                              w->abacus.digits[rail + w->abacus.shiftPercent + 2];
            }
      }
      if (w->abacus.decks[BOTTOM].piece != 0) {
            w->abacus.decks[BOTTOM].position[pieceRail] = pieces[BOTTOM];
            if (w->abacus.decks[TOP].piece == 0 ||
                        w->abacus.decks[TOP].number == 0)
                  w->abacus.decks[TOP].position[pieceRail] = 0;
            else
                  w->abacus.decks[TOP].position[pieceRail] = pieces[TOP];
            w->abacus.digits[w->abacus.rails + CARRY -
                  w->abacus.decimalPosition] = p;
      }
      if (w->abacus.decks[BOTTOM].piecePercent != 0) {
            w->abacus.decks[BOTTOM].position[piecePercentRail] =
                  piecePercents[BOTTOM];
            if (w->abacus.decks[TOP].piecePercent == 0 ||
                        w->abacus.decks[TOP].number == 0)
                  w->abacus.decks[TOP].position[piecePercentRail] = 0;
            else
                  w->abacus.decks[TOP].position[piecePercentRail] =
                        piecePercents[TOP];
            w->abacus.digits[w->abacus.rails + CARRY -
                  w->abacus.decimalPosition + w->abacus.shiftPercent +
                  ((w->abacus.decks[BOTTOM].piece == 0) ? 0 : 1)] = pp;
      }
}

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

      for (rail = 0; rail < w->abacus.rails; rail++) {
            for (deck = BOTTOM; deck <= TOP; deck++) {
                  if (w->abacus.sign && (rail == w->abacus.rails - 1) &&
                              deck == TOP) {
                        continue;
                  }
                  if (w->abacus.decks[BOTTOM].piece != 0 &&
                              (rail == w->abacus.decimalPosition - 1) &&
                              deck == TOP &&
                              (w->abacus.decks[TOP].number == 0 ||
                              w->abacus.decks[TOP].piece == 0)) {
                        continue;
                  }
                  if (w->abacus.decks[BOTTOM].piecePercent != 0 &&
                              (rail == w->abacus.decimalPosition -
                              w->abacus.shiftPercent - 1 -
                              ((w->abacus.decks[BOTTOM].piece == 0) ?
                              0 : 1)) &&
                              deck == TOP &&
                              (w->abacus.decks[TOP].number == 0 ||
                              w->abacus.decks[TOP].piecePercent == 0)) {
                        continue;
                  }
                  if (checkSubdeck(w, 3) && (rail ==
                              w->abacus.decimalPosition - 2)) {
                        if (deck == BOTTOM) {
                          int d;

                          for (d = 0; d < w->abacus.subdeck; d++)
                            if (w->abacus.decks[BOTTOM].orientation)
                              moveBeadsUp(w, d, rail,
                              w->abacus.subdecks[d].room, True);
                            else
                              moveBeadsDown(w, d, rail, 1, True);
                        }
                        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
complementRails(AbacusWidget w)
{
      int rail, deck;

      for (rail = 0; rail < w->abacus.rails; rail++) {
            for (deck = BOTTOM; deck <= TOP; deck++) {
                  if (w->abacus.sign && (rail == w->abacus.rails - 1) &&
                              deck == TOP) {
                        continue;
                  }
                  if (w->abacus.decks[BOTTOM].piece != 0 &&
                              (rail == w->abacus.decimalPosition - 1)) {
                        continue;
                  }
                  if (w->abacus.decks[BOTTOM].piecePercent != 0 &&
                              (rail == w->abacus.decimalPosition -
                              w->abacus.shiftPercent - 1 -
                              ((w->abacus.decks[BOTTOM].piece == 0) ?
                              0 : 1))) {
                        continue;
                  }
                  if (checkSubdeck(w, 3) && (rail ==
                              w->abacus.decimalPosition - 2)) {
                        continue;
                  }
                  {
                        int number = w->abacus.decks[deck].number;
                        int bead = w->abacus.decks[deck].position[rail];
                        Boolean orient = w->abacus.decks[deck].orientation;
                        int offset = 0;
                        int factor, extra;

                        if (deck == 1 && w->abacus.decks[0].number >= w->abacus.base - 1)
                              continue;
                        factor = (deck == 0) ? w->abacus.decks[1].factor :
                              w->abacus.base / w->abacus.decks[deck].factor;
                        extra = number - factor + 1;
                        if (orient) {
                              if (bead > w->abacus.decks[deck].number - extra + 1 || bead < extra)
                                    continue; /* not really well defined here so ignore */
                              if (bead - extra < factor / 2)
                                    offset = w->abacus.decks[deck].spaces - 1 + 2 * extra;
                              else
                                    offset = 2 * extra;
                              moveBeadsByPos(w, deck, rail, factor - bead + offset, True);
                        } else {
                              if (bead > w->abacus.decks[deck].number - extra || bead < 0)
                                    continue; /* not really well defined here so ignore */
                              if (bead < factor / 2)
                                    offset = w->abacus.decks[deck].spaces - 1;
                              moveBeadsByPos(w, deck, rail, factor - bead + offset, True);
                        }
                  }
            }
      }
}

static void
drawAllBeads(AbacusWidget w)
{
      int deck, rail, j, spaces;

      if (w->abacus.sign) {
            deck = BOTTOM;
            rail = w->abacus.rails - 1;
            drawBead(w, deck, rail, 1, 1,
                  (w->abacus.decks[deck].position[rail] == 1),
                  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,
                  (w->abacus.decks[deck].position[rail] == 0),
                  False, FALSE, 0, 0);
      }
      if (w->abacus.decks[BOTTOM].piece != 0) {
            int pieces = 0;

            for (deck = BOTTOM; deck <= TOP; deck++) {
                  rail = w->abacus.decimalPosition - 1;
                  pieces = numberPieces(w, deck);
                  if (pieces == 0)
                        continue;
                  spaces = w->abacus.decks[deck].room - pieces;
                  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.decks[BOTTOM].piece != 0 &&
                  w->abacus.decks[BOTTOM].piecePercent != 0) {
            int piecePercents = 0;

            for (deck = BOTTOM; deck <= TOP; deck++) {
                  rail = w->abacus.decimalPosition -
                        w->abacus.shiftPercent - 1 -
                        ((w->abacus.decks[BOTTOM].piece == 0) ? 0 : 1);
                  piecePercents = numberPiecePercents(w, deck);
                  if (piecePercents == 0)
                        continue;
                  spaces = w->abacus.decks[deck].room - piecePercents;
                  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 (checkSubdeck(w, 3)) {
            int offset, d = BOTTOM;

            rail = w->abacus.decimalPosition - 2;
            for (deck = 0; deck < w->abacus.subdeck; deck++) {
                  spaces = w->abacus.subdecks[deck].spaces;
                  offset = numberSubbeadsOffset(w, deck);
                  for (j = 1; j <= w->abacus.subdecks[deck].position;
                              j++) {
                        drawBead(w, d, rail, j + offset, j + offset,
                              True, False, FALSE, 0, 0);
                  }
                  for (j = w->abacus.subdecks[deck].position + 1;
                              j < spaces +
                              w->abacus.subdecks[deck].position + 1;
                              j++) {
                        drawBead(w, d, rail, offset, j + offset,
                              False, False, FALSE, 0, 0);
                  }
                  for (j = spaces + w->abacus.subdecks[deck].position + 1;
                              j <= w->abacus.subdecks[deck].room; j++) {
                        drawBead(w, d, rail,
                              j + offset - spaces, j + offset,
                              True, False, FALSE, 0, 0);
                  }
            }
      }
      for (rail = 0; rail < w->abacus.rails - ((w->abacus.sign) ? 1 : 0);
                  rail++) {
            if ((w->abacus.decks[BOTTOM].piece != 0 &&
                        (rail == w->abacus.decimalPosition - 1)) ||
                        (w->abacus.decks[BOTTOM].piecePercent != 0 &&
                        (rail == w->abacus.decimalPosition -
                        w->abacus.shiftPercent - 1 -
                        ((w->abacus.decks[BOTTOM].piece == 0) ?
                        0 : 1))) || (checkSubdeck(w, 3) &&
                        (rail == w->abacus.decimalPosition - 2 ||
                        rail == w->abacus.decimalPosition - 3))) {
                  continue;
            }
            for (deck = BOTTOM; deck <= TOP; 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 newRail)
{
      int rail = newRail;
      int j;

      if (w->abacus.script) {
#ifdef WINVER
            (void) fprintf(w->abacus.fp, "%d %d %d %d 4\n",
                  PRIMARY, 2,
                  rail - w->abacus.decimalPosition, 0);
            (void) fprintf(w->abacus.fp,
                  "Lesson\n\n\nPress Space-bar to Continue\n");
#else
            setAbacusMove(w, ACTION_SCRIPT,
                  w->abacus.aux, 2,
                  rail - w->abacus.decimalPosition, 0);
#endif
      }
      if (checkSubdeck(w, 3)) {
            return;
      }
      if (rail <= w->abacus.shiftPercent + 1 &&
                  w->abacus.decks[BOTTOM].piecePercent != 0) {
            w->abacus.decks[BOTTOM].piecePercent = 0;
            w->abacus.decks[TOP].piecePercent = 0;
            if (rail <= 0 && w->abacus.decks[BOTTOM].piece != 0)
                  rail = 1;
            (void) deleteSpecialRail(w, False, False, True);
            setAbacus(w, ACTION_QUARTER_PERCENT);
      } else if (rail <= 0 && w->abacus.decks[BOTTOM].piece != 0) {
            w->abacus.decks[BOTTOM].piece = 0;
            w->abacus.decks[TOP].piece = 0;
            (void) deleteSpecialRail(w, False, True, False);
            setAbacus(w, ACTION_QUARTER);
      }
      if (w->abacus.sign && rail >= w->abacus.rails - 1)
            rail = w->abacus.rails - 2;
      if (w->abacus.decks[BOTTOM].piece != 0 ||
                  w->abacus.decks[BOTTOM].piecePercent != 0) {
            eraseFrame(w, 0);
      }
      drawFrame(w, 0, False, True);
      j = w->abacus.decimalPosition;
      w->abacus.decimalPosition = rail;
      drawFrame(w, 0, True, True);
      if (w->abacus.decks[BOTTOM].piece != 0 ||
                  w->abacus.decks[BOTTOM].piecePercent != 0) {
            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)
{
#ifdef DEBUG
      (void) printf("moveBeadsByValue: deck %d, rail %d, number %d\n",
                  deck, rail, number);
#endif
      if (deck != BOTTOM && deck != TOP) {
            setDecimal(w, number + w->abacus.decimalPosition);
            return;
      }
      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;
      } else 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.decks[BOTTOM].piece != 0 &&
                        rail == w->abacus.decimalPosition - 1) {
                  spaces = w->abacus.decks[deck].room -
                        numberPieces(w, deck);
            }
            if (w->abacus.decks[BOTTOM].piecePercent != 0 &&
                        rail == w->abacus.decimalPosition - 1 -
                        w->abacus.shiftPercent -
                        ((w->abacus.decks[BOTTOM].piece == 0) ?
                        0 : 1)) {
                  spaces = w->abacus.decks[deck].room -
                        numberPiecePercents(w, deck);
            }
            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);
      }
}

static Boolean
setBeadsForValue(AbacusWidget w, char *expression)
{
      int i, val = -1, topUnits, bottomUnits;
      int percentPosition = w->abacus.decimalPosition -
            w->abacus.shiftPercent -
            ((w->abacus.decks[BOTTOM].piece == 0) ? 0 : 1);
      int nPieces = 0; int nPiecePercents = 0;

#ifdef DEBUG
      (void) printf("setBeadsForValue: %s, minusSign %s\n", expression,
            ((w->abacus.minusSign) ? "true" : "false"));
#endif
      for (i = 0; i < (int) strlen(expression) - CARRY; i++) {
            char a = expression[i + CARRY];

            val = char2Int(a);
            if (w->abacus.decks[BOTTOM].piece != 0 &&
                        w->abacus.rails - i !=
                        w->abacus.decimalPosition) {
                  nPieces = w->abacus.decks[BOTTOM].piece;
                  if (w->abacus.decks[TOP].piece != 0)
                        nPieces *= w->abacus.decks[TOP].piece;
            } else if (w->abacus.decks[BOTTOM].piecePercent != 0 &&
                        w->abacus.rails - i != percentPosition) {
                  nPiecePercents = w->abacus.decks[BOTTOM].piecePercent;
                  if (w->abacus.decks[TOP].piecePercent != 0)
                        nPiecePercents *=
                              w->abacus.decks[TOP].piecePercent;
            }
            if (w->abacus.decks[BOTTOM].piece != 0 &&
                        w->abacus.rails - i ==
                        w->abacus.decimalPosition) {
                  if (val >= nPieces)
                        val -= nPieces;
                  if (w->abacus.decks[TOP].number == 0) {
                        bottomUnits = val % nPieces;
                        moveBeadsByValue(w, BOTTOM,
                              w->abacus.rails - i - 1,
                              bottomUnits, True);
                  } else {
                        topUnits = val / w->abacus.decks[BOTTOM].piece;
                        bottomUnits = val % w->abacus.decks[BOTTOM].piece;
                        if (topUnits > w->abacus.decks[TOP].piece) {
                              return False;
                        }
                        moveBeadsByValue(w, TOP,
                              w->abacus.rails - i - 1,
                              topUnits, True);
                        moveBeadsByValue(w, BOTTOM,
                              w->abacus.rails - i - 1,
                              bottomUnits, True);
                  }
            } else if (w->abacus.decks[BOTTOM].piecePercent != 0 &&
                        w->abacus.rails - i == percentPosition) {
                  if (val >= nPiecePercents)
                        val -= nPiecePercents;
                  if (w->abacus.decks[TOP].number == 0) {
                        bottomUnits = val % nPiecePercents;
                        moveBeadsByValue(w, BOTTOM,
                              w->abacus.rails - i - 1,
                              bottomUnits, True);
                  } else {
                        topUnits = val / w->abacus.decks[BOTTOM].piecePercent;
                        bottomUnits = val % w->abacus.decks[BOTTOM].piecePercent;
                        if (topUnits > w->abacus.decks[TOP].piecePercent) {
                              return False;
                        }
                        moveBeadsByValue(w, TOP,
                              w->abacus.rails - i - 1,
                              topUnits, True);
                        moveBeadsByValue(w, BOTTOM,
                              w->abacus.rails - i - 1,
                              bottomUnits, True);
                  }
            } else {
                  if (checkSubdeck(w, 3) && w->abacus.rails - i <
                              w->abacus.decimalPosition)
                        continue;
                  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);
            }
      }
      if (w->abacus.sign) {
            moveBeadsByValue(w, BOTTOM, w->abacus.rails - 1,
                  (w->abacus.decks[BOTTOM].orientation) ?
                  ((w->abacus.minusSign) ? 0 :
                  w->abacus.decks[BOTTOM].room -
                  w->abacus.decks[BOTTOM].spaces) :
                  ((w->abacus.minusSign) ? w->abacus.decks[BOTTOM].room -
                  w->abacus.decks[BOTTOM].spaces: 0), True);
      }
      return True;
}

void
clearRails(AbacusWidget w)
{
      clearAllBeads(w);
#ifndef WINVER
      if (w->abacus.demo) {
            setAbacus(w, ACTION_CLEAR);
      }
#endif
      if (!emptyCounter(w)) {
            DISPLAY_WARNING("corruption (clearRails)");
      }
      setCounter(w, 0, w->abacus.decimalPosition, 0); /* needed when 0 */
}


void
clearAuxRails(AbacusWidget w, int aux)
{
#ifndef WINVER
      abacusCallbackStruct cb;

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

static void
checkDecimal(AbacusWidget w)
{
      if (w->abacus.decimalPosition >= w->abacus.rails -
                  ((w->abacus.sign) ? 1 : 0) +
                  ((w->abacus.decks[BOTTOM].piece == 0) ? 0 : 1) +
                  ((w->abacus.decks[BOTTOM].piecePercent == 0) ? 0 : 1)) {
            drawFrame(w, 0, False, True);
            w->abacus.decimalPosition = w->abacus.rails - 1 -
                  ((w->abacus.sign) ? 1 : 0) +
                  ((w->abacus.decks[BOTTOM].piece == 0) ? 0 : 1) +
                  ((w->abacus.decks[BOTTOM].piecePercent == 0) ? 0 : 1);
            drawFrame(w, 0, True, True);
            setCounter(w, 0, w->abacus.decimalPosition, 0);
      }
}

/* via increment/decrement or by sign and pieces */
static void
shiftRails(AbacusWidget w, int oldRails, int newRails,
            Boolean oldSign, Boolean piece, Boolean piecePercent)
{
      AbacusPart old;
      int deck, rail, offset;
      int piecePosition[MAX_DECKS], piecePercentPosition[MAX_DECKS];
      int pieceNumber[MAX_DECKS], piecePercentNumber[MAX_DECKS];
      int shift = newRails - oldRails;
      int decimalShift = 0;
      Boolean signPosition = False;

      piecePosition[TOP] = piecePosition[BOTTOM] = 0;
      piecePercentPosition[TOP] = piecePercentPosition[BOTTOM] = 0;
      pieceNumber[BOTTOM] = numberPieces(w, BOTTOM);
      pieceNumber[TOP] = numberPieces(w, TOP);
      piecePercentNumber[BOTTOM] = numberPiecePercents(w, BOTTOM);
      piecePercentNumber[TOP] = numberPiecePercents(w, TOP);
      old.sign = w->abacus.sign;
      old.decks[TOP].piece = w->abacus.decks[TOP].piece;
      old.decks[BOTTOM].piece = w->abacus.decks[BOTTOM].piece;
      old.decks[TOP].piecePercent = w->abacus.decks[TOP].piecePercent;
      old.decks[BOTTOM].piecePercent = w->abacus.decks[BOTTOM].piecePercent;
      deck = BOTTOM;
      /* special items added already, 2 is a dummy value */
      if (oldSign)
            old.sign = !w->abacus.sign;
      if (piece) {
            old.decks[BOTTOM].piece =
                  (w->abacus.decks[BOTTOM].piece == 0) ? 2 : 0;
      }
      if (piecePercent) {
            old.decks[BOTTOM].piecePercent =
                  (w->abacus.decks[BOTTOM].piecePercent == 0) ? 2 : 0;
      }
      /* Save sign, this will be erased */
      if (old.sign && !oldSign)
            signPosition = ((w->abacus.decks[deck].orientation &&
                  w->abacus.decks[deck].position[oldRails - 1] == 0) ||
                  (!w->abacus.decks[deck].orientation &&
                  w->abacus.decks[deck].position[oldRails - 1] != 0));
      old.rails = oldRails + ((shift > 0) ? shift : 0);
      old.decimalPosition = w->abacus.decimalPosition;
      for (deck = BOTTOM; deck <= TOP; deck++) {
            /* Alloc space to save the rails */
            if (!(old.decks[deck].position = (int *)
                        calloc((unsigned int) (old.rails),
                        sizeof (int)))) {
                  DISPLAY_ERROR("Not enough memory (shiftRails), exiting.");
            }
            /* initialization could be wrong if oriented from top */
            /* current pieces will be initialized later */
            if (w->abacus.decks[deck].orientation) {
                  for (rail = 0; rail < old.rails; rail++) {
                        old.decks[deck].position[rail] =
                              w->abacus.decks[deck].number;
                  }
                  if (old.decks[BOTTOM].piece == 0 && piece)
                        piecePosition[deck] = pieceNumber[deck];
                  if (old.decks[BOTTOM].piecePercent == 0 &&
                              piecePercent)
                        piecePercentPosition[deck] =
                              piecePercentNumber[deck];
            }
      }
      /* initialization from old */
      for (deck = BOTTOM; deck <= TOP; deck++) {
            offset = 0;
            if (old.decks[BOTTOM].piece != 0 && !piece)
                  offset--;
            if (old.decks[BOTTOM].piecePercent != 0 && !piecePercent)
                  offset--;
            for (rail = oldRails - ((old.sign) ? 1 : 0) - 1; rail >= 0; rail--) {
                  if (old.decks[BOTTOM].piece != 0 &&
                              rail == w->abacus.decimalPosition - 1) {
                        if (old.decks[deck].piece != 0 && !piece)
                              piecePosition[deck] =
                                    w->abacus.decks[deck].position[rail];
                        offset++;
                  } else if (old.decks[BOTTOM].piecePercent != 0 &&
                              rail == w->abacus.decimalPosition -
                              w->abacus.shiftPercent - 1 -
                              ((old.decks[BOTTOM].piece == 0) ? 0 : 1)) {
                        if (old.decks[deck].piecePercent != 0 &&
                                    !piecePercent)
                              piecePercentPosition[deck] =
                                    w->abacus.decks[deck].position[rail];
                        offset++;
                  } else {
                        old.decks[deck].position[rail + offset] =
                              w->abacus.decks[deck].position[rail];
                  }
            }
      }
      w->abacus.rails = newRails;
#ifdef DEBUG
      for (deck = TOP; deck >= BOTTOM; deck--) {
            for (rail = old.rails - 1; rail >= 0; rail--) {
                  (void) printf("%c",
                        int2Char(old.decks[deck].position[rail]));
            }
            (void) printf(":%d,p%d,pp%d", old.rails,
                  piecePosition[deck], piecePercentPosition[deck]);
            if (old.sign && !oldSign)
                  (void) printf(",s%d\n", signPosition);
            else
                  (void) printf("\n");
      }
      (void) printf("shiftRails decimalPosition w%d, rails w%d, shift%d\n",
            w->abacus.decimalPosition, w->abacus.rails, shift);
#endif
      if (w->abacus.decimalPosition > w->abacus.rails - 1 -
                  ((w->abacus.sign) ? 1 : 0)) {
            decimalShift = w->abacus.decimalPosition;
            w->abacus.decimalPosition = w->abacus.rails - 1 -
                  ((w->abacus.sign) ? 1 : 0);
            decimalShift -= w->abacus.decimalPosition;
      } else if (w->abacus.decimalPosition < ((w->abacus.sign) ? 1 : 0)) {
            w->abacus.decimalPosition = 0;
      }
      offset = 0;
      if (piece && old.decks[BOTTOM].piece == 0) {
            w->abacus.decimalPosition++;
      }
      if (piece && old.decks[BOTTOM].piece != 0) {
            offset--;
            w->abacus.decimalPosition--;
      }
      if (piecePercent && old.decks[BOTTOM].piecePercent == 0) {
            w->abacus.decimalPosition++;
      }
      if (piecePercent && old.decks[BOTTOM].piecePercent != 0) {
            offset--;
            w->abacus.decimalPosition--;
      }
#ifdef DEBUG
      (void) printf("shiftRails decimalPosition w%d, rails w%d, shift%d, offset%d\n",
            w->abacus.decimalPosition, w->abacus.rails, shift, offset);
#endif
      resetBeads(w);
      resizeAbacus(w);
#ifndef WINVER
      if (w->core.visible && XtWindow(w) != 0)
#endif
      {
            resizeBead(w);
            drawAllBufferedBeads(w);
            eraseFrame(w, 0);
            drawFrame(w, 0, True, True);
            drawAllBeads(w);
      }
      for (deck = BOTTOM; deck <= TOP; deck++) {
            int localOffset = offset;

            for (rail = 0; rail < w->abacus.rails + ((offset < 0) ? -offset : 0) -
                        (((old.sign && !oldSign) ||
                        (!old.sign && oldSign)) ? 1 : 0);
                        rail++) {
                  if (w->abacus.decks[BOTTOM].piece != 0 &&
                              rail + localOffset == w->abacus.decimalPosition - 1) {
                        if (deck != TOP || pieceNumber[TOP] != 0) {
                              if (w->abacus.decks[deck].orientation) {
                                    moveBeadsByValue(w, deck, rail + localOffset,
                                          pieceNumber[deck] -
                                          piecePosition[deck], True);
                              } else {
                                    moveBeadsByValue(w, deck, rail + localOffset,
                                          piecePosition[deck], True);
                              }
                        }
                        localOffset++;
                  } else if (w->abacus.decks[BOTTOM].piecePercent != 0 &&
                              rail + localOffset == w->abacus.decimalPosition -
                              w->abacus.shiftPercent - 1 -
                              ((w->abacus.decks[BOTTOM].piece == 0) ?
                              0 : 1)) {
                        if (deck != TOP || piecePercentNumber[TOP] != 0) {
                              if (w->abacus.decks[deck].orientation) {
                                    moveBeadsByValue(w, deck, rail + localOffset,
                                          piecePercentNumber[deck] -
                                          piecePercentPosition[deck], True);
                              } else {
                                    moveBeadsByValue(w, deck, rail + localOffset,
                                          piecePercentPosition[deck], True);
                              }
                        }
                        localOffset++;
                  }
                  if (rail + localOffset < w->abacus.rails) {
                        if (w->abacus.decks[deck].orientation)
                              moveBeadsByValue(w, deck, rail + localOffset,
                                    w->abacus.decks[deck].number -
                                    old.decks[deck].position[rail + decimalShift],
                                    True);
                        else
                              moveBeadsByValue(w, deck, rail + localOffset,
                                    old.decks[deck].position[rail + decimalShift],
                                    True);
                  }
            }
      }
      if ((old.sign && !oldSign) || (!old.sign && oldSign)) {
            deck = BOTTOM;
            rail = w->abacus.rails - 1;
            if (w->abacus.decks[deck].orientation) {
                  moveBeadsByPos(w, deck, rail,
                        (signPosition) ?
                        1 : w->abacus.decks[deck].room,
                        True);
            } else {
                  moveBeadsByPos(w, deck, rail,
                        (signPosition) ?
                        w->abacus.decks[deck].room : 1,
                        True);
            }
      }
#ifdef DEBUG
      for (deck = TOP; deck >= BOTTOM; deck--) {
            for (rail = w->abacus.rails - 1; rail >= 0; rail--) {
                  (void) printf("%c",
                        int2Char(w->abacus.decks[deck].position[rail]));
            }
            (void) printf(":%d,p%d,pp%d", w->abacus.rails,
                  piecePosition[deck], piecePercentPosition[deck]);
            if (old.sign && !oldSign)
                  (void) printf(",s%d\n", signPosition);
            else
                  (void) printf("\n");
            if (deck == TOP) {
                  for (rail = w->abacus.rails - 1; rail >= 0; rail--) {
                        if (w->abacus.decimalPosition == rail)
                              (void) printf(".");
                        else if ((rail > w->abacus.decimalPosition) &&
                                    ((w->abacus.decimalPosition - rail) % 3 == 0))
                              (void) printf(",");
                        else if ((w->abacus.decks[BOTTOM].piece != 0) &&
                                    (rail == w->abacus.decimalPosition - 1))
                              (void) printf("+");
                        else if ((w->abacus.decks[BOTTOM].piecePercent != 0) &&
                                    (rail == w->abacus.decimalPosition -
                                    w->abacus.shiftPercent - 1 -
                                    ((w->abacus.decks[BOTTOM].piece == 0) ? 0 : 1)))
                              (void) printf("+");
                        else
                              (void) printf(" ");
                  }
                  (void) printf("\n");
            }
      }
#endif
      for (deck = BOTTOM; deck <= TOP; deck++) {
            if (old.decks[deck].position)
                  free(old.decks[deck].position);
      }
}

static Boolean
insertSpecialRail(AbacusWidget w,
            Boolean sign, Boolean piece, Boolean piecePercent)
{
      int minRails = ((w->abacus.demo) ? MIN_DEMO_RAILS : MIN_RAILS);

      if (w->abacus.rails + 2 <= minRails + ((w->abacus.sign) ? 1 : 0) +
                  ((w->abacus.decks[BOTTOM].piece == 0) ? 0 : 1) +
                  ((w->abacus.decks[BOTTOM].piecePercent == 0) ?
                  0 : w->abacus.shiftPercent + 1))
            return False;
      shiftRails(w, w->abacus.rails, w->abacus.rails + 1,
            sign, piece, piecePercent);
      setAbacus(w, ACTION_INCREMENT);
      return True;
}

static Boolean
deleteSpecialRail(AbacusWidget w,
            Boolean sign, Boolean piece, Boolean piecePercent)
{
      int minRails = ((w->abacus.demo) ? MIN_DEMO_RAILS : MIN_RAILS);

      if (w->abacus.rails <= minRails + ((w->abacus.sign) ? 1 : 0) +
                  ((w->abacus.decks[BOTTOM].piece == 0) ? 0 : 1) +
                  ((w->abacus.decks[BOTTOM].piecePercent == 0) ?
                  0 : w->abacus.shiftPercent + 1) +
                  (checkSubdeck(w, 3) ? 2 : 0))
            return False;
      shiftRails(w, w->abacus.rails, w->abacus.rails - 1,
            sign, piece, piecePercent);
      setAbacus(w, ACTION_DECREMENT);
      checkDecimal(w);
      return True;
}

static void
incrementRails(AbacusWidget w)
{
      shiftRails(w, w->abacus.rails, w->abacus.rails + 1,
            False, False, False);
      setAbacus(w, ACTION_INCREMENT);
}

static void
decrementRails(AbacusWidget w)
{
      int minRails = ((w->abacus.demo) ? MIN_DEMO_RAILS : MIN_RAILS);

      if (w->abacus.rails <= minRails + ((w->abacus.sign) ? 1 : 0) +
                  ((w->abacus.decks[BOTTOM].piece == 0) ? 0 : 1) +
                  ((w->abacus.decks[BOTTOM].piecePercent == 0) ?
                  0 : w->abacus.shiftPercent + 1) +
                  (checkSubdeck(w, 3) ? 2 : 0))
            return;
      shiftRails(w, w->abacus.rails, w->abacus.rails - 1,
            False, False, False);
      setAbacus(w, ACTION_DECREMENT);
      checkDecimal(w);
}

static void
speedBeed(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)
{
      char * buffer;

      if (!(buffer = (char *) malloc(sizeof (char) *
                  (strlen(w->abacus.digits) + 1)))) {
            DISPLAY_ERROR("Not enough memory (reformatRails), exiting.");
      }
      (void) strcpy(buffer, w->abacus.digits);
      resetBeads(w);
      resizeAbacus(w);
#ifndef WINVER
      if (w->core.visible && XtWindow(w) != 0)
#endif
      {
            resizeBead(w);
            drawAllBufferedBeads(w);
            eraseFrame(w, 0);
            drawFrame(w, 0, True, True);
            drawAllBeads(w);
      }
      if (w->abacus.decks[BOTTOM].piecePercent != 0 &&
                  w->abacus.decimalPosition - w->abacus.shiftPercent -
                  ((w->abacus.decks[BOTTOM].piece == 0) ? 0 : 1) < 1)
            w->abacus.decks[BOTTOM].piecePercent = 0;
      if (w->abacus.decks[BOTTOM].piece != 0 &&
                  w->abacus.decimalPosition < 1)
            w->abacus.decks[BOTTOM].piece = 0;
      if (!setBeadsForValue(w, buffer)) {
            resetBeads(w);
      }
      free(buffer);
}

static void
formatRails(AbacusWidget w)
{
      Boolean other = False;

      if (w->abacus.mode < CHINESE || w->abacus.mode >= GENERIC) {
            w->abacus.mode = CHINESE;
            if (w->abacus.demo)
                  other = True;
      } else
            w->abacus.mode = (w->abacus.mode + 1) % MAX_FORMATS;
      /*if (w->abacus.demo && w->abacus.mode == GENERIC) {
            w->abacus.mode = CHINESE;
      }*/
      if (w->abacus.sign) {
            if (w->abacus.decks[BOTTOM].orientation)
                  w->abacus.minusSign =
                        w->abacus.decks[BOTTOM].position[w->abacus.rails - 1] == 0;
            else
                  w->abacus.minusSign =
                        w->abacus.decks[BOTTOM].position[w->abacus.rails - 1] != 0;
      }
      /* clear special beads */
      if (checkSubdeck(w, 3)) {
            int deck = 0;

            for (deck = 0; deck < w->abacus.subdeck; deck++) {
                  moveBeadsDown(w,
                        deck, w->abacus.decimalPosition - 2,
                        w->abacus.subdecks[deck].room - 1, True);
            }
            /* This should not be necessary. */
            w->abacus.digits[w->abacus.rails] = '0';
      }
      checkBeads(w);
      if (!other) /* errors out otherwise */
            reformatRails(w);
      setAbacus(w, ACTION_FORMAT);
}

static void
museumRails(AbacusWidget w)
{
      if (w->abacus.submode < IT || w->abacus.submode > MAX_MUSEUMS)
            w->abacus.submode = NRAND(MAX_MUSEUMS);
      else
            w->abacus.submode = (w->abacus.submode + 1) % MAX_MUSEUMS;
      eraseFrame(w, 0);
      drawFrame(w, 0, True, True);
      drawAllBeads(w);
}

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

static void
toggleGroupDisplay(AbacusWidget w)
{
      w->abacus.group = !w->abacus.group;
      setCounter(w, 0, w->abacus.decimalPosition, 0);
}

static void
toggleSignRail(AbacusWidget w)
{
      w->abacus.sign = !w->abacus.sign;
      if ((w->abacus.sign && (w->abacus.teach ||
                  !insertSpecialRail(w, True, False, False))) ||
                  (!w->abacus.sign &&
                  !deleteSpecialRail(w, True, False, False))) {
            w->abacus.sign = !w->abacus.sign;
            return;
      }
      setAbacus(w, ACTION_SIGN);
}

static void
togglePieceRail(AbacusWidget w, int topPieces, int bottomPieces)
{
      int oldPiece[MAX_DECKS];

      oldPiece[TOP] = w->abacus.decks[TOP].piece;
      oldPiece[BOTTOM] = w->abacus.decks[BOTTOM].piece;
      if (w->abacus.decks[BOTTOM].piece != 0 &&
                  w->abacus.decks[BOTTOM].piecePercent != 0)
            return;
      if (w->abacus.decks[TOP].number == 0 && topPieces != 0) {
            if (w->abacus.decks[BOTTOM].room <= topPieces * bottomPieces) {
                  w->abacus.decks[BOTTOM].room = topPieces * bottomPieces + 1;
                  w->abacus.decks[BOTTOM].spaces = w->abacus.decks[BOTTOM].room -
                        w->abacus.decks[BOTTOM].number;
            }
      } else {
            if (checkBottomSpace(w) < bottomPieces) {
                  w->abacus.decks[BOTTOM].spaces -=
                        (checkBottomSpace(w) - bottomPieces);
                  w->abacus.decks[BOTTOM].room = w->abacus.decks[BOTTOM].number +
                        w->abacus.decks[BOTTOM].spaces;
            }
      }
      w->abacus.decks[BOTTOM].piece =
            (w->abacus.decks[BOTTOM].piece == 0) ?
            bottomPieces : 0;
      w->abacus.decks[TOP].piece =
            (w->abacus.decks[TOP].piece != 0 ||
             w->abacus.decks[BOTTOM].piece == 0) ?
            0 : topPieces;
      if (checkSubdeck(w, 2)) {
            w->abacus.decks[BOTTOM].position[1] = 0;
      }
      if (w->abacus.decks[BOTTOM].piece == 0) {
            if (!deleteSpecialRail(w, False, True, False)) {
                  w->abacus.decks[BOTTOM].piece = oldPiece[BOTTOM];
                  w->abacus.decks[TOP].piece = oldPiece[TOP];
            }
      } else {
            if (!insertSpecialRail(w, False, True, False)) {
                  w->abacus.decks[BOTTOM].piece = oldPiece[BOTTOM];
                  w->abacus.decks[TOP].piece = oldPiece[TOP];
            }
      }
      if (w->abacus.decks[BOTTOM].piece != oldPiece[BOTTOM] ||
                  w->abacus.decks[TOP].piece != oldPiece[TOP]) {
            if (bottomPieces == QUARTERS && topPieces == 0)
                  setAbacus(w, ACTION_QUARTER);
            else if (bottomPieces == TWELFTHS / 2 && topPieces == 2)
                  setAbacus(w, ACTION_TWELFTH);
      }
}

static void
togglePiecePercentRail(AbacusWidget w,
            int topPiecePercents, int bottomPiecePercents)
{
      int oldPiecePercent[MAX_DECKS];

      oldPiecePercent[TOP] = w->abacus.decks[TOP].piecePercent;
      oldPiecePercent[BOTTOM] = w->abacus.decks[BOTTOM].piecePercent;
      if (w->abacus.decimalPosition < 1 + w->abacus.shiftPercent)
            return;
      if (w->abacus.decks[BOTTOM].piece == 0 &&
                  w->abacus.decks[BOTTOM].piecePercent == 0)
            return;
      if (w->abacus.decks[TOP].number == 0 && topPiecePercents != 0) {
            if (w->abacus.decks[BOTTOM].room <= topPiecePercents * bottomPiecePercents) {
                  w->abacus.decks[BOTTOM].room = topPiecePercents * bottomPiecePercents + 1;
                  w->abacus.decks[BOTTOM].spaces = w->abacus.decks[BOTTOM].room -
                        w->abacus.decks[BOTTOM].number;
            }
      } else {
            if (checkBottomSpace(w) < bottomPiecePercents) {
                  w->abacus.decks[BOTTOM].spaces -=
                        (checkBottomSpace(w) - bottomPiecePercents);
                  w->abacus.decks[BOTTOM].room = w->abacus.decks[BOTTOM].number +
                        w->abacus.decks[BOTTOM].spaces;
            }
      }
      w->abacus.decks[BOTTOM].piecePercent =
            (w->abacus.decks[BOTTOM].piecePercent != 0) ?
            0 : bottomPiecePercents;
      w->abacus.decks[TOP].piecePercent =
            (w->abacus.decks[TOP].piecePercent != 0 ||
             w->abacus.decks[BOTTOM].piecePercent == 0) ?
            0 : topPiecePercents;
      if (checkSubdeck(w, 4)) {
            w->abacus.decks[BOTTOM].position[2] = 0;
      }
      if (w->abacus.decks[BOTTOM].piecePercent != 0) {
            if (!deleteSpecialRail(w, False, False, True)) {
                  w->abacus.decks[BOTTOM].piecePercent = oldPiecePercent[BOTTOM];
                  if (topPiecePercents != 0)
                        w->abacus.decks[TOP].piecePercent = oldPiecePercent[TOP];
            }
      } else {
            if (!insertSpecialRail(w, False, False, True)) {
                  w->abacus.decks[BOTTOM].piecePercent = oldPiecePercent[BOTTOM];
                  if (topPiecePercents != 0)
                        w->abacus.decks[TOP].piecePercent = oldPiecePercent[TOP];
            }
      }
      if ((w->abacus.decks[BOTTOM].piecePercent != oldPiecePercent[BOTTOM] ||
                  w->abacus.decks[TOP].piecePercent !=
                  oldPiecePercent[TOP]) &&
                  bottomPiecePercents == QUARTER_PERCENTS &&
                  topPiecePercents == 0)
            setAbacus(w, ACTION_QUARTER_PERCENT);
}

static void
toggleSubdeckRail(AbacusWidget w, int ndecks, int nbeads)
{
      int deck;

      if (w->abacus.subdeck == 0) {
            w->abacus.subdeck = ndecks;
            w->abacus.subbead = nbeads;
            for (deck = 0; deck < ndecks; deck++) {
                  w->abacus.subdecks[deck].number =
                        numberSubbeads(w, BOTTOM);
                  w->abacus.subdecks[deck].room =
                        w->abacus.subdecks[deck].number + 1;
                  w->abacus.subdecks[deck].position =
                        (w->abacus.decks[BOTTOM].orientation) ?
                        w->abacus.subdecks[deck].number : 0;
            }
      } else {
            /* clear special beads */
            if (checkSubdeck(w, 3)) {
                  for (deck = 0; deck < w->abacus.subdeck; deck++) {
                        moveBeadsDown(w,
                              deck, w->abacus.decimalPosition - 2,
                              w->abacus.subdecks[deck].room - 1, True);
                  }
                  /* This should not be necessary. */
                  w->abacus.digits[w->abacus.rails] = '0';
            }
            w->abacus.subdeck = 0;
      }
      if (w->abacus.sign) {
            if (w->abacus.decks[BOTTOM].orientation)
                  w->abacus.minusSign =
                        w->abacus.decks[BOTTOM].position[w->abacus.rails - 1] == 0;
            else
                  w->abacus.minusSign =
                        w->abacus.decks[BOTTOM].position[w->abacus.rails - 1] != 0;
      }
      reformatRails(w);
}

static void
toggleAnomalyRails(AbacusWidget w, int anomalyRail, int anomalySqRail)
{
      if (w->abacus.anomaly == 0) {
            if (w->abacus.teach)
                  return;
            w->abacus.anomaly = anomalyRail;
      } else {
            w->abacus.anomaly = 0;
      }
      w->abacus.anomalySq = anomalySqRail;
      if (w->abacus.sign) {
            if (w->abacus.decks[BOTTOM].orientation)
                  w->abacus.minusSign =
                        w->abacus.decks[BOTTOM].position[w->abacus.rails - 1] == 0;
            else
                  w->abacus.minusSign =
                        w->abacus.decks[BOTTOM].position[w->abacus.rails - 1] != 0;
      }
      reformatRails(w);
}

static void
toggleRightToLeftAddTeach(AbacusWidget w)
{
      w->abacus.rightToLeftAdd = !w->abacus.rightToLeftAdd;
}

static void
toggleRightToLeftMultTeach(AbacusWidget w)
{
      w->abacus.rightToLeftMult = !w->abacus.rightToLeftMult;
}

#if 0
static void
toggleVerticalRails(AbacusWidget w)
{
      eraseFrame(w, 0);
      w->abacus.vertical = !w->abacus.vertical;
      resizeAbacus(w);
#ifndef WINVER
      if (w->core.visible && XtWindow(w) != 0)
#endif
      {
            resizeBead(w);
            drawAllBufferedBeads(w);
            drawFrame(w, 0, True, True);
            drawAllBeads(w);
      }
}
#endif

#define BRIGHT_FACTOR 0.8
#define DARK_FACTOR 0.75

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

      if (temp < i)
            temp = i;
      return MIN(temp / BRIGHT_FACTOR, MAX_INTENSITY);
}

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

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

      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.decks[TOP].piece = GetPrivateProfileInt(SECTION,
            "topPiece", 0, INIFILE);
      w->abacus.decks[BOTTOM].piece = GetPrivateProfileInt(SECTION,
            "bottomPiece", 0, INIFILE);
      w->abacus.decks[TOP].piecePercent = GetPrivateProfileInt(SECTION,
            "topPiecePercent", 0, INIFILE);
      w->abacus.decks[BOTTOM].piecePercent = GetPrivateProfileInt(SECTION,
            "bottomPiecePercent", 0, INIFILE);
      w->abacus.shiftPercent = GetPrivateProfileInt(SECTION,
            "shiftPercent", 2, INIFILE);
      w->abacus.subdeck = GetPrivateProfileInt(SECTION,
            "subdeck", 0, INIFILE);
      w->abacus.subbead = GetPrivateProfileInt(SECTION,
            "subbead", 4, INIFILE);
      w->abacus.decimalPosition = GetPrivateProfileInt(SECTION,
            "decimalPosition", 2, INIFILE);
      w->abacus.groupSize = GetPrivateProfileInt(SECTION,
            "groupSize", 3, INIFILE);
      w->abacus.decimalComma = (BOOL) GetPrivateProfileInt(SECTION,
            "decimalComma", 0, INIFILE);
      w->abacus.rails = GetPrivateProfileInt(SECTION, "rails", 13, INIFILE);
      w->abacus.colorScheme = GetPrivateProfileInt(SECTION,
            "colorScheme", 0, INIFILE);
      w->abacus.slot = (BOOL) GetPrivateProfileInt(SECTION,
            "slot", FALSE, INIFILE);
      w->abacus.diamond = (BOOL) GetPrivateProfileInt(SECTION,
            "diamond", FALSE, INIFILE);
      w->abacus.railIndex = GetPrivateProfileInt(SECTION,
            "railIndex", 0, INIFILE);
      w->abacus.vertical = (BOOL) GetPrivateProfileInt(SECTION,
            "vertical", FALSE, INIFILE);
      (void) GetPrivateProfileString(SECTION, "format", "Chinese",
            szBuf, sizeof (szBuf), INIFILE);
      (void) strncpy(w->abacus.format, szBuf, 80);
      (void) GetPrivateProfileString(SECTION, "museum", "--",
            szBuf, sizeof (szBuf), INIFILE);
      (void) strncpy(w->abacus.museum, szBuf, 3);
      w->abacus.base = GetPrivateProfileInt(SECTION,
            "base", 10, INIFILE);
      w->abacus.anomaly = GetPrivateProfileInt(SECTION,
            "anomaly", 0, INIFILE);
      w->abacus.shiftAnomaly = GetPrivateProfileInt(SECTION,
            "shiftAnomaly", 2, INIFILE);
      w->abacus.anomalySq = GetPrivateProfileInt(SECTION,
            "anomalySq", 0, INIFILE);
      w->abacus.shiftAnomalySq = GetPrivateProfileInt(SECTION,
            "shiftAnomalySq", 2, INIFILE);
      w->abacus.displayBase = GetPrivateProfileInt(SECTION,
            "displayBase", 10, INIFILE);
      w->abacus.pressOffsetY= GetPrivateProfileInt(SECTION,
            "pressOffset", 0, INIFILE);
      w->abacus.romanNumerals = (BOOL) GetPrivateProfileInt(SECTION,
            "romanNumerals", FALSE, INIFILE);
      w->abacus.latin = (BOOL) GetPrivateProfileInt(SECTION,
            "latin", FALSE, INIFILE);
      w->abacus.ancientRoman = (BOOL) GetPrivateProfileInt(SECTION,
            "ancientRoman", FALSE, INIFILE);
      w->abacus.modernRoman = (BOOL) GetPrivateProfileInt(SECTION,
            "modernRoman", FALSE, INIFILE);
      w->abacus.mono = (BOOL) GetPrivateProfileInt(SECTION,
            "mono", DEFAULT_MONO, INIFILE);
      w->abacus.reverse = (BOOL) GetPrivateProfileInt(SECTION,
            "reverseVideo", DEFAULT_REVERSE, INIFILE);
      /* DarkRed */
      (void) GetPrivateProfileString(SECTION, "primaryBeadColor", "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.symbolGC = w->abacus.beadShadeGC[1];
      /* brown (burlywood4) */
      (void) GetPrivateProfileString(SECTION, "secondaryBeadColor", "139 115 85",
            szBuf, sizeof (szBuf), INIFILE);
      (void) sscanf(szBuf, "%d %d %d",
            &(color.red), &(color.green), &(color.blue));
      w->abacus.beadShadeGC[5] = RGB(color.red, color.green, color.blue);
      w->abacus.beadShadeGC[4] = RGB(brighter(color.red),
            brighter(color.green), brighter(color.blue));
      w->abacus.beadShadeGC[6] = RGB(darker(color.red),
            darker(color.green), darker(color.blue));
      w->abacus.beadShadeGC[7] = RGB(darker(darker(color.red)),
            darker(darker(color.green)), darker(darker(color.blue)));
      /* brown (burlywood4) */
      (void) GetPrivateProfileString(SECTION, "highlightBeadColor", "255 0 255",
            szBuf, sizeof (szBuf), INIFILE);
      (void) sscanf(szBuf, "%d %d %d",
            &(color.red), &(color.green), &(color.blue));
      w->abacus.beadShadeGC[9] = RGB(color.red, color.green, color.blue);
      w->abacus.beadShadeGC[8] = RGB(brighter(color.red),
            brighter(color.green), brighter(color.blue));
      w->abacus.beadShadeGC[10] = RGB(darker(color.red),
            darker(color.green), darker(color.blue));
      w->abacus.beadShadeGC[11] = RGB(darker(darker(color.red)),
            darker(darker(color.green)), darker(darker(color.blue)));
      /* gold */
      (void) GetPrivateProfileString(SECTION, "primaryRailColor", "255 215 0",
            szBuf, sizeof (szBuf), INIFILE);
      (void) sscanf(szBuf, "%d %d %d",
            &(color.red), &(color.green), &(color.blue));
      w->abacus.railGC[0] = RGB(color.red, color.green, color.blue);
      /* silver (LightSteelBlue1) */
      (void) GetPrivateProfileString(SECTION, "secondaryRailColor", "202 225 255",
            szBuf, sizeof (szBuf), INIFILE);
      (void) sscanf(szBuf, "%d %d %d",
            &(color.red), &(color.green), &(color.blue));
      w->abacus.railGC[1] = RGB(color.red, color.green, color.blue);
      /* Purple */
      (void) GetPrivateProfileString(SECTION, "highlightRailColor", "160 32 240",
            szBuf, sizeof (szBuf), INIFILE);
      (void) sscanf(szBuf, "%d %d %d",
            &(color.red), &(color.green), &(color.blue));
      w->abacus.railGC[2] = RGB(color.red, color.green, color.blue);
      /* gray25 */
      (void) GetPrivateProfileString(SECTION, "borderColor", "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);
      /* Tan (wheat4) */
      (void) GetPrivateProfileString(SECTION, "frameColor", "139 126 102",
            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", FALSE, INIFILE);
      (void) GetPrivateProfileString(SECTION, "bumpSound", BUMPSOUND,
            szBuf, sizeof (szBuf), INIFILE);
      (void) strncpy(w->abacus.bumpSound, szBuf, 80);
      (void) GetPrivateProfileString(SECTION, "moveSound", MOVESOUND,
            szBuf, sizeof (szBuf), INIFILE);
      (void) strncpy(w->abacus.moveSound, szBuf, 80);
      w->abacus.script = (BOOL) GetPrivateProfileInt(SECTION,
            "script", FALSE, INIFILE);
      w->abacus.demo = (BOOL) GetPrivateProfileInt(SECTION,
            "demo", FALSE, INIFILE);
      w->abacus.teach = (BOOL) GetPrivateProfileInt(SECTION,
            "teach", FALSE, INIFILE);
      w->abacus.rightToLeftAdd = (BOOL) GetPrivateProfileInt(SECTION,
            "rightToLeftAdd", FALSE, INIFILE);
      w->abacus.rightToLeftMult = (BOOL) GetPrivateProfileInt(SECTION,
            "rightToLeftMult", FALSE, INIFILE);
      /* black */
      (void) GetPrivateProfileString(SECTION, "textColor", "0 0 0",
            szBuf, sizeof (szBuf), INIFILE);
      (void) sscanf(szBuf, "%d %d %d",
            &(color.red), &(color.green), &(color.blue));
      w->abacusDemo.foregroundGC = RGB(color.red, color.green, color.blue);
      (void) GetPrivateProfileString(SECTION, "demoPath", DEMOPATH,
            szBuf, sizeof (szBuf), INIFILE);
      (void) strncpy(w->abacusDemo.path, szBuf, 80);
}

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

            (void) fclose(w->abacus.fp);
            (void) sprintf(buf, "Saved to %s.", SCRIPTFILE);
            DISPLAY_INFO(buf);
      }
      (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 MAX_INTENSITY 0xFFFF

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

      color.pixel = pixel;
      VOID 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 / BRIGHT_FACTOR, MAX_INTENSITY);
      color.green = (unsigned short) MIN(color.green / BRIGHT_FACTOR, MAX_INTENSITY);
      color.blue = (unsigned short) MIN(color.blue / BRIGHT_FACTOR, MAX_INTENSITY);
      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;
      VOID XQueryColor(XtDisplay(w), w->abacus.colormap, &color);
      color.red = (unsigned short) (color.red * DARK_FACTOR);
      color.green = (unsigned short) (color.green * DARK_FACTOR);
      color.blue = (unsigned short) (color.blue * DARK_FACTOR);
      if (XAllocColor(XtDisplay(w), w->abacus.colormap, &color))
            return color.pixel;
      return pixel;
}

static void
setAllColors(AbacusWidget w)
{
      XGCValues values;
      XtGCMask valueMask;
      int i;

      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) {
            w->abacus.symbolGC = w->abacus.inverseGC;
            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);
      for (i = 0; i < 3; i++) {
            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[i];
                  values.background = w->abacus.borderColor;
            }
            if (w->abacus.railGC[i])
                  XtReleaseGC((Widget) w, w->abacus.railGC[i]);
            w->abacus.railGC[i] = XtGetGC((Widget) w, valueMask, &values);
      }
      for (i = 0; i < 3; i++) {
            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[i];
                  values.background = w->abacus.borderColor;
            }
            if (!w->abacus.mono && (BlackPixelOfScreen(XtScreen(w)) ==
                        w->abacus.beadColor[i])) {
                  w->abacus.beadColor[i] = brighter(w, values.foreground);
                  values.foreground = w->abacus.beadColor[i];
            }
            if (w->abacus.beadShadeGC[1 + i * 4])
                  XtReleaseGC((Widget) w, w->abacus.beadShadeGC[1 + i * 4]);
            w->abacus.beadShadeGC[1 + i * 4] = XtGetGC((Widget) w, valueMask, &values);
            if (!w->abacus.mono) {
                  values.foreground = brighter(w, w->abacus.beadColor[i]);
            }
            if (w->abacus.beadShadeGC[i * 4])
                  XtReleaseGC((Widget) w, w->abacus.beadShadeGC[i * 4]);
            w->abacus.beadShadeGC[i * 4] = XtGetGC((Widget) w, valueMask, &values);
            if (!w->abacus.mono) {
                  values.foreground = darker(w, w->abacus.beadColor[i]);
            }
            if (w->abacus.beadShadeGC[2 + i * 4])
                  XtReleaseGC((Widget) w, w->abacus.beadShadeGC[2 + i * 4]);
            w->abacus.beadShadeGC[2 + i * 4] = XtGetGC((Widget) w, valueMask, &values);
            if (!w->abacus.mono) {
                  values.foreground = darker(w, values.foreground);
            }
            if (w->abacus.beadShadeGC[3 + i * 4])
                  XtReleaseGC((Widget) w, w->abacus.beadShadeGC[3 + i * 4]);
            w->abacus.beadShadeGC[3 + i * 4] = 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.borderColor;
            values.background = w->abacus.beadColor[0];
      }
      if (w->abacus.borderGC)
            XtReleaseGC((Widget) w, w->abacus.borderGC);
      w->abacus.borderGC = XtGetGC((Widget) w, valueMask, &values);
      if (!w->abacus.mono) {
            w->abacus.symbolGC = w->abacus.beadShadeGC[1];
      }
}

static Boolean
setValuesAbacus(Widget current, Widget request, Widget renew)
{
      AbacusWidget c = (AbacusWidget) current, w = (AbacusWidget) renew;
      Boolean redraw = False;
      Boolean redrawBeads = False;

      if (w->abacus.demo && ((w->abacus.mode != c->abacus.mode) ||
                  (w->abacus.demo != c->abacus.demo))) {
            clearAllBeads(w);
            if (!emptyCounter(w)) {
                  DISPLAY_WARNING("corruption (setValuesAbacus)");
            }
            setCounter(w, 0, w->abacus.decimalPosition, 0); /* needed when 0 */
      }
      if (strncasecmp(w->abacus.format, c->abacus.format,
                  MAX_FORMAT_LENGTH) != 0) {
            setModeFromFormat(w);
            setAbacus(w, ACTION_FORMAT);
            if (w->abacus.demo)
                  clearRails(w);
      }
      if (strncasecmp(w->abacus.museum, c->abacus.museum,
                  MAX_FORMAT_LENGTH) != 0) {
            setSubmodeFromMuseum(w);
            redraw = True;
      }
      if (strcmp(w->abacus.teachBuffer, "") != 0 &&
                  w->abacus.deck == TEACH_DECK) {
            teachStep(w, w->abacus.teachBuffer, 0);
            w->abacus.deck = IGNORE_DECK;
      }
      if (w->abacus.decks[BOTTOM].piece != 0 &&
                  w->abacus.decimalPosition < 1) {
            w->abacus.decks[BOTTOM].piece = 0;
            c->abacus.decks[BOTTOM].piece = 0;
            setAbacus(w, ACTION_QUARTER);
      }
      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[0] != c->abacus.beadColor[0] ||
                  w->abacus.beadColor[1] != c->abacus.beadColor[1] ||
                  w->abacus.beadColor[2] != c->abacus.beadColor[2] ||
                  w->abacus.railColor[0] != c->abacus.railColor[0] ||
                  w->abacus.railColor[1] != c->abacus.railColor[1] ||
                  w->abacus.railColor[2] != c->abacus.railColor[2] ||
                  w->abacus.reverse != c->abacus.reverse ||
                  w->abacus.mono != c->abacus.mono) {
            setAllColors(w);
            redrawBeads = True;
      }
      if (w->abacus.rails != c->abacus.rails) {
            /* via slider */
            (void) shiftRails(w, c->abacus.rails, w->abacus.rails,
                  False, False, False);
      }
      if (w->abacus.sign != c->abacus.sign) {
            if (w->abacus.sign) {
                  if (!insertSpecialRail(w, True, False, False)) {
                        w->abacus.sign = !w->abacus.sign;
                        setAbacus(w, ACTION_SIGN);
                  }
            } else {
                  if (!deleteSpecialRail(w, True, False, False)) {
                        w->abacus.sign = !w->abacus.sign;
                        setAbacus(w, ACTION_SIGN);
                  }
            }
      }
      if (w->abacus.decks[BOTTOM].piece != c->abacus.decks[BOTTOM].piece) {
            if (w->abacus.decks[BOTTOM].piece != 0) {
                  if (!insertSpecialRail(w, False, True, False)) {
                        w->abacus.decks[BOTTOM].piece =
                              c->abacus.decks[BOTTOM].piece;
                        setAbacus(w, ACTION_QUARTER);
                  }
            } else {
                  if (!deleteSpecialRail(w, False, True, False)) {
                        w->abacus.decks[BOTTOM].piece =
                              c->abacus.decks[BOTTOM].piece;
                        setAbacus(w, ACTION_QUARTER);
                  }
            }
      }
      if (w->abacus.decks[BOTTOM].piecePercent !=
                  c->abacus.decks[BOTTOM].piecePercent) {
            if (w->abacus.decks[BOTTOM].piecePercent != 0) {
                  if (!insertSpecialRail(w, False, False, True)) {
                        w->abacus.decks[BOTTOM].piecePercent =
                              (w->abacus.decks[BOTTOM].piecePercent != 0) ?
                              0 : QUARTER_PERCENTS;
                        setAbacus(w, ACTION_QUARTER_PERCENT);
                  }
            } else {
                  if (!deleteSpecialRail(w, False, False, True)) {
                        w->abacus.decks[BOTTOM].piecePercent =
                              (w->abacus.decks[BOTTOM].piecePercent != 0) ?
                              0 : QUARTER_PERCENTS;
                        setAbacus(w, ACTION_QUARTER_PERCENT);
                  }
            }
      }
      if (w->abacus.vertical != c->abacus.vertical) {
            resizeAbacus(w);
            if (w->core.visible && XtWindow(w) != 0) {
                  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.subdeck != c->abacus.subdeck ||
                  w->abacus.subbead != c->abacus.subbead ||
                  w->abacus.subbase != c->abacus.subbase ||
                  w->abacus.base != c->abacus.base) {
      if (w->abacus.sign) {
            if (w->abacus.decks[BOTTOM].orientation)
                  w->abacus.minusSign =
                        w->abacus.decks[BOTTOM].position[w->abacus.rails - 1] == 0;
            else
                  w->abacus.minusSign =
                        w->abacus.decks[BOTTOM].position[w->abacus.rails - 1] != 0;
      }
            reformatRails(w);
            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 != ACTION_IGNORE) {
            int menu = w->abacus.menu;

            w->abacus.menu = ACTION_IGNORE;
            switch (menu) {
            case ACTION_CLEAR:
                  clearRails(w);
                  break;
            case ACTION_COMPLEMENT:
                  complementRails(w);
                  break;
            case ACTION_INCREMENT:
                  incrementRails(w);
                  break;
            case ACTION_DECREMENT:
                  decrementRails(w);
                  break;
            case ACTION_FORMAT:
                  formatRails(w);
                  break;
            case ACTION_MUSEUM:
                  museumRails(w);
                  break;
            case ACTION_ROMAN_NUMERAL:
                  toggleRomanNumeralsDisplay(w);
                  break;
            case ACTION_GROUP:
                  toggleGroupDisplay(w);
                  break;
            case ACTION_SIGN:
                  toggleSignRail(w);
                  break;
            case ACTION_QUARTER:
                  togglePieceRail(w, 0, QUARTERS);
                  break;
            case ACTION_QUARTER_PERCENT:
                  togglePiecePercentRail(w, 0, QUARTER_PERCENTS);
                  break;
            case ACTION_TWELFTH:
                  togglePieceRail(w, 2, TWELFTHS / 2);
                  break;
            case ACTION_SUBDECK:
                  w->abacus.subbase = TWELFTHS;
                  toggleSubdeckRail(w, DEFAULT_SUBDECKS, DEFAULT_SUBBEADS);
                  break;
            case ACTION_EIGHTH:
                  w->abacus.subbase = EIGHTHS;
                  toggleSubdeckRail(w, DEFAULT_SUBDECKS, DEFAULT_SUBBEADS);
                  break;
            case ACTION_ANOMALY:
                  toggleAnomalyRails(w, 2, 0);
                  break;
            case ACTION_WATCH:
                  toggleAnomalyRails(w, 4, 4);
                  break;
            case ACTION_RIGHT_TO_LEFT_ADD:
                  toggleRightToLeftAddTeach(w);
                  break;
            case ACTION_RIGHT_TO_LEFT_MULT:
                  toggleRightToLeftMultTeach(w);
                  break;
            case ACTION_SPEED:
                  speedBeed(w);
                  break;
            case ACTION_SLOW:
                  slowBead(w);
                  break;
            case ACTION_SOUND:
                  soundBead(w);
                  break;
            /*case ACTION_VERTICAL:
                  toggleVerticalRails(w);
                  break;*/
            default:
                  break;
            }
      }
      if (w->abacus.deck == CLEAR_DECK) {
            w->abacus.deck = IGNORE_DECK;
            clearAllBeads(w);
      } else if (w->abacus.deck == CALC_DECK) {
            w->abacus.deck = IGNORE_DECK;
            calculate(w, w->abacus.mathBuffer, w->abacus.aux);
      } else if (w->abacus.deck != IGNORE_DECK) {
            if (checkMove(w)) {
                  moveBeadsByValue(w, w->abacus.deck, w->abacus.rail
                        + w->abacus.decimalPosition, w->abacus.number,
                        False);
            }
            w->abacus.deck = IGNORE_DECK;
      }
      return (redraw);
}

static void
quitAbacus(AbacusWidget w
#ifndef WINVER
, XEvent *event, char **args, int nArgs
#endif
)
{
      if (w->abacus.demo) {
            setAbacus(w, ACTION_DEMO);
            return;
      }
#ifdef WINVER
      if (w->abacus.freeDC) {
            int color, pressed, shade;

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

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

#if 0
#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
#endif
#if defined( USE_SOUND ) && defined( USE_ESOUND )
      if (w->abacus.aux == PRIMARY)
            (void) shutdown_sound();
#endif
      for (i = 0; i < MAX_SHADES; i++)
            XtReleaseGC(old, w->abacus.beadShadeGC[i]);
      for (i = 0; i < 3; i++)
            XtReleaseGC(old, w->abacus.railGC[i]);
      XtReleaseGC(old, w->abacus.borderGC);
      XtReleaseGC(old, w->abacus.frameGC);
      XtReleaseGC(old, w->abacus.inverseGC);
      XtRemoveCallbacks(old, XtNselectCallback, w->abacus.select);
}
#endif

static void
resizeBead(AbacusWidget w)
{
      int color, pressed, shade;
      Point size;

#ifdef WINVER
      if (w->core.memDC == NULL) {
            w->core.memDC = CreateCompatibleDC(w->core.hDC);
            if (w->core.memDC == NULL) {
                  char buf[512];

                  (void) sprintf(buf,
                        "CreateCompatibleDC failure (%d), exiting",
                        GetLastError());
                  DISPLAY_ERROR(buf);
            }
      }
#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
      if (w->abacus.vertical) {
            size.x = w->abacus.pos.y - w->abacus.pressOffsetY;
            size.y = w->abacus.beadSize.x + w->abacus.pressOffsetX;
      } else {
            size.x = w->abacus.beadSize.x + w->abacus.pressOffsetX;
            size.y = w->abacus.pos.y - w->abacus.pressOffsetY;
      }
      for (color = 0; color < 3; color++)
         for (pressed = 0; pressed < 2; pressed++)
            for (shade = 0; shade < 2; shade++) {
#ifdef WINVER
                  if (w->abacus.bufferBead[color][pressed][shade] != NULL) {
                        DeleteObject(w->abacus.bufferBead[color][pressed][shade]);
                        w->abacus.bufferBead[color][pressed][shade] = NULL;
                  }
                  if ((w->abacus.bufferBead[color][pressed][shade] =
                              CreateCompatibleBitmap(w->core.hDC,
                              size.x, size.y)) == NULL) {
                        char buf[512];

                        (void) sprintf(buf,
                              "CreateCompatibleBitmap failure (%d), exiting.",
                              GetLastError());
                        DISPLAY_ERROR(buf);
                  }
#else
                  if (w->abacus.bufferBead[color][pressed][shade] != None) {
                        VOID XFreePixmap(display,
                              w->abacus.bufferBead[color][pressed][shade]);
                        w->abacus.bufferBead[color][pressed][shade] = None;
                  }
                  if ((w->abacus.bufferBead[color][pressed][shade] =
                        XCreatePixmap(display, window,
                              size.x, size.y, xgwa.depth)) == None) {
                        DISPLAY_ERROR("Not enough memory(resizeBead), 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;
#ifdef DEMO_FRAMED
      if (w->abacus.demo) {
            w->abacusDemo.fontHeight = 16;
            w->core.height -= LINES * w->abacusDemo.fontHeight;
            w->abacusDemo.framed = True;
      }
#endif
#endif

      w->abacus.delta.x = 8;
      w->abacus.delta.y = 1 + w->abacus.pressOffsetY;
      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 = MAX(((int) w->abacus.frameSize.x -
            w->abacus.width + 2) / 2, 0);
      w->abacus.offset.y = MAX(((int) w->abacus.frameSize.y - height -
            w->abacus.midHeight + 5) / 2 + 1, 0);
      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 color, pressed, shade;
      int deck;
#ifdef WINVER
      setValuesAbacus(w);
      brush = CreateSolidBrush(w->abacus.inverseGC);
      SETBACK(w->core.hWnd, brush);
      (void) SRAND(time(NULL));
      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);
            }
      }
#else
      AbacusWidget w = (AbacusWidget) renew;
      int i;

      (void) SRAND(getpid());
      w->abacus.colormap = None;
      for (i = 0; i < MAX_SHADES; i++)
            w->abacus.beadShadeGC[i] = NULL;
      for (i = 0; i < 3; i++)
            w->abacus.railGC[i] = NULL;
      w->abacus.borderGC = NULL;
      w->abacus.frameGC = NULL;
      w->abacus.inverseGC = NULL;
#endif
      for (color = 0; color < 3; color++)
          for (pressed = 0; pressed < 2; pressed++)
            for (shade = 0; shade < 2; shade++)
                  w->abacus.bufferBead[color][pressed][shade] = None;
      w->abacus.pressOffsetX = 1;
      w->abacus.focus = False;
      w->abacus.numSlices = ((w->abacus.delay < 5 * MAX_SLICES) ?
            w->abacus.delay / 5 + 1 : MAX_SLICES);
      for (deck = 0; deck < MAX_DECKS; deck++)
            w->abacus.decks[deck].position = NULL;
      w->abacus.digits = NULL;
      w->abacus.subdecks = NULL;
      w->abacus.minusSign = False;
      w->abacus.sign = False;
      w->abacus.carryAnomaly = False;
      w->abacus.carryAnomalySq = False;
      if (w->abacus.decks[BOTTOM].piece != 0)
            w->abacus.decimalPosition++;
      if (w->abacus.decks[BOTTOM].piecePercent != 0)
            w->abacus.decimalPosition++;
      /* w->abacus.decimalPosition = w->abacus.rails / 2 */
      w->abacus.railIndex = 0;
      setModeFromFormat(w);
      setSubmodeFromMuseum(w);
      resetSubdecks(w);
      checkBeads(w);
      resetBeads(w);
      resizeAbacus(w);
#ifdef USE_SOUND
#ifdef USE_NAS
      dsp = XtDisplay(w);
#endif
#ifdef USE_ESOUND
      if (w->abacus.aux == PRIMARY)
            (void) init_sound();
#endif
#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 || XtWindow(w) == 0)
            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, ACTION_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 = 0, bead, j = 0;
#ifndef WINVER
      int x = event->xbutton.x, y = event->xbutton.y;
#endif
      
      w->abacus.step = 0; /* reset teach */
      if (w->abacus.demo) {
            clearAllBeads(w);
            setAbacus(w, ACTION_CLEAR);
#ifdef WINVER
            clearAbacusDemo(w);
#endif
            w->abacus.currentDeck = IGNORE_DECK;
      } 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 - 1 - w->abacus.railWidth / 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 (checkSubdeck(w, 3) && rail == w->abacus.decimalPosition - 2) {
                  if (bead > w->abacus.subdecks[deck].position)
                        bead -= w->abacus.subdecks[deck].spaces;
                  bead = j + numberSubbeadsOffset(w, deck);
                  j = bead;
                  bead -= w->abacus.subdecks[deck].spaces;
                  deck = BOTTOM;
            } else {
                  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 = IGNORE_DECK;
      }
}

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

      if (w->abacus.currentDeck == IGNORE_DECK)
            return;
      deck = w->abacus.currentDeck;
      rail = w->abacus.currentRail;
      j = w->abacus.currentPosition;
      bead = j;
      if (checkSubdeck(w, 3) && rail == w->abacus.decimalPosition - 2) {
            if (bead > w->abacus.subdecks[deck].position)
                  bead -= w->abacus.subdecks[deck].spaces;
            bead = j + numberSubbeadsOffset(w, deck);
            j = bead;
            bead -= w->abacus.subdecks[deck].spaces;
            deck = BOTTOM;
      } else {
            if (bead > w->abacus.decks[deck].position[rail])
                  bead -= w->abacus.decks[deck].spaces;
      }
      drawBead(w, deck, rail, bead, j, False, False, TRUE, 0, 0);
      drawBead(w, deck, rail, bead, j, True, False, FALSE, 0, 0);
      moveBeadsByPos(w, w->abacus.currentDeck, rail,
            w->abacus.currentPosition, False);
      w->abacus.currentDeck = IGNORE_DECK;
}

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

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

#ifndef WINVER
static
void
clearWithQueryAbacus(AbacusWidget w
, XEvent *event, char **args, int nArgs
)
{
#ifdef HAVE_MOTIF
      if (!isEmptyCounter(w) && w->abacus.aux == PRIMARY) {
            /* Check if one really wants to destroy calculations. */
            setAbacus(w, ACTION_CLEAR_QUERY);
      }
#endif
}

static
void
clearWithDoubleClickAbacus(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
speedUpAbacus(AbacusWidget w
#ifndef WINVER
, XEvent *event, char **args, int nArgs
#endif
)
{
      speedBeed(w);
}

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

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

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

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

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

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

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

#ifndef WINVER
static
#endif
void
toggleQuartersAbacus(AbacusWidget w
#ifndef WINVER
, XEvent *event, char **args, int nArgs
#endif
)
{
      togglePieceRail(w, 0, QUARTERS);
}

#ifndef WINVER
static
#endif
void
toggleQuarterPercentsAbacus(AbacusWidget w
#ifndef WINVER
, XEvent *event, char **args, int nArgs
#endif
)
{
      togglePiecePercentRail(w, 0, QUARTER_PERCENTS);
}

#ifndef WINVER
static
#endif
void
toggleTwelfthsAbacus(AbacusWidget w
#ifndef WINVER
, XEvent *event, char **args, int nArgs
#endif
)
{
      togglePieceRail(w, 2, TWELFTHS / 2);
}

#ifndef WINVER
static
#endif
void
toggleSubdecksAbacus(AbacusWidget w
#ifndef WINVER
, XEvent *event, char **args, int nArgs
#endif
)
{
      w->abacus.subbase = TWELFTHS;
      toggleSubdeckRail(w, DEFAULT_SUBDECKS, DEFAULT_SUBBEADS);
}

#ifndef WINVER
static
#endif
void
toggleEighthsAbacus(AbacusWidget w
#ifndef WINVER
, XEvent *event, char **args, int nArgs
#endif
)
{
      w->abacus.subbase = EIGHTHS;
      toggleSubdeckRail(w, DEFAULT_SUBDECKS, DEFAULT_SUBBEADS);
}

#ifndef WINVER
static
#endif
void
toggleAnomalyAbacus(AbacusWidget w
#ifndef WINVER
, XEvent *event, char **args, int nArgs
#endif
)
{
      toggleAnomalyRails(w, 2, 0);
}

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

#ifndef WINVER
static
void
toggleDemoAbacus(AbacusWidget w
, XEvent *event, char **args, int nArgs
)
{
      if (w->abacus.teach)
            setAbacus(w, ACTION_TEACH);
      setAbacus(w, ACTION_DEMO);
}

static
void
showNextAbacus(AbacusWidget w
, XEvent *event, char **args, int nArgs
)
{
      if (w->abacus.demo) {
            setAbacus(w, ACTION_NEXT);
      }
}

static
void
showRepeatAbacus(AbacusWidget w
, XEvent *event, char **args, int nArgs
)
{
      if (w->abacus.demo) {
            setAbacus(w, ACTION_REPEAT);
      }
}

static
void
showMoreAbacus(AbacusWidget w
, XEvent *event, char **args, int nArgs
)
{
      if (w->abacus.demo) {
            setAbacus(w, ACTION_MORE);
      }
}

static
void
toggleTeachAbacus(AbacusWidget w
, XEvent *event, char **args, int nArgs
)
{
      if (w->abacus.demo)
            setAbacus(w, ACTION_DEMO);
      setAbacus(w, ACTION_TEACH);
}
#endif

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

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

#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 */
void
drawDiskXI(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);
}

void
drawDiskPointsXI(Display *display, Window window, GC gc,
            int ctrX, int ctrY, int x, int y, int p)
{
      VOID XfillRectangle(display, window, gc,
            ctrX - x, ctrY - y, 2 * x + p + 1, 1);
      VOID XfillRectangle(display, window, gc,
            ctrX - x, ctrY + y + p, 2 * x + p + 1, 1);
      VOID XfillRectangle(display, window, gc,
            ctrX - y, ctrY - x, 2 * y + p + 1, 1);
      VOID XfillRectangle(display, window, gc,
            ctrX - y, ctrY + x + p, 2 * y + p + 1, 1);
#if 0
      VOID XDrawLine(display, window, gc,
            ctrX - x, ctrY - y, ctrX + x + p, ctrY - y);
      VOID XDrawLine(display, window, gc,
            ctrX - x, ctrY + y + p, ctrX + x + p, ctrY + y + p);
      VOID XDrawLine(display, window, gc,
            ctrX - y, ctrY - x, ctrX + y + p, ctrY - x);
      VOID XDrawLine(display, window, gc,
            ctrX - y, ctrY + x + p, ctrX + y + p, ctrY + x + p);
#endif
}

#endif

Generated by  Doxygen 1.6.0   Back to index