home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / misc / pocketcalc.lha / PocketCalc / Source / PocketCalc.c next >
Encoding:
C/C++ Source or Header  |  1995-02-27  |  15.4 KB  |  436 lines

  1. /*
  2. **       $Filename: PocketCalc.c $
  3. **       $Release: 1 $
  4. **       $Revision: 37.1 $
  5. **       $Date: 26/02/95 $
  6. **
  7. **       (C) Copyright 1995 Alex Taylor
  8. **       All Rights Reserved
  9. */
  10.  
  11. /*----------------------------------------------------------------------------*/
  12. /*    Main include                                                            */
  13. /*----------------------------------------------------------------------------*/
  14.  
  15. #include "PocketCalc.h"
  16.  
  17. /*----------------------------------------------------------------------------*/
  18. /*    Main program                                                            */
  19. /*----------------------------------------------------------------------------*/
  20.  
  21. void main(void)
  22. {
  23.  
  24. BOOL Running = TRUE;
  25. ULONG Signals;
  26. long double Temp;
  27.  
  28.    if (MUIMasterBase = OpenLibrary("muimaster.library", MUIMASTER_VMIN))
  29.    {
  30.       if (MakeMUIApp())
  31.       {
  32.          ClearBuffer();
  33.          set(Win, MUIA_Window_Open, TRUE);
  34.  
  35.          while (Running)
  36.          {
  37.             switch(DoMethod(App, MUIM_Application_Input, &Signals))
  38.             {
  39.                case MUIV_Application_ReturnID_Quit:
  40.                   Running = FALSE;                          /* break the loop */
  41.                   break;
  42.  
  43.                case ID_ALLCLEAR:
  44.                   Memory = 0;                              /* clear variables */
  45.                   NextOperation = 0;
  46.                   Operand1 = Operand2 = CurrentOperand = 0;      /* fall-thru */
  47.                case ID_CLEAR:
  48.                   ClearBuffer();
  49.                   Error = FALSE;
  50.                   break;
  51.  
  52.                case ID_MEMPLUS:                           /* memory functions */
  53.                   sscanf(DigitBuffer, "%lf", &Temp);
  54.                   Memory += Temp;
  55.                   Cursor = 0;
  56.                   break;
  57.  
  58.                case ID_MEMMINUS:
  59.                   sscanf(DigitBuffer, "%lf", &Temp);
  60.                   Memory -= Temp;
  61.                   Cursor = 0;
  62.                   break;
  63.  
  64.                default:
  65.                   break;
  66.             }
  67.             if (Running && Signals) Wait(Signals);
  68.          }
  69.          set(Win, MUIA_Window_Open, FALSE);
  70.  
  71.          MUI_DisposeObject(App);
  72.       }
  73.       CloseLibrary(MUIMasterBase);
  74.    }
  75. }      
  76.  
  77. /*----------------------------------------------------------------------------*/
  78. /*    MakeMUIApp - creates the user interface                                 */
  79. /*----------------------------------------------------------------------------*/
  80.  
  81. static BOOL MakeMUIApp(void)
  82. {
  83.  
  84. APTR MRecall, MPlus, MMinus, Clear, AllClear, Seven, Eight, Nine;
  85. APTR Divide, SqrRoot, Four, Five, Six, Multiply, Square, One, Two, Three;
  86. APTR Minus, Negate, Period, Zero, Equals, Plus, Pi;
  87.  
  88. static const struct Hook DigitHook = { { NULL, NULL },
  89.                                           (void *)ProcessDigit, NULL, NULL };
  90. static const struct Hook OPHook    = { { NULL, NULL },
  91.                                           (void *)DoOperation, NULL, NULL };
  92.  
  93.    if (!(App = ApplicationObject,
  94.       MUIA_Application_Title,       "PocketCalc",
  95.       MUIA_Application_Version,     "$VER: PocketCalc 37.1 (26.02.95)",
  96.       MUIA_Application_Copyright,   "© 1995 Alex Taylor",
  97.       MUIA_Application_Author,      "Alex Taylor",
  98.       MUIA_Application_Description, "Pocket Calculator",
  99.       MUIA_Application_Base,        "PCALC",
  100.  
  101.       SubWindow, Win = WindowObject,
  102.          MUIA_Window_Title, "PocketCalc",
  103.          MUIA_Window_ID, MAKEID('C','A','L','C'),
  104.  
  105.          WindowContents,
  106.             VGroup, MUIA_Group_SameHeight, TRUE,
  107.                Child, Display = TextObject,
  108.                                 TextFrame,
  109.                                 MUIA_Text_PreParse, "\33r",
  110.                                 MUIA_Text_Contents, "0.",
  111.             End,
  112.  
  113.             Child, HGroup, GroupSpacing(10), MUIA_Group_SameWidth, TRUE,
  114.                Child, MRecall  = MakeButton("MR", 'R'),
  115.                Child, MPlus    = MakeButton("M+", 'm'),
  116.                Child, MMinus   = MakeButton("M-", 'M'),
  117.                Child, Clear    = MakeButton("C", 'c'),
  118.                Child, AllClear = MakeButton("AC", 'a'),
  119.             End,
  120.  
  121.             Child, HGroup, GroupSpacing(10), MUIA_Group_SameWidth, TRUE,
  122.                Child, Seven   = MakeButton("7", '7'),
  123.                Child, Eight   = MakeButton("8", '8'),
  124.                Child, Nine    = MakeButton("9", '9'),
  125.                Child, Divide  = MakeButton("÷", '/'),
  126.                Child, SqrRoot = MakeButton("Sqrt", 'r'),
  127.             End,
  128.  
  129.             Child, HGroup, GroupSpacing(10), MUIA_Group_SameWidth, TRUE,
  130.                Child, Four     = MakeButton("4", '4'),
  131.                Child, Five     = MakeButton("5", '5'),
  132.                Child, Six      = MakeButton("6", '6'),
  133.                Child, Multiply = MakeButton("×", '*'),
  134.                Child, Square   = MakeButton("x²", 's'),
  135.             End,
  136.  
  137.             Child, HGroup, GroupSpacing(10), MUIA_Group_SameWidth, TRUE,
  138.                Child, One    = MakeButton("1", '1'),
  139.                Child, Two    = MakeButton("2", '2'),
  140.                Child, Three  = MakeButton("3", '3'),
  141.                Child, Minus  = MakeButton("-", '-'),
  142.                Child, Negate = MakeButton("±", 'n'),
  143.             End,
  144.  
  145.             Child, HGroup, GroupSpacing(10), MUIA_Group_SameWidth, TRUE,
  146.                Child, Zero       = MakeButton("0", '0'),
  147.                Child, Period     = MakeButton("·", '.'),
  148.                Child, Equals     = MakeButton("=", 13),
  149.                Child, Plus       = MakeButton("+", '+'),
  150.                Child, Pi         = MakeButton("Pi", 'p'),
  151.             End,
  152.          End,
  153.       End,
  154.    End)) return(FALSE);
  155.  
  156.       /* the 'end program' flag */
  157.  
  158.    DoMethod(Win, MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
  159.       App, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);
  160.  
  161.       /* all digits, the decimal point, Pi and MRecall are processed by
  162.          'ProcessDigit()', which is called automatically via the structure
  163.          'DigitHook', defined above */
  164.  
  165.    DoMethod(Zero, MUIM_Notify, MUIA_Pressed, FALSE,
  166.       App, 3, MUIM_CallHook, &DigitHook, '0');
  167.  
  168.    DoMethod(One, MUIM_Notify, MUIA_Pressed, FALSE,
  169.       App, 3, MUIM_CallHook, &DigitHook, '1');
  170.  
  171.    DoMethod(Two, MUIM_Notify, MUIA_Pressed, FALSE,
  172.       App, 3, MUIM_CallHook, &DigitHook, '2');
  173.  
  174.    DoMethod(Three, MUIM_Notify, MUIA_Pressed, FALSE,
  175.       App, 3, MUIM_CallHook, &DigitHook, '3');
  176.  
  177.    DoMethod(Four, MUIM_Notify, MUIA_Pressed, FALSE,
  178.       App, 3, MUIM_CallHook, &DigitHook, '4');
  179.  
  180.    DoMethod(Five, MUIM_Notify, MUIA_Pressed, FALSE,
  181.       App, 3, MUIM_CallHook, &DigitHook, '5');
  182.  
  183.    DoMethod(Six, MUIM_Notify, MUIA_Pressed, FALSE,
  184.       App, 3, MUIM_CallHook, &DigitHook, '6');
  185.  
  186.    DoMethod(Seven, MUIM_Notify, MUIA_Pressed, FALSE,
  187.       App, 3, MUIM_CallHook, &DigitHook, '7');
  188.  
  189.    DoMethod(Eight, MUIM_Notify, MUIA_Pressed, FALSE,
  190.       App, 3, MUIM_CallHook, &DigitHook, '8');
  191.  
  192.    DoMethod(Nine, MUIM_Notify, MUIA_Pressed, FALSE,
  193.       App, 3, MUIM_CallHook, &DigitHook, '9');
  194.  
  195.    DoMethod(Period, MUIM_Notify, MUIA_Pressed, FALSE,
  196.       App, 3, MUIM_CallHook, &DigitHook, '.');
  197.  
  198.    DoMethod(Pi, MUIM_Notify, MUIA_Pressed, FALSE,
  199.       App, 3, MUIM_CallHook, &DigitHook, ID_PI);
  200.  
  201.    DoMethod(MRecall, MUIM_Notify, MUIA_Pressed, FALSE,
  202.       App, 3, MUIM_CallHook, &DigitHook, ID_RECALL);
  203.  
  204.    /* + - * / and = are handled by 'DoOperation()', called via 'OPHook' */
  205.  
  206.    DoMethod(Plus, MUIM_Notify, MUIA_Pressed, FALSE,
  207.       App, 3, MUIM_CallHook, &OPHook, PLUS);
  208.  
  209.    DoMethod(Minus, MUIM_Notify, MUIA_Pressed, FALSE,
  210.       App, 3, MUIM_CallHook, &OPHook, MINUS);
  211.  
  212.    DoMethod(Multiply, MUIM_Notify, MUIA_Pressed, FALSE,
  213.       App, 3, MUIM_CallHook, &OPHook, MULTIPLY);
  214.  
  215.    DoMethod(Divide, MUIM_Notify, MUIA_Pressed, FALSE,
  216.       App, 3, MUIM_CallHook, &OPHook, DIVIDE);
  217.  
  218.    DoMethod(SqrRoot, MUIM_Notify, MUIA_Pressed, FALSE,
  219.       App, 3, MUIM_CallHook, &OPHook, SQRT);
  220.  
  221.    DoMethod(Square, MUIM_Notify, MUIA_Pressed, FALSE,
  222.       App, 3, MUIM_CallHook, &OPHook, SQUARE);
  223.  
  224.    DoMethod(Negate, MUIM_Notify, MUIA_Pressed, FALSE,
  225.       App, 3, MUIM_CallHook, &OPHook, NEGATE);
  226.  
  227.    DoMethod(Equals, MUIM_Notify, MUIA_Pressed, FALSE,
  228.       App, 3, MUIM_CallHook, &OPHook, EQUALS);
  229.  
  230.    /* 'C', 'AC', 'M+' and 'M-' are handled by the main event loop */
  231.  
  232.    DoMethod(Clear, MUIM_Notify, MUIA_Pressed, FALSE,
  233.       App, 2, MUIM_Application_ReturnID, ID_CLEAR);
  234.  
  235.    DoMethod(AllClear, MUIM_Notify, MUIA_Pressed, FALSE,
  236.       App, 2, MUIM_Application_ReturnID, ID_ALLCLEAR);
  237.  
  238.    DoMethod(MPlus, MUIM_Notify, MUIA_Pressed, FALSE,
  239.       App, 2, MUIM_Application_ReturnID, ID_MEMPLUS);
  240.  
  241.    DoMethod(MMinus, MUIM_Notify, MUIA_Pressed, FALSE,
  242.       App, 2, MUIM_Application_ReturnID, ID_MEMMINUS);
  243.  
  244.    return(TRUE);
  245. }
  246.  
  247. /*----------------------------------------------------------------------------*/
  248. /*    MakeButton                                                              */
  249. /*----------------------------------------------------------------------------*/
  250.  
  251. static APTR MakeButton(UBYTE *Label, UBYTE Key)
  252. {
  253.    return(TextObject, ButtonFrame, MUIA_Text_Contents, Label,
  254.                                    MUIA_Text_PreParse, "\33c",
  255.                                    MUIA_ControlChar, Key,
  256.                                    MUIA_InputMode, MUIV_InputMode_RelVerify,
  257.                                    MUIA_Background, MUII_ButtonBack,
  258.           End);
  259. }
  260.  
  261. /*----------------------------------------------------------------------------*/
  262. /*    ProcessDigit                                                            */
  263. /*----------------------------------------------------------------------------*/
  264.  
  265. static ASM void ProcessDigit(REG(a2) APTR Object, REG(a1) UBYTE *Digit)
  266. {
  267.    if (Error) return;                /* only AC or C can clear the Error flag */
  268.  
  269.    if (!Cursor) ClearBuffer();      /* zero cursor = new number to be entered */
  270.  
  271.    if (Digit[3] == ID_PI)                                   /* exception - Pi */
  272.    {
  273.       UpdateDisplay(PI);                 /* constant for Pi defined in math.h */
  274.       Cursor = MaxChars - 1;                                 /* adjust cursor */
  275.       return;
  276.    }
  277.  
  278.    if (Digit[3] == ID_RECALL)                          /* exception - MRecall */
  279.    {
  280.       UpdateDisplay(Memory);
  281.       Cursor = MaxChars - 1;
  282.       return;
  283.    }
  284.  
  285.    if (Cursor < MaxChars - (1-Decimal))     /* while still room in the buffer */
  286.    {
  287.       if (Digit[3] == '0' && Cursor == 0) return;   /* suppress leading zeros */
  288.  
  289.       if (Digit[3] == '.')
  290.       {
  291.          if (Decimal) return;               /* this is already a float number */
  292.          if (!Cursor) DigitBuffer[Cursor++] = '0';
  293.                                        /* insert a single leading zero - '0.' */
  294.          Decimal = TRUE;                                      /* set the flag */
  295.       }
  296.  
  297.       DigitBuffer[Cursor++] = Digit[3];                /* add digit to buffer */
  298.       if (!Decimal) DigitBuffer[Cursor] = '.';        /* add decimal point to */
  299.                                                    /* end if still an integer */
  300.       set(Display, MUIA_Text_Contents, DigitBuffer);        /* update display */
  301.    }
  302. }
  303.  
  304. /*----------------------------------------------------------------------------*/
  305. /*    DoOperation                                                             */
  306. /*----------------------------------------------------------------------------*/
  307.  
  308. static ASM void DoOperation(REG(a2) APTR Object, REG(a1) ULONG *Operator)
  309. {
  310.    if (Error) return;                   /* only the AC or C buttons can clear */
  311.                                                             /* the Error flag */
  312.    if (Operator[0] >= SQRT && Operator[0] <= NEGATE)     /* is it a function? */
  313.    {
  314.       sscanf(DigitBuffer, "%lf", &CurrentOperand);     /* convert the display */
  315.  
  316.       switch (Operator[0])        /* 'Operator' is a pointer to a ULONG which */
  317.       {                           /* contains the code of the operation to be */
  318.          case SQUARE:             /* performed */
  319.             CurrentOperand *=CurrentOperand;
  320.             break;
  321.  
  322.          case SQRT:
  323.             if (CurrentOperand) CurrentOperand = sqrt(CurrentOperand);
  324.             else                                              /* trap sqrt(0) */
  325.             {
  326.                DoError();
  327.                return;
  328.             }
  329.             break;
  330.  
  331.          case NEGATE:
  332.             CurrentOperand = -CurrentOperand;
  333.             break;
  334.  
  335.          default:
  336.             break;
  337.       }
  338.       UpdateDisplay(CurrentOperand);
  339.    }
  340.    else                                                     /* or an operator */
  341.    {
  342.       if (!NextOperation)        /* no operation pending, so the display must */
  343.       {                                          /* contain the first operand */
  344.          sscanf(DigitBuffer, "%lf", &Operand1);
  345.       }
  346.       else
  347.       {
  348.          sscanf(DigitBuffer, "%lf", &Operand2);             /* second operand */
  349.  
  350.          switch (NextOperation)
  351.          {
  352.             case PLUS:
  353.                Operand1 += Operand2;
  354.                break;
  355.  
  356.             case MINUS:
  357.                Operand1 -= Operand2;
  358.                break;
  359.  
  360.             case MULTIPLY:
  361.                Operand1 *= Operand2;
  362.                break;
  363.  
  364.             case DIVIDE:
  365.                if (Operand2) Operand1 /= Operand2;
  366.                else                                  /* trap division-by-zero */
  367.                {
  368.                   DoError();
  369.                   return;
  370.                }
  371.                break;
  372.  
  373.             case EQUALS:
  374.                Operand1 = Operand2;
  375.                break;
  376.  
  377.             default:
  378.                break;
  379.          }
  380.          Operand2 = 0;                                /* clear second operand */
  381.          UpdateDisplay(Operand1);   /* and update the display with the result */
  382.       }
  383.       NextOperation = Operator[0];    /* store next operation to be performed */
  384.    }
  385.    Cursor = 0;
  386. }
  387.  
  388. /*----------------------------------------------------------------------------*/
  389. /*    ClearBuffer                                                             */
  390. /*----------------------------------------------------------------------------*/
  391.  
  392. static void ClearBuffer(void)
  393. {
  394.    for (Cursor=0; Cursor<BufferSize; Cursor++) DigitBuffer[Cursor] = 0;
  395.    Cursor = 0;
  396.    Decimal = FALSE;
  397.  
  398.    set(Display, MUIA_Text_Contents, "0.");
  399. }
  400.  
  401. /*----------------------------------------------------------------------------*/
  402. /*    DoError                                                                 */
  403. /*----------------------------------------------------------------------------*/
  404.  
  405. static void DoError(void)
  406. {
  407.    set(Display, MUIA_Text_Contents, "\33c- Error -");
  408.    Error = TRUE;                      /* set flag to prevent operations until */
  409. }                                                               /* an AC or C */
  410.  
  411. /*----------------------------------------------------------------------------*/
  412. /*    UpdateDisplay                                                           */
  413. /*----------------------------------------------------------------------------*/
  414.  
  415. static void UpdateDisplay(long double Value)
  416. {
  417.  
  418. ULONG Places, BufPos = 0;
  419.  
  420.    sprintf(DigitBuffer, "%.9Lf", Value);
  421.    while (DigitBuffer[BufPos++] != '.');    /* no more than 10 digits allowed */
  422.    Places = MaxChars - BufPos;            /* these lines calculate the number */
  423.    sprintf(DigitBuffer, "%.*Lf", Places, Value);      /* of decimal places to */
  424.                                                       /* display */
  425.    BufPos = strlen(DigitBuffer) - 1;
  426.  
  427.    while (DigitBuffer[BufPos] == '0')     /* these lines strip trailing zeros */
  428.    {
  429.       DigitBuffer[BufPos--] = 0;
  430.    }
  431.  
  432.    set(Display, MUIA_Text_Contents, DigitBuffer);
  433. }
  434.  
  435. /*----------------------------------------------------------------------------*/
  436.