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

xabacus.c

/*-
# MOTIF/X-BASED ABACUS
#
#  xabacus.c
#
###
#
#  Copyright (c) 1993 - 2005  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.
#
*/

/*-
  Version 7: 03/11/15 X/Windows
  Version 5: 95/09/30 Xt/Motif
  Version 4: 94/05/07 Xt
  Version 3: 93/02/03 Motif
  Version 2: 91/12/17 XView
  Version 1: 91/02/14 SunView
*/

#ifndef WINVER
static const char aboutHelp[] = {
      "Abacus Version 7.1.6\n"
      "Send bugs (reports or fixes) to the author: "
      "David Bagley <bagleyd@tux.org>\n"
      "The latest version is at: "
      "http://www.tux.org/~bagleyd/abacus.html\n"
      "Some coding was also done by Luis Fernandes <elf@ee.ryerson.ca>\n"
      "and Sarat Chandran <saratcmahadevan@yahoo.com>\n"
};

static const char optionsHelp[] = {
      "\t[-geometry [{width}][x{height}] [{+-}{xoff}[{+-}{yoff}]]]\n"
      "\t[-display [{host}]:[{vs}]] [-[no]mono] [-[no]{reverse|rv}]\n"
      "\t[-{foreground|fg} {color}] [-{background|bg} {color}]\n"
      "\t[-{border|bd} {color}] [-frame {color}] [-rail {color}]\n"
      "\t[-bead {color}] [-rails {int}] [-[no]slot] [-[no]diamond]\n"
      "\t[-{chinese|japanese|korean|roman|russian|other}]\n"
      "\t[-base {int}] [-displayBase {int}]\n"
      "\t[-no]romanNumerals] [-[no]sign] [-[no]quarter]\n"
      "\t[-tnumber {int}] [-bnumber {int}] [-tfactor {int}]\n"
      "\t[-bfactor {int}] [-tspaces {int}] [-bspaces {int}]\n"
      "\t[-[no]torient] [-[no]borient] [-delay msecs]\n"
      "\t[-[no]sound] [-bumpSound {filename}] [-moveSound {filename}]\n"
      "\t[-[no]demo] [-[no]script] [-demopath {path}]\n"
      "\t[-{demofont|demofn} {fontname}]\n"
      "\t[-{demoforeground|demofg} {color}]\n"
      "\t[-{demobackground|demobg} {color}] [-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 on a color screen "
      "as if monochrome (resource name \"mono\").\n"
      "-[no]{reverse|rv}    "
      "This option allows you to see the abacus window in "
      "reverse video (resource name \"reverse\").\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"
      "-{border|bd} color    "
      "This option specifies the foreground of  the  border "
      "of the beads (resource name \"borderColor\").\n"
      "-frame color    "
      "This option specifies the foreground  of  the  frame "
      "(resource name \"frameColor\").\n"
      "-rail color    "
      "This option specifies the foreground  of  the  rails "
      "(resource name \"railColor\").\n"
      "-bead color    "
      "This option specifies the foreground  of  the  beads "
      "(resource name \"beadColor\").\n"
      "-rails int    "
      "This option specifies the number of rails (resource "
      "name \"rails\").\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"
      "-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 \"quarter\".\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"
      "-base int    "
      "This option specifies the base used (default is base "
      "10) (resource name \"base\").\n"
      "        By default, one has to set the format mode to "
      "not be Other for this to work (unless you know what you are doing).\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"
};

static const char options2Help[] = {
      "-[no]vertical    "
      "This option allows you to set the abacus to allow "
      "a Russian orientation (resource name \"vertical\").\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\n"
      "        above 3,999,999 were not represented historically.  "
      "Roman numerals change with displayBase in an \"experimental\" way.\n"
      "-[no]sign    "
      "This option allows you to set the abacus to allow "
      "negatives (resource name \"sign\").\n"
      "-[no]quarter    "
      "This option allows you to set the abacus to allow "
      "quarters (resource name \"quarter\").\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"
      "-[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"
      "-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."
      "-moveSound filename    "
      "This option specifies the file for the move sound."
      "-[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"
      "-[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"
      "  If you want to add a \"do nothing\", the first\n"
      "        line generated is an example of that.  For  example: "
      "\"xabacus -script > Abacus5.les\"\n"
      "-demopath path    "
      "This option specifies the path for the demo,  possibly"
      "  /usr/share/games/xabacus  (resource name\n"
      "        \"demoPath\").  It initially looks for Abacus1.les."
      "  If it finds  that, it  will later look for Abacus2.les, etc.\n"
      "-{demofont|demofn} fontstring    "
      "This option specifies the  font  for  the "
      "explanatory text  that appears in the secondary\n"
      "        window, during the demo.  The default font is 18  point "
      "Times-Roman  (-*-times-*-r-*-*-*-180-*).  The\n"
      "        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"
      "-version    "
      "This option tells you what version of xcubes 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  doing the mul-\n"
      "tiplications while  adding  up  the intermediate results.  "
      "Division  would  be similar where the intermediate results are\n"
      "subtracted.  There are techniques like using your thumb  and "
      "forefinger which does not apply with mouse entry.  Also with\n"
      "multiplication, one can carry out calculations on different "
      "parts of the abacus, here it is nice to have a long 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 thirds 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, 1 for  quarters, "
      "and the bottom 2 for thirds).  In another surviving example:\n"
      "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 (currently the xabacus\n"
      "can not be oriented that way and  one has to  move the beads "
      "down).   It has colored beads in the middle for ease of use.\n"
      "Quarters represent  1/4  Rubles and are only  present  historically"
      " on  the  Russian  abacus (Schoty).  Some of the older\n"
      "Schoty have a extra place for the 1/4  Kopek  (quarter  percent)"
      " as well as the 1/4 Ruble (quarter).\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 row and 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, and Russian formats.\n"
      "\n"
      "Press \"V\" or \"v\" keys to toggle vertical Russian orientation.\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.\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", "Other"
};

