home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1993 #2 / Image.iso / database / pk4pak.zip / POPCALC.SC < prev    next >
Text File  |  1993-03-15  |  57KB  |  1,532 lines

  1. ;==============================================================================
  2. ; (c) Copyright Elect Software International Inc., 1992, Toronto. Anyone can
  3. ; use this code for anything as long as it is not resold as a software
  4. ; development resource, as long as the copyright notice isn't removed, as
  5. ; long as changes are clearly marked as to authorship, and as long as users
  6. ; indemnify Elect from any liability.
  7. ; Comments welcome. Henrik Bechmann, CIS:72701,3717; Tel:416-534-8176.
  8. ; Mar-92, Apr-92, Jun-92, Jul-92
  9. ;==============================================================================
  10.  
  11. ;==============================================================================
  12. ;                        ESI-PD40B CALCULATOR INTERFACE
  13. ;==============================================================================
  14. ; Calculator.Constructor() ; This configures the calculator in memory. Since
  15. ;                          ; the key variables are all created here, the
  16. ;                          ; calculator is re-entrant using
  17. ;                          ; Calculator.Dialog(). In other words, the user
  18. ;                          ; is able to hit [Esc] to temporarily leave
  19. ;                          ; the calculator (say to look something up) and then
  20. ;                          ; be able to re-enter it to find it in the same
  21. ;                          ; state as it was when [Esc] was hit.
  22. ;                          ; The constructor should be called at the beginning
  23. ;                          ; of a session, to save time in calling the
  24. ;                          ; calculator during the session.
  25. ; Calculator.Dialog()      ; This calls the calculator. Returns blanknum() if
  26. ;                          ; the user exited by hitting [Esc], otherwise returns
  27. ;                          ; a number (N).
  28. ; Calculator.Destructor()  ; Destroys the calculator's global variables (ie.
  29. ;                          ; destroys the calculator) at the end of a session.
  30.  
  31. ; Calculator.Value
  32. ; Calculator.IsActive
  33.  
  34. ;==============================================================================
  35. ;                       CALCULATOR IMPLEMENTATION
  36. ;==============================================================================
  37. ;----------------------------------------------------------------------------
  38. ; Calculator.Constructor() Sets up variables and arrays for the calculator
  39. ; in memory. These variables are technically global, which makes the
  40. ; calculator re-entrant.
  41. ;----------------------------------------------------------------------------
  42.  
  43. Proc Calculator.Constructor()
  44.    Private
  45.       i,j,
  46.       Element
  47.    ;-------------------------------------------------------------------------
  48.    ; Provide message to user...
  49.    ;-------------------------------------------------------------------------
  50.    Message "Initializing calculator..."
  51.    ;-------------------------------------------------------------------------
  52.    ; Initialize constants, and control variables...
  53.    ; First, universal null...
  54.    ;-------------------------------------------------------------------------
  55.    Calculator_NULL         = 255
  56.    ;-------------------------------------------------------------------------
  57.    ; Keystroke types...
  58.    ;-------------------------------------------------------------------------
  59.    Calculator_OPCHAR       = 1
  60.    Calculator_FUNCCHAR     = 2
  61.    Calculator_NUMCHAR      = 3
  62.    Calculator_EDITCHAR     = 4
  63.    ;-------------------------------------------------------------------------
  64.    ; Token types... (Only FLOATING and OPERATOR are currently used)
  65.    ;-------------------------------------------------------------------------
  66. ;   Calculator_TIME         = 1
  67. ;   Calculator_SECONDS      = 2
  68. ;   Calculator_MINUTES      = 3
  69. ;   Calculator_HOURS        = 4
  70. ;   Calculator_DAYS         = 5
  71. ;   Calculator_WEEKS        = 6
  72. ;   Calculator_MONTHS       = 7
  73. ;   Calculator_YEARS        = 8
  74. ;   Calculator_DATE         = 9
  75.    Calculator_FLOATING     = 10
  76. ;   Calculator_INTEGER      = 11
  77. ;   Calculator_MONEY        = 12
  78. ;   Calculator_STRING       = 13
  79.    Calculator_OPERATOR     = 14
  80.    ;-------------------------------------------------------------------------
  81.    ; Input cell states...
  82.    ;-------------------------------------------------------------------------
  83.    Calculator_WAITING = 0
  84.    Calculator_CALC = 1
  85.    ;-------------------------------------------------------------------------
  86.    ; Token type names... (not currently used.)
  87.    ;-------------------------------------------------------------------------
  88. ;   Dynarray Calculator_TokenTypeName[]
  89. ;   Calculator_TokenTypeName[Calculator_TIME]     = "Time"
  90. ;   Calculator_TokenTypeName[Calculator_SECONDS]  = "Seconds"
  91. ;   Calculator_TokenTypeName[Calculator_MINUTES]  = "Minutes"
  92. ;   Calculator_TokenTypeName[Calculator_HOURS]    = "Hours"
  93. ;   Calculator_TokenTypeName[Calculator_DAYS]     = "Days"
  94. ;   Calculator_TokenTypeName[Calculator_WEEKS]    = "Weeks"
  95. ;   Calculator_TokenTypeName[Calculator_MONTHS]   = "Months"
  96. ;   Calculator_TokenTypeName[Calculator_YEARS]    = "Years"
  97. ;   Calculator_TokenTypeName[Calculator_DATE]     = "Date"
  98. ;   Calculator_TokenTypeName[Calculator_FLOATING] = "Floating"
  99. ;   Calculator_TokenTypeName[Calculator_INTEGER]  = "Integer"
  100. ;   Calculator_TokenTypeName[Calculator_MONEY]    = "Money"
  101. ;   Calculator_TokenTypeName[Calculator_STRING]   = "String"
  102. ;   Calculator_TokenTypeName[Calculator_OPERATOR] = "Operator"
  103.    ;-------------------------------------------------------------------------
  104.    ; Keycode data...
  105.    ;-------------------------------------------------------------------------
  106.    Calculator_Keycode = BlankNum()
  107.    Calculator_KeycodeAttribute = Calculator_NULL
  108.    ;-------------------------------------------------------------------------
  109.    ; Calculator input cell data...
  110.    ; Set the Accept statement defualt variables here as well...
  111.    ;-------------------------------------------------------------------------
  112.    Calculator_CellDataType      = "N"
  113.    Calculator_DecimalFlag       = False
  114.    Calculator!KeyPadModeLine() ; sets Calculator_KeyPadModeLine
  115.    Calculator_CellStatus        = Calculator_WAITING
  116.    Calculator.Value             = 0
  117.    Calculator_Value             = 0 ; to transfer escaped value to .Value
  118.    Calculator_CellAttribute     = Calculator_FLOATING ; data type
  119.    Calculator_CellLastValue     = Calculator.Value
  120.    Calculator_CellLastAttribute = Calculator_CellAttribute
  121.    ;-------------------------------------------------------------------------
  122.    ; Expression status...
  123.    ;-------------------------------------------------------------------------
  124.    Calculator_CurrentOperator = Calculator_NULL
  125.    Calculator_LastOperator = Calculator_NULL
  126.    ;-------------------------------------------------------------------------
  127.    ; Internal token data...
  128.    ;-------------------------------------------------------------------------
  129.    Dynarray Calculator_StackValue[]
  130.    Dynarray Calculator_StackAttribute[] ; data type/operator
  131.    Calculator_StackPtr = 0
  132.    ;-------------------------------------------------------------------------
  133.    ; Classification of characters streaming in...
  134.    ;-------------------------------------------------------------------------
  135.    Dynarray Calculator_KeyCodeType[] ; 32 total
  136.    Calculator_KeycodeType[Asc("Del")]           = Calculator_EDITCHAR
  137.    Calculator_KeycodeType[Asc("Backspace")]     = Calculator_EDITCHAR
  138.    Calculator_KeycodeType[Asc("CtrlBackspace")] = Calculator_EDITCHAR
  139.    Calculator_KeycodeType[Asc("Right")]         = Calculator_EDITCHAR
  140.    Calculator_KeycodeType[Asc("Left")]          = Calculator_EDITCHAR
  141.    Calculator_KeycodeType[Asc("Home")]          = Calculator_EDITCHAR
  142.    Calculator_KeycodeType[Asc("End")]           = Calculator_EDITCHAR
  143.    Calculator_KeycodeType[Asc("0")]             = Calculator_NUMCHAR
  144.    Calculator_KeycodeType[Asc("1")]             = Calculator_NUMCHAR
  145.    Calculator_KeycodeType[Asc("2")]             = Calculator_NUMCHAR
  146.    Calculator_KeycodeType[Asc("3")]             = Calculator_NUMCHAR
  147.    Calculator_KeycodeType[Asc("4")]             = Calculator_NUMCHAR
  148.    Calculator_KeycodeType[Asc("5")]             = Calculator_NUMCHAR
  149.    Calculator_KeycodeType[Asc("6")]             = Calculator_NUMCHAR
  150.    Calculator_KeycodeType[Asc("7")]             = Calculator_NUMCHAR
  151.    Calculator_KeycodeType[Asc("8")]             = Calculator_NUMCHAR
  152.    Calculator_KeycodeType[Asc("9")]             = Calculator_NUMCHAR
  153.    Calculator_KeycodeType[Asc(".")]             = Calculator_NUMCHAR
  154.    Calculator_KeycodeType[Asc("%")]             = Calculator_FUNCCHAR
  155.    Calculator_KeycodeType[Asc(">")]             = Calculator_FUNCCHAR
  156.    Calculator_KeycodeType[Asc("<")]             = Calculator_FUNCCHAR
  157.    Calculator_KeycodeType[-16]                  = Calculator_FUNCCHAR ; Alt-Q, square root
  158.    Calculator_KeycodeType[-49]                  = Calculator_FUNCCHAR ; Alt-N, round
  159.    Calculator_KeycodeType[Asc("!")]             = Calculator_FUNCCHAR
  160.    Calculator_KeycodeType[Asc("^")]             = Calculator_OPCHAR
  161.    Calculator_KeycodeType[Asc("*")]             = Calculator_OPCHAR
  162.    Calculator_KeycodeType[Asc("/")]             = Calculator_OPCHAR
  163.    Calculator_KeycodeType[Asc("+")]             = Calculator_OPCHAR
  164.    Calculator_KeycodeType[Asc("-")]             = Calculator_OPCHAR
  165.    Calculator_KeycodeType[Asc("=")]             = Calculator_OPCHAR
  166.    Calculator_KeycodeType[Asc("Enter")]         = Calculator_OPCHAR
  167.    Calculator_KeycodeType[Asc("Do_It!")]        = Calculator_OPCHAR
  168.    Calculator_KeycodeType[Asc("Esc")]           = Calculator_OPCHAR
  169.    ;-------------------------------------------------------------------------
  170.    ; Set up a key event list for all keycode types. This will be used when
  171.    ; Calculator_CellStatus = Calculator_WAITING
  172.    ;-------------------------------------------------------------------------
  173.    Array Calculator_CharEventKey[33]
  174.    i = 0
  175.    ForEach Element In Calculator_KeyCodeType
  176.       i = i + 1
  177.       Calculator_CharEventKey[i] = Numval(Element)
  178.    Endforeach
  179. ;   j = i
  180. ;   For i From j + 1 to 31
  181. ;      Calculator_CharEventKey[i] = Calculator_NULL
  182. ;   EndFor
  183.    ;-------------------------------------------------------------------------
  184.    ; Set up a key event list for operator keycode types. This will be used
  185.    ; when Calculator_CellStatus = Calculator_CALC
  186.    ;-------------------------------------------------------------------------
  187.    Array Calculator_OpEventKey[15]
  188.    Calculator_OpEventKey[1] = Asc("^")
  189.    Calculator_OpEventKey[2] = Asc("%")
  190.    Calculator_OpEventKey[2] = Asc("<")
  191.    Calculator_OpEventKey[2] = Asc(">")
  192.    Calculator_OpEventKey[3] = Asc("!")
  193.    Calculator_OpEventKey[4] = Asc("*")
  194.    Calculator_OpEventKey[5] = Asc("/")
  195.    Calculator_OpEventKey[6] = Asc("+")
  196.    Calculator_OpEventKey[7] = Asc("-")
  197.    Calculator_OpEventKey[8] = Asc("=")
  198.    Calculator_OpEventKey[9] = Asc("Enter")
  199.    Calculator_OpEventKey[10] = -16 ; Alt-Q, square root
  200.    Calculator_OpEventKey[11] = -49 ; Alt-N, round
  201.    Calculator_OpEventKey[12] = Asc("<")
  202.    Calculator_OpEventKey[13] = Asc(">")
  203.    Calculator_OpEventKey[14] = Asc("Do_It!")
  204.    Calculator_OpEventKey[15] = Asc("Esc")
  205.    ;-------------------------------------------------------------------------
  206.    ; Set up a list of procedures to call in response to the operator
  207.    ; keystrokes...
  208.    ;-------------------------------------------------------------------------
  209.    Dynarray Calculator_ResponseProc[] ; 20 total
  210.    Calculator_ResponseProc[Asc("^")]     = "Calculator!Exponent"
  211.    Calculator_ResponseProc[Asc("%")]     = "Calculator!Percent"
  212.    Calculator_ResponseProc[Asc("!")]     = "Calculator!Factorial"
  213.    Calculator_ResponseProc[Asc("*")]     = "Calculator!Multiply"
  214.    Calculator_ResponseProc[Asc("/")]     = "Calculator!Divide"
  215.    Calculator_ResponseProc[Asc("+")]     = "Calculator!Add"
  216.    Calculator_ResponseProc[Asc("-")]     = "Calculator!Subtract"
  217.    Calculator_ResponseProc[Asc("=")]     = "Calculator!Equals"
  218.    Calculator_ResponseProc[Asc("Enter")] = "Calculator!Equals"
  219.    Calculator_ResponseProc[Asc("R")]     = "Calculator!PlusMinus"
  220.    Calculator_ResponseProc[Asc("S")]     = "Calculator!Subtotal"
  221.    Calculator_ResponseProc[Asc("C")]     = "Calculator!Clear"
  222.    Calculator_ResponseProc[Asc("√")]     = "Calculator!Sqrt"
  223.    Calculator_ResponseProc[-16]          = "Calculator!Sqrt" ; Alt-Q
  224.    Calculator_ResponseProc[-49]          = "Calculator!Round" ; Alt-N
  225.    Calculator_ResponseProc[Asc("N")]     = "Calculator!Round" ; Alt-N
  226.    Calculator_ResponseProc[Asc(">")]     = "Calculator!SaveMem"
  227.    Calculator_ResponseProc[Asc("<")]     = "Calculator!GetMem"
  228.    Calculator_ResponseProc[Asc("Do_It!")] = "Calculator!OK"
  229.    Calculator_ResponseProc[Asc("Esc")]    = "Calculator!Escape"
  230.    ;-------------------------------------------------------------------------
  231.    ; Define an engine for the DialogProc. This controller directs the thread
  232.    ; of control with an execproc statement to the procedure matching the
  233.    ; event.
  234.    ;-------------------------------------------------------------------------
  235.    Dynarray Calculator_EventEngine[]
  236.    Calculator_EventEngine["Open"]   = "Calculator!Open"
  237.    Calculator_EventEngine["Event"]  = "Calculator!Event"
  238.    ;-------------------------------------------------------------------------
  239.    ; Paper tape facsimile at top of calculator
  240.    ;-------------------------------------------------------------------------
  241.    Array Calculator_Tape[5]
  242.    For i From 1 to 5
  243.       Calculator_Tape[i] = ""
  244.    Endfor
  245.    Calculator_TapeFile = "CalcTape.Txt"
  246.    Calculator_TapeIsOn = False
  247.    Calculator!TapeModeLine()  ; calculates Calculator_TapeModeLine
  248.    ;-------------------------------------------------------------------------
  249.    ; Explanation file...
  250.    ;-------------------------------------------------------------------------
  251.    Calculator.ExplainFile = "PopCalc.hlp"
  252.    ;-------------------------------------------------------------------------
  253.    ; Dialog window information...
  254.    ;-------------------------------------------------------------------------
  255.    Calculator_WindowHandle = Blanknum()
  256.    Calculator_WindowBag = Blanknum()
  257.    Calculator_WindowRow = Blanknum()
  258.    Calculator_WindowCol = Blanknum()
  259.    ;-------------------------------------------------------------------------
  260.    ; Memory value...
  261.    ;-------------------------------------------------------------------------
  262.    Calculator_MemoryValue = BlankNum()
  263.    Calculator_MemoryAttribute = Calculator_NULL
  264.    ;-------------------------------------------------------------------------
  265.    ; Clear message to user...
  266.    ;-------------------------------------------------------------------------
  267.    Calculator.IsActive = True
  268.    Message ""
  269. EndProc ; Calculator.Constructor
  270.  
  271. ;----------------------------------------------------------------------------
  272. ; To release global variables set up in the constructor...
  273. ;----------------------------------------------------------------------------
  274. Proc Calculator.Destructor()
  275.    Release Vars
  276.       Calculator_NULL,
  277.       Calculator_OPCHAR,
  278.       Calculator_FUNCCHAR,
  279.       Calculator_NUMCHAR,
  280.       Calculator_EDITCHAR,
  281.       Calculator_TIME,
  282.       Calculator_SECONDS,
  283.       Calculator_MINUTES,
  284.       Calculator_HOURS,
  285.       Calculator_DAYS,
  286.       Calculator_WEEKS,
  287.       Calculator_MONTHS,
  288.       Calculator_YEARS,
  289.       Calculator_DATE,
  290.       Calculator_FLOATING,
  291.       Calculator_INTEGER,
  292.       Calculator_MONEY,
  293.       Calculator_STRING,
  294.       Calculator_OPERATOR,
  295.       Calculator_WAITING,
  296.       Calculator_CALC,
  297.       Calculator_TokenTypeName,
  298.       Calculator_Keycode,
  299.       Calculator_KeycodeAttribute,
  300.       Calculator_CellDataType,
  301.       Calculator_DecimalFlag,
  302.       Calculator_KeyPadModeLine,
  303.       Calculator_CellStatus,
  304.       Calculator.Value,
  305.       Calculator_Value,
  306.       Calculator_CellAttribute,
  307.       Calculator_CellLastValue,
  308.       Calculator_CellLastAttribute,
  309.       Calculator_CurrentOperator,
  310.       Calculator_LastOperator,
  311.       Calculator_StackValue,
  312.       Calculator_StackAttribute,
  313.       Calculator_StackPtr,
  314.       Calculator_KeyCodeType,
  315.       Calculator_CharEventKey,
  316.       Calculator_OpEventKey,
  317.       Calculator_ResponseProc,
  318.       Calculator_EventEngine,
  319.       Calculator_Tape,
  320.       Calculator_TapeFile,
  321.       Calculator_TapeModeLine,
  322.       Calculator.ExplainFile,
  323.       Calculator_WindowHandle,
  324.       Calculator_WindowBag,
  325.       Calculator_WindowRow,
  326.       Calculator_WindowCol,
  327.       Calculator_MemoryValue,
  328.       Calculator_MemoryAttribute,
  329.       Calculator.IsActive
  330. EndProc ; Calculator.Destructor
  331.  
  332. ;----------------------------------------------------------------------------
  333. ; Returns blanknum() or a number, depending on user's acceptance of the
  334. ; result.
  335. ;----------------------------------------------------------------------------
  336. Proc Calculator.Dialog()
  337.    Private
  338.       CalcKey
  339.  
  340.    ShowDialog "ESI-PD40B Calculator"
  341.    Proc "Calculator!DialogProc"
  342.    Trigger "Open"
  343.    @2,13 Height 20 Width 30
  344.    @0,0 ?? Calculator_Tape[1]
  345.    @1,0 ?? Calculator_Tape[2]
  346.    @2,0 ?? Calculator_Tape[3]
  347.    @3,0 ?? Calculator_Tape[4]
  348.    @4,0 ?? Calculator_Tape[5]
  349.    @5,0 ?? Calculator_TapeModeLine
  350.    @7,0 ?? Calculator_KeyPadModeLine
  351.    Accept
  352.       @6,0 Width 28
  353.       Calculator_CellDataType
  354.       Required
  355.       Tag "Cell"
  356.       To Calculator.Value
  357.    PushButton
  358.       @8,0 Width 5 "7"
  359.       Value Calculator!NumKey("7")
  360.       Tag "7"
  361.       To CalcKey
  362.    PushButton
  363.       @8,5 Width 5 "8"
  364.       Value Calculator!NumKey("8")
  365.       Tag "8"
  366.       To CalcKey
  367.    PushButton
  368.       @8,10 Width 5 "9"
  369.       Value Calculator!NumKey("9")
  370.       Tag "9"
  371.       To CalcKey
  372.    PushButton
  373.       @8,15 Width 7 "~R~ev"
  374.       Value Calculator!PlusMinus()
  375.       Tag "Rev"
  376.       To CalcKey
  377.    PushButton
  378.       @8,22 Width 5 "/"
  379.       Value Calculator!Divide()
  380.       Tag "/"
  381.       To CalcKey
  382.    PushButton
  383.       @10,0 Width 5 "4"
  384.       Value Calculator!NumKey("4")
  385.       Tag "4"
  386.       To CalcKey
  387.    PushButton
  388.       @10,5 Width 5 "5"
  389.       Value Calculator!NumKey("5")
  390.       Tag "5"
  391.       To CalcKey
  392.    PushButton
  393.       @10,10 Width 5 "6"
  394.       Value Calculator!NumKey("6")
  395.       Tag "6"
  396.       To CalcKey
  397.    PushButton
  398.       @10,15 Width 7 "C~l~r"
  399.       Value Calculator!Clear()
  400.       Tag "Clr"
  401.       To CalcKey
  402.    PushButton
  403.       @10,22 Width 5 "*"
  404.       Value Calculator!Multiply()
  405.       Tag "*"
  406.       To CalcKey
  407.    PushButton
  408.       @12,0 Width 5 "1"
  409.       Value Calculator!NumKey("1")
  410.       Tag "1"
  411.       To CalcKey
  412.    PushButton
  413.       @12,5 Width 5 "2"
  414.       Value Calculator!NumKey("2")
  415.       Tag "2"
  416.       To CalcKey
  417.    PushButton
  418.       @12,10 Width 5 "3"
  419.       Value Calculator!NumKey("3")
  420.       Tag "3"
  421.       To CalcKey
  422.    PushButton
  423.       @12,15 Width 7 "~S~ub"
  424.       Value Calculator!Subtotal()
  425.       Tag "Sub"
  426.       To CalcKey
  427.    PushButton
  428.       @12,22 Width 5 "-"
  429.       Value Calculator!Subtract()
  430.       Tag "-"
  431.       To CalcKey
  432.    PushButton
  433.       @14,0 Width 10 "0"
  434.       Value Calculator!NumKey("0")
  435.       Tag "0"
  436.       To CalcKey
  437.    PushButton
  438.       @14,10 Width 5 "."
  439.       Value Calculator!Decimal()
  440.       Tag "."
  441.       To CalcKey
  442.    PushButton
  443.       @14,15 Width 7 "="
  444.       Value Calculator!Equals()
  445.       Tag "="
  446.       To CalcKey
  447.    PushButton
  448.       @14,22 Width 5 "+"
  449.       Value Calculator!Add()
  450.       Tag "+"
  451.       To CalcKey
  452.    PushButton
  453.       @16,0 Width 6 "~O~K"
  454.       OK
  455.       Value Calculator!OK()
  456.       Tag "OK"
  457.       To CalcKey
  458.    PushButton
  459.       @16,6 Width 7 "~E~sc"
  460.       Cancel
  461.       Value Calculator!Escape()
  462.       Tag "Esc"
  463.       To CalcKey
  464.    PushButton
  465.       @16,13 Width 6 "O~p~"
  466.       Value Calculator!Op()
  467.       Tag "Op"
  468.       To CalcKey
  469.    PushButton
  470.       @16,19 Width 8 "~M~enu"
  471.       Value Calculator!Menu()
  472.       Tag "Menu"
  473.       To CalcKey
  474.    EndDialog
  475.    If Not Retval Then
  476.       Calculator.Value = Calculator_Value
  477.    Endif
  478.    Return retval
  479. EndProc ; Calculator.Dialog
  480.  
  481. Proc Calculator!ViewExplain()
  482.    Private
  483.       WindowHandle,
  484.       WindowBag,
  485.       EventBag,
  486.       KeyCode
  487.  
  488.    Calculator!GetCoordinates()
  489.    Window Move Calculator_WindowHandle To 500,500 ; off the screen
  490.    ShowPullDown EndMenu
  491.    If IsFile(Calculator.ExplainFile) Then
  492.       Editor Open Calculator.ExplainFile
  493.    Else
  494.       Editor New Calculator.ExplainFile
  495.    Endif
  496.    Menu {Options}{WordWrap}{Set}
  497.    WindowHandle = GetWindow()
  498.    Window Select WindowHandle
  499.    Window Maximize WindowHandle
  500.    Dynarray EventBag[]
  501.    Dynarray WindowBag[]
  502.    WindowBag["Title"] = "ESI-PD40B Calculator"
  503.    WindowBag["CanMaximize"] = False
  504.    Window SetAttributes WindowHandle From WindowBag
  505.    Echo Normal
  506.    Prompt "Hit [F2] or [Esc] to return to the calculator",""
  507.    While True
  508.       GetEvent To EventBag
  509.       Switch
  510.          Case EventBag["Type"] = "KEY":
  511.          ;------------------------------
  512.             Keycode = EventBag["Keycode"]
  513.             Switch
  514.                Case Keycode = Asc("F2"):
  515.                   ExecEvent EventBag
  516.                   Quitloop
  517.                Case KeyCode = Asc("Esc"):
  518.                   Window Close
  519.                   Quitloop
  520.                Case KeyCode = Asc("F1"):
  521.                   ; (do nothing; suppress Help)
  522.                Case Keycode = Asc("Home") or
  523.                     Keycode = Asc("End") or
  524.                     Keycode = Asc("PgUp") or
  525.                     Keycode = Asc("PgDn") or
  526.                     Keycode = Asc("Left") or
  527.                     Keycode = Asc("Right") or
  528.                     Keycode = Asc("Up") or
  529.                     Keycode = Asc("Down") or
  530.                     Keycode = Asc("CtrlPgUp") or
  531.                     Keycode = Asc("CtrlPgDn") or
  532.                     Keycode = Asc("CtrlLeft") or
  533.                     Keycode = Asc("CtrlRight"):
  534.                   ExecEvent EventBag
  535.                OtherWise: ; do nothing
  536.             EndSwitch
  537.          Case EventBag["Type"] = "MESSAGE":
  538.          ;----------------------------------
  539.             Switch
  540.                Case EventBag["Message"] = "CLOSE":
  541.                   ExecEvent EventBag
  542.                   Quitloop
  543.                Case EventBag["Message"] = "NEXT":
  544.                   Beep
  545.                   Message "Close window to return to calculator."
  546.                   Sleep 2000
  547.                   Message ""
  548.                   ; do nothing, repress this
  549.                Otherwise:
  550.                   ExecEvent EventBag
  551.             EndSwitch
  552.          Otherwise:
  553.          ;---------
  554.             ExecEvent EventBag
  555.       EndSwitch
  556.    EndWhile
  557.    Release Vars EventBag
  558.    Prompt
  559.    Window Move Calculator_WindowHandle To Calculator_Row,Calculator_Col
  560.    Echo Off
  561. EndProc ; Calculator!ViewExplain
  562.  
  563. Proc PopCalc!CloseWindowWithConfirm()
  564.    Private
  565.       WindowHandle,
  566.       EventBag
  567.    WindowHandle = GetWindow()
  568.    WinClose
  569.    While IsWindow(WindowHandle) And (GetWindow() <> WindowHandle)
  570.       ;--------------------------------------------------------------
  571.       ; ie. we're on a confirmation menu, so eat events until
  572.       ; accept or deny of winclose is indirectly confirmed. Accept is
  573.       ; detected by absence of WindowHandle; deny is detected by
  574.       ; return to the WindowHandle.
  575.       ;--------------------------------------------------------------
  576.       GetEvent to EventBag
  577.       ExecEvent EventBag
  578.    EndWhile
  579.    If IsWindow(WindowHandle) Then
  580.       Return false
  581.    Else
  582.       Return true
  583.    Endif
  584. EndProc ; PopCalc!CloseWindowWithConfirm
  585.  
  586. Proc Calculator!GetCoordinates()
  587.    Window Handle Dialog to Calculator_WindowHandle
  588.    Window GetAttributes Calculator_WindowHandle To Calculator_WindowBag
  589.    Calculator_Row = Calculator_WindowBag["OriginRow"]
  590.    Calculator_Col = Calculator_WindowBag["OriginCol"]
  591. EndProc ; Calculator!GetCoordinates
  592.  
  593. Proc Calculator!ViewTape()
  594.    Private
  595.       WindowHandle,
  596.       WindowBag,
  597.       EventBag
  598.  
  599.    Calculator!GetCoordinates()
  600.    Window Move Calculator_WindowHandle To 500,500 ; off the screen
  601.    ShowPullDown EndMenu
  602.    If IsFile(Calculator_TapeFile) Then
  603.       Editor Open Calculator_TapeFile
  604.    Else
  605.       Editor New Calculator_TapeFile
  606.    Endif
  607.    Menu {Options}{WordWrap}{Clear}
  608.    WindowHandle = GetWindow()
  609.    Window Select WindowHandle
  610.    Dynarray EventBag[]
  611.    Dynarray WindowBag[]
  612.    WindowBag["OriginRow"] = Calculator_Row
  613.    WindowBag["OriginCol"] = Calculator_Col
  614.    WindowBag["Height"] = 20
  615.    WindowBag["Width"] = 30
  616.    WindowBag["Title"] = "Calculator Tape"
  617.    Window SetAttributes WindowHandle From WindowBag
  618.    Echo Normal
  619.    Prompt "Hit [F2] or [Esc] to return to the calculator",""
  620.    While True
  621.       GetEvent To EventBag
  622.       Switch
  623.          Case EventBag["Type"] = "KEY":
  624.          ;------------------------------
  625.             Switch
  626.                Case EventBag["Keycode"] = Asc("F2"):
  627.                   ExecEvent EventBag
  628.                   Quitloop
  629.                Case EventBag["KeyCode"] = Asc("Esc"):
  630.                   Window Close
  631.                   Quitloop
  632.                Case EventBag["KeyCode"] = Asc("F1"):
  633.                   ; (do nothing; suppress Help)
  634.                OtherWise:
  635.                   ExecEvent EventBag
  636.             EndSwitch
  637.          Case EventBag["Type"] = "MESSAGE":
  638.          ;----------------------------------
  639.             Switch
  640.                Case EventBag["Message"] = "CLOSE":
  641.                   If PopCalc!CloseWindowWithConfirm() Then
  642.                      QuitLoop
  643.                   Endif
  644.                Case EventBag["Message"] = "NEXT":
  645.                   Beep
  646.                   Message "Close window to return to calculator."
  647.                   Sleep 2000
  648.                   Message ""
  649.                   ; do nothing, repress this
  650.                Otherwise:
  651.                   ExecEvent EventBag
  652.             EndSwitch
  653.          OtherWise:
  654.          ;---------
  655.             ExecEvent EventBag
  656.       EndSwitch
  657.    EndWhile
  658.    Release Vars EventBag
  659.    Prompt
  660.    Window Move Calculator_WindowHandle To Calculator_Row,Calculator_Col
  661.    Echo Off
  662. EndProc ; ViewTape
  663.  
  664. Proc Calculator!KeyPadModeLine()
  665.    If Not Calculator_DecimalFlag Then
  666.       Calculator_KeyPadModeLine = Fill("─",28)
  667.    Else
  668.       Calculator_KeyPadModeLine = "─Decimal flag" + fill("─",15)
  669.    Endif
  670. EndProc ; Calculator!KeyPadModeLine
  671.  
  672. Proc Calculator!TapeModeLine()
  673.    If Not Calculator_TapeIsOn Then
  674.       Calculator_TapeModeLine = "─Record is off" + fill("─",14)
  675.    Else
  676.       Calculator_TapeModeLine = "─Record is on" + fill("─",15)
  677.    Endif
  678. EndProc ; Calculator!TapeModeLine
  679.  
  680. Proc Calculator!DialogProc(EventType,TagValue,EventBag,ElementValue)
  681.    Private
  682.       OK
  683.    ExecProc Calculator_EventEngine[EventType]
  684.    OK = Retval
  685.    Return OK
  686. EndProc ; Calculator!DialogProc
  687.  
  688. ;============================================================================
  689. ; Control trigger procs
  690. ;============================================================================
  691.  
  692. ;----------------------------------------------------------------------------
  693. ; Called once at start of session, ready to take any legal character...
  694. ;----------------------------------------------------------------------------
  695. Proc Calculator!Open()
  696.    Calculator!SetCharKeys()
  697.    Return true
  698. EndProc ; Calculator!Open
  699.  
  700. ;----------------------------------------------------------------------------
  701. ; Adds keycode list of all legal calculator keys. Supports the
  702. ; Calculator_WAITING state.
  703. ;----------------------------------------------------------------------------
  704. Proc Calculator!SetCharKeys()
  705.    NewDialogSpec
  706.    Key
  707.      Calculator_CharEventKey[1],
  708.      Calculator_CharEventKey[2],
  709.      Calculator_CharEventKey[3],
  710.      Calculator_CharEventKey[4],
  711.      Calculator_CharEventKey[5],
  712.      Calculator_CharEventKey[6],
  713.      Calculator_CharEventKey[7],
  714.      Calculator_CharEventKey[8],
  715.      Calculator_CharEventKey[9],
  716.      Calculator_CharEventKey[10],
  717.      Calculator_CharEventKey[11],
  718.      Calculator_CharEventKey[12],
  719.      Calculator_CharEventKey[13],
  720.      Calculator_CharEventKey[14],
  721.      Calculator_CharEventKey[15],
  722.      Calculator_CharEventKey[16],
  723.      Calculator_CharEventKey[17],
  724.      Calculator_CharEventKey[18],
  725.      Calculator_CharEventKey[19],
  726.      Calculator_CharEventKey[20],
  727.      Calculator_CharEventKey[21],
  728.      Calculator_CharEventKey[22],
  729.      Calculator_CharEventKey[23],
  730.      Calculator_CharEventKey[24],
  731.      Calculator_CharEventKey[25],
  732.      Calculator_CharEventKey[26],
  733.      Calculator_CharEventKey[27],
  734.      Calculator_CharEventKey[28],
  735.      Calculator_CharEventKey[29],
  736.      Calculator_CharEventKey[30],
  737.      Calculator_CharEventKey[31],
  738.      Calculator_CharEventKey[32],
  739.      Calculator_CharEventKey[33]
  740. EndProc ; Calculator!SetCharKeys
  741.  
  742. ;----------------------------------------------------------------------------
  743. ; Adds keycode list of legal operator type calculator keys. Supports the
  744. ; Calculator_CALC state.
  745. ;----------------------------------------------------------------------------
  746. Proc Calculator!SetOpKeys()
  747.    NewDialogSpec
  748.    Key
  749.      Calculator_OpEventKey[1],
  750.      Calculator_OpEventKey[2],
  751.      Calculator_OpEventKey[3],
  752.      Calculator_OpEventKey[4],
  753.      Calculator_OpEventKey[5],
  754.      Calculator_OpEventKey[6],
  755.      Calculator_OpEventKey[7],
  756.      Calculator_OpEventKey[8],
  757.      Calculator_OpEventKey[9],
  758.      Calculator_OpEventKey[10],
  759.      Calculator_OpEventKey[11],
  760.      Calculator_OpEventKey[12],
  761.      Calculator_OpEventKey[13],
  762.      Calculator_OpEventKey[14],
  763.      Calculator_OpEventKey[15]
  764. EndProc ; Calculator!SetOpKeys
  765.  
  766. ;----------------------------------------------------------------------------
  767. ; Traps for EVENT type messages. In particular traps for legal
  768. ; keys. Once trapped, they are classified and dispatched, followed
  769. ; by processing of the operator or function.
  770. ; Numchar and Editchar types cause the CellStatus to be set to CALC
  771. ; (something new has happened.), with the associated more limited eventlist.
  772. ; This leads to some performance improvement, as well as greater refinement
  773. ; in calculator logic.
  774. ;----------------------------------------------------------------------------
  775. Proc Calculator!Event()
  776.    Private
  777.       OK
  778.    Switch
  779.       Case EventBag["Type"] = "KEY":
  780.          Calculator_Keycode = EventBag["Keycode"]
  781.          Calculator_KeycodeAttribute = Calculator_KeycodeType[Calculator_Keycode]
  782.          If (Calculator_KeyCodeAttribute = Calculator_OPCHAR) or
  783.             (Calculator_KeyCodeAttribute = Calculator_FUNCCHAR) Then
  784.             If TagValue <> "Cell" and Calculator_KeyCode = Asc("Enter") Then
  785.                OK = True ; Allow the keystroke
  786.             Else
  787.                Calculator.Value = ControlValue("Cell")
  788.                ExecProc Calculator_ResponseProc[Calculator_Keycode]
  789.                OK = False
  790.             Endif
  791.          Else ; NUMCHAR or EDITCHAR
  792.             Calculator_CellStatus = Calculator_CALC
  793.             Calculator!SetOpKeys()
  794.             OK = True
  795.          Endif
  796.    EndSwitch
  797.    Return OK
  798. EndProc ; Calculator!Event
  799.  
  800. ;----------------------------------- OPTIONS ----------------------------------
  801.  
  802. Proc Calculator!Escape()
  803.    Calculator_Value = ControlValue("Cell")
  804.    CancelDialog
  805.    ; Calculator!Clear()
  806.    Return True
  807. EndProc ; Calculator!Escape
  808.  
  809. Proc Calculator!OK()
  810.    If Calculator_StackPtr > 0 Then
  811.       Calculator!Equals()
  812.    Endif
  813.    AcceptDialog
  814.    Return true
  815. EndProc ; Calculator!OK
  816.  
  817. Proc Calculator!Menu()
  818.    Private
  819.       OK,
  820.       Command,
  821.       TapeChoice
  822.  
  823.    OK = True
  824.    If Calculator_TapeIsOn Then
  825.       TapeChoice = "√ ~T~ape toggle"
  826.    Else
  827.       TapeChoice = "  ~T~ape toggle"
  828.    Endif
  829.    ShowPopup "Options" Centered
  830.       TapeChoice:"Toggle tape on and off":"TapeOn",
  831.       "  ~V~iew tape":"Full editable view of the \"paper\" tape.":"ViewTape",
  832.       Separator,
  833.       "  ~E~xplain":"A help screen which explains the use of the calculator.":"Explain"
  834.    EndMenu
  835.    To Command
  836.    If Retval Then
  837.       Switch
  838.          Case Command = "TapeOn":
  839.             Calculator_TapeIsOn = Not Calculator_TapeIsOn
  840.             Calculator!TapeModeLine()
  841.          Case Command = "ViewTape":
  842.             Calculator!ViewTape()
  843.          Case Command = "Explain":
  844.             Calculator!ViewExplain()
  845.       EndSwitch
  846.    Else
  847.       OK = false
  848.    Endif
  849.    SelectControl "Cell"
  850.    Return OK
  851. EndProc ; Calculator!Menu
  852.  
  853. Proc Calculator!Op()
  854.    Private
  855.       OK,
  856.       Command
  857.    ShowPopup "Operators" Centered
  858.       "~A~dd":"The operator [+]":"+",
  859.       "S~u~btract":"The operator [-]":"-",
  860.       "~M~ultiply":"The operator [*]":"*",
  861.       "~D~ivide":"The operator [/]":"/",
  862.       "~E~xponent":"The operator [^]":"^",
  863.       Separator,
  864.       "~P~ercent":"The function [%]":"%",
  865.       "~F~actorial":"The function [!]":"!",
  866.       "~R~everse sign":"The function [Alt-R]":"R",
  867.       "S~q~uare root":"The square root function [Alt-Q]":"√",
  868.       "Rou~n~d,2":"Round to 2 decimal places [Alt-N]":"N",
  869.       Separator,
  870.       "Sa~v~e memory":"Save the current cell value to memory [>]":">",
  871.       "~G~et memory":"Retrieve the current cell value from memory [<]":"<",
  872.       Separator,
  873.       "~S~ubtotal":"Subtotal operator [Alt-S]":"S",
  874.       "~T~otal":"Total operator [=] or [Enter]":"=",
  875.       Separator,
  876.       "C~l~ear":"Clear operator [Alt-L]":"C"
  877.    EndMenu
  878.    To Command
  879.    If Retval Then
  880.       ExecProc Calculator_ResponseProc[Asc(Command)]
  881.       OK = true
  882.    Else
  883.       OK = false
  884.    Endif
  885.    SelectControl "Cell"
  886.    Return OK
  887. EndProc ; Calculator!Op
  888.  
  889. ;----------------------------------------------------------------------------
  890. ; Clear abandons the current calculation, and resets everything as though it
  891. ; had just been initialized. Stack items are abandoned (garbage) rather than
  892. ; re-initialized or deleted.
  893. ;----------------------------------------------------------------------------
  894. Proc Calculator!Clear()
  895.    Private
  896.       OK
  897.    OK = True
  898.    Calculator_DecimalFlag = False
  899.    Calculator!KeyPadModeLine()
  900.    Calculator_CellStatus = Calculator_WAITING
  901.    Calculator!SetCharKeys()
  902.    Calculator.Value = 0
  903.    Calculator!RefreshTape(BlankNum(),"Clear")
  904.    Calculator_CellAttribute = Calculator_FLOATING
  905.    Calculator_CellLastValue = Calculator.Value
  906.    Calculator_CellLastAttribute = Calculator_CellAttribute
  907.    Calculator_StackPtr = 0
  908.    ResyncControl "Cell"
  909.    SelectControl "Cell"
  910.    Return OK
  911. EndProc ; Calculator!Clear
  912.  
  913. ;------------------------------ FUNCTIONS -----------------------------------
  914.  
  915. Proc Calculator!Percent()
  916.    Private
  917.       OK
  918.    If Not IsBlank(Calculator.Value) Then
  919.       OK = True
  920.       Calculator_LastOperator = Calculator_CurrentOperator
  921.       Calculator_CurrentOperator = "%"
  922.       Calculator!RefreshTape(Calculator.Value,"% =")
  923.       Calculator.Value = Calculator.Value/100
  924.       Calculator!RefreshTape(Calculator.Value,":")
  925.       Calculator_CellLastValue = Calculator.Value
  926.       Calculator_CellLastAttribute = Calculator_CellAttribute
  927.       Calculator_CellStatus = Calculator_CALC
  928.       Calculator!SetOpKeys()
  929.       ResyncControl "Cell"
  930.    Else
  931.       OK = false
  932.       Beep
  933.       Message "Cannot take percent of blank value."
  934.       Sleep 2000
  935.       Message ""
  936.    Endif
  937.    SelectControl "Cell"
  938.    Return OK
  939. EndProc ; Calculator!Percent
  940.  
  941. Proc Calculator!Sqrt()
  942.    Private
  943.       OK
  944.    If Not IsBlank(Calculator.Value) And
  945.       Not (Calculator.Value < 0) Then
  946.       OK = True
  947.       Calculator_LastOperator = Calculator_CurrentOperator
  948.       Calculator_CurrentOperator = "√"
  949.       Calculator!RefreshTape(Calculator.Value,"√ =")
  950.       Calculator.Value = Sqrt(Calculator.Value)
  951.       Calculator!RefreshTape(Calculator.Value,":")
  952.       Calculator_CellLastValue = Calculator.Value
  953.       Calculator_CellLastAttribute = Calculator_CellAttribute
  954.       Calculator_CellStatus = Calculator_CALC
  955.       Calculator!SetOpKeys()
  956.       ResyncControl "Cell"
  957.    Else
  958.       OK = false
  959.       Beep
  960.       Message "Cannot take square root (√) of blank or negative value."
  961.       Sleep 2000
  962.       Message ""
  963.    Endif
  964.    SelectControl "Cell"
  965.    Return OK
  966. EndProc ; Calculator!Sqrt
  967.  
  968. Proc Calculator!Round()
  969.    Private
  970.       OK
  971.    If Not IsBlank(Calculator.Value) Then
  972.       OK = True
  973.       Calculator_LastOperator = Calculator_CurrentOperator
  974.       Calculator_CurrentOperator = "N"
  975.       Calculator!RefreshTape(Calculator.Value,"rnd,2 =")
  976.       Calculator.Value = Round(Calculator.Value,2)
  977.       Calculator!RefreshTape(Calculator.Value,":")
  978.       Calculator_CellLastValue = Calculator.Value
  979.       Calculator_CellLastAttribute = Calculator_CellAttribute
  980.       Calculator_CellStatus = Calculator_CALC
  981.       Calculator!SetOpKeys()
  982.       ResyncControl "Cell"
  983.    Else
  984.       OK = false
  985.       Beep
  986.       Message "Cannot round blank value."
  987.       Sleep 2000
  988.       Message ""
  989.    Endif
  990.    SelectControl "Cell"
  991.    Return OK
  992. EndProc ; Calculator!Round
  993.  
  994. Proc Calculator!SaveMem()
  995.    Private
  996.       OK
  997.    OK = True
  998.    Calculator_MemoryValue = Calculator.Value
  999.    Calculator_MemoryAttribute = Calculator_CellAttribute
  1000.    Calculator!RefreshTape(Calculator.Value,">")
  1001.    SelectControl "Cell"
  1002.    Return OK
  1003. EndProc ; Calculator!SaveMem
  1004.  
  1005. Proc Calculator!GetMem()
  1006.    Private
  1007.       OK
  1008.    OK = True
  1009.    Calculator_LastOperator = Calculator_CurrentOperator
  1010.    Calculator_CurrentOperator = "<"
  1011.    Calculator.Value = Calculator_MemoryValue
  1012.    Calculator_CellAttribute = Calculator_MemoryAttribute
  1013.    Calculator_CellLastValue = Calculator.Value
  1014.    Calculator_CellLastAttribute = Calculator_CellAttribute
  1015.    Calculator!RefreshTape(Calculator.Value,"<")
  1016.    Calculator_CellStatus = Calculator_CALC
  1017.    Calculator!SetOpKeys()
  1018.    ResyncControl "Cell"
  1019.    SelectControl "Cell"
  1020.    Return OK
  1021. EndProc ; Calculator!GetMem
  1022.  
  1023. Proc Calculator!Factorial()
  1024.    Private
  1025.       OK,i
  1026.    If Not IsBlank(Calculator.Value) Then
  1027.       OK = True
  1028.       If Int(Calculator.Value) > 170 Then
  1029.          Beep
  1030.          Message "Cannot take factorial of > 170."
  1031.          Sleep 2000
  1032.          Message ""
  1033.       Else
  1034.          Calculator_LastOperator = Calculator_CurrentOperator
  1035.          Calculator_CurrentOperator = "!"
  1036.          Calculator!RefreshTape(Calculator.Value,"! =")
  1037.          Calculator.Value = Int(Calculator.Value)
  1038.          For i From Calculator.Value  To 2 Step - 1
  1039.             Calculator.Value = Calculator.Value * (i - 1)
  1040.          EndFor
  1041.          Calculator!RefreshTape(Calculator.Value,":")
  1042.          Calculator_CellLastValue = Calculator.Value
  1043.          Calculator_CellLastAttribute = Calculator_CellAttribute
  1044.          Calculator_DecimalFlag = False
  1045.          Calculator!KeyPadModeLine()
  1046.          Calculator_CellStatus = Calculator_CALC
  1047.          Calculator!SetOpKeys()
  1048.          ResyncControl "Cell"
  1049.       Endif
  1050.    Else
  1051.       OK = false
  1052.       Beep
  1053.       Message "Cannot take factorial of blank value."
  1054.       Sleep 2000
  1055.       Message ""
  1056.    Endif
  1057.    SelectControl "Cell"
  1058.    Return OK
  1059. EndProc ; Calculator!Factorial
  1060.  
  1061. Proc Calculator!PlusMinus() ; Reverse
  1062.    Private
  1063.       OK
  1064.    If Not IsBlank(Calculator.Value) Then
  1065.       OK = True
  1066.       Calculator_LastOperator = Calculator_CurrentOperator
  1067.       Calculator_CurrentOperator = "R"
  1068.       Calculator!RefreshTape(Calculator.Value,"+/- =")
  1069.       Calculator.Value = -Calculator.Value
  1070.       Calculator!RefreshTape(Calculator.Value,":")
  1071.       Calculator_CellLastValue = Calculator.Value
  1072.       Calculator_CellLastAttribute = Calculator_CellAttribute
  1073.       Calculator_CellStatus = Calculator_CALC
  1074.       Calculator!SetOpKeys()
  1075.       ResyncControl "Cell"
  1076.    Else
  1077.       OK = false
  1078.       Beep
  1079.       Message "Cannot reverse sign of blank value."
  1080.       Sleep 2000
  1081.       Message ""
  1082.    Endif
  1083.    SelectControl "Cell"
  1084.    Return OK
  1085. EndProc ; Calculator!PlusMinus
  1086.  
  1087. ;------------------------------ OPERATORS -----------------------------------
  1088.  
  1089. Proc Calculator!Exponent()
  1090.    Private
  1091.       OK
  1092.    OK = Calculator!InfixOperator("^")
  1093.    Return OK
  1094. EndProc ; Calculator!Exponent
  1095.  
  1096. ;------------------------------ MULTIPLY/DIVIDE -----------------------------
  1097.  
  1098. Proc Calculator!Multiply()
  1099.    Private
  1100.       OK
  1101.    OK = Calculator!InfixOperator("*")
  1102.    Return OK
  1103. EndProc ; Multiply
  1104.  
  1105. Proc Calculator!Divide()
  1106.    Private
  1107.       OK
  1108.    OK = Calculator!InfixOperator("/")
  1109.    Return OK
  1110. EndProc ; Divide
  1111.  
  1112. Proc Calculator!InfixOperator(Operator)
  1113.    Private
  1114.       OK
  1115.    If isBlank(Calculator.Value) Then
  1116.       Beep
  1117.       Message "Cannot use [",Operator,"] with blank value."
  1118.       Sleep 2000
  1119.       Message ""
  1120.       OK = false
  1121.    Else
  1122.       Calculator!PrepStackForOp()
  1123.       Calculator.Value = Calculator_StackValue[Calculator_Stackptr]
  1124.       Calculator_CellAttribute = Calculator_StackAttribute[Calculator_Stackptr]
  1125.       Calculator_StackPtr = Calculator_StackPtr + 1
  1126.       Calculator_StackValue[Calculator_StackPtr] = Operator
  1127.       Calculator_StackAttribute[Calculator_Stackptr] = Calculator_OPERATOR
  1128.  
  1129.       ResyncControl "Cell"
  1130.       Calculator_DecimalFlag = False
  1131.       Calculator!KeyPadModeLine()
  1132.       Calculator_CellStatus = Calculator_WAITING
  1133.       Calculator!SetCharKeys()
  1134.  
  1135.       OK = True
  1136.    Endif
  1137.    SelectControl "Cell"
  1138.    Return OK
  1139. EndProc ; InfixOperator
  1140.  
  1141. Proc Calculator!PrepStackForOp()
  1142.    Calculator_LastOperator = Calculator_CurrentOperator
  1143.    Calculator_CurrentOperator = Operator
  1144.    If (Calculator_CellStatus = Calculator_WAITING) Then
  1145.       Calculator.Value = Calculator_CellLastValue
  1146.       Calculator_CellAttribute = Calculator_CellLastAttribute
  1147.    Else
  1148.       Calculator_CellLastValue = Calculator.Value
  1149.       Calculator_CellLastAttribute = Calculator_CellAttribute
  1150.    Endif
  1151.    Calculator_StackPtr = Calculator_StackPtr + 1
  1152.    Calculator_StackValue[Calculator_StackPtr] = Calculator.Value
  1153.    Calculator_StackAttribute[Calculator_StackPtr] = Calculator_CellAttribute
  1154.    OK = Calculator!DoInfixOperator() ; to resolve existing expressions
  1155.    If OK Then
  1156.       Calculator!RefreshTape(Calculator.Value,"=")
  1157.       Calculator!RefreshTape(Calculator_StackValue[Calculator_StackPtr],
  1158.          Operator)
  1159.       Calculator_CellLastValue = Calculator_StackValue[Calculator_StackPtr]
  1160.       Calculator_CellLastAttribute = Calculator_StackValue[Calculator_StackPtr]
  1161.    Else
  1162.       Calculator!RefreshTape(Calculator.Value,Operator)
  1163.    Endif
  1164. Endproc ; Calculator!PrepStackForOp
  1165.  
  1166. Proc Calculator!DoInfixOperator()
  1167.    Private
  1168.       Operator,
  1169.       OK
  1170.    OK = false
  1171.    ;-------------------------------------------------------------------------
  1172.    ; Operation must be binary...
  1173.    ;-------------------------------------------------------------------------
  1174.    If (Calculator_StackPtr > 2) And
  1175.       (Calculator_StackAttribute[Calculator_StackPtr - 2] <>
  1176.       Calculator_OPERATOR) Then
  1177.       Operator = Calculator_StackValue[Calculator_StackPtr - 1]
  1178.       If Operator = "*" or Operator = "/" Or Operator = "^" Then
  1179.          OK = True
  1180.          ;-------------------------------------------------------------------
  1181.          ; Perform the operation. The resultant Stack attribute is not
  1182.          ; changed for now.
  1183.          ;-------------------------------------------------------------------
  1184.          Switch
  1185.             Case Operator = "*":
  1186.                Calculator_StackValue[Calculator_StackPtr - 2] =
  1187.                Calculator_StackValue[Calculator_StackPtr - 2] *
  1188.                Calculator_StackValue[Calculator_StackPtr]
  1189.             Case Operator = "/":
  1190.                Calculator_StackValue[Calculator_StackPtr - 2] =
  1191.                Calculator_StackValue[Calculator_StackPtr - 2] /
  1192.                Calculator_StackValue[Calculator_StackPtr]
  1193.             Case Operator = "^":
  1194.                Calculator_StackValue[Calculator_StackPtr - 2] =
  1195.                Pow(Calculator_StackValue[Calculator_StackPtr - 2],
  1196.                   Calculator_StackValue[Calculator_StackPtr])
  1197.                If Calculator_StackValue[Calculator_StackPtr - 2] =
  1198.                   "Error" Then
  1199.                   Calculator_StackValue[Calculator_StackPtr - 2] = 0
  1200.                   Calculator!RefreshTape(BlankNum(),"Error")
  1201.                Endif
  1202.          EndSwitch
  1203.          Calculator_StackPtr = Calculator_StackPtr - 2
  1204.       Endif
  1205.    Endif
  1206.    Return OK
  1207. EndProc ; DoInfixOperator
  1208.  
  1209. ;------------------------------- ADD/SUBTRACT -------------------------------
  1210.  
  1211. Proc Calculator!Add()
  1212.    Private
  1213.       OK
  1214.    OK = Calculator!AddSubtract("+")
  1215.    Return OK
  1216. EndProc ; Add
  1217.  
  1218. Proc Calculator!Subtract()
  1219.    Private
  1220.       OK
  1221.    OK = Calculator!AddSubtract("-")
  1222.    Return OK
  1223. EndProc ; Subtract
  1224.  
  1225. Proc Calculator!AddSubtract(Operator)
  1226.    Private
  1227.       OK
  1228.    If isBlank(Calculator.Value) Then
  1229.       Beep
  1230.       Message "Cannot use [",Operator,"] with blank value."
  1231.       Sleep 2000
  1232.       Message ""
  1233.       OK = false
  1234.    Else
  1235.       Calculator!PrepStackForOp()
  1236.       Calculator_StackPtr = Calculator_StackPtr + 1
  1237.       Calculator_StackValue[Calculator_StackPtr] = Operator
  1238.       Calculator_StackAttribute[Calculator_StackPtr] = Calculator_OPERATOR
  1239.       Calculator!DoAddSubtract()
  1240.       Calculator.Value = Calculator_StackValue[Calculator_Stackptr]
  1241.       Calculator_CellAttribute = Calculator_StackAttribute[Calculator_StackPtr]
  1242.       ResyncControl "Cell"
  1243.       Calculator_DecimalFlag = False
  1244.       Calculator!KeyPadModeLine()
  1245.       Calculator_CellStatus = Calculator_WAITING
  1246.       Calculator!SetCharKeys()
  1247.  
  1248.       OK = True
  1249.    Endif
  1250.    SelectControl "Cell"
  1251.    Return OK
  1252. EndProc ; AddSubtract
  1253.  
  1254. Proc Calculator!DoAddSubtract()
  1255.    Private
  1256.       Operator
  1257.    Operator = Calculator_StackValue[Calculator_StackPtr]
  1258.    If Operator = "+" or Operator = "-" Then
  1259.       If Calculator_StackPtr = 2 Or
  1260.          Calculator_StackAttribute[Calculator_StackPtr - 2] =
  1261.          Calculator_OPERATOR Then ; This is a unary Plus or minus
  1262.          If Operator = "-" Then
  1263.             Calculator_StackValue[Calculator_StackPtr - 1] =
  1264.             -Calculator_StackValue[Calculator_StackPtr - 1]
  1265.          Endif
  1266.          Calculator_StackPtr = Calculator_StackPtr - 1
  1267.       Else
  1268.          If Operator = "+" Then
  1269.             Calculator_StackValue[Calculator_StackPtr - 2] =
  1270.             Calculator_StackValue[Calculator_StackPtr - 2] +
  1271.             Calculator_StackValue[Calculator_Stackptr - 1]
  1272.          Else
  1273.             Calculator_StackValue[Calculator_StackPtr - 2] =
  1274.             Calculator_StackValue[Calculator_StackPtr - 2] -
  1275.             Calculator_StackValue[Calculator_Stackptr - 1]
  1276.          Endif
  1277.          Calculator_StackPtr = Calculator_StackPtr - 2
  1278.       Endif
  1279.    Endif
  1280. EndProc ; DoAddSubtract
  1281.  
  1282. ;------------------------------ TERMINATORS ---------------------------------
  1283.  
  1284. ;----------------------------------------------------------------------------
  1285. ; Equals deterministically terminates the current calculation. If there is a
  1286. ; blank value in the CellValue, it is set to 0. Outstanding expressions on
  1287. ; the stack are resolved, and the result of the calculation is saved to
  1288. ; CellLastValue for the use of the next calculation.
  1289. ;----------------------------------------------------------------------------
  1290. Proc Calculator!Equals()
  1291.    Private
  1292.       OK
  1293.    Calculator_LastOperator = Calculator_CurrentOperator
  1294.    Calculator_CurrentOperator = "="
  1295.    Calculator!ResolveStack()
  1296.    ;-------------------------------------------------------------------------
  1297.    ; At this point, the only possible unresolved expressions are subtotal
  1298.    ; adds, so we do them now...
  1299.    ;-------------------------------------------------------------------------
  1300.    Calculator!DoSubTotal()
  1301.    Calculator.Value = Calculator_StackValue[Calculator_StackPtr]
  1302.    Calculator_CellAttribute = Calculator_StackAttribute[Calculator_StackPtr]
  1303.    Calculator!RefreshTape(Calculator.Value,"Total")
  1304.    ;-------------------------------------------------------------------------
  1305.    ; Remember the result of this calculation to use as the result value of
  1306.    ; the next operation if a WAITING cell is operated upon...
  1307.    ;-------------------------------------------------------------------------
  1308.    Calculator_CellLastValue = Calculator.Value
  1309.    Cakculator_CellLastAttribute = Calculator_CellAttribute
  1310.    Calculator_StackPtr = Calculator_StackPtr - 1
  1311.    If Calculator_StackPtr <> 0 Then
  1312.       Beep
  1313.       Debug ; Stack pointer should be 0 with equals
  1314.    Endif
  1315.  
  1316.    Calculator_DecimalFlag = False
  1317.    Calculator!KeyPadModeLine()
  1318.    Calculator_CellStatus = Calculator_WAITING
  1319.    Calculator!SetCharKeys()
  1320.    ResyncControl "Cell"
  1321.    SelectControl "Cell"
  1322.    OK = true
  1323.    Return OK
  1324. EndProc ; Equals
  1325.  
  1326. ;----------------------------------------------------------------------------
  1327. ; Subtotal resolves outstanding expressions for the subtotal, leaves the sub-
  1328. ; total on the stack, and tops the stack with an "S" operator, which can only
  1329. ; be resolved by DoSubTotal() as called by Equals, the ultimate terminator.
  1330. ;----------------------------------------------------------------------------
  1331. Proc Calculator!Subtotal()
  1332.    Calculator_LastOperator = Calculator_CurrentOperator
  1333.    Calculator_CurrentOperator = "S"
  1334.    Calculator!ResolveStack()
  1335.    Calculator.Value = Calculator_StackValue[Calculator_StackPtr]
  1336.    Calculator_CellAttribute = Calculator_StackAttribute[Calculator_StackPtr]
  1337.    Calculator!RefreshTape(Calculator.Value,"Subtotal")
  1338.    Calculator_CellLastValue = Calculator.Value
  1339.    Calculator_CellLastAttribute = Calculator_CellAttribute
  1340.    Calculator_StackPtr = Calculator_StackPtr + 1
  1341.    Calculator_StackValue[Calculator_StackPtr] = "S"
  1342.    Calculator_StackAttribute[Calculator_StackPtr] = Calculator_OPERATOR
  1343.  
  1344.    Calculator_DecimalFlag = False
  1345.    Calculator!KeyPadModeLine()
  1346.    Calculator_CellStatus = Calculator_WAITING
  1347.    Calculator!SetCharKeys()
  1348.    ResyncControl "Cell"
  1349.    SelectControl "Cell"
  1350.    OK = true
  1351.    Return OK
  1352. EndProc ; SubTotal
  1353.  
  1354. Proc Calculator!DoSubTotal()
  1355.    Private
  1356.       Operator
  1357.    While Calculator_StackPtr > 1
  1358.       Operator = Calculator_StackValue[Calculator_StackPtr - 1]
  1359.       If Operator = "S" Then
  1360.          Calculator_StackValue[Calculator_StackPtr - 2] =
  1361.          Calculator_StackValue[Calculator_StackPtr - 2] +
  1362.          Calculator_StackValue[Calculator_Stackptr]
  1363.          Calculator_StackPtr = Calculator_StackPtr - 2
  1364.       Else
  1365.          Beep
  1366.          Debug ; expecting Subtotal operator
  1367.       Endif
  1368.    EndWhile
  1369. EndProc ; DoSubTotal
  1370.  
  1371. Proc Calculator!ResolveStack()
  1372.    ;-------------------------------------------------------------------------
  1373.    ; Anticipate add operation to resolve unresolved expressions...
  1374.    ;-------------------------------------------------------------------------
  1375.    If IsBlank(Calculator.Value) Then
  1376.       Calculator.Value = 0
  1377.    Endif
  1378.    ;-------------------------------------------------------------------------
  1379.    ; if the current value of CellValue is carried forward from the results
  1380.    ; of the previous operation, then neutralize it.
  1381.    ;-------------------------------------------------------------------------
  1382.    If Calculator_CellStatus = Calculator_WAITING Then
  1383.       ;----------------------------------------------------------------------
  1384.       ; if the stackpointer is greater than 0 then there has been a previous
  1385.       ; operation, so neutralize the carried forward result...
  1386.       ;----------------------------------------------------------------------
  1387.       If Calculator_Stackptr > 0 Then
  1388.          ;-------------------------------------------------------------------
  1389.          ; There may be an operator on top of the stack...
  1390.          ;-------------------------------------------------------------------
  1391.          If (Calculator_StackAttribute[Calculator_StackPtr] = Calculator_OPERATOR) Then
  1392.             If (Calculator_CurrentOperator = "S") Or
  1393.                (Calculator_StackValue[Calculator_StackPtr] <> "S") Then
  1394.                Calculator_StackPtr = Calculator_StackPtr + 1
  1395.                Calculator_StackValue[Calculator_StackPtr] = Calculator_CellLastValue
  1396.                Calculator_StackAttribute[Calculator_StackPtr] = Calculator_CellLastAttribute
  1397.                Calculator.Value = Calculator_CellLastValue
  1398.                Calculator_CellAttribute = Calculator_CellLastAttribute
  1399.             Else ; current operator is "=" and top of stack = "S"
  1400.                Calculator_StackPtr = Calculator_StackPtr - 1
  1401.             Endif
  1402.          Endif
  1403.       Else
  1404.          Calculator.Value = Calculator_CellLastValue
  1405.          Calculator_CellAttribute = Calculator_CellLastAttribute
  1406.          Calculator_CellStatus = Calculator_CALC
  1407.       Endif
  1408.    Endif
  1409.    ;-------------------------------------------------------------------------
  1410.    ; The only WAITING state that can arrive here is a held over result from
  1411.    ; an [Enter] before any operators were used in this calculation. This
  1412.    ; causes the result of the previous calculation to be used as the result
  1413.    ; of the current calculation.
  1414.    ;-------------------------------------------------------------------------
  1415.    If Calculator_CellStatus = Calculator_CALC Then
  1416.       Calculator!Add()
  1417.    Else
  1418.       OK = Calculator!DoInfixOperator() ; anything unresolved
  1419.       If OK Then
  1420.          Calculator!RefreshTape(Calculator.Value,"=")
  1421.          Calculator!RefreshTape(Calculator_StackValue[Calculator_StackPtr],"+")
  1422.       Endif
  1423.       If Calculator_StackPtr > 0 Then
  1424.          If Calculator_StackAttribute[Calculator_StackPtr] <> Calculator_OPERATOR Then
  1425.             Calculator_StackPtr = Calculator_StackPtr + 1
  1426.             Calculator_StackValue[Calculator_StackPtr] = "+"
  1427.             Calculator_StackAttribute[Calculator_StackPtr] = Calculator_OPERATOR
  1428.          Endif
  1429.       Endif
  1430.       Calculator!DoAddSubtract()
  1431.    Endif
  1432. EndProc ; ResolveStack
  1433.  
  1434. ;--------------------------- NUMERIC KEYPAD ---------------------------------
  1435.  
  1436. ;----------------------------------------------------------------------------
  1437. ; It would be better to stuff the keyboard here, as this doesn't cope with ".",
  1438. ; nor does it recognize the position of the cursor within the input string,
  1439. ; but keystroke initiation within ShowDialog is not available in Paradox 4
  1440. ;----------------------------------------------------------------------------
  1441. Proc Calculator!NumKey(Numeral)
  1442.    Private
  1443.       String,
  1444.       OriginalValue
  1445.    OriginalValue = Calculator.Value
  1446.    If Calculator_CellStatus = Calculator_WAITING Then
  1447.       Calculator.Value = BlankNum()
  1448.       Calculator_CellStatus = Calculator_CALC
  1449.       Calculator!SetOpKeys()
  1450.    Endif
  1451.    String = StrVal(Calculator.Value)
  1452.    If Calculator_DecimalFlag then
  1453.       OK = Match(String,"..\".\"..")
  1454.       If Not OK Then
  1455.          String = String + "."
  1456.       Endif
  1457.    Endif
  1458.    Calculator.Value = NumVal(String + Numeral)
  1459.    If Calculator.Value = "Error" Then
  1460.       Beep
  1461.       Message "Error"
  1462.       Sleep 2000
  1463.       Message ""
  1464.       Calculator.Value = OriginalValue
  1465.       OK = False
  1466.    Else
  1467.       OK = True
  1468.    Endif
  1469.    ResyncControl "Cell"
  1470.    SelectControl "Cell"
  1471.    Return OK
  1472. EndProc ; Calculator!NumKey
  1473.  
  1474. Proc Calculator!Decimal()
  1475.    If Calculator_DecimalFlag Then
  1476.       Calculator_DecimalFlag = False
  1477.    Else
  1478.       Calculator_DecimalFlag = True
  1479.    Endif
  1480.    Calculator!KeyPadModeLine()
  1481.    RepaintDialog ; to repaint the keypad mode line
  1482.    SelectControl "Cell"
  1483.    Return true
  1484. EndProc ; Calculator!Decimal
  1485.  
  1486. ;----------------------------------------------------------------------------
  1487. ;                             PAPER TAPE
  1488. ;----------------------------------------------------------------------------
  1489. Proc Calculator!RefreshTape(Amount,OperationName)
  1490.    Private
  1491.       TapeString,
  1492.       i
  1493.    TapeString = Format("W21.2,EC",Amount) + " " + OperationName
  1494.    For i From 2 to 5
  1495.       Calculator_Tape[i-1] = Calculator_Tape[i]
  1496.    EndFor
  1497.    Calculator_Tape[5] = TapeString
  1498.    If Calculator_TapeIsOn Then
  1499.       Print File Calculator_TapeFile
  1500.          TapeString,"\n"
  1501.    Endif
  1502.    RepaintDialog
  1503. EndProc ; Calculator!RefreshTape
  1504.  
  1505. ;----------------------------------------------------------------------------
  1506. ;                            MAINLINE
  1507. ;----------------------------------------------------------------------------
  1508. Proc Closed Calculator.Show()
  1509.    useVArs autolib
  1510.    Calculator.Constructor()
  1511.    If Calculator.Dialog() Then
  1512.       If (SysMode() = "Edit" or SysMode() = "CoEdit") And
  1513.          ImageType() = "Display" Then
  1514.          If (Not IsFieldView()) And
  1515.             (FieldType() = "N" or FieldType() = "$") Then
  1516.             [] = Calculator.Value
  1517.          Endif
  1518.          If IsFieldView() And
  1519.             Substr(FieldType(),1,1) = "M" Then
  1520.             Editor Insert Calculator.Value
  1521.          Endif
  1522.          If Substr(FieldType(),1,1) = "A" Then
  1523.             Typein Calculator.Value
  1524.          Endif
  1525.       Endif
  1526.    Endif
  1527.    Calculator.Destructor()
  1528. EndProc ; Calculator.Show()
  1529.  
  1530. If Not IsAssigned(Librarian.HasControl) Then
  1531.    Calculator.Show()
  1532. Endif