/*- # X-BASED ABACUS # # Abacus.c # ### # # Copyright (c) 1994 - 2007 David Albert Bagley, bagleyd@tux.org # # All Rights Reserved # # Permission to use, copy, modify, and distribute this software and # its documentation for any purpose and without fee is hereby granted, # provided that the above copyright notice appear in all copies and # that both that copyright notice and this permission notice appear in # supporting documentation, and that the name of the author not be # used in advertising or publicity pertaining to distribution of the # software without specific, written prior permission. # # This program is distributed in the hope that it will be "useful", # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # */ /* Methods file for Abacus */ #include "file.h" #include "rngs.h" #include "sound.h" #include "AbacusP.h" static Boolean DeleteSpecialRail(AbacusWidget w, Boolean sign, Boolean piece, Boolean piecePercent); #if 1 #ifndef SCRIPTFILE #define SCRIPTFILE "Abacus.les" #endif #endif #define DX 1 /* DY = 0 Experimental... want to get rid of space between beads eventually */ #define DY 1 #ifdef WINVER #ifndef INIFILE #define INIFILE "wabacus.ini" #endif #define SECTION "setup" #else static Boolean SetValuesAbacus(Widget current, Widget request, Widget renew); static void QuitAbacus(AbacusWidget w, XEvent *event, char **args, int nArgs); static void DestroyAbacus(Widget old); static void ResizeAbacus(AbacusWidget w); static void InitializeAbacus(Widget request, Widget renew); static void ExposeAbacus(Widget renew, XEvent *event, Region region); static void HideAbacus(AbacusWidget w, XEvent *event, char **args, int nArgs); static void SelectAbacus(AbacusWidget w, XEvent *event, char **args, int nArgs); static void ReleaseAbacus(AbacusWidget w, XEvent *event, char **args, int nArgs); static void ClearAbacus(AbacusWidget w, XEvent *event, char **args, int nArgs); static void ClearAbacusMaybe(AbacusWidget w, XEvent *event, char **args, int nArgs); static void ClearAbacus2(AbacusWidget w, XEvent *event, char **args, int nArgs); static void IncrementAbacus(AbacusWidget w, XEvent *event, char **args, int nArgs); static void DecrementAbacus(AbacusWidget w, XEvent *event, char **args, int nArgs); static void SpeedAbacus(AbacusWidget w, XEvent *event, char **args, int nArgs); static void SlowAbacus(AbacusWidget w, XEvent *event, char **args, int nArgs); static void SoundAbacus(AbacusWidget w, XEvent *event, char **args, int nArgs); static void FormatAbacus(AbacusWidget w, XEvent *event, char **args, int nArgs); static void MuseumAbacus(AbacusWidget w, XEvent *event, char **args, int nArgs); static void RomanNumeralsAbacus(AbacusWidget w, XEvent *event, char **args, int nArgs); static void GroupAbacus(AbacusWidget w, XEvent *event, char **args, int nArgs); static void SignAbacus(AbacusWidget w, XEvent *event, char **args, int nArgs); static void QuarterAbacus(AbacusWidget w, XEvent *event, char **args, int nArgs); static void QuarterPercentAbacus(AbacusWidget w, XEvent *event, char **args, int nArgs); static void TwelfthAbacus(AbacusWidget w, XEvent *event, char **args, int nArgs); static void SubdeckAbacus(AbacusWidget w, XEvent *event, char **args, int nArgs); static void EighthAbacus(AbacusWidget w, XEvent *event, char **args, int nArgs); static void AnomalyAbacus(AbacusWidget w, XEvent *event, char **args, int nArgs); static void WatchAbacus(AbacusWidget w, XEvent *event, char **args, int nArgs); static void DemoAbacus(AbacusWidget w, XEvent *event, char **args, int nArgs); static void NextAbacus(AbacusWidget w, XEvent *event, char **args, int nArgs); static void RepeatAbacus(AbacusWidget w, XEvent *event, char **args, int nArgs); static void MoreAbacus(AbacusWidget w, XEvent *event, char **args, int nArgs); static void EnterAbacus(AbacusWidget w, XEvent *event, char **args, int nArgs); static void LeaveAbacus(AbacusWidget w, XEvent *event, char **args, int nArgs); static char defaultTranslationsAbacus[] = "q: Quit()\n\ CtrlC: Quit()\n\ osfCancel: Hide()\n\ Escape: Hide()\n\ osfEscape: Hide()\n\ Ctrl[: Hide()\n\ 0x1B: Hide()\n\ 0x2E: Speed()\n\ 0x3E: Speed()\n\ 0x3C: Slow()\n\ 0x2C: Slow()\n\ Shift2: Sound()\n\ : Select()\n\ : Release()\n\ c: Clear()\n\ : ClearMaybe()\n\ (2+): Clear2()\n\ i: Increment()\n\ d: Decrement()\n\ f: Format()\n\ e: Museum()\n\ m: RomanNumerals()\n\ g: Group()\n\ s: Sign()\n\ u: Quarter()\n\ p: QuarterPercent()\n\ t: Twelfth()\n\ b: Subdeck()\n\ h: Eighth()\n\ l: Anomaly()\n\ w: Watch()\n\ o: Demo()\n\ n: Next()\n\ r: Repeat()\n\ 0x20: More()\n\ KP_Space: More()\n\ Return: More()\n\ : Enter()\n\ : Leave()"; static XtActionsRec actionsListAbacus[] = { {(char *) "Quit", (XtActionProc) QuitAbacus}, {(char *) "Hide", (XtActionProc) HideAbacus}, {(char *) "Select", (XtActionProc) SelectAbacus}, {(char *) "Release", (XtActionProc) ReleaseAbacus}, {(char *) "Clear", (XtActionProc) ClearAbacus}, {(char *) "ClearMaybe", (XtActionProc) ClearAbacusMaybe}, {(char *) "Clear2", (XtActionProc) ClearAbacus2}, {(char *) "Increment", (XtActionProc) IncrementAbacus}, {(char *) "Decrement", (XtActionProc) DecrementAbacus}, {(char *) "Speed", (XtActionProc) SpeedAbacus}, {(char *) "Slow", (XtActionProc) SlowAbacus}, {(char *) "Sound", (XtActionProc) SoundAbacus}, {(char *) "Format", (XtActionProc) FormatAbacus}, {(char *) "Museum", (XtActionProc) MuseumAbacus}, {(char *) "RomanNumerals", (XtActionProc) RomanNumeralsAbacus}, {(char *) "Group", (XtActionProc) GroupAbacus}, {(char *) "Sign", (XtActionProc) SignAbacus}, {(char *) "Quarter", (XtActionProc) QuarterAbacus}, {(char *) "QuarterPercent", (XtActionProc) QuarterPercentAbacus}, {(char *) "Twelfth", (XtActionProc) TwelfthAbacus}, {(char *) "Subdeck", (XtActionProc) SubdeckAbacus}, {(char *) "Eighth", (XtActionProc) EighthAbacus}, {(char *) "Anomaly", (XtActionProc) AnomalyAbacus}, {(char *) "Watch", (XtActionProc) WatchAbacus}, {(char *) "Demo", (XtActionProc) DemoAbacus}, {(char *) "Next", (XtActionProc) NextAbacus}, {(char *) "Repeat", (XtActionProc) RepeatAbacus}, {(char *) "More", (XtActionProc) MoreAbacus}, {(char *) "Enter", (XtActionProc) EnterAbacus}, {(char *) "Leave", (XtActionProc) LeaveAbacus} }; static XtResource resourcesAbacus[] = { {XtNwidth, XtCWidth, XtRDimension, sizeof (Dimension), XtOffset(AbacusWidget, core.width), XtRString, (caddr_t) "234"}, {XtNheight, XtCHeight, XtRDimension, sizeof (Dimension), XtOffset(AbacusWidget, core.height), XtRString, (caddr_t) "123"}, {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) XtDefaultBackground}, {XtNframeColor, XtCColor, XtRPixel, sizeof (Pixel), XtOffset(AbacusWidget, abacus.frameColor), XtRString, (caddr_t) "wheat4" /*XtDefaultForeground*/}, {XtNrailColor0, XtCForeground, XtRPixel, sizeof (Pixel), XtOffset(AbacusWidget, abacus.railColor[0]), XtRString, (caddr_t) "gold" /*XtDefaultForeground*/}, {XtNrailColor1, XtCForeground, XtRPixel, sizeof (Pixel), XtOffset(AbacusWidget, abacus.railColor[1]), XtRString, (caddr_t) "LightSteelBlue1" /*XtDefaultForeground*/}, {XtNbeadColor0, XtCForeground, XtRPixel, sizeof (Pixel), XtOffset(AbacusWidget, abacus.beadColor[0]), XtRString, (caddr_t) "DarkRed" /*XtDefaultForeground*/}, {XtNbeadColor1, XtCForeground, XtRPixel, sizeof (Pixel), XtOffset(AbacusWidget, abacus.beadColor[1]), XtRString, (caddr_t) "wheat4" /*XtDefaultForeground*/}, {XtNbeadBorder, XtCForeground, XtRPixel, sizeof (Pixel), XtOffset(AbacusWidget, abacus.borderColor), XtRString, (caddr_t) "gray25" /*XtDefaultForeground*/}, {XtNdelay, XtCDelay, XtRInt, sizeof (int), XtOffset(AbacusWidget, abacus.delay), XtRString, (caddr_t) "50"}, {XtNsound, XtCSound, XtRBoolean, sizeof (Boolean), XtOffset(AbacusWidget, abacus.sound), XtRString, (caddr_t) "FALSE"}, {XtNbumpSound, XtCBumpSound, XtRString, sizeof (String), XtOffset(AbacusWidget, abacus.bumpSound), XtRString, (caddr_t) BUMPSOUND}, {XtNmoveSound, XtCMoveSound, XtRString, sizeof (String), XtOffset(AbacusWidget, abacus.moveSound), XtRString, (caddr_t) MOVESOUND}, {XtNscript, XtCScript, XtRBoolean, sizeof (Boolean), XtOffset(AbacusWidget, abacus.script), XtRString, (caddr_t) "FALSE"}, {XtNdemo, XtCDemo, XtRBoolean, sizeof (Boolean), XtOffset(AbacusWidget, abacus.demo), XtRString, (caddr_t) "FALSE"}, {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}, {XtNlee, XtCLee, XtRBoolean, sizeof (Boolean), XtOffset(AbacusWidget, abacus.lee), XtRString, (caddr_t) "TRUE"}, {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 */ {XtNgroupSize, XtCGroupSize, XtRInt, sizeof (int), XtOffset(AbacusWidget, abacus.groupSize), XtRString, (caddr_t) "3"}, {XtNrails, XtCRails, XtRInt, sizeof (int), XtOffset(AbacusWidget, abacus.rails), XtRString, (caddr_t) "13"}, {XtNbase, XtCBase, XtRInt, sizeof (int), XtOffset(AbacusWidget, abacus.base), XtRString, (caddr_t) "10"}, {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"}, {XtNromanNumerals, XtCRomanNumerals, XtRBoolean, sizeof (Boolean), XtOffset(AbacusWidget, abacus.romanNumerals), XtRString, (caddr_t) "FALSE"}, {XtNgroup, XtCGroup, XtRBoolean, sizeof (Boolean), XtOffset(AbacusWidget, abacus.group), XtRString, (caddr_t) "FALSE"}, {XtNmode, XtCMode, XtRInt, sizeof (int), XtOffset(AbacusWidget, abacus.mode), XtRString, (caddr_t) "6"}, /* OTHER */ {XtNformat, XtCFormat, XtRString, sizeof (String), XtOffset(AbacusWidget, abacus.format), XtRString, (caddr_t) "Other"}, {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 */ {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"}, {XtNaux, XtCAux, XtRBoolean, sizeof (Boolean), XtOffset(AbacusWidget, abacus.aux), XtRString, (caddr_t) "FALSE"}, {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"}, {XtNselectCallback, XtCCallback, XtRCallback, sizeof (caddr_t), XtOffset(AbacusWidget, abacus.select), XtRCallback, (caddr_t) NULL} }; AbacusClassRec abacusClassRec = { { (WidgetClass) & widgetClassRec, /* superclass */ (char *) "Abacus", /* class name */ sizeof (AbacusRec), /* widget size */ NULL, /* class initialize */ NULL, /* class part initialize */ FALSE, /* class inited */ (XtInitProc) InitializeAbacus, /* initialize */ NULL, /* initialize hook */ XtInheritRealize, /* realize */ actionsListAbacus, /* actions */ XtNumber(actionsListAbacus), /* num actions */ resourcesAbacus, /* resources */ XtNumber(resourcesAbacus), /* num resources */ NULLQUARK, /* xrm class */ TRUE, /* compress motion */ TRUE, /* compress exposure */ TRUE, /* compress enterleave */ TRUE, /* visible interest */ (XtWidgetProc) DestroyAbacus, /* destroy */ (XtWidgetProc) ResizeAbacus, /* resize */ (XtExposeProc) ExposeAbacus, /* expose */ (XtSetValuesFunc) SetValuesAbacus, /* set values */ NULL, /* set values hook */ XtInheritSetValuesAlmost, /* set values almost */ NULL, /* get values hook */ NULL, /* accept focus */ XtVersion, /* version */ NULL, /* callback private */ defaultTranslationsAbacus, /* tm table */ NULL, /* query geometry */ NULL, /* display accelerator */ NULL /* extension */ }, { 0 /* ignore */ } }; WidgetClass abacusWidgetClass = (WidgetClass) & abacusClassRec; void setAbacus(AbacusWidget w, int reason) { abacusCallbackStruct cb; cb.reason = reason; XtCallCallbacks((Widget) w, (char *) XtNselectCallback, &cb); } void setAbacusMove(AbacusWidget w, int reason, int aux, int deck, int rail, int number) { abacusCallbackStruct cb; cb.reason = reason; cb.aux = aux; cb.deck = deck; cb.rail = rail; cb.number = number; XtCallCallbacks((Widget) w, (char *) XtNselectCallback, &cb); } static void setAbacusString(AbacusWidget w, int reason, char * string) { abacusCallbackStruct cb; cb.reason = reason; cb.buffer = string; XtCallCallbacks((Widget) w, (char *) XtNselectCallback, &cb); } #endif static void ResizeBead(AbacusWidget w); static void SetSubmodeFromMuseum(AbacusWidget w) { if (strncasecmp("it", w->abacus.museum, COUNTRYSIZE) == 0) { w->abacus.submode = IT; } else if (strncasecmp("uk", w->abacus.museum, COUNTRYSIZE) == 0) { w->abacus.submode = UK; } else if (strncasecmp("fr", w->abacus.museum, COUNTRYSIZE) == 0) { w->abacus.submode = FR; } else { w->abacus.submode = NRAND(MAXMUSEUMS); } } static Boolean submodeSlotsSeparate(int submode) { return (submode == UK); } static void SetModeFromFormat(AbacusWidget w) { if (strncasecmp("chinese", w->abacus.format, MAXLENFORMAT) == 0) { w->abacus.mode = CHINESE; } else if (strncasecmp("japanese", w->abacus.format, MAXLENFORMAT) == 0) { w->abacus.mode = JAPANESE; } else if (strncasecmp("korean", w->abacus.format, MAXLENFORMAT) == 0) { w->abacus.mode = KOREAN; } else if (strncasecmp("roman", w->abacus.format, MAXLENFORMAT) == 0) { w->abacus.mode = ROMAN; } else if (strncasecmp("italian", w->abacus.format, MAXLENFORMAT) == 0) { w->abacus.mode = ROMAN; } else if (strncasecmp("russian", w->abacus.format, MAXLENFORMAT) == 0) { w->abacus.mode = RUSSIAN; } else if (strncasecmp("danish", w->abacus.format, MAXLENFORMAT) == 0) { w->abacus.mode = DANISH; } else if (strncasecmp("cn", w->abacus.format, MAXLENFORMAT) == 0) { w->abacus.mode = CHINESE; } else if (strncasecmp("ja", w->abacus.format, MAXLENFORMAT) == 0) { w->abacus.mode = JAPANESE; } else if (strncasecmp("jp", w->abacus.format, MAXLENFORMAT) == 0) { w->abacus.mode = JAPANESE; } else if (strncasecmp("ko", w->abacus.format, MAXLENFORMAT) == 0) { w->abacus.mode = KOREAN; } else if (strncasecmp("ro", w->abacus.format, MAXLENFORMAT) == 0) { w->abacus.mode = ROMAN; } else if (strncasecmp("it", w->abacus.format, MAXLENFORMAT) == 0) { w->abacus.mode = ROMAN; } else if (strncasecmp("ru", w->abacus.format, MAXLENFORMAT) == 0) { w->abacus.mode = RUSSIAN; } else if (strncasecmp("da", w->abacus.format, MAXLENFORMAT) == 0) { w->abacus.mode = DANISH; } else if (strncasecmp("dk", w->abacus.format, MAXLENFORMAT) == 0) { w->abacus.mode = DANISH; } else { w->abacus.mode = OTHER; } } /* 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 RomanFactor(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 + baseToBottom(w->abacus.base) - 1; } static 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 * w->abacus.subdecks[BOTTOM].spaces && 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) { factor = w->abacus.decks[BOTTOM].piece; localBase *= w->abacus.decks[TOP].piece; } else break; } 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) ? 1 : 0); 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) { factor = w->abacus.decks[BOTTOM].piecePercent; localBase *= w->abacus.decks[TOP].piecePercent; } else break; } 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) * RomanFactor(w, deck); } else { sum += w->abacus.subdecks[deck].position * RomanFactor(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 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 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 && 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 = DEFAULTSHIFTPERCENT; } 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 > MAXBASE) { intCat(&buf1, "Bottom Piece must be less than or equal to ", MAXBASE); DISPLAY_WARNING(buf1); free(buf1); w->abacus.decks[BOTTOM].piece = 0; } else if (w->abacus.decks[BOTTOM].piece != 0 && w->abacus.decks[BOTTOM].piece < MINBASE) { intCat(&buf1, "Bottom Piece must be greater than or equal to ", MINBASE); 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 < MINBASE) { intCat(&buf1, "Top Piece must be greater than or equal to ", MINBASE); stringCat(&buf2, buf1, ", or 0"); free(buf1); DISPLAY_WARNING(buf2); free(buf2); w->abacus.decks[TOP].piece = 0; } if (w->abacus.decks[BOTTOM].piecePercent > MAXBASE) { intCat(&buf1, "Bottom Piece Percent must be less than or equal to ", MAXBASE); DISPLAY_WARNING(buf1); free(buf1); w->abacus.decks[BOTTOM].piecePercent = 0; } else if (w->abacus.decks[BOTTOM].piecePercent != 0 && w->abacus.decks[BOTTOM].piecePercent < MINBASE) { intCat(&buf1, "Bottom Piece Percent must be greater than or equal to ", MINBASE); 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 < MINBASE) { intCat(&buf1, "Top Piece Percent must be greater than or equal to ", MINBASE); stringCat(&buf2, buf1, ", or 0"); free(buf1); DISPLAY_WARNING(buf2); free(buf2); w->abacus.decks[TOP].piecePercent = 0; } if (w->abacus.base > MAXBASE) { intCat(&buf1, "Base must be less than or equal to ", MAXBASE); DISPLAY_WARNING(buf1); free(buf1); w->abacus.base = DEFAULTBASE; setAbacus(w, ACTION_BASE_DEFAULT); } else if (w->abacus.base < MINBASE) { intCat(&buf1, "Base must be greater than or equal to ", MINBASE); DISPLAY_WARNING(buf1); free(buf1); w->abacus.base = DEFAULTBASE; setAbacus(w, ACTION_BASE_DEFAULT); } else if (w->abacus.base != DEFAULTBASE && w->abacus.demo) { intCat(&buf1, "Base must be equal to ", DEFAULTBASE); stringCat(&buf2, buf1, ", for demo"); free(buf1); DISPLAY_WARNING(buf2); free(buf2); w->abacus.base = DEFAULTBASE; setAbacus(w, 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 = DEFAULTSHIFTANOMALY; } 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 = DEFAULTSHIFTANOMALY; } if (w->abacus.displayBase > MAXBASE) { intCat(&buf1, "Display Base must be less than or equal to ", MAXBASE); DISPLAY_WARNING(buf1); free(buf1); w->abacus.displayBase = DEFAULTBASE; } else if (w->abacus.displayBase < MINBASE) { intCat(&buf1, "Display Base must be greater than or equal to ", MINBASE); DISPLAY_WARNING(buf1); free(buf1); w->abacus.displayBase = DEFAULTBASE; } else if (w->abacus.displayBase != DEFAULTBASE && w->abacus.demo) { intCat(&buf1, "Display Base must be equal to ", DEFAULTBASE); stringCat(&buf2, buf1, ", for demo"); free(buf1); DISPLAY_WARNING(buf2); free(buf2); w->abacus.displayBase = DEFAULTBASE; } if (w->abacus.mode == OTHER && w->abacus.demo && !w->abacus.aux) { /*DISPLAY_WARNING("Format must not be \"Other\", for demo");*/ w->abacus.mode = CHINESE; } /* If a particular mode, ignore improper settings */ if (w->abacus.mode == DANISH) { w->abacus.colorScheme = COLORHALF; 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 = DEFAULTBOTTOMORIENT; w->abacus.decks[TOP].orientation = DEFAULTTOPORIENT; w->abacus.decks[BOTTOM].spaces = 4 * DEFAULTBOTTOMSPACES; 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 = COLORMIDDLE | COLOR1STOFGROUP; w->abacus.decks[BOTTOM].factor = 1; w->abacus.decks[TOP].factor = w->abacus.base; w->abacus.decks[BOTTOM].number = w->abacus.base; w->abacus.decks[TOP].number = 0; w->abacus.decks[BOTTOM].orientation = DEFAULTTOPORIENT; w->abacus.decks[TOP].orientation = DEFAULTTOPORIENT; w->abacus.decks[BOTTOM].spaces = DEFAULTBOTTOMSPACES; 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 = baseToBottom(w->abacus.base); w->abacus.decks[BOTTOM].number = w->abacus.decks[TOP].factor - 1; w->abacus.decks[TOP].number = w->abacus.base / w->abacus.decks[TOP].factor - 1; w->abacus.decks[BOTTOM].orientation = DEFAULTBOTTOMORIENT; w->abacus.decks[TOP].orientation = DEFAULTTOPORIENT; if (w->abacus.subdeck < 0) w->abacus.subdeck = DEFAULTSUBDECKS; w->abacus.vertical = False; if (w->abacus.mode == JAPANESE) { w->abacus.slot = False; w->abacus.diamond = True; w->abacus.decks[BOTTOM].spaces = DEFAULTBOTTOMSPACES - 1; w->abacus.decks[TOP].spaces = DEFAULTTOPSPACES - 1; } else if (w->abacus.mode == ROMAN) { w->abacus.slot = True; w->abacus.diamond = False; w->abacus.decks[BOTTOM].spaces = DEFAULTBOTTOMSPACES + 1; w->abacus.decks[TOP].spaces = DEFAULTTOPSPACES + 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 = baseToBottom(w->abacus.base); w->abacus.decks[BOTTOM].number = w->abacus.decks[TOP].factor; w->abacus.decks[TOP].number = w->abacus.base / w->abacus.decks[TOP].factor - 1; w->abacus.decks[BOTTOM].orientation = DEFAULTBOTTOMORIENT; w->abacus.decks[TOP].orientation = DEFAULTTOPORIENT; w->abacus.decks[BOTTOM].spaces = DEFAULTBOTTOMSPACES - 1; w->abacus.decks[TOP].spaces = DEFAULTTOPSPACES - 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 = baseToBottom(w->abacus.base); w->abacus.decks[BOTTOM].number = w->abacus.decks[TOP].factor; w->abacus.decks[TOP].number = w->abacus.base / w->abacus.decks[TOP].factor; w->abacus.decks[BOTTOM].orientation = DEFAULTBOTTOMORIENT; w->abacus.decks[TOP].orientation = DEFAULTTOPORIENT; w->abacus.decks[BOTTOM].spaces = DEFAULTBOTTOMSPACES; w->abacus.decks[TOP].spaces = DEFAULTTOPSPACES; 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) { /* Trying to keep these at a minimum... */ if (w->abacus.rails < MINDEMORAILS) { intCat(&buf1, "Number of rails must be at least ", MINDEMORAILS); stringCat(&buf2, buf1, ", for demo"); free(buf1); DISPLAY_WARNING(buf2); free(buf2); w->abacus.rails = MINDEMORAILS; } if (w->abacus.rails - w->abacus.decimalPosition < MINDEMORAILS) { if (w->abacus.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 < MINRAILS) { intCat(&buf1, "Number of rails must be at least ", MINRAILS); DISPLAY_WARNING(buf1); free(buf1); w->abacus.rails = MINRAILS; } if (w->abacus.decks[TOP].factor < 1 || w->abacus.decks[TOP].factor > w->abacus.base) { intCat(&buf1, "Factor of Top Beads out of bounds, use 1..", w->abacus.base); DISPLAY_WARNING(buf1); free(buf1); w->abacus.decks[TOP].factor = 5; } if (w->abacus.decks[BOTTOM].factor < 1 || w->abacus.decks[BOTTOM].factor > w->abacus.base) { intCat(&buf1, "Factor of Bottom Beads out of bounds, use 1..", w->abacus.base); DISPLAY_WARNING(buf1); free(buf1); w->abacus.decks[BOTTOM].factor = 1; } } if (w->abacus.decks[TOP].number < 0 || w->abacus.decks[TOP].number > w->abacus.base) { intCat(&buf1, "Number of Top Beads out of bounds, use 1..", w->abacus.base); DISPLAY_WARNING(buf1); free(buf1); w->abacus.decks[TOP].number = 2; } if (w->abacus.decks[BOTTOM].number < 0 || w->abacus.decks[BOTTOM].number > w->abacus.base) { intCat(&buf1, "Number of Bottom Beads out of bounds, use 1..", w->abacus.base); DISPLAY_WARNING(buf1); free(buf1); w->abacus.decks[BOTTOM].number = 5; } if (w->abacus.decks[TOP].spaces < 0) { DISPLAY_WARNING("Number of Top Spaces must be at least 0"); w->abacus.decks[TOP].spaces = 2; } if (w->abacus.decks[BOTTOM].spaces < 0) { DISPLAY_WARNING("Number of Bottom Spaces must be at least 0"); w->abacus.decks[BOTTOM].spaces = 2; } if (w->abacus.decks[TOP].spaces == 0 && w->abacus.decks[BOTTOM].spaces == 0) { DISPLAY_WARNING("Number of Top 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 = DEFAULTGROUPSIZE; } 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 == PLACESETTING) { /* moving decimal point */ if (w->abacus.number + w->abacus.decimalPosition >= w->abacus.rails || w->abacus.number + w->abacus.decimalPosition < 0) { intCat(&buf1, "Corrupted number for input value ", w->abacus.number); stringCat(&buf2, buf1, " out of bounds, use "); free(buf1); intCat(&buf1, buf2, -w->abacus.decimalPosition); free(buf2); stringCat(&buf2, buf1, ".."); free(buf1); intCat(&buf1, buf2, w->abacus.rails - w->abacus.decimalPosition); free(buf2); DISPLAY_WARNING(buf1); free(buf1); return False; } return True; } deck_number = w->abacus.decks[w->abacus.deck].number; deck_position = w->abacus.decks[w->abacus.deck].position[w->abacus.rail + w->abacus.decimalPosition]; if (w->abacus.decks[w->abacus.deck].orientation && (w->abacus.number < -deck_number + deck_position || w->abacus.number > deck_position)) { intCat(&buf1, "Corrupted number for input value ", w->abacus.number); stringCat(&buf2, buf1, " out of bounds, use "); free(buf1); intCat(&buf1, buf2, -deck_number + deck_position); free(buf2); stringCat(&buf2, buf1, ".."); free(buf1); intCat(&buf1, buf2, deck_position); free(buf2); DISPLAY_WARNING(buf1); free(buf1); return False; } if (!w->abacus.decks[w->abacus.deck].orientation && (w->abacus.number < -deck_position || w->abacus.number > deck_number - deck_position)) { intCat(&buf1, "Corrupted number for input value ", w->abacus.number); stringCat(&buf2, buf1, " out of bounds, use "); free(buf1); intCat(&buf1, buf2, -deck_position); free(buf2); stringCat(&buf2, buf1, ".."); free(buf1); intCat(&buf1, buf2, deck_number - deck_position); free(buf2); DISPLAY_WARNING(buf1); free(buf1); return False; } return True; } static void ResetSubdecks(AbacusWidget w) { int deck, ndecks; if (w->abacus.subdecks) free(w->abacus.subdecks); ndecks = (w->abacus.subdeck <= 0) ? DEFAULTSUBDECKS : 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 = SUBDECKSPACE; 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) ? 1 : 0); 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))))) { 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] = '.'; 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) ? 2 : 1) * 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); 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); /* shift to proper piece percent place */ shiftDecimal(finalBuf, stringBuf, w->abacus.shiftPercent, 0); /* get piece + piecePercent */ addStrings(stringBuf, finalBuf, midBuf, w->abacus.base); /* shift out piece part */ /*shiftDecimal(midBuf, buffer, -1, 0); */ 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); /* get pieces + piece percent + normal */ addStrings(finalBuf, stringBuf, midBuf, w->abacus.base); } 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 * pieceFractions, char2Int(w->abacus.digits[n + half + 1]), precision); /* get piece + pieceFraction */ addStrings(stringBuf, finalBuf, midBuf, w->abacus.base); /* No fixing because no digits after Roman fraction */ /* get pieces + piece percent + normal */ addStrings(finalBuf, stringBuf, buffer, w->abacus.base); } 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); } (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 SCRIPTFILE (void) fprintf(w->abacus.fp, "%d %d %d %d 4\n", PRIMARY, deck, rail - w->abacus.decimalPosition, number); (void) fprintf(w->abacus.fp, "Lesson\n\n\nPress Space-bar\n"); #else setAbacusMove(w, ACTION_SCRIPT, PRIMARY /* FIXME */, 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); } else { convertString(buff, buffer, w->abacus.base, w->abacus.displayBase, w->abacus.decimalPosition, 0, w->abacus.shiftAnomaly, False, 0, w->abacus.shiftAnomalySq, False); } 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)))) { DISPLAY_ERROR("Not enough memory (SetCounter5), exiting."); } (void) string2Roman(romanString, buffer, w->abacus.displayBase, pieces, valuePiece(w), valueSubdeck(w), w->abacus.subbase); (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); 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, wd, 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; #ifdef WINVER wd = 2; ht = w->abacus.midHeight; #else wd = 0; ht = w->abacus.midHeight - 1; #endif 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, x + 2 + wd, y + ht); VDRAWLINE(w, dr, gc, x + 2, y, x - 2 - wd, 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; } 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; 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); 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; } 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; } 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 % 2 == 1) ? 1 : 0; hoffset = (w->abacus.railWidth % 2 == 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; Boolean anomalyActive; 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) { /* 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 - ((!w->abacus.vertical && w->abacus.decks[TOP].number == 0) ? 1 : 0), x - 1, w->abacus.midHeight + ((w->abacus.decks[TOP].number == 0) ? 1 : 0)); } if (w->abacus.slot) { DrawRomanI(w, w->abacus.rails - w->abacus.decimalPosition, show); if (w->abacus.rails - w->abacus.decimalPosition - 1 > 0) DrawRomanX(w, w->abacus.rails - w->abacus.decimalPosition - 1, show); if (w->abacus.rails - w->abacus.decimalPosition - 2 > 0) DrawRomanC(w, w->abacus.rails - w->abacus.decimalPosition - 2, show); if (w->abacus.rails - w->abacus.decimalPosition - 3 > 0) DrawRomanM(w, w->abacus.rails - w->abacus.decimalPosition - 3, show); if (w->abacus.rails - w->abacus.decimalPosition - 4 > 0) DrawRomanx(w, w->abacus.rails - w->abacus.decimalPosition - 4, show); if (w->abacus.rails - w->abacus.decimalPosition - 5 > 0) DrawRomanc(w, w->abacus.rails - w->abacus.decimalPosition - 5, show); if (w->abacus.rails - w->abacus.decimalPosition - 6 > 0) 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); 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) ? 1 : 0) + 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) ? 1 : 0) + w->abacus.shiftPercent, show); } anomalyActive = CheckAnomaly(w); 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 -= DY; 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 * DY, 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 + 3, 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 - 1 + 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 & COLORMIDDLE) > 0) { if ((((bead == pieces / 2) && ((pieces & 1) == 0)) || bead == pieces / 2 + 1) && pieces > 2) special++; } else if ((w->abacus.colorScheme & COLORHALF) > 0) { if ((pieces & 1) == 1) { 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 & COLORMIDDLE) > 0) { if ((((bead == piecePercents / 2) && ((piecePercents & 1) == 0)) || bead == piecePercents / 2 + 1) && piecePercents > 2) special++; } else if ((w->abacus.colorScheme & COLORHALF) > 0) { if ((piecePercents & 1) == 1) { 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 & COLORMIDDLE) > 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 & COLOR1STOFGROUP) > 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 & COLORHALF) > 0) { if ((w->abacus.decks[deck].number & 1) == 1) { 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 - 1; dx += pressed * DX; dy += pressed * DY; if (!moving && pressed == 0) { VFILLRECTANGLE(w, dr, w->abacus.inverseGC, dx, dy + w->abacus.beadSize.y + 1, w->abacus.beadSize.x, 1); /* 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 - pressed, dy - pressed, w->abacus.beadSize.x, 1); VFILLRECTANGLE(w, dr, w->abacus.inverseGC, dx - pressed, dy - pressed, 1, w->abacus.beadSize.y); 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 - pressed, dy - pressed, w->abacus.railWidth, 1); } } if (w->abacus.vertical) { sx = w->abacus.pos.y - 1; sy = w->abacus.beadSize.x + 1; yOffset = dx; dx = dy + 1 - DY; dy = yOffset; } else { sx = w->abacus.beadSize.x + 1; sy = w->abacus.pos.y - 1; dy = dy + 1 - DY; } #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, pressed, w->abacus.beadSize.y + 3); } } 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 = 1; shadeDot = 0; } if (special == 1) { shadeFill++; shadeLine++; shadeDot++; } if (color == 1) { shadeFill += 4; shadeLine += 4; shadeDot += 4; } } VFILLRECTANGLE(w, *dr, w->abacus.inverseGC, 0, 0, w->abacus.beadSize.x + 1, w->abacus.pos.y - 1); 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; 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; 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); 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); 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); 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, 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; #if WINVER int beadTweak = (beadDiameter % 2) ? 1 : 0; #else int beadTweak = 0; #endif 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); 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 + beadTweak, beadDiameter / 2, w->abacus.beadSize.x, 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); VFILLRECTANGLE(w, *dr, w->abacus.beadShadeGC[shadeFill], w->abacus.beadSize.x / 2 - (w->abacus.beadSize.x - beadDiameter) / 2, 0, w->abacus.beadSize.x - beadDiameter, w->abacus.beadSize.y); VFILLRECTANGLE(w, *dr, w->abacus.beadShadeGC[shadeFill], w->abacus.beadSize.x / 2 - (w->abacus.beadSize.x - beadDiameter) / 2 - beadDiameter / 2 + beadTweak, beadDiameter / 2, w->abacus.beadSize.x, beadOffset); #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 < 2; 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 = 0; inc < w->abacus.pos.y + gapJ; inc += gapJ) { if (inc > w->abacus.pos.y) { gapJ = w->abacus.pos.y + gapJ - inc; inc = w->abacus.pos.y; } for (aBead = numBeads - 1; aBead >= 0; aBead--) { beadOff = NEWPOS(dir, aBead); posOff = NEWPOS(dir, (aBead + space)); /* actual bead, bead position */ DrawBead(w, deck, rail, bead + beadOff, j, True, True, FALSE, 0, NEWPOS(dir, inc) + posOff * w->abacus.pos.y); /* Erase old slivers */ if ((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 + 1, 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) ? 1 : 0))) { 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) ? 1 : 0)))) 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) ? 1 : 0))) { 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) ? 1 : 0)))) 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 > MAXBASE) { DISPLAY_WARNING("corruption (MoveUp)"); 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 > MAXBASE) { DISPLAY_WARNING("corruption (MoveDown)"); 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) ? 1 : 0))) { 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, RomanFactor(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, 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) ? 1 : 0))) { 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, RomanFactor(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 x, int y, int *deck, int *rail, int *j) { int pieces, piecePercents; if (w->abacus.vertical) { int temp = x; x = y; y = w->abacus.frameSize.y - 1 - temp; } x -= w->abacus.offset.x; y -= w->abacus.offset.y; if (y > w->abacus.decks[TOP].height) { y = y - w->abacus.decks[TOP].height; *deck = BOTTOM; } else { *deck = TOP; } if (w->abacus.decks[*deck].number == 0) { return False; } *rail = w->abacus.rails - 1 - (x - w->abacus.delta.x / 2) / w->abacus.pos.x; *j = (y - w->abacus.delta.y / 2) / w->abacus.pos.y + 1; if (*rail < 0) *rail = 0; else if (*rail >= w->abacus.rails) *rail = w->abacus.rails - 1; if (*j < 1) *j = 1; else if (*j > w->abacus.decks[*deck].room) *j = w->abacus.decks[*deck].room; if (*rail == w->abacus.rails - 1 && w->abacus.sign) { if (*deck == TOP) return False; return ((*j == 1 && w->abacus.decks[*deck].position[*rail] == 1) || (*j == w->abacus.decks[*deck].room && w->abacus.decks[*deck].position[*rail] == 0)); } if (w->abacus.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) ? 1 : 0))) { 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)) { if (deck == TOP) return; } if (w->abacus.decks[BOTTOM].piece != 0 && (rail == w->abacus.decimalPosition - 1)) { if (deck == TOP && (w->abacus.decks[TOP].piece == 0 || w->abacus.decks[TOP].number == 0)) return; } if (w->abacus.decks[BOTTOM].piecePercent != 0 && (rail == w->abacus.decimalPosition - w->abacus.shiftPercent - 1 - ((w->abacus.decks[BOTTOM].piece != 0) ? 1 : 0))) { if (deck == TOP && (w->abacus.decks[TOP].piecePercent == 0 || w->abacus.decks[TOP].number == 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[MAXDECKS], piecePercents[MAXDECKS]; int pieceRail = w->abacus.decimalPosition - 1; int piecePercentRail = w->abacus.decimalPosition - w->abacus.shiftPercent - 1 - ((w->abacus.decks[BOTTOM].piece != 0) ? 1 : 0); int oldPieceRail = oldDecimalPosition - 1; int oldPiecePercentRail = oldDecimalPosition - w->abacus.shiftPercent - 1 - ((w->abacus.decks[BOTTOM].piece != 0) ? 1 : 0); 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) ? 1 : 0); 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] = pieces[TOP]; else w->abacus.decks[TOP].position[pieceRail] = 0; 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] = piecePercents[TOP]; else w->abacus.decks[TOP].position[piecePercentRail] = 0; w->abacus.digits[w->abacus.rails + CARRY - w->abacus.decimalPosition + w->abacus.shiftPercent + ((w->abacus.decks[BOTTOM].piece != 0) ? 1 : 0)] = 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)) { if (deck == TOP) continue; } if (w->abacus.decks[BOTTOM].piece != 0 && (rail == w->abacus.decimalPosition - 1)) { if (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) ? 1 : 0))) { if (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 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, (1 == w->abacus.decks[deck].position[rail]), False, FALSE, 0, 0); for (j = 2; j < w->abacus.decks[deck].room; j++) DrawBead(w, deck, rail, 0, j, False, False, FALSE, 0, 0); DrawBead(w, deck, rail, 1, w->abacus.decks[deck].room, (0 == w->abacus.decks[deck].position[rail]), False, FALSE, 0, 0); } if (w->abacus.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) ? 1 : 0); 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) ? 1 : 0))) || (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 rail) { int j; if (w->abacus.script) { #ifdef SCRIPTFILE (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\n"); #else setAbacusMove(w, ACTION_SCRIPT, PRIMARY /* FIXME */, 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_QUARTERPERCENT); } 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) ? 1 : 0)) { 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) ? 1 : 0); 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 */ } static void CheckDecimal(AbacusWidget w) { if (w->abacus.decimalPosition >= w->abacus.rails - ((w->abacus.sign) ? 1 : 0) + ((w->abacus.decks[BOTTOM].piece != 0) ? 1 : 0) + ((w->abacus.decks[BOTTOM].piecePercent != 0) ? 1 : 0)) { DrawFrame(w, 0, False, True); w->abacus.decimalPosition = w->abacus.rails - 1 - ((w->abacus.sign) ? 1 : 0) + ((w->abacus.decks[BOTTOM].piece != 0) ? 1 : 0) + ((w->abacus.decks[BOTTOM].piecePercent != 0) ? 1 : 0); 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[MAXDECKS], piecePercentPosition[MAXDECKS]; int pieceNumber[MAXDECKS], piecePercentNumber[MAXDECKS]; 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) ? 0 : 2; } if (piecePercent) { old.decks[BOTTOM].piecePercent = (w->abacus.decks[BOTTOM].piecePercent != 0) ? 0 : 2; } /* 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) ? 1 : 0)) { 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) ? 1 : 0)) { 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) ? 1 : 0))) (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) ? MINDEMORAILS : MINRAILS); if (w->abacus.rails + 2 <= minRails + ((w->abacus.sign) ? 1 : 0) + ((w->abacus.decks[BOTTOM].piece != 0) ? 1 : 0) + ((w->abacus.decks[BOTTOM].piecePercent != 0) ? w->abacus.shiftPercent + 1 : 0)) 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) ? MINDEMORAILS : MINRAILS); if (w->abacus.rails <= minRails + ((w->abacus.sign) ? 1 : 0) + ((w->abacus.decks[BOTTOM].piece != 0) ? 1 : 0) + ((w->abacus.decks[BOTTOM].piecePercent != 0) ? w->abacus.shiftPercent + 1 : 0) + (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) ? MINDEMORAILS : MINRAILS); if (w->abacus.rails <= minRails + ((w->abacus.sign) ? 1 : 0) + ((w->abacus.decks[BOTTOM].piece != 0) ? 1 : 0) + ((w->abacus.decks[BOTTOM].piecePercent != 0) ? w->abacus.shiftPercent + 1 : 0) + (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 SpeedBead(AbacusWidget w) { w->abacus.delay -= 10; if (w->abacus.delay < 0) w->abacus.delay = 0; } static void SlowBead(AbacusWidget w) { w->abacus.delay += 10; } static void SoundBead(AbacusWidget w) { w->abacus.sound = !w->abacus.sound; } static void ReformatRails(AbacusWidget w) { 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) ? 1 : 0) < 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 >= OTHER) { w->abacus.mode = CHINESE; if (w->abacus.demo) other = True; } else w->abacus.mode = (w->abacus.mode + 1) % MAXFORMATS; /*if (w->abacus.demo && w->abacus.mode == OTHER) { 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 > MAXMUSEUMS) w->abacus.submode = NRAND(MAXMUSEUMS); else w->abacus.submode = (w->abacus.submode + 1) % MAXMUSEUMS; EraseFrame(w, 0); DrawFrame(w, 0, True, True); DrawAllBeads(w); } static void RomanNumeralsRails(AbacusWidget w) { w->abacus.romanNumerals = !w->abacus.romanNumerals; SetCounter(w, 0, w->abacus.decimalPosition, 0); } static void GroupRails(AbacusWidget w) { w->abacus.group = !w->abacus.group; SetCounter(w, 0, w->abacus.decimalPosition, 0); } static void SignRails(AbacusWidget w) { Boolean oldSign = w->abacus.sign; w->abacus.sign = !w->abacus.sign; if (w->abacus.sign) { if (!InsertSpecialRail(w, True, False, False)) w->abacus.sign = oldSign; } else { if (!DeleteSpecialRail(w, True, False, False)) w->abacus.sign = oldSign; } if (w->abacus.sign != oldSign) { setAbacus(w, ACTION_SIGN); } } static void PieceRails(AbacusWidget w, int topPieces, int bottomPieces) { int oldPiece[MAXDECKS]; 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) ? 0 : bottomPieces; 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 (!InsertSpecialRail(w, False, True, False)) { w->abacus.decks[BOTTOM].piece = oldPiece[BOTTOM]; w->abacus.decks[TOP].piece = oldPiece[TOP]; } } else { if (!DeleteSpecialRail(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 PiecePercentRails(AbacusWidget w, int topPiecePercents, int bottomPiecePercents) { int oldPiecePercent[MAXDECKS]; 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 (!InsertSpecialRail(w, False, False, True)) { w->abacus.decks[BOTTOM].piecePercent = oldPiecePercent[BOTTOM]; if (topPiecePercents != 0) w->abacus.decks[TOP].piecePercent = oldPiecePercent[TOP]; } } else { if (!DeleteSpecialRail(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]) { if (bottomPiecePercents == QUARTERPERCENTS && topPiecePercents == 0) setAbacus(w, ACTION_QUARTERPERCENT); } } static void SubdeckRail(AbacusWidget w, int ndecks, int nbeads) { int deck; if (w->abacus.subdeck != 0) { /* 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; } else { 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; } } 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 AnomalyRails(AbacusWidget w, int anomalyRail, int anomalySqRail) { if (w->abacus.anomaly != 0) w->abacus.anomaly = 0; else w->abacus.anomaly = anomalyRail; 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); } #if 0 static void VerticalRails(AbacusWidget w) { EraseFrame(w, 0); w->abacus.vertical = !w->abacus.vertical; ResizeAbadcus(w); #ifndef WINVER if (w->core.visible && XtWindow(w) != 0) #endif { ResizeBead(w); DrawAllBufferedBeads(w); DrawFrame(w, 0, True, True); DrawAllBeads(w); } } #endif #define FACTOR 0.7 #ifdef WINVER #define MAXINTENSITY 0xFF static int brighter(const int light) { int i = (int) ((1 - FACTOR) * MAXINTENSITY); int temp = light; if (temp < i) temp = i; return MIN(temp / FACTOR, MAXINTENSITY); } static int darker(const int light) { return (int) (light * FACTOR); } static void SetValuesAbacus(AbacusWidget w) { struct tagColor { int red, green, blue; } color; char szBuf[STRINGSIZE]; 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", 2, INIFILE); w->abacus.decks[BOTTOM].piece = GetPrivateProfileInt(SECTION, "bottomPiece", 0, INIFILE); w->abacus.decks[TOP].piecePercent = GetPrivateProfileInt(SECTION, "topPiecePercent", 2, 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.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", "Other", szBuf, sizeof (szBuf), INIFILE); (void) strcpy(w->abacus.format, szBuf); w->abacus.format[80] = 0; (void) GetPrivateProfileString(SECTION, "museum", "--", szBuf, sizeof (szBuf), INIFILE); (void) strcpy(w->abacus.museum, szBuf); w->abacus.museum[2] = 0; 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.romanNumerals = (BOOL) GetPrivateProfileInt(SECTION, "romanNumerals", FALSE, INIFILE); w->abacus.mono = (BOOL) GetPrivateProfileInt(SECTION, "mono", DEFAULTMONO, INIFILE); w->abacus.reverse = (BOOL) GetPrivateProfileInt(SECTION, "reverseVideo", DEFAULTREVERSE, INIFILE); /* DarkRed */ (void) GetPrivateProfileString(SECTION, "beadColor0", "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, "beadColor1", "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))); /* gray25 */ (void) GetPrivateProfileString(SECTION, "beadBorder", "64 64 64", szBuf, sizeof (szBuf), INIFILE); (void) sscanf(szBuf, "%d %d %d", &(color.red), &(color.green), &(color.blue)); w->abacus.borderGC = RGB(color.red, color.green, color.blue); /* gold */ (void) GetPrivateProfileString(SECTION, "railColor0", "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, "railColor1", "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); /* 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", 0, INIFILE); (void) GetPrivateProfileString(SECTION, "bumpSound", BUMPSOUND, szBuf, sizeof (szBuf), INIFILE); (void) strcpy(w->abacus.bumpSound, szBuf); (void) GetPrivateProfileString(SECTION, "moveSound", MOVESOUND, szBuf, sizeof (szBuf), INIFILE); (void) strcpy(w->abacus.moveSound, szBuf); w->abacus.script = (BOOL) GetPrivateProfileInt(SECTION, "script", 0, INIFILE); w->abacus.demo = (BOOL) GetPrivateProfileInt(SECTION, "demo", 0, INIFILE); /* 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) strcpy(w->abacusDemo.path, szBuf); w->abacusDemo.path[80] = 0; } void DestroyAbacus(AbacusWidget w, HBRUSH brush) { #ifdef SCRIPTFILE if (w->abacus.script) { char buf[512]; (void) fclose(w->abacus.fp); (void) sprintf(buf, "Saved to %s.", SCRIPTFILE); DISPLAY_INFO(buf); } #endif (void) DeleteObject(brush); PostQuitMessage(0); } void setAbacusMove(AbacusWidget w, int reason, int aux, int deck, int rail, int number) { if (aux != PRIMARY) return; w->abacus.deck = deck; w->abacus.rail = rail; w->abacus.number = number; if (CheckMove(w)) { MoveBeadsByValue(w, deck, rail + w->abacus.decimalPosition, w->abacus.number, False); } } #else #define MAXINTENSITY 0xFFFF static Pixel brighter(AbacusWidget w, Pixel pixel) { XColor color; int i = (int) ((1 - FACTOR) * MAXINTENSITY); color.pixel = pixel; 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 / FACTOR, MAXINTENSITY); color.green = (unsigned short) MIN(color.green / FACTOR, MAXINTENSITY); color.blue = (unsigned short) MIN(color.blue / FACTOR, MAXINTENSITY); if (XAllocColor(XtDisplay(w), w->abacus.colormap, &color)) return color.pixel; return pixel; } static Pixel darker(AbacusWidget w, Pixel pixel) { XColor color; color.pixel = pixel; VOID XQueryColor(XtDisplay(w), w->abacus.colormap, &color); color.red = (unsigned short) (color.red * FACTOR); color.green = (unsigned short) (color.green * FACTOR); color.blue = (unsigned short) (color.blue * FACTOR); if (XAllocColor(XtDisplay(w), w->abacus.colormap, &color)) return color.pixel; return pixel; } static void SetAllColors(AbacusWidget w) { XGCValues values; XtGCMask valueMask; valueMask = GCForeground | GCBackground; if (w->abacus.reverse) { values.foreground = w->abacus.foreground; values.background = w->abacus.background; } else { values.foreground = w->abacus.background; values.background = w->abacus.foreground; } if (w->abacus.inverseGC) XtReleaseGC((Widget) w, w->abacus.inverseGC); w->abacus.inverseGC = XtGetGC((Widget) w, valueMask, &values); if (w->abacus.mono) { 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); 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[0]; values.background = w->abacus.borderColor; } if (w->abacus.railGC[0]) XtReleaseGC((Widget) w, w->abacus.railGC[0]); w->abacus.railGC[0] = XtGetGC((Widget) w, valueMask, &values); if (w->abacus.mono) { if (w->abacus.reverse) { values.foreground = w->abacus.background; values.background = w->abacus.foreground; } else { values.foreground = w->abacus.foreground; values.background = w->abacus.background; } } else { values.foreground = w->abacus.railColor[1]; values.background = w->abacus.borderColor; } if (w->abacus.railGC[1]) XtReleaseGC((Widget) w, w->abacus.railGC[1]); w->abacus.railGC[1] = XtGetGC((Widget) w, valueMask, &values); if (w->abacus.mono) { if (w->abacus.reverse) { values.foreground = w->abacus.foreground; values.background = w->abacus.background; } else { values.foreground = w->abacus.background; values.background = w->abacus.foreground; } } else { values.foreground = w->abacus.beadColor[0]; values.background = w->abacus.borderColor; } if (!w->abacus.mono && (BlackPixelOfScreen(XtScreen(w)) == w->abacus.beadColor[0])) { w->abacus.beadColor[0] = brighter(w, values.foreground); values.foreground = w->abacus.beadColor[0]; } if (w->abacus.beadShadeGC[1]) XtReleaseGC((Widget) w, w->abacus.beadShadeGC[1]); w->abacus.beadShadeGC[1] = XtGetGC((Widget) w, valueMask, &values); if (!w->abacus.mono) { values.foreground = brighter(w, w->abacus.beadColor[0]); } if (w->abacus.beadShadeGC[0]) XtReleaseGC((Widget) w, w->abacus.beadShadeGC[0]); w->abacus.beadShadeGC[0] = XtGetGC((Widget) w, valueMask, &values); if (!w->abacus.mono) { values.foreground = darker(w, w->abacus.beadColor[0]); } if (w->abacus.beadShadeGC[2]) XtReleaseGC((Widget) w, w->abacus.beadShadeGC[2]); w->abacus.beadShadeGC[2] = XtGetGC((Widget) w, valueMask, &values); if (!w->abacus.mono) { values.foreground = darker(w, values.foreground); } if (w->abacus.beadShadeGC[3]) XtReleaseGC((Widget) w, w->abacus.beadShadeGC[3]); w->abacus.beadShadeGC[3] = XtGetGC((Widget) w, valueMask, &values); if (w->abacus.mono) { 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[1]; values.background = w->abacus.borderColor; } if (!w->abacus.mono && (BlackPixelOfScreen(XtScreen(w)) == w->abacus.beadColor[1])) { w->abacus.beadColor[1] = brighter(w, values.foreground); values.foreground = w->abacus.beadColor[1]; } if (w->abacus.beadShadeGC[5]) XtReleaseGC((Widget) w, w->abacus.beadShadeGC[5]); w->abacus.beadShadeGC[5] = XtGetGC((Widget) w, valueMask, &values); if (!w->abacus.mono) { values.foreground = brighter(w, w->abacus.beadColor[1]); } if (w->abacus.beadShadeGC[4]) XtReleaseGC((Widget) w, w->abacus.beadShadeGC[4]); w->abacus.beadShadeGC[4] = XtGetGC((Widget) w, valueMask, &values); if (!w->abacus.mono) { values.foreground = darker(w, w->abacus.beadColor[1]); } if (w->abacus.beadShadeGC[6]) XtReleaseGC((Widget) w, w->abacus.beadShadeGC[6]); w->abacus.beadShadeGC[6] = XtGetGC((Widget) w, valueMask, &values); if (!w->abacus.mono) { values.foreground = darker(w, values.foreground); } if (w->abacus.beadShadeGC[7]) XtReleaseGC((Widget) w, w->abacus.beadShadeGC[7]); w->abacus.beadShadeGC[7] = 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, MAXLENFORMAT) != 0) { SetModeFromFormat(w); setAbacus(w, ACTION_FORMAT); if (w->abacus.demo) ClearRails(w); } if (strncasecmp(w->abacus.museum, c->abacus.museum, MAXLENFORMAT) != 0) { SetSubmodeFromMuseum(w); redraw = True; } 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.railColor[0] != c->abacus.railColor[0] || w->abacus.railColor[1] != c->abacus.railColor[1] || 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 : QUARTERPERCENTS; setAbacus(w, ACTION_QUARTERPERCENT); } } else { if (!DeleteSpecialRail(w, False, False, True)) { w->abacus.decks[BOTTOM].piecePercent = (w->abacus.decks[BOTTOM].piecePercent != 0) ? 0 : QUARTERPERCENTS; setAbacus(w, ACTION_QUARTERPERCENT); } } } 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.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_INCREMENT: IncrementRails(w); break; case ACTION_DECREMENT: DecrementRails(w); break; case ACTION_FORMAT: FormatRails(w); break; case ACTION_MUSEUM: MuseumRails(w); break; case ACTION_ROMANNUMERAL: RomanNumeralsRails(w); break; case ACTION_GROUP: GroupRails(w); break; case ACTION_SIGN: SignRails(w); break; case ACTION_QUARTER: PieceRails(w, 0, QUARTERS); break; case ACTION_QUARTERPERCENT: PiecePercentRails(w, 0, QUARTERPERCENTS); break; case ACTION_TWELFTH: PieceRails(w, 2, TWELFTHS / 2); break; case ACTION_SUBDECK: w->abacus.subbase = TWELFTHS; SubdeckRail(w, DEFAULTSUBDECKS, DEFAULTSUBBEADS); break; case ACTION_EIGHTH: w->abacus.subbase = EIGHTHS; SubdeckRail(w, DEFAULTSUBDECKS, DEFAULTSUBBEADS); break; case ACTION_ANOMALY: AnomalyRails(w, 2, 0); break; case ACTION_WATCH: AnomalyRails(w, 4, 4); break; case ACTION_SPEED: SpeedBead(w); break; case ACTION_SLOW: SlowBead(w); break; case ACTION_SOUND: SoundBead(w); break; /*case ACTION_VERTICAL: VerticalRails(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; if (!CheckAnomaly(w)) calculate(w, w->abacus.mathBuffer); } 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 < 2; 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; #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 #if 0 #if defined( USE_SOUND ) && defined( USE_ESOUND ) (void) shutdown_sound(); #endif #endif for (i = 0; i < 8; i++) XtReleaseGC(old, w->abacus.beadShadeGC[i]); XtReleaseGC(old, w->abacus.borderGC); XtReleaseGC(old, w->abacus.railGC[0]); XtReleaseGC(old, w->abacus.railGC[1]); 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 - DY; size.y = w->abacus.beadSize.x + DX; } else { size.x = w->abacus.beadSize.x + DX; size.y = w->abacus.pos.y - DY; } for (color = 0; color < 2; 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; if (w->abacus.demo) { w->abacusDemo.fontHeight = 16; w->core.height -= LINES * w->abacusDemo.fontHeight; w->abacusDemo.framed = True; } #endif w->abacus.delta.x = 8; w->abacus.delta.y = 1 + DY; 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)); #else AbacusWidget w = (AbacusWidget) renew; int i; (void) SRAND(getpid()); w->abacus.colormap = None; for (i = 0; i < 8; i++) w->abacus.beadShadeGC[i] = NULL; w->abacus.borderGC = NULL; w->abacus.railGC[0] = NULL; w->abacus.railGC[1] = NULL; w->abacus.frameGC = NULL; w->abacus.inverseGC = NULL; #endif for (color = 0; color < 2; color++) for (pressed = 0; pressed < 2; pressed++) for (shade = 0; shade < 2; shade++) w->abacus.bufferBead[color][pressed][shade] = None; w->abacus.focus = False; w->abacus.numSlices = ((w->abacus.delay < 5 * MAXSLICES) ? w->abacus.delay / 5 + 1 : MAXSLICES); for (deck = 0; deck < MAXDECKS; 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); #if 0 #if defined( USE_SOUND ) && defined( USE_ESOUND ) (void) init_sound(); #endif #endif #ifdef SCRIPTFILE if (w->abacus.script) { if ((w->abacus.fp = fopen(SCRIPTFILE, "w")) == NULL) { char buf[512]; (void) sprintf(buf, "Can not write to %s.", SCRIPTFILE); DISPLAY_WARNING(buf); } } #endif } #ifndef WINVER static #endif void ExposeAbacus( #ifdef WINVER AbacusWidget w #else Widget renew, XEvent *event, Region region #endif ) { #ifndef WINVER AbacusWidget w = (AbacusWidget) renew; if (!w->core.visible || 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 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 void ClearAbacusMaybe(AbacusWidget w , XEvent *event, char **args, int nArgs ) { #ifdef HAVE_MOTIF if (!isEmptyCounter(w) && !w->abacus.aux) { /* Check if one really wants to destroy calculations. */ setAbacus(w, ACTION_CLEAR_QUERY); } #endif } static void ClearAbacus2(AbacusWidget w , XEvent *event, char **args, int nArgs ) { #ifndef HAVE_MOTIF ClearRails(w); #endif } #endif #ifndef WINVER static #endif void IncrementAbacus(AbacusWidget w #ifndef WINVER , XEvent *event, char **args, int nArgs #endif ) { IncrementRails(w); } #ifndef WINVER static #endif void DecrementAbacus(AbacusWidget w #ifndef WINVER , XEvent *event, char **args, int nArgs #endif ) { DecrementRails(w); } #ifndef WINVER static #endif void SpeedAbacus(AbacusWidget w #ifndef WINVER , XEvent *event, char **args, int nArgs #endif ) { SpeedBead(w); } #ifndef WINVER static #endif void SlowAbacus(AbacusWidget w #ifndef WINVER , XEvent *event, char **args, int nArgs #endif ) { SlowBead(w); } #ifndef WINVER static #endif void SoundAbacus(AbacusWidget w #ifndef WINVER , XEvent *event, char **args, int nArgs #endif ) { SoundBead(w); } #ifndef WINVER static #endif void FormatAbacus(AbacusWidget w #ifndef WINVER , XEvent *event, char **args, int nArgs #endif ) { FormatRails(w); } #ifndef WINVER static #endif void MuseumAbacus(AbacusWidget w #ifndef WINVER , XEvent *event, char **args, int nArgs #endif ) { MuseumRails(w); } #ifndef WINVER static #endif void RomanNumeralsAbacus(AbacusWidget w #ifndef WINVER , XEvent *event, char **args, int nArgs #endif ) { RomanNumeralsRails(w); } #ifndef WINVER static #endif void GroupAbacus(AbacusWidget w #ifndef WINVER , XEvent *event, char **args, int nArgs #endif ) { GroupRails(w); } #ifndef WINVER static #endif void SignAbacus(AbacusWidget w #ifndef WINVER , XEvent *event, char **args, int nArgs #endif ) { SignRails(w); } #ifndef WINVER static #endif void QuarterAbacus(AbacusWidget w #ifndef WINVER , XEvent *event, char **args, int nArgs #endif ) { PieceRails(w, 0, QUARTERS); } #ifndef WINVER static #endif void QuarterPercentAbacus(AbacusWidget w #ifndef WINVER , XEvent *event, char **args, int nArgs #endif ) { PiecePercentRails(w, 0, QUARTERPERCENTS); } #ifndef WINVER static #endif void TwelfthAbacus(AbacusWidget w #ifndef WINVER , XEvent *event, char **args, int nArgs #endif ) { PieceRails(w, 2, TWELFTHS / 2); } #ifndef WINVER static #endif void SubdeckAbacus(AbacusWidget w #ifndef WINVER , XEvent *event, char **args, int nArgs #endif ) { w->abacus.subbase = TWELFTHS; SubdeckRail(w, DEFAULTSUBDECKS, DEFAULTSUBBEADS); } #ifndef WINVER static #endif void EighthAbacus(AbacusWidget w #ifndef WINVER , XEvent *event, char **args, int nArgs #endif ) { w->abacus.subbase = EIGHTHS; SubdeckRail(w, DEFAULTSUBDECKS, DEFAULTSUBBEADS); } #ifndef WINVER static #endif void AnomalyAbacus(AbacusWidget w #ifndef WINVER , XEvent *event, char **args, int nArgs #endif ) { AnomalyRails(w, 2, 0); } #ifndef WINVER static #endif void WatchAbacus(AbacusWidget w #ifndef WINVER , XEvent *event, char **args, int nArgs #endif ) { AnomalyRails(w, 4, 4); } #ifndef WINVER static void DemoAbacus(AbacusWidget w , XEvent *event, char **args, int nArgs ) { setAbacus(w, ACTION_DEMO); } static void NextAbacus(AbacusWidget w , XEvent *event, char **args, int nArgs ) { if (w->abacus.demo) { setAbacus(w, ACTION_NEXT); } } static void RepeatAbacus(AbacusWidget w , XEvent *event, char **args, int nArgs ) { if (w->abacus.demo) { setAbacus(w, ACTION_REPEAT); } } static void MoreAbacus(AbacusWidget w , XEvent *event, char **args, int nArgs ) { if (w->abacus.demo) { setAbacus(w, ACTION_MORE); } } #endif #ifndef WINVER static #endif void EnterAbacus(AbacusWidget w #ifndef WINVER , XEvent *event, char **args, int nArgs #endif ) { w->abacus.focus = True; DrawFrame(w, 0, True, w->abacus.focus); } #ifndef WINVER static #endif void LeaveAbacus(AbacusWidget w #ifndef WINVER , XEvent *event, char **args, int nArgs #endif ) { w->abacus.focus = False; DrawFrame(w, 0, True, w->abacus.focus); } #ifdef OLDANDINTHEWAY /* This routine will do a XFillArc for a circle */ void DiskXI(Display *display, Window window, GC gc, int diameter, int ctrX, int ctrY) { int x, y, p, d; x = 0; y = diameter >> 1; p = diameter & 1; d = 1 - 2 * y + p; while (x < y) { DiskPointsXI(display, window, gc, ctrX, ctrY, x, y, p); if (d < 0) d = d + (4 * x) + 6; else { d = d + (4 * (x - y)) + 10; y--; } x++; } if (x == y) DiskPointsXI(display, window, gc, ctrX, ctrY, x, y, p); } void DiskPointsXI(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