#ifdef WINVER
#include "AbacusP.h"
#include "wabacus.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;
      Boolean demo, sign, quarter, quarterPercent;

      forceNormalParams(w);
      mode = w->abacus.mode;
      sign = w->abacus.sign;
      quarter = w->abacus.quarter;
      quarterPercent = w->abacus.quarterPercent;
      demo = w->abacus.demo;
      if (mode == OTHER) {
            FormatAbacus(w);
      }
      min = ((sign) ? 1: 0) + ((quarter) ? 1 : 0) +
            ((quarterPercent) ? 1 + MAX_FRACTION_DIGITS : 0) +
            ((demo) ? MINDEMORAILS : MINRAILS);
      while (w->abacus.rails < min) {
            IncrementAbacus(w);
      }
}

void
SetAbacus(AbacusWidget w, int reason)
{
      switch (reason) {
            case ABACUS_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 ABACUS_BASE_DEFAULT:
                  forceNormalParams(w);
                  break;
            case ABACUS_DEMO_DEFAULT:
                  forceDemoParams(w);
                  break;
            case ABACUS_CLEAR:
                  ClearAbacusDemo(w);
                  break;
            case ABACUS_HIDE:
                  ShowWindow(w->core.hWnd, SW_SHOWMINIMIZED);
                  break;
            case ABACUS_CLEAR_QUERY:
                  break;
            case ABACUS_DEMO:
                  DemoAbacusDemo(w);
                  break;
            case ABACUS_NEXT:
                  NextAbacusDemo(w);
                  break;
            case ABACUS_REPEAT:
                  RepeatAbacusDemo(w);
                  break;
            case ABACUS_MORE:
                  MoreAbacusDemo(w);
                  break;
            case ABACUS_INC:
            case ABACUS_DEC:
            case ABACUS_FORMAT:
            case ABACUS_VERTICAL:
            case ABACUS_ROMANNUMERAL:
            case ABACUS_SIGN:
            case ABACUS_QUARTER:
            case ABACUS_QUARTERPERCENT:
                  break;
      }
}

