/*- # MOTIF/X-BASED ABACUS # # xabacus.c # ### # # Copyright (c) 1993 - 2007 David Albert Bagley, bagleyd@tux.org # # Abacus demo and neat pointers from # Copyright (c) 1991 - 1998 Luis Fernandes, elf@ee.ryerson.ca # # 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. # */ #ifndef WINVER static const char aboutHelp[] = { "Abacus Version 7.3.2\n" "Send bugs (reports or fixes) to the author: " "David Bagley \n" "The latest version is at: " "http://www.tux.org/~bagleyd/abacus.html\n" "Some coding was also done by Luis Fernandes \n" "and Sarat Chandran \n" }; static const char optionsHelp[] = { "[-geometry [{width}][x{height}] [{+-}{xoff}[{+-}{yoff}]]]\n" "[-display [{host}]:[{vs}]] [-[no]mono] [-[no]{reverse|rv}]\n" "[-{foreground|fg} {color}] [-{background|bg} {color}]\n" "[-bead {color}] [-frame {color}] [-rail {color}]\n" "[-{border|bd} {color}] [-delay msecs] [-[no]sound]\n" "[-bumpSound {filename}] [-moveSound {filename}]\n" "[-[no]demo] [-[no]script] [-demopath {path}]\n" "[-{demofont|demofn} {fontname}]\n" "[-{demoforeground|demofg} {color}] [-[no]lee]] [-[no]vertical]\n" "[-colorScheme {int}] [-[no]slot] [no]diamond]\n" "[-railIndex {int}] [-[no]torient] [-[no]borient]\n" "[-tnumber {int}] [-bnumber {int}] [-tfactor {int}]\n" "[-bfactor {int}] [-tspaces {int}] [-bspaces {int}]\n" "[-tpiece {int}] [-bpiece {int}] [-tpiecePercent {int}]\n" "[-bpiecePercent {int}] [-shiftPercent {int}]\n" "[-subdeck {int}] [-subbead {int}] [-[no]sign]\n" "[-decimalPosition {int}] [-groupSize {int}] [-rails {int}]\n" "[-base {int}] [-[no]eighth] [-anomaly {int}]\n" "[-shiftAnomaly {int}] [-anomalySq {int}] [-shiftAnomalySq {int}]\n" "[-displayBase {int}] [-[no]romanNumerals] [-[no]group]\n" "[-{chinese|japanese|korean|roman|russian|danish|other}]\n" "[-{it|uk|fr}] [-version]\n" }; #endif #ifdef HAVE_MOTIF static const char options1Help[] = { "-geometry {+|-}X{+|-}Y " "This option sets the initial position of the abacus " "window (resource name \"geometry\").\n" "-display host:dpy " "This option specifies the X server to contact.\n" "-[no]mono " "This option allows you to display the abacus window " "on a color screen as if it were monochrome\n" " (resource name \"mono\").\n" "-[no]{reverse|rv} " "This option allows you to see the abacus window in " "reverse video (resource name \"reverseVideo\").\n" "-{foreground|fg} color " "This option specifies the foreground of the abacus " "window (resource name \"foreground\").\n" "-{background|bg} color " "This option specifies the background of the abacus " "window (resource name \"background\").\n" "-frame color " "This option specifies the foreground of the frame " "(resource name \"frameColor\").\n" "-rail color0 " "This option specifies the foreground of the rails " "(resource name \"railColor0\").\n" "-rail color1 " "This option specifies the foreground of the rails " "(resource name \"railColor1\").\n" "-bead color0 " "This option specifies the foreground of the beads " "(resource name \"beadColor0\").\n" "-bead color1 " "This option specifies the foreground of the beads " "(resource name \"beadColor1\").\n" "-{border|bd} color " "This option specifies the foreground of the border " "of the beads (resource name \"borderColor\").\n" "-delay msecs " "This option specifies the number of milliseconds it " "takes to move a bead or a group of beads\n" " one space (resource name \"delay\").\n" "-[no]sound " "This option specifies if a sliding bead should " "make a sound or not (resource name \"sound\").\n" "-bumpSound filename " "This option specifies the file for the bump sound.\n" "-moveSound filename " "This option specifies the file for the move sound.\n" "-[no]demo " "This option specifies to run in demo mode. In this " "mode, the abacus is controlled by the current\n" " lesson (resource name \"demo\"). When started with " "the demo option, a window contains descriptive text,\n" " and user prompts are displayed in this window. Pressing " "'q' during the demo will quit it. Clicking the\n" " left mouse-button with the pointer in the window " "will restart the demo (beginning of current lesson).\n" " The demo uses Abacus1_1.les for the first Chinese Abacus " "lesson, Abacusjp1_1.les for the first Japanese (and\n" " Roman) Abacus lesson, Abacusko1_1.les for the Korean " "Abacus, and Abacusru1_1.les for the Russian Abacus.\n" "-[no]script " "This option specifies to log application to stdout, " "every time the user clicks to move the\n" " beads (resource name \"script\"). The output is a set " "of deck, rail, beads added or subtracted, and\n" " the number of text lines (4). This can be edited to add " "text to the lesson and used as a new demo keeping\n" " the generated numbers and the number of lines constant." " It writes to Abacus.les by default.\n" "-demopath path " "This option specifies the path for the demo, possibly" " /usr/local/share/games/xabacus (resource\n" " name \"demoPath\"). It initially looks for Abacus1_1.les," " first chapter, lesson 1. If it finds that, it\n" " will later look for Abacus1_2.les, etc.\n" "-{demofont|demofn} fontstring " "This option specifies the font for the " "explanatory text that appears in the\n" " secondary window, during the demo. The default font is " "18 point Times-Roman (-*-times-*-r-*-*-*-180-*).\n" " The alternate font is 8x13 (resource name \"demoFont\").\n" "-{demoforeground|demofg} color " "This option specifies the foreground of the abacus " "demo window (resource name\n" " \"demoForeground\").\n" "-{demobackground|demobg} color " "This option specifies the background of the abacus " "demo window (resource name\n" " \"demoBackground\").\n" "-[no]lee " "This option allows you to turn on and off the two extra " "auxiliary abaci (resource name \"lee\").\n" "-[no]vertical " "This option allows you to set the abacus to allow " "a Russian orientation (resource name \"vertical\").\n" "-colorScheme int " "This option specifies the color scheme for the " "abacus (resource name \"colorScheme\") where\n" " 0-> none, 1-> color middle (2 beads beads but if odd " "color 1 bead), 2-> color first of group, 3-> both 1 and\n" " 2, 4-> color first half (but if odd color middle " "bead).\n" "-[no]slot " "This option allows you to have either slots or rails " "(resource name \"slot\").\n" "-[no]diamond " "This option allows you to have diamond or round beads " "(resource name \"diamond\").\n" "-railIndex int " "This option specifies the index of color for the " "rails of the abacus (resource name \"railIndex\")\n" " where a value is 0 or 1.\n" }; static const char options2Help[] = { "-[no]torient " "This option specifies the orientation of the beads " "on top (resource name \"topOrient\").\n" "-[no]borient " "This option specifies the orientation of the beads " "on bottom (resource name \"bottomOrient\").\n" "-tnumber int " "This option specifies the number of beads on top " "(resource name \"topNumber\").\n" "-bnumber int " "This option specifies the number of beads on bottom " "(resource name \"bottomNumber\").\n" "-tfactor int " "This option specifies the multiply factor for the " "beads on top (resource name \"topFactor\").\n" "-bfactor int " "This option specifies the multiply factor for the " "beads on bottom (resource name \"bottomFactor\").\n" "-tspaces int " "This option specifies the number of spaces on top " "(resource name \"topSpaces\").\n" "-bspaces int " "This option specifies the number of spaces on bottom " "(resource name \"bottomSpaces\").\n" "-tpiece int " "This option specifies the number of pieces on top " "(resource name \"topPiece\").\n" "-bpiece int " "This option specifies the number of pieces on bottom " "(resource name \"bottomPiece\").\n" "-tpiecePercent int " "This option specifies the number of piece percents on top " "(resource name \"topPiecePercent\").\n" "-bpiecePercent int " "This option specifies the number of piece percents on bottom " "(resource name \"bottomPiecePercent\").\n" "-shiftPercent int " "This option specifies the shift of rails for piece percents " "and also may influence the\n" " precision of the calculation (resource name " "\"shiftPercent\").\n" "-subdeck int " "This option specifies the special subdecks column " "(resource name " "\"subdeck\").\n" "-subbead int " "This option specifies the special subbeads column " "(resource name " "\"subbead\").\n" "-[no]sign " "This option allows you to set the abacus to allow " "negatives (resource name \"sign\").\n" "-decimalPosition int " "This option specifies the number of rails to the " "right of the decimal point\n" " (normally 2) (resource name \"decimalPosition\").\n" "-groupSize int " "This option specifies the group size to the left of the " "decimal point (normally 3) (resource\n" " name \"groupSize\").\n" "-rails int " "This option specifies the number of rails (resource " "name \"rails\").\n" "-base int " "This option specifies the base used (default is base " "10) (resource name \"base\"). By default,\n" " one has to set the format mode to not be " "Other for this to work (unless you know what you are doing).\n" "-[no]eighth " "This option specifies the base for the Roman subdeck, " "(if set, the resource is set to 8, else\n" " it is set to 12) (resource " "name \"subbase\").\n" "-anomaly int " "This option specifies the offset from base for a " "multiplicative factor of the rail with the\n" " anomaly (if none, this is set to 0) " "(resource name \"anomalySq\").\n" "-shiftAnomaly int " "This option specifies the offset from decimal point " "for the anomaly (usually 2) (resource name\n" " \"shiftAnomaly\").\n" "-anomalySq int " "This option specifies the offset from base for the " "second anomaly (if none, this is set to 0)\n" " (resource name \"anomalySq\").\n" "-shiftAnomalySq int " "This option specifies the offset in rails from the " "first anomaly (usually 2) (resource\n" " name \"shiftAnomalySq\").\n" "-displayBase int " "This option specifies the base displayed (default is " "base 10) (resource name \"displayBase\").\n" " If this is different then \"base\" then it is " "implemented using \"long long\" and the calculation is\n" " limited by its bounds. Also the fractional " "part does not scale with the \"displayBase\" so if the\n" " \"displayBase\" is greater than the \"base\" it " "looses some precision. Also no rounding is done.\n" "-[no]romanNumerals " "This option allows you to set the abacus to " "allow Roman Numerals (resource name\n" " \"romanNumerals\"). Roman Numerals above 3999 are " "normally represented with bars on top, due to ASCII\n" " constraints this is represented instead in lower case " "(historically case was ignored). Roman Numerals above\n" " 3,999,999 were not represented historically. " "Roman numerals change with displayBase in an\n" " \"experimental\" way. When used with twelfths and " "subdecks, named fraction symbols are used. Due to\n" " ASCII constraints the sigma is represented as E, the " "backwards C is represented as a Q, the mu as a u, and\n" " the Z with a - through the center as a z. If " "available, decimal input is ignored.\n" "-[no]group " "This option allows you to group the displayed " "digits for readability (resource name\n" " \"group\").\n" }; static const char options3Help[] = { "-chinese " "This option specifies the format of the abacus " "(resource name \"format\") to \"Chinese\"\n" " for the Chinese Saun-pan.\n" "-japanese " "This option specifies the format of the abacus " "(resource name \"format\") to \"Japanese\"\n" " for the Japanese post-WWII Soroban. " "This is also similar to the Roman Hand Abacus.\n" "-korean " "This option specifies the format of the abacus " "(resource name \"format\") to \"Korean\"\n" " for the Korean Supan or Japanese pre-WWII " "Soroban.\n" "-roman " "This option specifies the format of the abacus " "(resource name \"format\") to \"Roman\"\n" " for the Roman Hand Abacus, note beads will " "move in slots. To complete, specify \"romanNumerals\".\n" "-russian " "This option specifies the format of the abacus " "(resource name \"format\") to \"Russian\"\n" " for the Russian Schoty. To complete, " "specify \"piece\" resource to be 4.\n" "-danish " "This option specifies the format of the abacus " "(resource name \"format\") to \"Danish\"\n" " for the Danish Elementary School Abacus " "teaching aid.\n" "-other " "This option specifies the format of the abacus " "(resource name \"format\") to \"Other\". This option specifies\n" " a format that is more configurable by using " "resources, since there are few rules to govern its behavior.\n" "-it " "This option specifies the country code of the museum of the " "abacus in Museum of the Thermae, Rome.\n" "-uk " "This option specifies the country code of the museum of the " "abacus in British Museum in London.\n" "-fr " "This option specifies the country code of the museum of the " "abacus in Cabinet de medailles, Bibliotheque\n" " nationale, Paris.\n" "-version " "This option tells you what version of xabacus you have.\n" }; #endif #if defined(HAVE_MOTIF) || defined(WINVER) static const char descriptionHelp[] = { "This is an implementation of the classic Chinese abacus " "(Saun-pan) which has its origins in the 12th century.\n" "\n" "The device has two decks. Each deck, separated by a partition," " normally has 13 rails on which are mounted beads.\n" "Each rail on the top deck contains 1 or 2 beads, and each " "rod on the bottom deck contains 4 or 5 beads. Each bead on\n" "the upper deck has a value of five, while each bead on the " "lower deck has value of one. Beads are considered counted,\n" "when moved towards the partition separating the decks, i.e. " "to add a value of one, a bead in the bottom deck is moved up,\n" "and to add a value of 5, a bead in the top deck is moved " "down.\n" "\n" "The basic operations of the abacus are addition and subtraction. " " Multiplication can be done by mentally multiplying the\n" "digits and adding up the intermediate results on the abacus. " " Division would be similar where the intermediate results\n" "are subtracted. There are techniques like using your thumb " "with forefinger which does not apply with mouse entry. Also\n" "with multiplication, one can carry out calculations on " "different parts of the abacus, here it is nice to have a long\n" "abacus.\n" "\n" "The pre-WWII Japanese abacus (Soroban) (or Korean Supan) is " "similar to the Chinese abacus but has only one bead per rail\n" "on the top deck. The later Japanese abacus was further " "simplified to have only 4 beads per rail on the bottom deck.\n" "\n" "The Roman hand-abacus predates the Chinese abacus and is " "very similar to the later Japanese abacus, but seems to have\n" "fallen out of use with the Fall of the Roman Empire (at " "least 3 are in existence). The Roman abaci are brass plates\n" "where the beads move in slots. In addition to the normal 7 " "columns of beads, they generally have 2 special columns on\n" "the right side. In two examples: the first special column " "was for 12ths (12 uncia (ounces) = 1 as) and had one extra\n" "bead in the bottom deck. Also the last column was a combination " "of halves, quarters, and twelfths of an ounce and had no\n" "beads in the top deck and 4 at the bottom (beads did not have " "to come to the top to be counted but at one of 3 marked\n" "points, where the top bead was for halves, the next bead for " "quarters, and the last two beads for twelfths). In another\n" "surviving example: the 2 special columns were switched and the " "combination column was broken into 3 separate slots.\n" "\n" "The Russian abacus was invented in the 17th century, here " "the beads are moved from right to left. It has colored beads\n" "in the middle for ease of use. Quarters represent 1/4 Rubles " "and are only present historically on the Russian abacus\n" "(Schoty). Some of the older Schoty have a extra place for " "the 1/4 Kopek (quarter percent) as well as the 1/4 Ruble\n" "(quarter).\n" "\n" "The Danish abacus was used in the early 20th century in " "elementary schools as a teaching aid.\n" "\n" "The Mesoamerican Nepohualtzintzin is a Japanese abacus base 20. " " The Mesoamericans had base 20 with the exception of the\n" "3rd decimal place where instead of 20 * 20 = 400 the third place " "marked 360 and the 4th place was 20 * 360, etc.. They\n" "independently created their own zero (only Babylon (base 60) " "and India (base 10) have done this) but the anomaly took\n" "away its true power.\n" "\n" "An easy way of figuring out time in seconds given hours, " "minutes, and seconds, can be done on the abacus with special\n" "anomaly \"watch\" settings.\n" "\n" "The Chinese Solid-and-Broken-Bar System is a base 12 numbering " "system and not really an abacus. When the abacus is setup\n" "in this way though (topFactor 3, topNumber 3, bottomNumber 2, " "base 12, displayBase 12), it is easy to relate the two.\n" "\n" "The signed bead is an invention of the author and is not " "present on any historical abacus (to his knowledge) and is\n" "used to represent negatives. \"New & Improved\" abacus " " models have two auxiliary decks stacked above the principal decks\n" "that enable multiplication, division, square-root, and " "cube-root computations to be performed with equal ease as addition\n" "and subtraction." }; static const char featuresHelp[] = { "Click \"mouse-left\" button on a bead you want to move. The " "beads will shift themselves to vacate the area of the column\n" "that was clicked.\n" "\n" "Click \"mouse-right\" button, or press \"C\" or \"c\" keys, to " "clear the abacus.\n" "\n" "Press \"O\" or \"o\" keys to toggle the demo mode.\n" "\n" "Press \"I\" or \"i\" keys to increment the number of rails.\n" "\n" "Press \"D\" or \"d\" keys to decrement the number of rails.\n" "\n" "Press \"F\" or \"f\" keys to switch between Chinese, Japanese, " "Korean, Roman, Russian, and Danish formats.\n" "\n" "Press \"E\" or \"e\" keys to switch between it, uk, and fr " "museum formats.\n" "\n" "Press \"M\" or \"m\" keys to toggle the availability of Roman " "Numerals.\n" "\n" "Press \"S\" or \"s\" keys to toggle the availability of sign " "bead.\n" "\n" "Press \"U\" or \"u\" keys to toggle the availability of quarter " "beads. (Mutually exclusive to twelfth beads). Intended for\n" "the Russian Abacus.\n" "\n" "Press \"P\" or \"p\" keys to toggle the availability of quarter " "percent beads. (Dependent on quarter beads (or twelfth\n" "beads)). Intended for the older Russian Abacus.\n" "\n" "Press \"T\" or \"t\" keys to toggle the availability of twelfth " "beads. (Mutually exclusive to quarter beads). Intended for\n" "the Roman Abacus.\n" "\n" "Press \"B\" or \"b\" keys to toggle the availability of subdecks." " (Dependent on twelfth beads (or quarter beads) and Roman\n" "format). Intended for the Roman Abacus, the lowest value of the " "rightmost beads are a tweltfh of the next column.\n" "\n" "Press \"H\" or \"h\" keys to toggle the availability of subdecks." " (Dependent on twelfth beads (or quarter beads) and Roman\n" "format). Intended for the Roman Abacus, the lowest value of the " "rightmost beads are an eighth of the next column.\n" "\n" "Press \"L\" or \"l\" keys to toggle the availability of anomaly " "bars. Intended to used with Japanese Abacus and base 20 for\n" "the Mesoamerican Abacus. (Mutually exclusive to watch bars).\n" "\n" "Press \"W\" or \"w\" keys to toggle the availability of watch " "bars. Intended to represent seconds where hours and minutes\n" "can be set. (Mutually exclusive to anomaly bars).\n" "\n" "Press \">\" or \".\" keys to speed up the movement of beads.\n" "\n" "Press \"<\" or \",\" keys to slow down the movement of beads.\n" "\n" "Press \"@\" key to toggle the sound.\n" "\n" "Press \"Esc\" key to hide program.\n" "\n" "Press \"Q\", \"q\", or \"CTRL-C\" keys to kill program.\n" "\n" "The abacus may be resized. Beads will reshape depending on " "the room they have. Demo Mode: In this mode, the abacus is\n" "controlled by the program. When started with the demo " "option, a second window is presented that should be placed\n" "directly below the abacus-window. Descriptive text, and user " "prompts are displayed in this window. Pressing 'q' during\n" "the demo will quit it. Clicking the left mouse-button with " "the pointer in the window will restart the demo (beginning\n" "of current lesson)." }; static const char referencesHelp[] = { "Luis Fernandes http://www.ee.ryerson.ca/~elf/abacus/\n" "Lee Kai-chen, How to Learn Lee's Abacus, 1958, 58 pages.\n" "Abacus Guide Book, 57 pages.\n" "Georges Ifrah, The Universal history of Numbers, Wiley Press " "2000, pp 209-211, 288-294.\n" "Review of above: http://www.ams.org/notices/200201/rev-dauben.pdf\n" "David Eugene Smith, History of Mathematics Volume II, " "Dover Publications, Inc 1958, pp 156-195.\n" }; #endif static const char *formatString[] = { "Chinese", "Japanese", "Korean", "Roman", "Russian", "Danish", "Other" }; #ifdef WINVER #include "AbacusP.h" #define TITLE "wabacus" static AbacusRec widget; #define MAXDIGITS 256 /* This limits the number of rails */ static void forceNormalParams(AbacusWidget w) { int base = DEFAULTBASE; int displayBase = DEFAULTBASE; w->abacus.base = base; w->abacus.displayBase = displayBase; } static void forceDemoParams(AbacusWidget w) { int min, mode; int bottomPiece, bottomPiecePercent; Boolean demo, sign; forceNormalParams(w); mode = w->abacus.mode; sign = w->abacus.sign; bottomPiece = w->abacus.decks[BOTTOM].piece; bottomPiecePercent = w->abacus.decks[BOTTOM].piecePercent; demo = w->abacus.demo; if (mode == OTHER) { FormatAbacus(w); } min = ((sign) ? 1: 0) + ((bottomPiece) ? 1 : 0) + ((bottomPiecePercent) ? 1 + w->abacus.shiftPercent : 0) + ((demo) ? MINDEMORAILS : MINRAILS); while (w->abacus.rails < min) { IncrementAbacus(w); } } void setAbacus(AbacusWidget w, int reason) { switch (reason) { case ACTION_SCRIPT: #if 0 { int deck, rail, number; deck = w->abacus.deck; rail = w->abacus.rail; number = w->abacus.number; (void) printf("%d %d %d %d\n", PRIMARY, deck, rail, number); } #endif break; case ACTION_BASE_DEFAULT: forceNormalParams(w); break; case ACTION_DEMO_DEFAULT: forceDemoParams(w); break; case ACTION_CLEAR: ClearAbacus(w); break; case ACTION_HIDE: ShowWindow(w->core.hWnd, SW_SHOWMINIMIZED); break; case ACTION_CLEAR_QUERY: break; case ACTION_DEMO: DemoAbacusDemo(w); break; case ACTION_NEXT: NextAbacusDemo(w); break; case ACTION_REPEAT: RepeatAbacusDemo(w); break; case ACTION_JUMP: JumpAbacusDemo(w); break; case ACTION_MORE: MoreAbacusDemo(w); break; case ACTION_INCREMENT: case ACTION_DECREMENT: case ACTION_FORMAT: case ACTION_ROMANNUMERAL: case ACTION_SIGN: case ACTION_QUARTER: case ACTION_QUARTERPERCENT: case ACTION_TWELFTH: case ACTION_SUBDECK: case ACTION_ANOMALY: case ACTION_WATCH: break; } } void setAbacusString(AbacusWidget w, int reason, char *string) { if (reason == ACTION_SCRIPT || reason == ACTION_IGNORE) { char szBuf[MAXDIGITS + 67]; int mode = w->abacus.mode; (void) sprintf(szBuf, "%s %s %s", string, (mode < 0 || mode >= MAXFORMATS) ? "" : formatString[mode], TITLE); SetWindowText(w->core.hWnd, (LPSTR) szBuf); } } static LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_COMMAND: if (LOWORD(wParam) == IDOK) { (void) EndDialog(hDlg, TRUE); return TRUE; } break; } return FALSE; } static LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { HBRUSH brush = (HBRUSH) NULL; PAINTSTRUCT paint; widget.core.hWnd = hWnd; if (GetFocus()) { if (!widget.abacus.focus) { widget.core.hDC = GetDC(hWnd); (void) SelectObject(widget.core.hDC, GetStockObject(NULL_BRUSH)); EnterAbacus(&widget); (void) EndPaint(hWnd, &paint); } } else { if (widget.abacus.focus) { widget.core.hDC = GetDC(hWnd); (void) SelectObject(widget.core.hDC, GetStockObject(NULL_BRUSH)); LeaveAbacus(&widget); (void) EndPaint(hWnd, &paint); } } switch (message) { case WM_CREATE: InitializeAbacus(&widget, brush); InitializeAbacusDemo(&widget); break; case WM_DESTROY: DestroyAbacus(&widget, brush); #if 0 if (widget.abacus.demo) DestroyAbacusDemo(); #endif break; case WM_SIZE: ResizeAbacus(&widget); (void) InvalidateRect(hWnd, NULL, TRUE); break; case WM_PAINT: widget.core.hDC = BeginPaint(hWnd, &paint); (void) SelectObject(widget.core.hDC, GetStockObject(NULL_PEN)); ExposeAbacus(&widget); if (widget.abacus.demo) { ExposeAbacusDemo(&widget); } (void) EndPaint(hWnd, &paint); break; case WM_LBUTTONDOWN: widget.core.hDC = GetDC(hWnd); (void) SelectObject(widget.core.hDC, GetStockObject(NULL_PEN)); #if 0 if (widget.abacus.demo) { ClearAbacus(&widget); ClearAbacusDemo(&widget); } else #endif { SelectAbacus(&widget, LOWORD(lParam), HIWORD(lParam)); } (void) ReleaseDC(hWnd, widget.core.hDC); break; case WM_LBUTTONUP: case WM_NCMOUSEMOVE: widget.core.hDC = GetDC(hWnd); (void) SelectObject(widget.core.hDC, GetStockObject(NULL_PEN)); ReleaseAbacus(&widget); (void) ReleaseDC(hWnd, widget.core.hDC); break; case WM_COMMAND: switch (LOWORD(wParam)) { case ACTION_EXIT: DestroyAbacus(&widget, brush); #if 0 if (widget.abacus.demo) DestroyAbacusDemo(brush); #endif break; case ACTION_HIDE: HideAbacus(&widget); break; case ACTION_CLEAR: widget.core.hDC = GetDC(hWnd); (void) SelectObject(widget.core.hDC, GetStockObject(NULL_PEN)); ClearAbacus(&widget); #if 0 if (widget.abacus.demo) clearDemo(&widget); #endif (void) ReleaseDC(hWnd, widget.core.hDC); break; case ACTION_INCREMENT: widget.core.hDC = GetDC(hWnd); (void) SelectObject(widget.core.hDC, GetStockObject(NULL_PEN)); IncrementAbacus(&widget); (void) ReleaseDC(hWnd, widget.core.hDC); break; case ACTION_DECREMENT: widget.core.hDC = GetDC(hWnd); (void) SelectObject(widget.core.hDC, GetStockObject(NULL_PEN)); DecrementAbacus(&widget); (void) ReleaseDC(hWnd, widget.core.hDC); break; case ACTION_FORMAT: widget.core.hDC = GetDC(hWnd); (void) SelectObject(widget.core.hDC, GetStockObject(NULL_PEN)); FormatAbacus(&widget); if (widget.abacus.demo) { ClearAbacusDemo(&widget); ClearAbacus(&widget); } break; case ACTION_MUSEUM: widget.core.hDC = GetDC(hWnd); (void) SelectObject(widget.core.hDC, GetStockObject(NULL_PEN)); MuseumAbacus(&widget); break; case ACTION_ROMANNUMERAL: RomanNumeralsAbacus(&widget); break; case ACTION_GROUP: GroupAbacus(&widget); break; case ACTION_SIGN: widget.core.hDC = GetDC(hWnd); (void) SelectObject(widget.core.hDC, GetStockObject(NULL_PEN)); SignAbacus(&widget); (void) ReleaseDC(hWnd, widget.core.hDC); break; case ACTION_QUARTER: widget.core.hDC = GetDC(hWnd); (void) SelectObject(widget.core.hDC, GetStockObject(NULL_PEN)); QuarterAbacus(&widget); (void) ReleaseDC(hWnd, widget.core.hDC); break; case ACTION_QUARTERPERCENT: widget.core.hDC = GetDC(hWnd); (void) SelectObject(widget.core.hDC, GetStockObject(NULL_PEN)); QuarterPercentAbacus(&widget); (void) ReleaseDC(hWnd, widget.core.hDC); break; case ACTION_TWELFTH: widget.core.hDC = GetDC(hWnd); (void) SelectObject(widget.core.hDC, GetStockObject(NULL_PEN)); TwelfthAbacus(&widget); (void) ReleaseDC(hWnd, widget.core.hDC); break; case ACTION_SUBDECK: widget.core.hDC = GetDC(hWnd); (void) SelectObject(widget.core.hDC, GetStockObject(NULL_PEN)); SubdeckAbacus(&widget); (void) ReleaseDC(hWnd, widget.core.hDC); break; case ACTION_EIGHTH: widget.core.hDC = GetDC(hWnd); (void) SelectObject(widget.core.hDC, GetStockObject(NULL_PEN)); EighthAbacus(&widget); (void) ReleaseDC(hWnd, widget.core.hDC); break; case ACTION_ANOMALY: widget.core.hDC = GetDC(hWnd); (void) SelectObject(widget.core.hDC, GetStockObject(NULL_PEN)); AnomalyAbacus(&widget); (void) ReleaseDC(hWnd, widget.core.hDC); break; case ACTION_WATCH: widget.core.hDC = GetDC(hWnd); (void) SelectObject(widget.core.hDC, GetStockObject(NULL_PEN)); WatchAbacus(&widget); (void) ReleaseDC(hWnd, widget.core.hDC); break; #if 0 case ACTION_VERTICAL: widget.core.hDC = GetDC(hWnd); (void) SelectObject(widget.core.hDC, GetStockObject(NULL_PEN)); VerticalAbacus(&widget); (void) ReleaseDC(hWnd, widget.core.hDC); break; #endif case ACTION_DEMO: DemoAbacusDemo(&widget); ResizeAbacus(&widget); (void) InvalidateRect(hWnd, NULL, TRUE); break; case ACTION_NEXT: widget.core.hDC = GetDC(hWnd); (void) SelectObject(widget.core.hDC, GetStockObject(NULL_PEN)); /* NextAbacus(&widget); */ if (widget.abacus.demo) NextAbacusDemo(&widget); (void) ReleaseDC(hWnd, widget.core.hDC); break; case ACTION_REPEAT: widget.core.hDC = GetDC(hWnd); (void) SelectObject(widget.core.hDC, GetStockObject(NULL_PEN)); /* RepeatAbacus(&widget); */ if (widget.abacus.demo) RepeatAbacusDemo(&widget); (void) ReleaseDC(hWnd, widget.core.hDC); break; case ACTION_JUMP: widget.core.hDC = GetDC(hWnd); (void) SelectObject(widget.core.hDC, GetStockObject(NULL_PEN)); /* JumpAbacus(&widget); */ if (widget.abacus.demo) JumpAbacusDemo(&widget); (void) ReleaseDC(hWnd, widget.core.hDC); break; case ACTION_CHAPTER1: case ACTION_CHAPTER2: case ACTION_CHAPTER3: case ACTION_CHAPTER4: case ACTION_CHAPTER5: widget.core.hDC = GetDC(hWnd); (void) SelectObject(widget.core.hDC, GetStockObject(NULL_PEN)); /* ChapterAbacus(&widget); */ if (widget.abacus.demo) ChapterAbacusDemo(&widget, LOWORD(wParam) - ACTION_CHAPTER1); (void) ReleaseDC(hWnd, widget.core.hDC); break; case ACTION_MORE: widget.core.hDC = GetDC(hWnd); (void) SelectObject(widget.core.hDC, GetStockObject(NULL_PEN)); /* MoreAbacus(&widget); */ if (widget.abacus.demo) MoreAbacusDemo(&widget); (void) ReleaseDC(hWnd, widget.core.hDC); break; case ACTION_SPEED: SpeedAbacus(&widget); break; case ACTION_SLOW: SlowAbacus(&widget); break; case ACTION_SOUND: SoundAbacus(&widget); break; case ACTION_DESCRIPTION: (void) MessageBox(hWnd, descriptionHelp, "Description", MB_OK); break; case ACTION_FEATURES: (void) MessageBox(hWnd, featuresHelp, "Features", MB_OK); break; case ACTION_REFERENCES: (void) MessageBox(hWnd, referencesHelp, "References", MB_OK); break; case ACTION_ABOUT: (void) DialogBox(widget.core.hInstance, "About", hWnd, (DLGPROC) About); break; } break; default: return (DefWindowProc(hWnd, message, wParam, lParam)); } return FALSE; } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int numCmdShow) { HWND hWnd; MSG msg; WNDCLASS wc; HACCEL hAccel; if (!hPrevInstance) { wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WindowProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(hInstance, TITLE); wc.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH) GetStockObject(GRAY_BRUSH); wc.lpszMenuName = TITLE; wc.lpszClassName = TITLE; if (!RegisterClass(&wc)) return FALSE; } widget.core.hInstance = hInstance; hWnd = CreateWindow(TITLE, TITLE, WS_OVERLAPPEDWINDOW, (signed) CW_USEDEFAULT, (signed) CW_USEDEFAULT, (signed) CW_USEDEFAULT, (signed) CW_USEDEFAULT, HWND_DESKTOP, (HMENU) NULL, hInstance, (void *) NULL); if (!hWnd) return FALSE; hAccel = (HACCEL) LoadAccelerators(hInstance, TITLE); (void) ShowWindow(hWnd, numCmdShow); (void) UpdateWindow(hWnd); while (GetMessage(&msg, (HWND) NULL, 0, 0)) { if (!TranslateAccelerator(hWnd, hAccel, &msg)) { (void) TranslateMessage(&msg); (void) DispatchMessage(&msg); } } return (msg.wParam); } #else #include "xwin.h" #include #include #ifdef HAVE_MOTIF #include #include #include #include #include #include #include #include #include #include #include #ifdef MOUSEBITMAPS #include "pixmaps/mouse-l.xbm" #include "pixmaps/mouse-r.xbm" #endif #endif #include "Abacus.h" #ifdef HAVE_XPM #include #include "pixmaps/abacus.t.xpm" #include "pixmaps/abacus.p.xpm" #include "pixmaps/abacus.s.xpm" #include "pixmaps/abacus.m.xpm" #include "pixmaps/abacus.l.xpm" #include "pixmaps/abacus.xpm" #define RESIZE_XPM(s) ((char **) ((s)<=32)?\ (((s)<=22)?(((s)<=16)?abacus_t_xpm:abacus_p_xpm):\ (((s)<=24)?abacus_s_xpm:abacus_m_xpm)):\ (((s)<=48)?abacus_l_xpm:abacus_xpm)) #endif #include "pixmaps/abacus.xbm" #define DEFINE_XBM (char *) abacus_bits, abacus_width, abacus_height #define FILENAMELEN 1024 #ifdef HAVE_MOTIF #define MAXRAILS 24 /* Totally arbitrary */ #define DEMO 0 #define NORMAL 1 #define BASE 2 #define COMPLEXITIES 3 #else /* Needs Motif */ #ifdef LEE_ABACUS #undef LEE_ABACUS #endif #define MAXDIGITS 256 /* This limits the number of rails */ #define TITLELEN (MAXDIGITS+FILENAMELEN+3) #endif #ifdef HAVE_MOTIF static Widget mainPanel, baseRowCol; static Widget sizeSlider, abacusBaseSlider, displayBaseSlider; static Widget complexityMenu, complexitySubMenu; static Widget formatMenu, formatSubMenu; static Widget complexityOptions[COMPLEXITIES], formatOptions[MAXMODES]; #ifdef LEE_ABACUS static Widget leftAuxAbacus = NULL, rightAuxAbacus = NULL; static Widget leftAuxTracker = NULL, rightAuxTracker = NULL; #endif #ifdef TOGGLES static Widget romanNumeralsSwitch, groupSwitch, signSwitch, pieceSwitch; static Widget piecePercentSwitch, anomalySwitch; #endif static Widget tracker; static Widget descriptionDialog, featuresDialog; static Widget optionsDialog, options1Dialog, options2Dialog, options3Dialog; static Widget referencesDialog, aboutDialog; static Widget clearDialog; static const char *complexityString[] = { "Demo", "Normal", "Base" }; static char *mathBuffer = NULL; static Boolean baseSet = False; static Arg arg[4]; #else static Widget shell = NULL; static char titleDsp[TITLELEN]; #endif static Pixmap pixmap = None; static char titleDspDemo[FILENAMELEN + 6]; static Widget topLevel, abacus, abacusDemo = NULL; static char *progDsp; static void Usage(char *programName) { unsigned int i; (void) fprintf(stderr, "usage: %s\n", programName); for (i = 0; i < strlen(optionsHelp); i++) { if (i == 0 || optionsHelp[i - 1] == '\n') (void) fprintf(stderr, "\t"); (void) fprintf(stderr, "%c", (optionsHelp[i])); } exit(1); } static XrmOptionDescRec options[] = { {(char *) "-mono", (char *) "*abacus.mono", XrmoptionNoArg, (char *) "TRUE"}, {(char *) "-nomono", (char *) "*abacus.mono", XrmoptionNoArg, (char *) "FALSE"}, {(char *) "-rv", (char *) "*abacus.reverseVideo", XrmoptionNoArg, (char *) "TRUE"}, {(char *) "-reverse", (char *) "*abacus.reverseVideo", XrmoptionNoArg, (char *) "TRUE"}, {(char *) "-norv", (char *) "*abacus.reverseVideo", XrmoptionNoArg, (char *) "FALSE"}, {(char *) "-noreverse", (char *) "*abacus.reverseVideo", XrmoptionNoArg, (char *) "FALSE"}, {(char *) "-foreground", (char *) "*abacus.Foreground", XrmoptionSepArg, NULL}, {(char *) "-fg", (char *) "*abacus.Foreground", XrmoptionSepArg, NULL}, {(char *) "-background", (char *) "*Background", XrmoptionSepArg, NULL}, {(char *) "-bg", (char *) "*Background", XrmoptionSepArg, NULL}, {(char *) "-frame", (char *) "*abacus.frameColor", XrmoptionSepArg, NULL}, {(char *) "-rail0", (char *) "*abacus.railColor0", XrmoptionSepArg, NULL}, {(char *) "-rail1", (char *) "*abacus.railColor1", XrmoptionSepArg, NULL}, {(char *) "-bead0", (char *) "*abacus.beadColor0", XrmoptionSepArg, NULL}, {(char *) "-bead1", (char *) "*abacus.beadColor1", XrmoptionSepArg, NULL}, {(char *) "-border", (char *) "*abacus.beadBorder", XrmoptionSepArg, NULL}, {(char *) "-bd", (char *) "*abacus.beadBorder", XrmoptionSepArg, NULL}, {(char *) "-delay", (char *) "*abacus.delay", XrmoptionSepArg, NULL}, {(char *) "-sound", (char *) "*abacus.sound", XrmoptionNoArg, (char *) "TRUE"}, {(char *) "-nosound", (char *) "*abacus.sound", XrmoptionNoArg, (char *) "FALSE"}, {(char *) "-bumpSound", (char *) "*abacus.bumpSound", XrmoptionSepArg, NULL}, {(char *) "-moveSound", (char *) "*abacus.moveSound", XrmoptionSepArg, NULL}, {(char *) "-demo", (char *) "*abacus.demo", XrmoptionNoArg, (char *) "TRUE"}, {(char *) "-nodemo", (char *) "*abacus.demo", XrmoptionNoArg, (char *) "FALSE"}, {(char *) "-script", (char *) "*abacus.script", XrmoptionNoArg, (char *) "TRUE"}, {(char *) "-noscript", (char *) "*abacus.script", XrmoptionNoArg, (char *) "FALSE"}, {(char *) "-demopath", (char *) "*abacus.demoPath", XrmoptionSepArg, NULL}, {(char *) "-demofont", (char *) "*abacus.demoFont", XrmoptionSepArg, NULL}, {(char *) "-demofn", (char *) "*abacus.demoFont", XrmoptionSepArg, NULL}, {(char *) "-demoforeground", (char *) "*abacus.demoForeground", XrmoptionSepArg, NULL}, {(char *) "-demofg", (char *) "*abacus.demoForeground", XrmoptionSepArg, NULL}, {(char *) "-demobackground", (char *) "*abacus.demoBackground", XrmoptionSepArg, NULL}, {(char *) "-demobg", (char *) "*abacus.demoBackground", XrmoptionSepArg, NULL}, {(char *) "-lee", (char *) "*abacus.lee", XrmoptionNoArg, (char *) "TRUE"}, {(char *) "-nolee", (char *) "*abacus.lee", XrmoptionNoArg, (char *) "FALSE"}, {(char *) "-vertical", (char *) "*abacus.vertical", XrmoptionNoArg, (char *) "TRUE"}, {(char *) "-novertical", (char *) "*abacus.vertical", XrmoptionNoArg, (char *) "FALSE"}, {(char *) "-colorScheme", (char *) "*abacus.colorScheme", XrmoptionSepArg, NULL}, {(char *) "-slot", (char *) "*abacus.slot", XrmoptionNoArg, (char *) "TRUE"}, {(char *) "-noslot", (char *) "*abacus.slot", XrmoptionNoArg, (char *) "FALSE"}, {(char *) "-diamond", (char *) "*abacus.diamond", XrmoptionNoArg, (char *) "TRUE"}, {(char *) "-nodiamond", (char *) "*abacus.diamond", XrmoptionNoArg, (char *) "FALSE"}, {(char *) "-railIndex", (char *) "*abacus.railIndex", XrmoptionSepArg, NULL}, {(char *) "-torient", (char *) "*abacus.topOrient", XrmoptionNoArg, (char *) "TRUE"}, {(char *) "-notorient", (char *) "*abacus.topOrient", XrmoptionNoArg, (char *) "FALSE"}, {(char *) "-borient", (char *) "*abacus.bottomOrient", XrmoptionNoArg, (char *) "TRUE"}, {(char *) "-noborient", (char *) "*abacus.bottomOrient", XrmoptionNoArg, (char *) "FALSE"}, {(char *) "-tnumber", (char *) "*abacus.topNumber", XrmoptionSepArg, NULL}, {(char *) "-bnumber", (char *) "*abacus.bottomNumber", XrmoptionSepArg, NULL}, {(char *) "-tfactor", (char *) "*abacus.topFactor", XrmoptionSepArg, NULL}, {(char *) "-bfactor", (char *) "*abacus.bottomFactor", XrmoptionSepArg, NULL}, {(char *) "-tspaces", (char *) "*abacus.topSpaces", XrmoptionSepArg, NULL}, {(char *) "-bspaces", (char *) "*abacus.bottomSpaces", XrmoptionSepArg, NULL}, {(char *) "-tpiece", (char *) "*abacus.topPiece", XrmoptionSepArg, NULL}, {(char *) "-bpiece", (char *) "*abacus.bottomPiece", XrmoptionSepArg, NULL}, {(char *) "-tpiecePercent", (char *) "*abacus.topPiecePercent", XrmoptionSepArg, NULL}, {(char *) "-bpiecePercent", (char *) "*abacus.bottomPiecePercent", XrmoptionSepArg, NULL}, {(char *) "-shiftPercent", (char *) "*abacus.shiftPercent", XrmoptionSepArg, NULL}, {(char *) "-subdeck", (char *) "*abacus.subdeck", XrmoptionSepArg, NULL}, {(char *) "-subbead", (char *) "*abacus.subbead", XrmoptionSepArg, NULL}, {(char *) "-sign", (char *) "*abacus.sign", XrmoptionNoArg, (char *) "TRUE"}, {(char *) "-nosign", (char *) "*abacus.sign", XrmoptionNoArg, (char *) "FALSE"}, {(char *) "-decimalPosition", (char *) "*abacus.decimalPosition", XrmoptionSepArg, NULL}, {(char *) "-groupSize", (char *) "*abacus.groupSize", XrmoptionSepArg, NULL}, {(char *) "-rails", (char *) "*abacus.rails", XrmoptionSepArg, NULL}, {(char *) "-base", (char *) "*abacus.base", XrmoptionSepArg, NULL}, {(char *) "-anomaly", (char *) "*abacus.anomaly", XrmoptionSepArg, NULL}, {(char *) "-shiftAnomaly", (char *) "*abacus.shiftAnomaly", XrmoptionSepArg, NULL}, {(char *) "-anomalySq", (char *) "*abacus.anomalySq", XrmoptionSepArg, NULL}, {(char *) "-shiftAnomalySq", (char *) "*abacus.shiftAnomalySq", XrmoptionSepArg, NULL}, {(char *) "-displayBase", (char *) "*abacus.displayBase", XrmoptionSepArg, NULL}, {(char *) "-romanNumerals", (char *) "*abacus.romanNumerals", XrmoptionNoArg, (char *) "TRUE"}, {(char *) "-noromanNumerals", (char *) "*abacus.romanNumerals", XrmoptionNoArg, (char *) "FALSE"}, {(char *) "-group", (char *) "*abacus.group", XrmoptionNoArg, (char *) "TRUE"}, {(char *) "-nogroup", (char *) "*abacus.group", XrmoptionNoArg, (char *) "FALSE"}, {(char *) "-chinese", (char *) "*abacus.format", XrmoptionNoArg, (char *) "chinese"}, {(char *) "-japanese", (char *) "*abacus.format", XrmoptionNoArg, (char *) "japanese"}, {(char *) "-korean", (char *) "*abacus.format", XrmoptionNoArg, (char *) "korean"}, {(char *) "-roman", (char *) "*abacus.format", XrmoptionNoArg, (char *) "roman"}, {(char *) "-russian", (char *) "*abacus.format", XrmoptionNoArg, (char *) "russian"}, {(char *) "-danish", (char *) "*abacus.format", XrmoptionNoArg, (char *) "danish"}, {(char *) "-other", (char *) "*abacus.format", XrmoptionNoArg, (char *) "other"}, {(char *) "-it", (char *) "*abacus.museum", XrmoptionNoArg, (char *) "it"}, {(char *) "-uk", (char *) "*abacus.museum", XrmoptionNoArg, (char *) "uk"}, {(char *) "-fr", (char *) "*abacus.museum", XrmoptionNoArg, (char *) "fr"}, {(char *) "-version", (char *) "*abacus.versionOnly", XrmoptionNoArg, (char *) "TRUE"} }; static void PrintState(Widget w, char *msg #ifndef HAVE_MOTIF , int mode #endif ) { #ifdef HAVE_MOTIF XtVaSetValues(w, XmNvalue, msg, NULL); #else (void) sprintf(titleDsp, "%s %s %s", msg, (mode < 0 || mode >= MAXFORMATS) ? "" : formatString[mode], progDsp); XtVaSetValues(w, XtNtitle, titleDsp, NULL); #endif } /* There's probably a better way to assure that they are the same but I do * not know it off hand. */ static void InitializeDemo(void) { int mode; Boolean mono, reverse; Pixel demoForeground, demoBackground; String demoPath, demoFont; XtVaGetValues(abacus, XtNmono, &mono, XtNreverseVideo, &reverse, XtNmode, &mode, XtNdemoForeground, &demoForeground, XtNdemoBackground, &demoBackground, XtNdemoPath, &demoPath, XtNdemoFont, &demoFont, NULL); XtVaSetValues(abacusDemo, XtNmono, mono, XtNreverseVideo, reverse, XtNmode, mode, XtNdemoForeground, demoForeground, XtNdemoBackground, demoBackground, XtNdemoPath, demoPath, XtNdemoFont, demoFont, XtNframed, True, NULL); } #ifdef LEE_ABACUS #define AUXWIN(n) (n == LEFTAUX) ? ((leftAuxAbacus) ? leftAuxAbacus : abacus) : ((n == RIGHTAUX ) ? ((rightAuxAbacus) ? rightAuxAbacus : abacus) : abacus) #else #define AUXWIN(n) abacus #endif static void CallbackAbacusDemo(Widget w, caddr_t clientData, abacusCallbackStruct *callData) { #ifndef HAVE_MOTIF int mode; XtVaGetValues(w, XtNmode, &mode, NULL); #endif switch (callData->reason) { case ACTION_BASE_DEFAULT: #ifdef HAVE_MOTIF XmScaleSetValue(abacusBaseSlider, DEFAULTBASE); #endif break; case ACTION_HIDE: (void) XIconifyWindow(XtDisplay(topLevel), XtWindow(topLevel), XScreenNumberOfScreen(XtScreen(topLevel))); #ifndef HAVE_MOTIF (void) XIconifyWindow(XtDisplay(shell), XtWindow(shell), XScreenNumberOfScreen(XtScreen(shell))); #endif break; case ACTION_MOVE: #ifndef LEE_ABACUS if (callData->aux == PRIMARY) #endif { XtVaSetValues(AUXWIN(callData->aux), XtNdeck, callData->deck, XtNrail, callData->rail, XtNnumber, callData->number, NULL); } break; case ACTION_CLEAR: XtVaSetValues(abacus, XtNdeck, CLEAR_DECK, NULL); #ifdef LEE_ABACUS /* Abacus demo clear is more complete */ if (leftAuxAbacus) XtVaSetValues(leftAuxAbacus, XtNdeck, CLEAR_DECK, NULL); if (rightAuxAbacus) XtVaSetValues(rightAuxAbacus, XtNdeck, CLEAR_DECK, NULL); #endif break; case ACTION_DEMO: XtDestroyWidget(abacusDemo); #ifndef HAVE_MOTIF XtDestroyWidget(shell); #endif XtVaSetValues(abacus, XtNdemo, False, NULL); #ifdef LEE_ABACUS if (leftAuxAbacus) XtVaSetValues(leftAuxAbacus, XtNdemo, False, NULL); if (rightAuxAbacus) XtVaSetValues(rightAuxAbacus, XtNdemo, False, NULL); #endif break; } if (callData->reason == ACTION_SCRIPT || callData->reason == ACTION_IGNORE) { #ifdef HAVE_MOTIF #ifdef LEE_ABACUS if (leftAuxTracker && leftAuxAbacus && w == leftAuxAbacus) PrintState(leftAuxTracker, callData->buffer); else if (rightAuxTracker && rightAuxAbacus && w == rightAuxAbacus) PrintState(rightAuxTracker, callData->buffer); else #endif PrintState(tracker, callData->buffer); #else PrintState(XtParent(w), callData->buffer, mode); #endif } } static void forceNormalParams(Widget w) { int base = DEFAULTBASE; int displayBase = DEFAULTBASE; #ifdef HAVE_MOTIF if (baseSet) { XmScaleSetValue(displayBaseSlider, displayBase); XmScaleSetValue(abacusBaseSlider, base); } #endif XtVaSetValues(abacus, XtNbase, base, XtNdisplayBase, displayBase, NULL); } static void forceDemoParams(Widget w) { int rails, min, mode; int bottomPiece, bottomPiecePercent, shiftPercent; Boolean demo, sign; forceNormalParams(w); XtVaGetValues(abacus, XtNmode, &mode, XtNrails, &rails, XtNsign, &sign, XtNbottomPiece, &bottomPiece, XtNbottomPiecePercent, &bottomPiecePercent, XtNshiftPercent, &shiftPercent, XtNdemo, &demo, NULL); if (mode == OTHER) { mode = CHINESE; XtVaSetValues(abacus, XtNmode, mode, NULL); #ifdef HAVE_MOTIF XtVaSetValues(formatMenu, XmNmenuHistory, formatOptions[mode], NULL); #endif } min = ((sign) ? 1: 0) + ((bottomPiece != 0) ? 1 : 0) + ((bottomPiecePercent != 0) ? 1 + shiftPercent : 0) + ((demo) ? MINDEMORAILS : MINRAILS); if (rails < min) { #ifdef HAVE_MOTIF XmScaleSetValue(sizeSlider, min); #endif XtVaSetValues(abacus, XtNrails, min, NULL); } } static void Initialize(Widget w) { Boolean versionOnly; XtVaGetValues(w, XtNversionOnly, &versionOnly, NULL); if (versionOnly) { (void) printf(aboutHelp); exit(0); } } static void createDemo(void) { (void) sprintf(titleDspDemo, "%s-demo", progDsp); #ifdef HAVE_MOTIF abacusDemo = XtCreateManagedWidget(titleDspDemo, abacusDemoWidgetClass, mainPanel, NULL, 0); XtAddCallback(abacusDemo, XtNselectCallback, (XtCallbackProc) CallbackAbacusDemo, (XtPointer) NULL); #else shell = XtCreateApplicationShell(titleDsp, topLevelShellWidgetClass, NULL, 0); XtVaSetValues(shell, XtNiconPixmap, pixmap, XtNinput, True, XtNtitle, titleDspDemo, NULL); abacusDemo = XtCreateManagedWidget("abacus", abacusDemoWidgetClass, shell, NULL, 0); XtAddCallback(abacusDemo, XtNselectCallback, (XtCallbackProc) CallbackAbacusDemo, (XtPointer) NULL); #endif InitializeDemo(); #ifndef HAVE_MOTIF XtRealizeWidget(shell); #endif VOID XGrabButton(XtDisplay(abacusDemo), (unsigned int) AnyButton, AnyModifier, XtWindow(abacusDemo), TRUE, (unsigned int) (ButtonPressMask | ButtonMotionMask | ButtonReleaseMask), GrabModeAsync, GrabModeAsync, XtWindow(abacusDemo), XCreateFontCursor(XtDisplay(abacusDemo), XC_hand2)); } static void CallbackAbacus(Widget w, caddr_t clientData, abacusCallbackStruct *callData) { int rails, mode; Boolean romanNumerals, group, sign, demo; int topPiece, bottomPiece, topPiecePercent, bottomPiecePercent; int subdeck, anomaly, anomalySq; XtVaGetValues(w, XtNdemo, &demo, XtNmode, &mode, NULL); switch (callData->reason) { case ACTION_HIDE: (void) XIconifyWindow(XtDisplay(topLevel), XtWindow(topLevel), XScreenNumberOfScreen(XtScreen(topLevel))); #ifndef HAVE_MOTIF if (demo) (void) XIconifyWindow(XtDisplay(shell), XtWindow(shell), XScreenNumberOfScreen(XtScreen(shell))); #endif break; case ACTION_CLEAR_QUERY: #ifdef HAVE_MOTIF XtManageChild(clearDialog); #else XtVaSetValues(w, XtNmenu, ACTION_CLEAR, NULL); #endif break; case ACTION_SCRIPT: (void) printf("%d %d %d %d 4\n", callData->aux, callData->deck, callData->rail, callData->number); (void) printf( "Lesson\n\n\nPress Space-bar to Continue\n"); break; case ACTION_MOVE: #ifndef LEE_ABACUS if (callData->aux == PRIMARY) #endif { XtVaSetValues(AUXWIN(callData->aux), XtNdeck, callData->deck, XtNrail, callData->rail, XtNnumber, callData->number, NULL); } break; case ACTION_CLEAR: XtVaSetValues(abacusDemo, XtNdeck, CLEAR_DECK, NULL); break; case ACTION_DEMO: demo = !demo; if (demo) { forceDemoParams(abacus); createDemo(); } else { XtDestroyWidget(abacusDemo); #ifndef HAVE_MOTIF XtDestroyWidget(shell); #endif } XtVaSetValues(abacus, XtNdemo, demo, NULL); #ifdef LEE_ABACUS if (leftAuxAbacus) XtVaSetValues(leftAuxAbacus, XtNdemo, demo, NULL); if (rightAuxAbacus) XtVaSetValues(rightAuxAbacus, XtNdemo, demo, NULL); #endif break; case ACTION_NEXT: XtVaSetValues(abacusDemo, XtNdeck, NEXT_DECK, NULL); break; case ACTION_REPEAT: XtVaSetValues(abacusDemo, XtNdeck, REPEAT_DECK, NULL); break; case ACTION_JUMP: XtVaSetValues(abacusDemo, XtNdeck, JUMP_DECK, NULL); break; case ACTION_MORE: XtVaSetValues(abacusDemo, XtNdeck, MORE_DECK, NULL); break; case ACTION_INCREMENT: if (w == abacus) { XtVaGetValues(w, XtNrails, &rails, NULL); #ifdef HAVE_MOTIF if (rails > MAXRAILS) XtVaSetValues(sizeSlider, XmNmaximum, rails, NULL); XmScaleSetValue(sizeSlider, rails); #endif } break; case ACTION_DECREMENT: if (w == abacus) { XtVaGetValues(w, XtNrails, &rails, NULL); #ifdef HAVE_MOTIF XmScaleSetValue(sizeSlider, rails); if (rails >= MAXRAILS) XtVaSetValues(sizeSlider, XmNmaximum, rails, NULL); #endif } break; case ACTION_FORMAT: if (w == abacus) { #ifdef HAVE_MOTIF XtVaSetValues(formatMenu, XmNmenuHistory, formatOptions[mode], NULL); #endif if (demo) { XtVaSetValues(abacusDemo, XtNdeck, CLEAR_DECK, XtNmode, mode, NULL); } } break; case ACTION_ROMANNUMERAL: XtVaGetValues(w, XtNromanNumerals, &romanNumerals, NULL); #ifdef HAVE_MOTIF #ifdef TOGGLES XmToggleButtonSetState(romanNumeralsSwitch, romanNumerals, False); #endif #endif break; case ACTION_GROUP: XtVaGetValues(w, XtNgroup, &group, NULL); #ifdef HAVE_MOTIF #ifdef TOGGLES XmToggleButtonSetState(groupSwitch, group, False); #endif #endif break; case ACTION_SIGN: XtVaGetValues(w, XtNsign, &sign, NULL); #ifdef HAVE_MOTIF #ifdef TOGGLES if (w == abacus) { XmToggleButtonSetState(signSwitch, sign, False); } #endif #endif break; case ACTION_QUARTER: XtVaGetValues(w, XtNbottomPiece, &bottomPiece, XtNtopPiece, &topPiece, NULL); #ifdef HAVE_MOTIF #ifdef TOGGLES if (w == abacus) { XmToggleButtonSetState(pieceSwitch, (bottomPiece == QUARTER), False); } #endif #endif break; case ACTION_QUARTERPERCENT: XtVaGetValues(w, XtNbottomPiecePercent, &bottomPiecePercent, XtNtopPiecePercent, &topPiecePercent, NULL); #ifdef HAVE_MOTIF #ifdef TOGGLES if (w == abacus) { XmToggleButtonSetState(piecePercentSwitch, (bottomPiecePercent == QUARTERPERCENT), False); } #endif #endif break; case ACTION_TWELFTH: XtVaGetValues(w, XtNtopPiece, &topPiece, XtNbottomPiece, &bottomPiece, NULL); #ifdef HAVE_MOTIF #ifdef TOGGLES if (w == abacus) { XmToggleButtonSetState(pieceSwitch, (topPiece * bottomPiece == TWELFTH), False); } #endif #endif break; case ACTION_SUBDECK: XtVaGetValues(w, XtNsubdeck, &subdeck, NULL); #ifdef HAVE_MOTIF #ifdef TOGGLES if (w == abacus) { XmToggleButtonSetState(subdeck, (subdeck == 3), False); } #endif #endif break; case ACTION_ANOMALY: XtVaGetValues(w, XtNanomaly, &anomaly, XtNanomalySq, &anomalySq, NULL); #ifdef HAVE_MOTIF #ifdef TOGGLES if (w == abacus) { XmToggleButtonSetState(anomalySwitch, (anomaly == 2 && anomalySq == 0), False); } #endif #endif break; case ACTION_WATCH: XtVaGetValues(w, XtNanomaly, &anomaly, XtNanomalySq, &anomalySq, NULL); #ifdef HAVE_MOTIF #ifdef TOGGLES if (w == abacus) { XmToggleButtonSetState(anomalySwitch, (anomaly == 4 && anomalySq == 4), False); } #endif #endif break; #if 0 case ACTION_VERTICAL: XtVaGetValues(w, XtNvertical, &vertical, NULL); #ifdef HAVE_MOTIF #ifdef TOGGLES if (w == abacus) { XmToggleButtonSetState(verticalSwitch, vertical, False); } #endif #endif break; #endif } if (callData->reason == ACTION_SCRIPT || callData->reason == ACTION_IGNORE) { #ifdef HAVE_MOTIF #ifdef LEE_ABACUS if (leftAuxTracker && leftAuxAbacus && w == leftAuxAbacus) PrintState(leftAuxTracker, callData->buffer); else if (rightAuxTracker && rightAuxAbacus && w == rightAuxAbacus) PrintState(rightAuxTracker, callData->buffer); else #endif PrintState(tracker, callData->buffer); #else PrintState(XtParent(w), callData->buffer, mode); #endif } } #ifdef HAVE_MOTIF static void CallbackAbacusMath(Widget w, caddr_t clientData, abacusCallbackStruct *callData) { Boolean demo; XtVaGetValues(abacus, XtNdemo, &demo, NULL); if (!demo) { unsigned int i, j = 0; if (mathBuffer) XtFree(mathBuffer); mathBuffer = XmTextGetString(w); /* strip out blanks */ for (i = 0; i < strlen(mathBuffer); i++) { if (mathBuffer[i] == '[' || mathBuffer[i] == ']') { mathBuffer[j] = '\0'; break; } else if (mathBuffer[i] != ' ' && mathBuffer[i] != '\t') { mathBuffer[j] = mathBuffer[i]; j++; } } /* check for math ops */ XtVaSetValues(abacus, XtNdeck, CALC_DECK, XtNmathBuffer, mathBuffer, NULL); } } static void CallbackAbacusClear(Widget w, XtPointer clientData, XmAnyCallbackStruct *cbs) { if (cbs->reason == XmCR_OK) { XtVaSetValues(abacus, XtNmenu, ACTION_CLEAR, NULL); } } static void RailSlider(Widget w, XtPointer clientData, XmScaleCallbackStruct *cbs) { int rails = cbs->value, old, min; int bottomPiece, bottomPiecePercent, shiftPercent; Boolean sign, demo; XtVaGetValues(abacus, XtNrails, &old, XtNsign, &sign, XtNbottomPiece, &bottomPiece, XtNbottomPiecePercent, &bottomPiecePercent, XtNshiftPercent, &shiftPercent, XtNdemo, &demo, NULL); min = ((sign) ? 1 : 0) + ((bottomPiece != 0) ? 1 : 0) + ((bottomPiecePercent != 0) ? 1 + shiftPercent : 0) + ((demo) ? MINDEMORAILS : MINRAILS); if (rails < min) { XmScaleSetValue(sizeSlider, old); } else if (old != rails) XtVaSetValues(abacus, XtNrails, rails, NULL); } static void AbacusBaseSlider(Widget w, XtPointer clientData, XmScaleCallbackStruct *cbs) { int base = cbs->value, old, bottomSpaces, mode; int bottomPiece, bottomPiecePercent; Boolean demo; XtVaGetValues(abacus, XtNbase, &old, XtNbottomPiece, &bottomPiece, XtNbottomPiecePercent, &bottomPiecePercent, XtNbottomSpaces, &bottomSpaces, XtNmode, &mode, XtNdemo, &demo, NULL); if (demo) { XmScaleSetValue(abacusBaseSlider, DEFAULTBASE); /* Odd bases produce round-off errors but OK */ /* When base divisible by 4, kind of silly but OK */ /* Well some of these have enough room in Russian but not others */ } else if ((base == 2 || base == 4) && bottomSpaces < 3) { XtVaSetValues(abacus, XtNbottomSpaces, 3, XtNbase, base, NULL); } else if ((base == 3 || base == 6 || base == 9) && bottomSpaces < 2) { XtVaSetValues(abacus, XtNbottomSpaces, 2, XtNbase, base, NULL); } else { XtVaSetValues(abacus, XtNbase, base, NULL); } } static void DisplayBaseSlider(Widget w, XtPointer clientData, XmScaleCallbackStruct *cbs) { int displayBase = cbs->value, old; Boolean demo; XtVaGetValues(abacus, XtNdisplayBase, &old, XtNdemo, &demo, NULL); if (demo) { XmScaleSetValue(displayBaseSlider, DEFAULTBASE); } else { XtVaSetValues(abacus, XtNdisplayBase, displayBase, NULL); } } #ifdef TOGGLES #if 0 static void VerticalToggle(Widget w, XtPointer clientData, XmToggleButtonCallbackStruct *cbs) { Boolean vertical = cbs->set; XtVaSetValues(abacus, XtNvertical, vertical, NULL); } #endif static void RomanNumeralToggle(Widget w, XtPointer clientData, XmToggleButtonCallbackStruct *cbs) { Boolean romanNumerals = cbs->set; XtVaSetValues(abacus, XtNromanNumerals, romanNumerals, NULL); } static void GroupToggle(Widget w, XtPointer clientData, XmToggleButtonCallbackStruct *cbs) { Boolean group = cbs->set; XtVaSetValues(abacus, XtNgroup, group, NULL); } static void SignToggle(Widget w, XtPointer clientData, XmToggleButtonCallbackStruct *cbs) { Boolean sign = cbs->set; XtVaSetValues(abacus, XtNsign, sign, NULL); } static void QuarterToggle(Widget w, XtPointer clientData, XmToggleButtonCallbackStruct *cbs) { Boolean quarter = cbs->set; XtVaSetValues(abacus, XtNtopPiece, 0, XtNbottomPiece, (quarter) ? QUARTERS : 0, NULL); } static void QuarterPercentToggle(Widget w, XtPointer clientData, XmToggleButtonCallbackStruct *cbs) { Boolean quarterPercent = cbs->set; XtVaSetValues(abacus, XtNtopPiecePercent, 0, XtNbottomPiecePercent, (quarterPercent) ? QUARTERPERCENTS : 0, NULL); } static void TwelfthToggle(Widget w, XtPointer clientData, XmToggleButtonCallbackStruct *cbs) { Boolean twelfth = cbs->set; XtVaSetValues(abacus, XtNtopPiece, 2, XtNbottomPiece, (twelfth) ? TWELFTH / 2 : 0, NULL); } static void SubdeckToggle(Widget w, XtPointer clientData, XmToggleButtonCallbackStruct *cbs) { Boolean subdeck = cbs->set; XtVaSetValues(abacus, XtNsubdeck, 3, NULL); } static void AnomalyToggle(Widget w, XtPointer clientData, XmToggleButtonCallbackStruct *cbs) { Boolean anomaly = cbs->set; XtVaSetValues(abacus, XtNanomaly, (watch) ? 2 : 0, XtNanomalySq, 0, NULL); } static void WatchToggle(Widget w, XtPointer clientData, XmToggleButtonCallbackStruct *cbs) { Boolean watch = cbs->set; XtVaSetValues(abacus, XtNanomaly, (watch) ? 4 : 0, XtNanomalySq, 4, NULL); } #endif static void createBase(int base, int displayBase) { baseRowCol = XtVaCreateManagedWidget("baseRowCol", xmRowColumnWidgetClass, mainPanel, XmNnumColumns, 1, XmNheight, 55, XmNorientation, XmHORIZONTAL, XmNpacking, XmPACK_COLUMN, NULL); abacusBaseSlider = XtVaCreateManagedWidget("abacusBase", xmScaleWidgetClass, baseRowCol, XtVaTypedArg, XmNtitleString, XmRString, "Abacus Base", 12, XmNminimum, MINBASE, XmNmaximum, MAXBASE, XmNscaleWidth, (MAXBASE - MINBASE + 1) * 3, XmNvalue, base, XmNshowValue, True, XmNorientation, XmHORIZONTAL, NULL); XtAddCallback(abacusBaseSlider, XmNvalueChangedCallback, (XtCallbackProc) AbacusBaseSlider, (XtPointer) NULL); displayBaseSlider = XtVaCreateManagedWidget("displayBase", xmScaleWidgetClass, baseRowCol, XtVaTypedArg, XmNtitleString, XmRString, "Display Base", 13, XmNminimum, MINBASE, XmNmaximum, MAXBASE, XmNscaleWidth, (MAXBASE - MINBASE + 1) * 3, XmNvalue, displayBase, XmNshowValue, True, XmNorientation, XmHORIZONTAL, NULL); XtAddCallback(displayBaseSlider, XmNvalueChangedCallback, (XtCallbackProc) DisplayBaseSlider, (XtPointer) NULL); } static void destroyBase(void) { XtDestroyWidget(displayBaseSlider); XtDestroyWidget(abacusBaseSlider); XtDestroyWidget(baseRowCol); } static void complexityCB(Widget w, void *value, void *clientData) { Boolean wasDemo; int val = (int) value; XtVaGetValues(abacus, XtNdemo, &wasDemo, NULL); if (wasDemo && val == DEMO) { return; } if (val == DEMO) { if (baseSet) { forceNormalParams(abacus); baseSet = False; destroyBase(); } forceDemoParams(abacus); XtVaSetValues(abacus, XtNdemo, !wasDemo, NULL); createDemo(); } else { if (wasDemo) { XtVaSetValues(abacus, XtNdemo, !wasDemo, NULL); XtDestroyWidget(abacusDemo); } if (val == BASE) { if (baseSet) return; baseSet = True; createBase(DEFAULTBASE, DEFAULTBASE); } else if (baseSet) { forceNormalParams(abacus); baseSet = False; destroyBase(); } } } static void formatCB(Widget w, void *value, void *clientData) { Boolean demo; int mode = (int) value, oldMode; XtVaGetValues(abacus, XtNmode, &oldMode, XtNdemo, &demo, NULL); if (mode < 0 || mode > MAXFORMATS) mode = OTHER; if (demo && mode == OTHER) { XtVaSetValues(formatMenu, XmNmenuHistory, formatOptions[oldMode], NULL); return; } XtVaSetValues(abacus, XtNmode, mode, NULL); if (demo) { XtVaSetValues(abacusDemo, XtNdeck, CLEAR_DECK, XtNmode, mode, NULL); } } static void fileCB(Widget w, void *value, void *clientData) { int val = (int) value; if (val == ACTION_EXIT) exit(0); XtVaSetValues(abacus, XtNmenu, val, NULL); /* Q */ } static void controlsCB(Widget w, void *value, void *clientData) { int val = (int) value - 1; XtVaSetValues(abacus, XtNmenu, val + ACTION_CLEAR, NULL); } static Widget createQuery(Widget w, char *text, char *title, XtCallbackProc callback) { Widget button, messageBox; char titleDsp[FILENAMELEN + 8]; XmString titleString = NULL, messageString = NULL; static XmStringCharSet charSet = (XmStringCharSet) XmSTRING_DEFAULT_CHARSET; messageString = XmStringCreateLtoR(text, charSet); (void) sprintf(titleDsp, "%s: %s\n", progDsp, title); titleString = XmStringCreateSimple((char *) titleDsp); XtSetArg(arg[0], XmNdialogTitle, titleString); XtSetArg(arg[1], XmNmessageString, messageString); messageBox = XmCreateWarningDialog(w, (char *) "queryBox", arg, 2); button = XmMessageBoxGetChild(messageBox, XmDIALOG_HELP_BUTTON); XtUnmanageChild(button); XmStringFree(titleString); XmStringFree(messageString); XtAddCallback(messageBox, XmNokCallback, (XtCallbackProc) CallbackAbacusClear, (XtPointer) NULL); XtAddCallback(messageBox, XmNcancelCallback, (XtCallbackProc) CallbackAbacusClear, (XtPointer) NULL); return messageBox; } static Widget createHelp(Widget w, char *text, char *title) { Widget button, messageBox; char titleDsp[FILENAMELEN + 8]; XmString titleString = NULL, messageString = NULL, buttonString = NULL; static XmStringCharSet charSet = (XmStringCharSet) XmSTRING_DEFAULT_CHARSET; messageString = XmStringCreateLtoR(text, charSet); (void) sprintf(titleDsp, "%s: %s\n", progDsp, title); titleString = XmStringCreateSimple((char *) titleDsp); buttonString = XmStringCreateSimple((char *) "OK"); XtSetArg(arg[0], XmNdialogTitle, titleString); XtSetArg(arg[1], XmNokLabelString, buttonString); XtSetArg(arg[2], XmNmessageString, messageString); messageBox = XmCreateInformationDialog(w, (char *) "helpBox", arg, 3); button = XmMessageBoxGetChild(messageBox, XmDIALOG_CANCEL_BUTTON); XtUnmanageChild(button); button = XmMessageBoxGetChild(messageBox, XmDIALOG_HELP_BUTTON); XtUnmanageChild(button); XmStringFree(titleString); XmStringFree(buttonString); XmStringFree(messageString); return messageBox; } static void helpCB(Widget w, XtPointer value, XtPointer clientData) { int val = (int) value; switch (val) { case 0: XtManageChild(descriptionDialog); break; case 1: XtManageChild(featuresDialog); break; case 2: XtManageChild(optionsDialog); break; case 3: XtManageChild(options1Dialog); break; case 4: XtManageChild(options2Dialog); break; case 5: XtManageChild(options3Dialog); break; case 6: XtManageChild(referencesDialog); break; case 7: XtManageChild(aboutDialog); break; default: { char *buf; intCat(&buf, "helpCB: %d", val); XtWarning(buf); free(buf); } } } #endif int main(int argc, char **argv) { Boolean demo; int pixmapSize; #ifdef HAVE_MOTIF int base = DEFAULTBASE, displayBase = DEFAULTBASE; Widget menuBar, pullDownMenu, widget; Widget menuBarPanel, controlPanel; Widget controlRowCol, trackerRowCol; Widget auxForm; #ifdef LEE_ABACUS Widget auxTrackerRowCol; XColor exactDef; Boolean lee; int leftAuxRails, rightAuxRails; #endif #ifdef TOGGLES Widget toggleRowCol; #endif XmString fileString, controlsString; XmString quitString, clearString, incrementString, decrementString; XmString romanNumeralsString, groupString, signString; XmString quarterString, quarterPercentString; XmString twelfthString, subdeckString; XmString anomalyString, watchString; XmString speedString, slowString, soundString; XmString complexity, complexityStrings[COMPLEXITIES]; XmString format, formatStrings[MAXMODES], museum; int rails, mode; int bottomPiece, bottomPiecePercent, anomaly; Boolean romanNumerals, group, sign; unsigned int i; #endif progDsp = argv[0]; #ifndef HAVE_MOTIF (void) sprintf(titleDsp, "%s %s", "0", progDsp); #endif topLevel = XtInitialize(argv[0], "Abacus", options, XtNumber(options), &argc, argv); if (argc != 1) Usage(argv[0]); #ifdef HAVE_MOTIF menuBarPanel = XtVaCreateManagedWidget("menuBarPanel", xmPanedWindowWidgetClass, topLevel, XmNseparatorOn, False, XmNsashWidth, 1, XmNsashHeight, 1, NULL); fileString = XmStringCreateSimple((char *) "File"); controlsString = XmStringCreateSimple((char *) "Controls"); menuBar = XmVaCreateSimpleMenuBar(menuBarPanel, (char *) "menuBar", XmVaCASCADEBUTTON, fileString, 'F', XmVaCASCADEBUTTON, controlsString, 'C', NULL); XmStringFree(fileString); XmStringFree(controlsString); quitString = XmStringCreateSimple((char *) "Quit"); (void) XmVaCreateSimplePulldownMenu(menuBar, (char *) "fileMenu", 0, fileCB, XmVaSEPARATOR, XmVaPUSHBUTTON, quitString, 'Q', NULL, NULL, NULL); XmStringFree(quitString); clearString = XmStringCreateSimple((char *) "Clear"); incrementString = XmStringCreateSimple((char *) "Increment"); decrementString = XmStringCreateSimple((char *) "Decrement"); format = XmStringCreateSimple((char *) "Format"); museum = XmStringCreateSimple((char *) "MusEum"); romanNumeralsString = XmStringCreateSimple((char *) "RoMan Numerals"); groupString = XmStringCreateSimple((char *) "Group"); signString = XmStringCreateSimple((char *) "Sign"); quarterString = XmStringCreateSimple((char *) "QUarter"); quarterPercentString = XmStringCreateSimple((char *) "Quarter Percent"); twelfthString = XmStringCreateSimple((char *) "Twelfth"); subdeckString = XmStringCreateSimple((char *) "SuBdeck"); anomalyString = XmStringCreateSimple((char *) "AnomaLy"); watchString = XmStringCreateSimple((char *) "Watch"); speedString = XmStringCreateSimple((char *) ">Speed"); slowString = XmStringCreateSimple((char *) "', NULL, NULL, XmVaPUSHBUTTON, slowString, '<', NULL, NULL, XmVaPUSHBUTTON, soundString, '@', NULL, NULL, NULL); XmStringFree(clearString); XmStringFree(incrementString); XmStringFree(decrementString); XmStringFree(format); XmStringFree(museum); XmStringFree(romanNumeralsString); XmStringFree(groupString); XmStringFree(signString); XmStringFree(quarterString); XmStringFree(quarterPercentString); XmStringFree(twelfthString); XmStringFree(subdeckString); XmStringFree(anomalyString); XmStringFree(watchString); XmStringFree(speedString); XmStringFree(slowString); XmStringFree(soundString); pullDownMenu = XmCreatePulldownMenu(menuBar, (char *) "helpPullDown", NULL, 0); widget = XtVaCreateManagedWidget("Help", xmCascadeButtonWidgetClass, menuBar, XmNsubMenuId, pullDownMenu, XmNmnemonic, 'H', NULL); XtVaSetValues(menuBar, XmNmenuHelpWidget, widget, NULL); widget = XtVaCreateManagedWidget("Description", xmPushButtonGadgetClass, pullDownMenu, XmNmnemonic, 'D', NULL); XtAddCallback(widget, XmNactivateCallback, helpCB, (char *) 0); widget = XtVaCreateManagedWidget("Features", xmPushButtonGadgetClass, pullDownMenu, XmNmnemonic, 'F', NULL); XtAddCallback(widget, XmNactivateCallback, helpCB, (char *) 1); widget = XtVaCreateManagedWidget("Options", xmPushButtonGadgetClass, pullDownMenu, XmNmnemonic, 'O', NULL); XtAddCallback(widget, XmNactivateCallback, helpCB, (char *) 2); widget = XtVaCreateManagedWidget("Options1", xmPushButtonGadgetClass, pullDownMenu, XmNmnemonic, '1', NULL); XtAddCallback(widget, XmNactivateCallback, helpCB, (char *) 3); widget = XtVaCreateManagedWidget("Options2", xmPushButtonGadgetClass, pullDownMenu, XmNmnemonic, '2', NULL); XtAddCallback(widget, XmNactivateCallback, helpCB, (char *) 4); widget = XtVaCreateManagedWidget("Options3", xmPushButtonGadgetClass, pullDownMenu, XmNmnemonic, '3', NULL); XtAddCallback(widget, XmNactivateCallback, helpCB, (char *) 5); widget = XtVaCreateManagedWidget("References", xmPushButtonGadgetClass, pullDownMenu, XmNmnemonic, 'R', NULL); XtAddCallback(widget, XmNactivateCallback, helpCB, (char *) 6); widget = XtVaCreateManagedWidget("About", xmPushButtonGadgetClass, pullDownMenu, XmNmnemonic, 'A', NULL); XtAddCallback(widget, XmNactivateCallback, helpCB, (char *) 7); XtManageChild(menuBar); descriptionDialog = createHelp(menuBar, (char *) descriptionHelp, (char *) "Description"); featuresDialog = createHelp(menuBar, (char *) featuresHelp, (char *) "Features"); optionsDialog = createHelp(menuBar, (char *) optionsHelp, (char *) "Options"); options1Dialog = createHelp(menuBar, (char *) options1Help, (char *) "Options1"); options2Dialog = createHelp(menuBar, (char *) options2Help, (char *) "Options2"); options3Dialog = createHelp(menuBar, (char *) options3Help, (char *) "Options3"); referencesDialog = createHelp(menuBar, (char *) referencesHelp, (char *) "References"); aboutDialog = createHelp(menuBar, (char *) aboutHelp, (char *) "About"); clearDialog = createQuery(topLevel, (char *) "Are you sure you want to destroy the calculation?", (char *) "Clear Query", (XtCallbackProc) CallbackAbacusClear); mainPanel = XtCreateManagedWidget("mainPanel", xmPanedWindowWidgetClass, menuBarPanel, NULL, 0); controlPanel = XtVaCreateManagedWidget("controlPanel", xmPanedWindowWidgetClass, mainPanel, XmNseparatorOn, False, XmNsashWidth, 1, XmNsashHeight, 1, NULL); #ifdef MOUSEBITMAPS { /* Takes up valuable real estate. */ Widget bitmapRowCol; Pixmap mouseLeftCursor, mouseRightCursor; Pixel fg, bg; bitmapRowCol = XtVaCreateManagedWidget("bitmapRowCol", xmRowColumnWidgetClass, controlPanel, XmNnumColumns, 4, XmNpacking, XmPACK_COLUMN, NULL); (void) XtVaGetValues(bitmapRowCol, XmNforeground, &fg, XmNbackground, &bg, NULL); mouseLeftCursor = XCreatePixmapFromBitmapData( XtDisplay(bitmapRowCol), RootWindowOfScreen(XtScreen(bitmapRowCol)), (char *) mouse_left_bits, mouse_left_width, mouse_left_height, fg, bg, DefaultDepthOfScreen(XtScreen(bitmapRowCol))); mouseRightCursor = XCreatePixmapFromBitmapData( XtDisplay(bitmapRowCol), RootWindowOfScreen(XtScreen(bitmapRowCol)), (char *) mouse_right_bits, mouse_right_width, mouse_right_height, fg, bg, DefaultDepthOfScreen(XtScreen(bitmapRowCol))); (void) XtVaCreateManagedWidget("mouseLeftText", xmLabelGadgetClass, bitmapRowCol, XtVaTypedArg, XmNlabelString, XmRString, "Move bead", 10, NULL); (void) XtVaCreateManagedWidget("mouseLeft", xmLabelGadgetClass, bitmapRowCol, XmNlabelType, XmPIXMAP, XmNlabelPixmap, mouseLeftCursor, NULL); (void) XtVaCreateManagedWidget("mouseRightText", xmLabelGadgetClass, bitmapRowCol, XtVaTypedArg, XmNlabelString, XmRString, " Clear", 10, NULL); (void) XtVaCreateManagedWidget("mouseRight", xmLabelGadgetClass, bitmapRowCol, XmNlabelType, XmPIXMAP, XmNlabelPixmap, mouseRightCursor, NULL); } #endif controlRowCol = XtVaCreateManagedWidget("controlRowCol", xmRowColumnWidgetClass, controlPanel, XmNnumColumns, 1, XmNorientation, XmHORIZONTAL, XmNpacking, XmPACK_COLUMN, NULL); #ifdef TOGGLES toggleRowCol = XtVaCreateManagedWidget("toggleRowCol", xmRowColumnWidgetClass, controlPanel, XmNorientation, XmHORIZONTAL, XmNpacking, XmPACK_COLUMN, NULL); #endif auxForm = XtVaCreateManagedWidget("auxForm", xmFormWidgetClass, mainPanel, NULL); /* abacusWidgetClass, mainPanel, */ abacus = XtVaCreateManagedWidget("abacus", #ifdef LEE_KO XtNformat, "Korean", #endif abacusWidgetClass, auxForm, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_POSITION, NULL); #ifdef LEE_ABACUS XtVaGetValues(abacus, XtNlee, &lee, XtNleftAuxRails, &leftAuxRails, XtNrightAuxRails, &rightAuxRails, NULL); if (lee) { XtVaSetValues(auxForm, XmNfractionBase, leftAuxRails + rightAuxRails, NULL); auxTrackerRowCol = XtVaCreateManagedWidget("auxTrackerRowCol", xmRowColumnWidgetClass, controlPanel, XmNorientation, XmHORIZONTAL, XmNnumColumns, 2, NULL); leftAuxTracker = XtVaCreateManagedWidget("0", xmTextWidgetClass, auxTrackerRowCol, NULL); rightAuxTracker = XtVaCreateManagedWidget("0", xmTextWidgetClass, auxTrackerRowCol, NULL); } #endif trackerRowCol = XtVaCreateManagedWidget("trackerRowCol", xmRowColumnWidgetClass, controlPanel, NULL); tracker = XtCreateManagedWidget("0", xmTextWidgetClass, trackerRowCol, NULL, 0); XtAddCallback(tracker, XmNactivateCallback, (XtCallbackProc) CallbackAbacusMath, (XtPointer) NULL); #ifdef LEE_ABACUS if (lee) { XtVaSetValues(abacus, XmNtopPosition, 5, NULL); } (void) XParseColor(XtDisplay(abacus), DefaultColormapOfScreen(XtScreen(abacus)), "LimeGreen", &exactDef); (void) XAllocColor(XtDisplay(abacus), DefaultColormapOfScreen(XtScreen(abacus)), &exactDef); if (lee) { leftAuxAbacus = XtVaCreateManagedWidget("leftAuxAbacus", abacusWidgetClass, auxForm, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_WIDGET, XmNrightAttachment, XmATTACH_POSITION, XmNbottomWidget, abacus, XtNformat, "Japanese", XtNaux, True, XtNbeadColor0, exactDef.pixel, XmNrightPosition, leftAuxRails, XtNrails, leftAuxRails, NULL); XtAddCallback(leftAuxAbacus, XtNselectCallback, (XtCallbackProc) CallbackAbacus, (XtPointer) NULL); (void) XParseColor(XtDisplay(abacus), DefaultColormapOfScreen(XtScreen(abacus)), "gainsboro", &exactDef); (void) XAllocColor(XtDisplay(abacus), DefaultColormapOfScreen(XtScreen(abacus)), &exactDef); rightAuxAbacus = XtVaCreateManagedWidget("rightAuxAbacus", abacusWidgetClass, auxForm, XmNtopAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, abacus, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, leftAuxAbacus, XtNformat, "Japanese", XtNaux, True, XtNbeadColor0, exactDef.pixel, XtNrails, rightAuxRails, NULL); XtAddCallback(rightAuxAbacus, XtNselectCallback, (XtCallbackProc) CallbackAbacus, (XtPointer) NULL); } #endif #else abacus = XtCreateManagedWidget("abacus", abacusWidgetClass, topLevel, NULL, 0); #endif XtVaGetValues(abacus, #ifdef HAVE_MOTIF XtNrails, &rails, XtNromanNumerals, &romanNumerals, XtNgroup, &group, XtNsign, &sign, XtNbottomPiece, &bottomPiece, XtNbottomPiecePercent, &bottomPiecePercent, XtNanomaly, &anomaly, XtNbase, &base, XtNdisplayBase, &displayBase, XtNmode, &mode, #endif XtNdemo, &demo, XtNpixmapSize, &pixmapSize, NULL); #ifdef HAVE_XPM { XpmAttributes xpmAttributes; XpmColorSymbol transparentColor[1] = {{NULL, (char *) "none", 0 }}; Pixel bg; xpmAttributes.valuemask = XpmColorSymbols | XpmCloseness; xpmAttributes.colorsymbols = transparentColor; xpmAttributes.numsymbols = 1; xpmAttributes.closeness = 40000; XtVaGetValues(topLevel, XtNbackground, &bg, NULL); transparentColor[0].pixel = bg; (void) XpmCreatePixmapFromData(XtDisplay(topLevel), RootWindowOfScreen(XtScreen(topLevel)), RESIZE_XPM(pixmapSize), &pixmap, NULL, &xpmAttributes); } if (pixmap == (Pixmap) NULL) #endif pixmap = XCreateBitmapFromData(XtDisplay(topLevel), RootWindowOfScreen(XtScreen(topLevel)), (char *) abacus_bits, abacus_width, abacus_height); XtVaSetValues(topLevel, #ifdef HAVE_MOTIF XmNkeyboardFocusPolicy, XmPOINTER, /* not XmEXPLICIT */ #else XtNinput, True, #endif XtNiconPixmap, pixmap, NULL); XtAddCallback(abacus, XtNselectCallback, (XtCallbackProc) CallbackAbacus, (XtPointer) NULL); #ifdef HAVE_MOTIF #ifdef TOGGLES { romanNumeralsSwitch = XtVaCreateManagedWidget("Roman", xmToggleButtonGadgetClass, toggleRowCol, NULL); XtAddCallback(romanNumeralsSwitch, XmNvalueChangedCallback, (XtCallbackProc) RomanNumeralToggle, (XtPointer) NULL); XmToggleButtonSetState(romanNumeralsSwitch, romanNumerals, False); groupSwitch = XtVaCreateManagedWidget("Group", xmToggleButtonGadgetClass, toggleRowCol, XmNset, FALSE, NULL); XtAddCallback(groupSwitch, XmNvalueChangedCallback, (XtCallbackProc) GroupToggle, (XtPointer) NULL); XmToggleButtonSetState(groupSwitch, group, False); signSwitch = XtVaCreateManagedWidget("Signed", xmToggleButtonGadgetClass, toggleRowCol, XmNset, FALSE, NULL); XtAddCallback(signSwitch, XmNvalueChangedCallback, (XtCallbackProc) SignToggle, (XtPointer) NULL); XmToggleButtonSetState(signSwitch, sign, False); pieceSwitch = XtVaCreateManagedWidget("Piece", xmToggleButtonGadgetClass, toggleRowCol, XmNset, FALSE, NULL); XtAddCallback(pieceSwitch, XmNvalueChangedCallback, (XtCallbackProc) QuarterToggle, (XtPointer) NULL); XmToggleButtonSetState(pieceSwitch, (bottomPiece != 0), False); piecePercentSwitch = XtVaCreateManagedWidget("PiecePercent", xmToggleButtonGadgetClass, toggleRowCol, XmNset, FALSE, NULL); XtAddCallback(piecePercentSwitch, XmNvalueChangedCallback, (XtCallbackProc) QuarterPercentToggle, (XtPointer) NULL); XmToggleButtonSetState(piecePercentSwitch, (bottomPiecePercent != 0), False); anomalySwitch = XtVaCreateManagedWidget("Anomaly", xmToggleButtonGadgetClass, toggleRowCol, XmNset, FALSE, NULL); XtAddCallback(anomalySwitch, XmNvalueChangedCallback, (XtCallbackProc) AnomalyToggle, (XtPointer) NULL); XmToggleButtonSetState(anomalySwitch, (anomaly != 0), False); #if 0 verticalSwitch= XtVaCreateManagedWidget("Vertical", xmToggleButtonGadgetClass, toggleRowCol, XmNset, FALSE, NULL); XtAddCallback(verticalSwitch, XmNvalueChangedCallback, (XtCallbackProc) VerticalToggle, (XtPointer) NULL); #endif } #endif sizeSlider = XtVaCreateManagedWidget("rails", xmScaleWidgetClass, controlRowCol, XtVaTypedArg, XmNtitleString, XmRString, "Abacus Size", 12, XmNminimum, MINRAILS, XmNmaximum, MAXRAILS, XmNscaleWidth, (MAXRAILS - MINRAILS + 1) * 4, XmNvalue, rails, XmNshowValue, True, XmNorientation, XmHORIZONTAL, NULL); XtAddCallback(sizeSlider, XmNvalueChangedCallback, (XtCallbackProc) RailSlider, (XtPointer) NULL); baseSet = ((base != DEFAULTBASE || displayBase != DEFAULTBASE) && !demo); if (mode < 0 || mode > MAXFORMATS) mode = OTHER; if (demo && mode == OTHER) mode = CHINESE; complexity = XmStringCreateSimple((char *) "Complexity:"); complexitySubMenu = XmCreatePulldownMenu(controlRowCol, (char *) "complexitySubMenu", NULL, 0); for (i = 0; i < COMPLEXITIES; i++) { complexityStrings[i] = XmStringCreateSimple((char *) complexityString[i]); XtSetArg(arg[0], XmNlabelString, complexityStrings[i]); XtSetArg(arg[1], XmNmnemonic, complexityString[i][0]); complexityOptions[i] = XmCreatePushButtonGadget(complexitySubMenu, (char *) complexityString[i], arg, 2); XtAddCallback(complexityOptions[i], XmNactivateCallback, complexityCB, (char *) i); } XtManageChildren(complexityOptions, COMPLEXITIES); XtSetArg(arg[0], XmNlabelString, complexity); XtSetArg(arg[1], XmNmnemonic, 'C'); XtSetArg(arg[2], XmNsubMenuId, complexitySubMenu); XtSetArg(arg[3], XmNmenuHistory, complexityOptions[((demo) ? 0 : ((baseSet) ? 2 : 1))]); complexityMenu = XmCreateOptionMenu(controlRowCol, (char *) "ComplexityMenu", arg, 4); for (i = 0; i < COMPLEXITIES; i++) XmStringFree(complexityStrings[i]); XmStringFree(complexity); XtManageChild(complexityMenu); format = XmStringCreateSimple((char *) "Format:"); formatSubMenu = XmCreatePulldownMenu(controlRowCol, (char *) "formatSubMenu", NULL, 0); for (i = 0; i < MAXMODES; i++) { formatStrings[i] = XmStringCreateSimple((char *) formatString[i]); XtSetArg(arg[0], XmNlabelString, formatStrings[i]); XtSetArg(arg[1], XmNmnemonic, formatString[i][0]); formatOptions[i] = XmCreatePushButtonGadget(formatSubMenu, (char *) formatString[i], arg, 2); XtAddCallback(formatOptions[i], XmNactivateCallback, formatCB, (char *) i); } XtManageChildren(formatOptions, MAXMODES); XtSetArg(arg[0], XmNlabelString, format); XtSetArg(arg[1], XmNmnemonic, 'F'); XtSetArg(arg[2], XmNsubMenuId, formatSubMenu); XtSetArg(arg[3], XmNmenuHistory, formatOptions[mode]); formatMenu = XmCreateOptionMenu(controlRowCol, (char *) "FormatMenu", arg, 4); for (i = 0; i < MAXMODES; i++) XmStringFree(formatStrings[i]); XmStringFree(format); XtManageChild(formatMenu); if (baseSet) { createBase(base, displayBase); } else { forceNormalParams(abacus); } #endif Initialize(abacus); if (demo) forceDemoParams(abacus); XtRealizeWidget(topLevel); VOID XGrabButton(XtDisplay(abacus), (unsigned int) AnyButton, AnyModifier, XtWindow(abacus), TRUE, (unsigned int) (ButtonPressMask | ButtonMotionMask | ButtonReleaseMask), GrabModeAsync, GrabModeAsync, XtWindow(abacus), XCreateFontCursor(XtDisplay(abacus), XC_crosshair)); if (demo) { createDemo(); } XtMainLoop(); #ifdef VMS return 1; #else return 0; #endif } #endif