': ____ ____ ____ ____ ____ ____ ____ ____ ____ ____
': ||C |||A |||L |||C |||U |||L |||A |||T |||O |||R ||
': ||__|||__|||__|||__|||__|||__|||__|||__|||__|||__||
': |/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|
':
': QB64 Calculator V1.0
': Terry Ritchie - 08/29/18
':
': Built as a clone of the Windows 7 standard calculator
': An exersize in getting to know the InForm library
':
': This program uses
': InForm - GUI library for QB64 - Beta version 7
': Fellippe Heitor, 2016-2018 - fellippe@qb64.org - [member=2]FellippeHeitor[/member]
': https://github.com/FellippeHeitor/InForm
'----------------------------------------------------------------------------------------------------------------------
': Program constants: -------------------------------------------------------------------------------------------------
': Controls' IDs: -----------------------------------------------------------------------------------------------------
': Program variables: -------------------------------------------------------------------------------------------------
': External modules: --------------------------------------------------------------------------------------------------
'$INCLUDE:'InForm\InForm.ui'
'$INCLUDE:'InForm\xp.uitheme'
'$INCLUDE:'Calculator.frm'
': Windows libraries : ------------------------------------------------------------------------------------------------
' Windows system sounds
' Code contributed by QB64.org Wiki - Author unknown
' http://qb64.org/wiki/Windows_Libraries#Windows_Sounds
' Note: this Windows library will fail in SDL versions of QB64
' change DECLARE LIBRARY to DECLARE DYNAMIC LIBRARY "Wimmm"
' to allow this library to work with SDL versions of QB64
': Program procedures: ------------------------------------------------------------------------------------------------
'----------------------------------------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------------------------------
' Plays Windows default sounds
' Sounds can be invoked using the following strings:
' "SystemDefault","SystemExclamation","SystemExit","SystemHand","SystemQuestion","SystemStart","SystemWelcome"
s
= PlaySound
("SystemDefault" + CHR$(0), 0, 65537) ' play Windows default system sound
'----------------------------------------------------------------------------------------------------------------------
'------------------------------------------------------------------------------------------------------------------
' Return number (n) as a string with no leading/trailing spaces
' Add leading zero if necessary
DIM c$
' n converted to a clean string
IF ASC(c$
, 1) = 46 THEN ' first character a decimal point? c$ = "0" + c$ ' yes, add leading zero
c$
= "-0" + RIGHT$(c$
, LEN(c$
) - 1) ' yes, add leading zero CLEAN$ = c$ ' return cleaned string
'----------------------------------------------------------------------------------------------------------------------
SUB UPDATEOPERAND
(n$
) ' UPDATEOPERAND() '------------------------------------------------------------------------------------------------------------------
' Add user entries to operand
' Keep operand to a max length of 16 numbers (not including decimal point)
' Reset user operand input as needed
' Keep leading zero for decimal values between one and negative one
IF resetoperand
THEN ' new operand input? operand$ = "" ' yes, reset operand
resetoperand = False ' reset trigger
IF n$
= "." THEN ' adding decimal point? IF INSTR(operand$
, ".") = 0 THEN ' yes, already a decimal point? IF operand$
= "" THEN ' no, has operand been reset? n$ = "0." ' yes, add leading zero
ELSE ' yes, decimal point exists n$ = "" ' ignore user request for decimal point
operand$ = operand$ + n$ ' update operand with user entry
olen
= LEN(operand$
) ' get length of operand IF INSTR(operand$
, ".") > 0 THEN olen
= olen
- 1 ' don't count decimal point if preset IF olen
> 16 THEN operand$
= LEFT$(operand$
, LEN(operand$
) - 1) ' keep operand within 16 number limit
'----------------------------------------------------------------------------------------------------------------------
SUB CALCULATE
() ' CALCULATE() '------------------------------------------------------------------------------------------------------------------
' Calculate operand values based on operator previously used
' Store result back into current operand
SELECT CASE previousoperator
' which operator to use? CASE ADDITION
' add the operands operand$ = CLEAN$(operand1 + operand2) ' perform clculation
CASE SUBTRACTION
' subtract the operands operand$ = CLEAN$(operand1 - operand2) ' perform calculation
CASE MULTIPLICATION
' multiply the operands operand$ = CLEAN$(operand1 * operand2) ' perform calculation
CASE DIVISION
' divide the operands IF operand2
= 0 THEN ' dividing by zero? ALERT ' get user's attention
operand$ = "Can't divide by zero!" ' yes, not in this universe!
ELSE ' no, physics is safe for now operand$ = CLEAN$(operand1 / operand2) ' perform calculation
calculated = True
'----------------------------------------------------------------------------------------------------------------------
SUB COMMITOPERAND
() ' COMMITOPERAND() '------------------------------------------------------------------------------------------------------------------
' Get value of current operand
' Calculate operands if necessary
' Save current operand value
' Remember the operator that invoked this routine
operand2
= VAL(operand$
) ' store value of current operand IF previousoperator
THEN ' previous operator selected? CALCULATE ' yes, calculate
operand1
= VAL(operand$
) ' move current total to previous value previousoperator = operator ' move current operator to previous operator
resetoperand = True ' trigger an operand reset
'----------------------------------------------------------------------------------------------------------------------
SUB SCANKEYBOARD
() ' SCANKEYBOARD() '------------------------------------------------------------------------------------------------------------------
' Scan the keyboard for user keystrokes
' Invoke the appropriate button for the desired key
DIM k$
' key pressed by user
k$
= INKEY$ ' look for a key press IF k$
<> "" THEN ' was a key pressed? CASE "0" ' zero key pressed __UI_Click (but0) ' manually click the zero button
__UI_Click (but1) ' etc..
__UI_Click (but2)
__UI_Click (but3)
__UI_Click (but4)
__UI_Click (but5)
__UI_Click (but6)
__UI_Click (but7)
__UI_Click (but8)
__UI_Click (but9)
__UI_Click (butPoint)
__UI_Click (butAdd)
__UI_Click (butSubtract)
__UI_Click (butMultiply)
__UI_Click (butDivide)
__UI_Click (butPercent)
CASE "=", CHR$(13) ' treat ENTER and = the same __UI_Click (butEqual)
__UI_Click (butBS)
CASE "c", "C" ' CTRL-C copy
' Will need to investigate how to capture CTRL-C and CTRL-V
' Neither the code above or below works
CASE "v", "V" ' CTRL-V paste IF __UI_CtrlIsDown
THEN ' is CTRL key presses?
'----------------------------------------------------------------------------------------------------------------------
SUB ADDHISTORY
(h$
) ' ADDHISTORY() '------------------------------------------------------------------------------------------------------------------
nohistory = False
history$ = history$ + h$
'----------------------------------------------------------------------------------------------------------------------
': Event procedures: --------------------------------------------------------------------------------------------------
operator$(1) = " + " ' define operator strings
operator$(2) = " - "
operator$(3) = " * "
operator$(4) = " / "
SUB __UI_BeforeUpdateDisplay
'This event occurs at approximately 30 frames per second.
'You can change the update frequency by calling SetFrameRate DesiredRate%
DIM answer$
' current operand displayed
SCANKEYBOARD ' process keys pressed by user
Caption(lblHistory) = history$ + operator$(operator) ' update history display
answer$ = operand$ ' copy operand
IF answer$
= "" THEN answer$
= "0" ' set to zero if empty
Caption(lblAnswer) = answer$ ' display current operand
IF memory
THEN ' does memory have value? Caption(lblMemory) = "M" ' yes, apply screen indication
Caption(lblMemory) = "" ' remove screen indication
'If you set __UI_UnloadSignal = False here you can
'cancel the user's request to close.
': memory buttons: ----------------------------------------------------------------------------------------
CASE butMC
' memory clear clicked memory = 0 ' reset memory value
CASE butMR
' memory recall clicked IF memory
THEN ' memory available? operand$ = CLEAN$(memory) ' Yes, make it the current operand
resetoperand = True ' trigger an operand reset
CASE butMS
' memory store clicked memory
= VAL(operand$
) ' overwrite memory with current operand resetoperand = True ' trigger an operand reset
CASE butMplus
' memory addition clicked memory
= memory
+ VAL(operand$
) ' add current operand to memory resetoperand = True ' trigger an operand reset
CASE butMminus
' memory subtraction clicked memory
= memory
- VAL(operand$
) ' subtract current operand from memory resetoperand = True ' trigger an operand reset
': clear buttons: -----------------------------------------------------------------------------------------
CASE butCE
' clear entry clicked operand$ = "" ' reset current operand
CASE butC
' clear clicked operand1 = 0 ' initialize all values
operand2 = 0
operator = 0
previousoperator = 0
operand$ = ""
history$ = ""
CASE butBS
' backspace clicked IF LEN(operand$
) THEN ' characters in operand? operand$
= LEFT$(operand$
, LEN(operand$
) - 1) ' yes, remove right-most character
': calculation buttons: -----------------------------------------------------------------------------------
CASE butReciprocate
' reciprocate clicked
ADDHISTORY (operator$(previousoperator) + "Reciproc(" + operand$ + ")")
nohistory = True ' skip operand history next time
operator = EQUATE
operand$
= CLEAN$
(1 / VAL(operand$
)) ' no, calculate reciprocate ELSE ' yes, physics will collapse! ALERT ' get user's attention
operand$ = "Can't divide by zero!" ' report error to user
resetoperand = True ' trigger an operand reset
CASE butSQR
' square root clicked
ADDHISTORY (operator$(previousoperator) + "SQRT(" + operand$ + ")")
nohistory = True ' skip operand history next time
operator = EQUATE
operand$
= CLEAN$
(SQR(VAL(operand$
))) ' yes, calculate square root ELSE ' no, value is negative ALERT ' get user's attention
operand$ = "Invalid input!" ' nice try buddy
resetoperand = True ' trigger an operand reset
CASE butPercent
' percent clicked operand$
= CLEAN$
(operand1
* VAL(operand$
) / 100) ' calculate percentage of previous operand resetoperand = True
CASE butSign
' sign clicked operand$
= CLEAN$
(-VAL(operand$
)) ' no, reverse sign of operand
': number buttons: ----------------------------------------------------------------------------------------
UPDATEOPERAND ("0") ' yes, append zero
UPDATEOPERAND ("1") ' append one
UPDATEOPERAND ("2") ' etc..
UPDATEOPERAND ("3")
UPDATEOPERAND ("4")
UPDATEOPERAND ("5")
UPDATEOPERAND ("6")
UPDATEOPERAND ("7")
UPDATEOPERAND ("8")
UPDATEOPERAND ("9")
UPDATEOPERAND (".")
': operator buttons: --------------------------------------------------------------------------------------
CASE butDivide
' divide clicked
ADDHISTORY (operator$(previousoperator) + operand$)
operator = DIVISION ' remember operator selected
COMMITOPERAND ' save operand
CASE butMultiply
' multiply clicked
ADDHISTORY (operator$(previousoperator) + operand$)
operator = MULTIPLICATION ' remember operator selected
COMMITOPERAND ' save operand
CASE butSubtract
' subtract clicked
ADDHISTORY (operator$(previousoperator) + operand$)
operator = SUBTRACTION ' remember operator selected
COMMITOPERAND ' save operand
CASE butAdd
' addition clicked
ADDHISTORY (operator$(previousoperator) + operand$)
operator = ADDITION ' remember operator selected
COMMITOPERAND ' save operand
CASE butEqual
' equal clicked
history$ = ""
operator = EQUATE ' remember operator selected
COMMITOPERAND ' save operand
previousoperator = 0
operand$ = "InForm Calculator 1.0"
resetoperand = True
'This event occurs right before a control loses focus.
'To prevent a control from losing focus, set __UI_KeepFocus = True below.
'When this event is fired, __UI_KeyHit will contain the code of the key hit.
'You can change it and even cancel it by making it = 0