void
SetAbacusString(AbacusWidget w, int reason, char *string)
{
      if (reason == ABACUS_SCRIPT || reason == ABACUS_IGNORE) {
            char szBuf[MAXDIGITS + 67];
            int mode = w->abacus.mode;

            (void) sprintf(szBuf, "%s %s =%s",
                  (mode < 0 || mode > MAXMODES) ? "" :
                  formatString[mode],
                  TITLE, string);
            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:
                  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 IDM_EXIT:
                              DestroyAbacus(&widget, brush);
#if 0
                              if (widget.abacus.demo)
                                    DestroyAbacusDemo(brush);
#endif
                              break;
                        case IDM_HIDE:
                              HideAbacus(&widget);
                              break;
                        case IDM_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 IDM_INCREMENT:
                              widget.core.hDC = GetDC(hWnd);
                              (void) SelectObject(widget.core.hDC,
                                    GetStockObject(NULL_PEN));
                              IncrementAbacus(&widget);
                              (void) ReleaseDC(hWnd,
                                    widget.core.hDC);
                              break;
                        case IDM_DECREMENT:
                              widget.core.hDC = GetDC(hWnd);
                              (void) SelectObject(widget.core.hDC,
                                    GetStockObject(NULL_PEN));
                              DecrementAbacus(&widget);
                              (void) ReleaseDC(hWnd,
                                    widget.core.hDC);
                              break;
                        case IDM_SPEED:
                              SpeedAbacus(&widget);
                              break;
                        case IDM_SLOW:
                              SlowAbacus(&widget);
                              break;
                        case IDM_SOUND:
                              SoundAbacus(&widget);
                              break;
                        case IDM_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 IDM_VERTICAL:
                              widget.core.hDC = GetDC(hWnd);
                              (void) SelectObject(widget.core.hDC,
                                    GetStockObject(NULL_PEN));
                              VerticalAbacus(&widget);
                              (void) ReleaseDC(hWnd,
                                    widget.core.hDC);
                              break;
                        case IDM_ROMANNUMERAL:
                              widget.core.hDC = GetDC(hWnd);
                              (void) SelectObject(widget.core.hDC,
                                    GetStockObject(NULL_PEN));
                              RomanNumeralsAbacus(&widget);
                              (void) ReleaseDC(hWnd,
                                    widget.core.hDC);
                              break;
                        case IDM_SIGN:
                              widget.core.hDC = GetDC(hWnd);
                              (void) SelectObject(widget.core.hDC,
                                    GetStockObject(NULL_PEN));
                              SignAbacus(&widget);
                              (void) ReleaseDC(hWnd,
                                    widget.core.hDC);
                              break;
                        case IDM_QUARTER:
                              widget.core.hDC = GetDC(hWnd);
                              (void) SelectObject(widget.core.hDC,
                                    GetStockObject(NULL_PEN));
                              QuarterAbacus(&widget);
                              (void) ReleaseDC(hWnd,
                                    widget.core.hDC);
                              break;
                        case IDM_QUARTERPERCENT:
                              widget.core.hDC = GetDC(hWnd);
                              (void) SelectObject(widget.core.hDC,
                                    GetStockObject(NULL_PEN));
                              QuarterPercentAbacus(&widget);
                              (void) ReleaseDC(hWnd,
                                    widget.core.hDC);
                              break;
                        case IDM_DEMO:
                              DemoAbacusDemo(&widget);
                              ResizeAbacus(&widget);
                              (void) InvalidateRect(hWnd, NULL,
                                    TRUE);
                              break;
                        case IDM_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 IDM_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 IDM_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 IDM_ABOUT:
                              (void) DialogBox(widget.core.hInstance,
                                    "About", hWnd,
                                    (DLGPROC) About);
                              break;
                        case IDM_DESCRIPTION:
                              (void) MessageBox(hWnd,
                                    descriptionHelp,
                                    "Description", MB_OK);
                              break;
                        case IDM_FEATURES:
                              (void) MessageBox(hWnd, featuresHelp,
                                    "Features", MB_OK);
                              break;
                        case IDM_REFERENCES:
                              (void) MessageBox(hWnd, referencesHelp,
                                    "References", MB_OK);
                              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 <X11/Shell.h>
#include <X11/cursorfont.h>
#ifdef HAVE_MOTIF
#include <Xm/PanedW.h>
#include <Xm/RowColumn.h>
#include <Xm/Text.h>
#include <Xm/LabelG.h>
#include <Xm/MessageB.h>
#include <Xm/PushBG.h>
#include <Xm/CascadeB.h>
#include <Xm/Scale.h>
#include <Xm/ToggleB.h>
#include <Xm/ToggleBG.h>
#include <Xm/Form.h>
#ifdef MOUSEBITMAPS
#include "icons/mouse-l.xbm"
#include "icons/mouse-r.xbm"
#endif
#endif
#include "Abacus.h"
#ifdef HAVE_XPM
#include <X11/xpm.h>
#include "icons/abacus.xpm"
#endif
#include "icons/abacus.xbm"

#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, rightAuxAbacus;
static Widget leftAuxTracker, rightAuxTracker;
#endif
#ifdef TOGGLES
static Widget verticalSwitch, romanNumeralSwitch;
static Widget signSwitch, quarterSwitch, quarterPercentSwitch;
#endif
static Widget tracker;
static Widget descriptionDialog, featuresDialog;
static Widget optionsDialog, options1Dialog, options2Dialog;
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 abacusIcon = None;
static char titleDspDemo[FILENAMELEN + 6];
static Widget topLevel, abacus, abacusDemo = NULL;
static char *progDsp;

static void
Usage(char * programName)
{
      (void) fprintf(stderr, "usage: %s\n", programName);
      (void) fprintf(stderr, optionsHelp);
      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.reverse", XrmoptionNoArg, (char *) "TRUE"},
      {(char *) "-reverse", (char *) "*abacus.reverse", XrmoptionNoArg, (char *) "TRUE"},
      {(char *) "-norv", (char *) "*abacus.reverse", XrmoptionNoArg, (char *) "FALSE"},
      {(char *) "-noreverse", (char *) "*abacus.reverse", XrmoptionNoArg, (char *) "FALSE"},
      {(char *) "-fg", (char *) "*abacus.Foreground", XrmoptionSepArg, NULL},
      {(char *) "-foreground", (char *) "*abacus.Foreground", XrmoptionSepArg, NULL},
      {(char *) "-bg", (char *) "*Background", XrmoptionSepArg, NULL},
      {(char *) "-background", (char *) "*Background", XrmoptionSepArg, NULL},
      {(char *) "-bd", (char *) "*abacus.beadBorder", XrmoptionSepArg, NULL},
      {(char *) "-border", (char *) "*abacus.beadBorder", XrmoptionSepArg, NULL},
      {(char *) "-frame", (char *) "*abacus.frameColor", XrmoptionSepArg, NULL},
      {(char *) "-rail", (char *) "*abacus.railColor", XrmoptionSepArg, NULL},
      {(char *) "-bead", (char *) "*abacus.beadColor", XrmoptionSepArg, NULL},
      {(char *) "-rails", (char *) "*abacus.rails", 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 *) "-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 *) "-other", (char *) "*abacus.format", XrmoptionNoArg, (char *) "other"},
      {(char *) "-base", (char *) "*abacus.base", XrmoptionSepArg, NULL},
      {(char *) "-displayBase", (char *) "*abacus.displayBase", XrmoptionSepArg, NULL},
      {(char *) "-vertical", (char *) "*abacus.vertical", XrmoptionNoArg, (char *) "TRUE"},
      {(char *) "-novertical", (char *) "*abacus.vertical", XrmoptionNoArg, (char *) "FALSE"},
      {(char *) "-romanNumerals", (char *) "*abacus.romanNumerals", XrmoptionNoArg, (char *) "TRUE"},
      {(char *) "-noromanNumerals", (char *) "*abacus.romanNumerals", XrmoptionNoArg, (char *) "FALSE"},
      {(char *) "-sign", (char *) "*abacus.sign", XrmoptionNoArg, (char *) "TRUE"},
      {(char *) "-nosign", (char *) "*abacus.sign", XrmoptionNoArg, (char *) "FALSE"},
      {(char *) "-quarter", (char *) "*abacus.quarter", XrmoptionNoArg, (char *) "TRUE"},
      {(char *) "-noquarter", (char *) "*abacus.quarter", XrmoptionNoArg, (char *) "FALSE"},
#ifdef QUARTER_PERCENT
      {(char *) "-quarterpercent", (char *) "*abacus.quarterPercent", XrmoptionNoArg, (char *) "TRUE"},
      {(char *) "-noquarterpercent", (char *) "*abacus.quarterPercent", XrmoptionNoArg, (char *) "FALSE"},
#endif
      {(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 *) "-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 *) "-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 *) "-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",
            (mode < 0 || mode > MAXMODES) ? "" : formatString[mode],
            progDsp, msg);
      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,
            XtNreverse, &reverse,
            XtNmode, &mode,
            XtNdemoForeground, &demoForeground,
            XtNdemoBackground, &demoBackground,
            XtNdemoPath, &demoPath,
            XtNdemoFont, &demoFont, NULL);
      XtVaSetValues(abacusDemo,
            XtNmono, mono,
            XtNreverse, reverse,
            XtNmode, mode,
            XtNdemoForeground, demoForeground,
            XtNdemoBackground, demoBackground,
            XtNdemoPath, demoPath,
            XtNdemoFont, demoFont,
            XtNframed, True, NULL);
}

#ifdef LEE_ABACUS
#define AUXWIN(n) (n == LEFTAUX) ? leftAuxAbacus : ((n == RIGHTAUX ) ? rightAuxAbacus : 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 ABACUS_BASE_DEFAULT:
#ifdef HAVE_MOTIF
                  XmScaleSetValue(abacusBaseSlider, DEFAULTBASE);
#endif
                  break;
            case ABACUS_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 ABACUS_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 ABACUS_CLEAR:
                  XtVaSetValues(abacus, XtNdeck, ABACUS_CLEAR, NULL);
#ifdef LEE_ABACUS
                  /* Abacus demo clear is more complete */
                  XtVaSetValues(leftAuxAbacus,
                        XtNdeck, ABACUS_CLEAR, NULL);
                  XtVaSetValues(rightAuxAbacus,
                        XtNdeck, ABACUS_CLEAR, NULL);
#endif
                  break;
            case ABACUS_DEMO:
                  XtDestroyWidget(abacusDemo);
#ifndef HAVE_MOTIF
                  XtDestroyWidget(shell);
#endif
                  XtVaSetValues(abacus,
                        XtNdemo, False, NULL);
#ifdef LEE_ABACUS
                  XtVaSetValues(leftAuxAbacus,
                        XtNdemo, False, NULL);
                  XtVaSetValues(rightAuxAbacus,
                        XtNdemo, False, NULL);
#endif
                  break;
      }
      if (callData->reason == ABACUS_SCRIPT || callData->reason == ABACUS_IGNORE) {
#ifdef HAVE_MOTIF
#ifdef LEE_ABACUS
            if (w == leftAuxAbacus)
                  PrintState(leftAuxTracker, callData->buffer);
            else if (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;
      Boolean demo, sign, quarter, quarterPercent;

      forceNormalParams(w);
      XtVaGetValues(abacus,
            XtNmode, &mode,
            XtNrails, &rails,
            XtNsign, &sign,
            XtNquarter, &quarter,
            XtNquarterPercent, &quarterPercent,
            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) + ((quarter) ? 1 : 0) +
            ((quarterPercent) ? 1 + MAX_FRACTION_DIGITS : 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, abacusIcon,
            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
      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 vertical, romanNumerals, sign, quarter, quarterPercent, demo;

      XtVaGetValues(w,
            XtNdemo, &demo,
            XtNmode, &mode, NULL);
      switch (callData->reason) {
            case ABACUS_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 ABACUS_CLEAR_QUERY:
#ifdef HAVE_MOTIF
                  XtManageChild(clearDialog);
#else
                  XtVaSetValues(w, XtNmenu, 1, NULL); /* menu choice */
#endif
                  break;
            case ABACUS_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 ABACUS_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 ABACUS_CLEAR:
                  XtVaSetValues(abacusDemo, XtNdeck, ABACUS_CLEAR, NULL);
                  break;
            case ABACUS_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
                  XtVaSetValues(leftAuxAbacus, XtNdemo, demo, NULL);
                  XtVaSetValues(rightAuxAbacus, XtNdemo, demo, NULL);
#endif
                  break;
            case ABACUS_NEXT:
                  XtVaSetValues(abacusDemo, XtNdeck, ABACUS_NEXT, NULL);
                  break;
            case ABACUS_REPEAT:
                  XtVaSetValues(abacusDemo,
                        XtNdeck, ABACUS_REPEAT, NULL);
                  break;
            case ABACUS_MORE:
                  XtVaSetValues(abacusDemo, XtNdeck, ABACUS_MORE, NULL);
                  break;
            case ABACUS_INC:
                  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 ABACUS_DEC:
                  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 ABACUS_FORMAT:
                  if (w == abacus) {
#ifdef HAVE_MOTIF
                        XtVaSetValues(formatMenu,
                              XmNmenuHistory, formatOptions[mode],
                              NULL);
#endif
                        if (demo) {
                              XtVaSetValues(abacusDemo,
                                    XtNdeck, ABACUS_CLEAR,
                                    XtNmode, mode, NULL);
                        }
                  }
                  break;
            case ABACUS_VERTICAL:
                  XtVaGetValues(w,
                        XtNvertical, &vertical, NULL);
#ifdef HAVE_MOTIF
#ifdef TOGGLES
                  if (w == abacus) {
                        XmToggleButtonSetState(verticalSwitch,
                              vertical, False);
                  }
#endif
#endif
                  break;
            case ABACUS_ROMANNUMERAL:
                  XtVaGetValues(w,
                        XtNromanNumerals, &romanNumerals,
                        NULL);
#ifdef HAVE_MOTIF
#ifdef TOGGLES
                  XmToggleButtonSetState(romanNumeralSwitch,
                        romanNumerals, False);
#endif
#endif
                  break;
            case ABACUS_SIGN:
                  XtVaGetValues(w,
                        XtNsign, &sign, NULL);
#ifdef HAVE_MOTIF
#ifdef TOGGLES
                  if (w == abacus) {
                        XmToggleButtonSetState(signSwitch, sign, False);
                  }
#endif
#endif
                  break;
            case ABACUS_QUARTER:
                  XtVaGetValues(w,
                        XtNquarter, &quarter, NULL);
#ifdef HAVE_MOTIF
#ifdef TOGGLES
                  if (w == abacus) {
                        XmToggleButtonSetState(quarterSwitch,
                              quarter, False);
                  }
#endif
#endif
                  break;
            case ABACUS_QUARTERPERCENT:
                  XtVaGetValues(w,
                        XtNquarterPercent, &quarterPercent, NULL);
#ifdef HAVE_MOTIF
#ifdef TOGGLES
                  if (w == abacus) {
                        XmToggleButtonSetState(quarterPercentSwitch,
                              quarterPercent, False);
                  }
#endif
#endif
                  break;
      }
      if (callData->reason == ABACUS_SCRIPT || callData->reason == ABACUS_IGNORE) {
#ifdef HAVE_MOTIF
#ifdef LEE_ABACUS
            if (w == leftAuxAbacus)
                  PrintState(leftAuxTracker, callData->buffer);
            else if (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, ABACUS_CALC,
                  XtNmathBuffer, mathBuffer, NULL);
      }
}

static void
CallbackAbacusClear(Widget w, XtPointer clientData, XmAnyCallbackStruct * cbs)
{
      if (cbs->reason == XmCR_OK) {
            XtVaSetValues(abacus, XtNmenu, 1, NULL); /* menu choice */
      }
}

static void
RailSlider(Widget w, XtPointer clientData, XmScaleCallbackStruct * cbs)
{
      int rails = cbs->value, old, min;
      Boolean demo, sign, quarter, quarterPercent;

      XtVaGetValues(abacus,
            XtNrails, &old,
            XtNsign, &sign,
            XtNquarter, &quarter,
            XtNquarterPercent, &quarterPercent,
            XtNdemo, &demo, NULL);
      min = ((sign) ? 1: 0) + ((quarter) ? 1 : 0) +
            ((quarterPercent) ? 1 + MAX_FRACTION_DIGITS : 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;
      Boolean demo, quarter, quarterPercent;

      XtVaGetValues(abacus,
            XtNbase, &old,
            XtNquarter, &quarter,
            XtNquarterPercent, &quarterPercent,
            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
static void
VerticalToggle(Widget w, XtPointer clientData, XmToggleButtonCallbackStruct * cbs)
{
      Boolean vertical = cbs->set;

      XtVaSetValues(abacus,
            XtNvertical, vertical, NULL);
}

static void
RomanNumeralToggle(Widget w, XtPointer clientData,
            XmToggleButtonCallbackStruct * cbs)
{
      Boolean romanNumerals = cbs->set;

      XtVaSetValues(abacus,
            XtNromanNumerals, romanNumerals, 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;
      int base, decimalPosition, bottomSpaces;

      XtVaGetValues(abacus,
            XtNbase, &base,
            XtNbottomSpaces, &bottomSpaces,
            XtNdecimalPosition, &decimalPosition, NULL);
      /* 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 */
      if ((base == 2 || base == 4) && bottomSpaces < 3) {
            XtVaSetValues(abacus,
                  XtNbottomSpaces, 3,
                  XtNquarter, quarter, NULL);
      } else if ((base == 3 || base == 6 || base == 9) && bottomSpaces < 2) {
            XtVaSetValues(abacus,
                  XtNbottomSpaces, 2,
                  XtNquarter, quarter, NULL);
      } else {
            XtVaSetValues(abacus,
                  XtNquarter, quarter, NULL);
      }
}

#ifdef QUARTER_PERCENT
static void
QuarterPercentToggle(Widget w, XtPointer clientData, XmToggleButtonCallbackStruct * cbs)
{
      Boolean quarterPercent = cbs->set;
      int base, decimalPosition, bottomSpaces;

      XtVaGetValues(abacus,
            XtNbase, &base,
            XtNbottomSpaces, &bottomSpaces,
            XtNdecimalPosition, &decimalPosition, NULL);
      if (decimalPosition < MAX_FRACTION_DIGITS) {
            XmToggleButtonSetState(quarterPercentSwitch, !quarterPercent,
                  False);
      }
      /* 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 */
      if ((base == 2 || base == 4) && bottomSpaces < 3) {
            XtVaSetValues(abacus,
                  XtNbottomSpaces, 3,
                  XtNquarterPercent, quarterPercent, NULL);
      } else if ((base == 3 || base == 6 || base == 9) && bottomSpaces < 2) {
            XtVaSetValues(abacus,
                  XtNbottomSpaces, 2,
                  XtNquarterPercent, quarterPercent, NULL);
      } else {
            XtVaSetValues(abacus,
                  XtNquarterPercent, quarterPercent, NULL);
      }
}
#endif
#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, ABACUS_CLEAR,
                  XtNmode, mode, NULL);
      }
}

static void
fileCB(Widget w, void *value, void *clientData)
{
      int val = (int) value;

      if (val == 0)
            exit(0);
      XtVaSetValues(abacus, XtNmenu, val, NULL);
}

static void
controlsCB(Widget w, void *value, void *clientData)
{
      int val = (int) value;
      XtVaSetValues(abacus, XtNmenu, val + 1, NULL); /* Q */
}

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(referencesDialog);
            break;
      case 6:
            XtManageChild(aboutDialog);
            break;
      default:
            {
                  char *buf;

                  intCat(&buf, "helpCB: %d", val);
                  XtWarning(buf);
                  free(buf);
            }
      }
}

#endif

int
main(int argc, char **argv)
{
      Boolean demo;
#ifdef HAVE_MOTIF
      int base = DEFAULTBASE, displayBase = DEFAULTBASE;
      Widget menuBar, pullDownMenu, widget;
      Widget menuBarPanel, controlPanel;
      Widget controlRowCol, trackerRowCol;
#ifdef LEE_ABACUS
      Widget auxForm, auxTrackerRowCol;
      XColor exactDef;
#endif
#ifdef TOGGLES
      Widget toggleRowCol;
#endif
      XmString fileString, controlsString;
      XmString quitString, clearString, incrementString, decrementString;
      XmString verticalString;
      XmString romanNumeralString, signString, quarterString;
#ifdef QUARTER_PERCENT
      XmString quarterPercentString;
#endif
      XmString speedString, slowString, soundString;
      XmString complexity, complexityStrings[COMPLEXITIES];
      XmString format, formatStrings[MAXMODES];
      int rails, mode;
      Boolean romanNumerals, sign, quarter, quarterPercent;
      unsigned int i;
#endif

      progDsp = argv[0];
#ifndef HAVE_MOTIF
      (void) sprintf(titleDsp, "%s =%s", progDsp, "0");
#endif
      topLevel = XtInitialize(argv[0], "Abacus",
            options, XtNumber(options), &argc, argv);
      if (argc != 1)
            Usage(argv[0]);

#if 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)),
                  (char **) abacus_xpm, &abacusIcon, NULL,
                  &xpmAttributes);
      }
      if (abacusIcon == (Pixmap) NULL)
#endif
            abacusIcon = XCreateBitmapFromData(XtDisplay(topLevel),
                  RootWindowOfScreen(XtScreen(topLevel)),
                  (char *) abacus_bits,
                  abacus_width, abacus_height);
#ifdef HAVE_MOTIF
      XtVaSetValues(topLevel,
            XtNiconPixmap, abacusIcon,
            XmNkeyboardFocusPolicy, XmPOINTER, NULL); /* not XmEXPLICIT */
      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");
      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");
      verticalString = XmStringCreateSimple((char *) "Vertical");
      romanNumeralString = XmStringCreateSimple((char *) "RoMan Numerals");
      signString = XmStringCreateSimple((char *) "Sign");
      quarterString = XmStringCreateSimple((char *) "QUarter");
#ifdef QUARTER_PERCENT
      quarterPercentString = XmStringCreateSimple((char *) "Quarter Percent");
#endif
      speedString = XmStringCreateSimple((char *) ">Speed");
      slowString = XmStringCreateSimple((char *) "<Slow");
      soundString = XmStringCreateSimple((char *) "@Sound");
      XmVaCreateSimplePulldownMenu(menuBar, (char *) "controlsMenu", 1, controlsCB,
            XmVaPUSHBUTTON, clearString, 'C', NULL, NULL,
            XmVaPUSHBUTTON, incrementString, 'I', NULL, NULL,
            XmVaPUSHBUTTON, decrementString, 'D', NULL, NULL,
            XmVaPUSHBUTTON, format, 'F', NULL, NULL,
            XmVaPUSHBUTTON, verticalString, 'V', NULL, NULL,
            XmVaPUSHBUTTON, romanNumeralString, 'M', NULL, NULL,
            XmVaPUSHBUTTON, signString, 'S', NULL, NULL,
            XmVaPUSHBUTTON, quarterString, 'U', NULL, NULL,
            XmVaPUSHBUTTON, speedString, '>', NULL, NULL,
            XmVaPUSHBUTTON, slowString, '<', NULL, NULL,
            XmVaPUSHBUTTON, soundString, '@', NULL, NULL,
            /* Reorder the following when working */
#ifdef QUARTER_PERCENT
            XmVaPUSHBUTTON, quarterPercentString, 'P', NULL, NULL,
#endif
            NULL);
      XmStringFree(clearString);
      XmStringFree(incrementString);
      XmStringFree(decrementString);
      XmStringFree(format);
      XmStringFree(verticalString);
      XmStringFree(romanNumeralString);
      XmStringFree(signString);
      XmStringFree(quarterString);
#ifdef QUARTER_PERCENT
      XmStringFree(quarterPercentString);
#endif
      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("Options1",
            xmPushButtonGadgetClass, pullDownMenu,
            XmNmnemonic, '1', NULL);
      XtAddCallback(widget, XmNactivateCallback, helpCB, (char *) 2);
      widget = XtVaCreateManagedWidget("Options2",
            xmPushButtonGadgetClass, pullDownMenu,
            XmNmnemonic, '2', NULL);
      XtAddCallback(widget, XmNactivateCallback, helpCB, (char *) 3);
      widget = XtVaCreateManagedWidget("References",
            xmPushButtonGadgetClass, pullDownMenu,
            XmNmnemonic, 'R', NULL);
      XtAddCallback(widget, XmNactivateCallback, helpCB, (char *) 4);
      widget = XtVaCreateManagedWidget("About",
            xmPushButtonGadgetClass, pullDownMenu,
            XmNmnemonic, 'A', NULL);
      XtAddCallback(widget, XmNactivateCallback, helpCB, (char *) 5);
      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");
      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
#if LEE_ABACUS
      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);
#if LEE_ABACUS
      auxForm = XtVaCreateManagedWidget("auxForm",
            xmFormWidgetClass, mainPanel,
            XmNfractionBase, 20,
            NULL);
      abacus = XtVaCreateManagedWidget("abacus",
            abacusWidgetClass, auxForm,
            XmNbottomAttachment, XmATTACH_FORM,
            XmNleftAttachment, XmATTACH_FORM,
            XmNrightAttachment, XmATTACH_FORM,
            XmNtopAttachment, XmATTACH_POSITION,
            XmNtopPosition, 5,
            NULL);
      (void) XParseColor(XtDisplay(abacus),
            DefaultColormapOfScreen(XtScreen(abacus)), "LimeGreen",
            &exactDef);
      (void) XAllocColor(XtDisplay(abacus),
            DefaultColormapOfScreen(XtScreen(abacus)), &exactDef);
#if !defined( LEE_CN ) && !defined( LEE_KO ) && !defined( LEE_ELF )
#define LEE_CN
#endif
      leftAuxAbacus = XtVaCreateManagedWidget("leftAuxAbacus",
            abacusWidgetClass, auxForm,
            XmNtopAttachment, XmATTACH_FORM,
            XmNleftAttachment, XmATTACH_FORM,
            XmNbottomAttachment, XmATTACH_WIDGET,
            XmNrightAttachment, XmATTACH_POSITION,
            XmNbottomWidget, abacus,
            XtNformat, "Japanese",
            XtNaux, True,
            XtNbeadColor, exactDef.pixel,
#ifdef LEE_CN
            XmNrightPosition, 7,
            XtNrails, 7,
#else
#ifdef LEE_KO
            XmNrightPosition, 8,
            XtNrails, 7,
#else
            XtNrails, 9,
            XmNrightPosition, 10,
#endif
#endif
            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,
            XtNbeadColor, exactDef.pixel,
#ifdef LEE_CN
            XtNrails, 13,
#else
#ifdef LEE_KO
            XtNrails, 11,
#else
            XtNrails, 9,
#endif
#endif
            NULL);
      XtAddCallback(rightAuxAbacus, XtNselectCallback,
            (XtCallbackProc) CallbackAbacus, (XtPointer) NULL);

#else
      abacus = XtVaCreateManagedWidget("abacus",
            abacusWidgetClass, mainPanel,
#ifdef LEE_KO
            XtNformat, "Korean",
#endif
            NULL);
#endif
#else
      XtVaSetValues(topLevel,
            XtNiconPixmap, abacusIcon,
            XtNinput, True, NULL);
      abacus = XtCreateManagedWidget("abacus",
            abacusWidgetClass, topLevel, NULL, 0);
#endif
      XtAddCallback(abacus, XtNselectCallback,
            (XtCallbackProc) CallbackAbacus, (XtPointer) NULL);

      XtVaGetValues(abacus,
#ifdef HAVE_MOTIF
            XtNrails, &rails,
            XtNromanNumerals, &romanNumerals,
            XtNsign, &sign,
            XtNquarter, &quarter,
            XtNquarterPercent, &quarterPercent,
            XtNbase, &base,
            XtNdisplayBase, &displayBase,
            XtNmode, &mode,
#endif
            XtNdemo, &demo, NULL);
#ifdef HAVE_MOTIF
#ifdef TOGGLES
      {
      verticalSwitch= XtVaCreateManagedWidget("Vertical",
            xmToggleButtonGadgetClass, toggleRowCol, NULL);
      XtAddCallback(verticalSwitch, XmNvalueChangedCallback,
            (XtCallbackProc) VerticalToggle, (XtPointer) NULL);
      romanNumeralSwitch= XtVaCreateManagedWidget("Roman",
            xmToggleButtonGadgetClass, toggleRowCol, NULL);
      XtAddCallback(romanNumeralSwitch, XmNvalueChangedCallback,
            (XtCallbackProc) RomanNumeralToggle, (XtPointer) NULL);
      XmToggleButtonSetState(romanNumeralSwitch, romanNumerals, False);
      signSwitch= XtVaCreateManagedWidget("Signed",
            xmToggleButtonGadgetClass, toggleRowCol, NULL);
      XtAddCallback(signSwitch, XmNvalueChangedCallback,
            (XtCallbackProc) SignToggle, (XtPointer) NULL);
      XmToggleButtonSetState(signSwitch, sign, False);
      quarterSwitch= XtVaCreateManagedWidget("Quarters",
            xmToggleButtonGadgetClass, toggleRowCol, NULL);
      XtAddCallback(quarterSwitch, XmNvalueChangedCallback,
            (XtCallbackProc) QuarterToggle, (XtPointer) NULL);
      XmToggleButtonSetState(quarterSwitch, quarter, False);
#ifdef QUARTER_PERCENT
      quarterPercentSwitch= XtVaCreateManagedWidget("Quarter %'s",
            xmToggleButtonGadgetClass, toggleRowCol, NULL);
      XtAddCallback(quarterPercentSwitch, XmNvalueChangedCallback,
            (XtCallbackProc) QuarterPercentToggle, (XtPointer) NULL);
      XmToggleButtonSetState(quarterPercentSwitch, quarterPercent, False);
#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);
      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

Generated by  Doxygen 1.6.0   Back to index