Time for action – making the calculator buttons
Using the screenshot shown at the start of this chapter as a guide, let's build the calculator buttons (the scripts you will type are also listed if you later want to make sure you typed them correctly):
- If you're not already there, go to the second card, the currently empty one.
- Make sure the Edit button is selected in the Tools palette and drag a Push button to the card, to the position of the
7
button. - In the Basic Properties panel of the Inspector palette, set the Style drop-down menu to Rounded Rectangle (in real life, you would take the time to have nice graphical buttons; here, you are just matching my ugly "programmer art"!).
- Set the name of the button to
number7
and the label to7
. - Select Object Script from the Object menu to see the starter script as you did with the Begin button.
- In the empty line between
on mouseUp
andend mouseUp
, typenumberPressed the label of me
. Note thatnumberPressed
is a new handler that needs to be defined later. When used,me
refers to the current object; in this case, the button pressed. - Close and save the script.
- Select the button and make a copy of it by choosing Duplicate Objects from the Edit menu and position it where the 8 button will be. Copy/Paste and Alt-drag are two other ways to duplicate an object.
- Set the name to
number8
, and label to8
. - Repeat steps 8 and 9 for the buttons 9, 4, 5, 6, 1, 2, 3, 0, and the decimal point using the corresponding number instead of
8
. For the decimal point, let the name bedecimalpoint
. - Duplicate one of the buttons again, name the new button
divide
, and type/
for its label. - Select
Object Script
for the divide button and changenumberPressed
in the middle line to sayoperatorPressed
, making the whole lineoperatorPressed the short name of me
. - Duplicate the divide button three more times and set the names to
multiply
,plus
, andminus
. Set the labels to*
,+
, and-
. - Duplicate the divide button again, giving the new button a name
equals
and a label=
, and change the middle line of script to sayequalsPressed
. - Duplicate the = button and set the new button's name to
toggleSign
and label to+-
; then, change the middle line of script totoggleSign
. - Duplicate the = button and set the new button's name to
clear
and label toC
; then, change the middle line of script to beclearPressed
. - Drag a Label field from the Tools palette and in the Inspector palette, choose
Text Formatting
from the drop-down menu. In theText Formatting
settings, choose a nice looking font, right-justified text, and a large font size. Name the fielddisplay
. - Edit the script of the
display
field. With fields, you don't get the starter script that you get with buttons, so you will need to type themouseUp
lines yourself. Type these three lines in the script:on mouseUp
,set the clipboarddata["TEXT"] to me
, andend mouseUp
. DO enter the quote marks on either side of the word"TEXT"
. - Move all the buttons in their right spots and select the sets of buttons to then use the Align tools and make your calculator layout match the screenshot.
- Save it now!
What just happened?
Quite a lot just happened! We have now made all the card level objects and typed in their scripts. Most of the scripts are "calling" up to a card level handler that we will be setting up next. Before doing that, it's worth trying to understand some of the lines we just entered.
Verbosity, synonyms, and "me"
The English-like nature of the programming language in LiveCode is amazingly powerful, but rigidly so. In some other tools, you have a choice of whether you want to use verbose English-like syntax, less verbose, or what is called dot syntax. The Lingo language, in Adobe Director, is a good comparison.
Suppose we want to change the text inside a field, that is the first entry of a director movie's cast, we can perform the following verbose syntax:
put "hello world" into the text of member 1
We can perform a slightly less verbose syntax:
the text of member 1 = "hello world"
Or, we can perform a dot-syntax:
member(1).text = "hello world"
In LiveCode, there isn't a choice. What you type has to be in the form of:
put value into container
However, you do have a choice about whether to use a long version of a word, short version, or an abbreviated form. There are also synonyms, which allow you to use a word that makes more sense to you.
Here are the two ways of saying the same thing, with the second variation using an abbreviated form of the keywords:
put character 3 of word 2 of card field "name of field 1" into aVariable put char 3 of word 2 of fld 1 into aVariable
When you are dealing with the contents of the object that has the script running, you can use the keyword me
to save on some typing, and LiveCode will also try to work out what you have in mind, if possible.
Take the lines we have entered as examples:
numberPressed the label of me
Here, numberPressed
will propagate up to a card handler that we will add (soon) and the label of me
will look at the Label that you have set for the object that the script is inside of:
set the clipboarddata["TEXT"] to me
In this case, me
would normally refer to the object (as is the case with the label of me
), but because we gave the extra clue of ["TEXT"]
, LiveCode knows that it's the text contents of the field that have the script and not the field itself. Still, because there is potential for confusion, when reading your own code later, you could add a couple of words to make the meaning more clear:
set the clipboarddata["TEXT"] to the text of me
Note
By the way, the display field script is not needed for the calculator to work. It's just there so that at any point of time, you can click on the field and have the current value copied to the clipboard in order to paste it in other applications.
You might choose to be more verbose than is needed, just for readability reasons, and in these chapters, this is going to be the case. It is easier to tell what is going to happen by using:
put the text of me into textvariable
The following will be less verbose compared to the preceding entry, even though they are equally valid:
put me into textVariable
In either case, as it's a field, LiveCode knows what you meant.
You see in the script that we typed short name of me
, what's that all about? Objects in LiveCode have a lengthy description of where they are located, for example, the buttonname
button of the 1234
card ID of the path/to/stack.livecode
stack. In the calculator application, we need only the single word that you set as the name of the button. If we asked for name of me
, it would still say "the buttonname
button". To just grab the name itself, we use short name of me
.
There are times when you will want to use the other variations of name
, including the long name and the abbreviated name, which you can read about in the LiveCode Dictionary entry for name
. In addition to a description of the different ways to use name
, there are a number of cautions you need to be aware of.
Tip
Case sensitivity
If any of you use advanced LiveCode, you may notice that in some cases, I have the casing wrong. LiveCode doesn't mind what casing you have used and so, when I incorrectly said clipboarddata
instead of clipboardData
, it didn't matter. This feature isn't unique to LiveCode, but it is common among near-English programming languages to not demand that the user gets the casing exactly right before the command works.
Adding the card handlers
If you dared to go ahead and tried using the calculator buttons, you will see a lot of script errors. We need to add in the card level handlers to be at the receiving end of the calls that the buttons make. Instead of walking you through, typing a line of code at a time, it probably would be quicker to present the lines in one go and explain what each line does. As a practice run, here are the lines that we have entered so far:
On all the number buttons and the decimal point button, you should have this script:
on mouseup numberPressed the label of me end mouseup
The on mouseUp
event is triggered when you press and release the left mouse button while on the numberPressed
call. This event will call a card handler named numberPressed
, passing with it, the label that you had set for the button that holds this script.
The C (clear) button has this script:
on mouseUp clearPressed end mouseUp
The clearPressed
event will call a card script named clearPressed
.
The other buttons all work the same way; they call a handler of the name used, which we're about to add to the card script. This is script for the +, -, *, and / buttons, passing to the card level, the name of the button in question:
on mouseUp operatorPressed the short name of me end mouseUp
The following script is for the +- button:
on mouseUp toggleSign end mouseUp
The display field has this script:
on mouseUp set the clipboardData["TEXT"] to me end mouseUp
In the field's case, only one line of code is being executed, so no need to put that up on the card level, unless we had a lot of fields doing the same thing.
So, why don't we add all those card level scripts! We will take them one at a time, with an explanation of how each one works. But first, let's see how LiveCode handles variables.
Tip
Downloading the example code
You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.
Variable types in LiveCode
Generally speaking, variables are memory locations where you store values that you need to access later, but in most programming languages, you can dictate which routines have access to which variables. Less English-like languages may include the terms public
, private
, and protected
. Things are not that different in LiveCode, but words are used that more accurately describe the region that the variable can be used in. If a variable is to be readable everywhere, it would be global
. If it's just to be used in the current script, it's local
.
LiveCode also has custom property variables, and as an aside, many people would use these for performing the calculator button values instead of relying on the label of the button. Perhaps, we'll use them later!
Now, where was I… oh yes, card level scripts. This is the first line of the card script:
global currentTotal,currentValue,currentCommand,newNumber
As discussed, these are the variables that will allow the many handlers to pass values to each other. In this case, the variables could be local, but often, you may make them global instead, thinking that a case may come up later where you need to get at the variables from outside the script you're in.
It's good to reset things when you start the app and LiveCode has an openCard
event that we can pick up on. The following code resets things:
on openCard clearPressed end openCard on clearPressed put true into newNumber put 0 into field "display" put 0 into currentTotal put 0 into currentValue put empty into currentCommand end clearPressed
Having the reset lines in their own clearPressed
handler will allow us to call it at other times, not just when the card opens, and we do call it directly when we click on the C clear button. This will zero out the display field, the running total for your calculation and the last number that you entered into the calculator. It also clears the variable that is used to remember which operator button you last pressed, and a Boolean (true or false) variable is used to recognize whether a number button that you press should clear the display or append to the display.
All the numbered buttons and the decimal point button call this handler:
on numberPressed n if newnumber is true then put n into field "display" put false into newnumber else put n after field "display" end if end numberPressed
The n
comment after the handler name, is a parameter variable that stores the content that was sent to the handler. In this case, it's the label of the button that was pressed. All this routine needs to add is a character to the end of the display field, except when you are typing in a new number. That's where the newNumber
Boolean variable comes in; if it is set to true
, the incoming character replaces all the contents of the display field. If it's false
, the character is added to the end of the field.
This is the handler to be used when you press the +, -, *, or /, buttons:
on operatorPressed operator if currentCommand is empty then put field "display" into currentTotal put operator into currentCommand put true into newNumber else put operator into currentCommand equalsPressed end if end operatorPressed
When you use a calculator, you type in one number, an operator, and then another number, followed by either another operator or the equals
button. Now you press the operator button as there is no way to know what you're doing (since you haven't entered the next number in the calculation yet), so we have to remember the operator when we press the equals button. If the currentCommand
variable doesn't already have a value, we store the display field text into a currentTotal
variable, store the operator character that you pressed into the currentCommand
variable, and make sure that newNumber
is set to true
. Doing this makes sure that the next number button you press will clear the display field. If currentCommand
already has a value, we replace it with the new value and then call the same handler that is used when you press the equals
button.
There are most likely shorter ways to cope with the equals
button being pressed, but here, we'll use several if
statements and run the appropriate calculation code:
on equalsPressed put field "display" into currentValue if currentCommand is empty then exit equalsPressed if currentCommand is "divide" then put currentTotal / currentValue into field "display" if currentCommand is "multiply" then put currentTotal * currentValue into field "display" if currentCommand is "minus" then put currentTotal - currentValue into field "display" if currentCommand is "plus" then put currentTotal + currentValue into field "display" put field "display" into currentTotal put true into newNumber put empty into currentCommand end equalsPressed
The contents of the display field are stored in the currentValue
variable and the last operator button you pressed (that is stored in currentCommand
) is looked at, to see what happens next. If there wasn't a previous operator, as would be the case if you pressed "equals" twice in a row, we'd ignore the button press and exit the routine. For the four operators, we do the appropriate calculation. Afterwards, we store the new running total in the currentTotal
variable, make sure that the newNumber
Boolean is true
(so that the next number button pressed will clear the display field), and we forget the last operator button that was pressed by putting empty
in the currentCommand
variable.
One thing to note is that LiveCode is smart enough to know that the text string inside the display field is to be treated as a floating-point number.
The togglesign
last handler is as follows:
on togglesign if character 1 of field "display" is "-" then delete character 1 of field "display" else put "-" before field "display" end if end togglesign
This is a very simple routine that doesn't have to understand that it's floating point numbers are being represented. It simply checks whether the first character is a minus or not and if it is, it deletes the character; if not, it inserts a hyphen that LiveCode will later interpret as a negative value.
Pop quiz – try to remember…
As you get to learn a new tool, you can end up taking a lot of time remembering where everything you may need, is located. You know what you want to do, you know how to do it, but you can't remember where that thing is located! For example:
Q1. Where did you go to set the text styling for the calculator's title field?
- The Edit menu.
- The Object menu.
- The Text Formatting section of the Inspector palette.
- The Text menu.
Answer: 3
Getting to this section involved selecting the Edit tool from the Tools palette, clicking on the title field on card 1, and choosing Text Formatting from the Inspector palette drop-down menu. However, there is indeed a Text menu. Really, that's what we should have used!
Extending the calculator
It is possible to add more features to the simple calculator. If we consider the functions in the card script and how the buttons are named, we can start to see the processes that are involved in adding a new ability, some of these processes are as follows:
- The calculator operator buttons are named so that the card script knows which one you clicked on.
- When the "equals" button is pressed there is a set of
if
statements in theequalsPressed
handler that determine what happens next.
Have a go hero – getting to the root of things
On Windows, you can add a square root symbol with Alt 251
and on Mac, with the shortcut option + v. Unfortunately, LiveCode doesn't like these as button labels! At least on Mac, when you type the character in the Inspector palette, the character immediately vanishes. One workaround would be to use the message box and type this:
set the label of btn "squareroot" to "√"
This should give you the right symbol as the button label.
LiveCode has a square root function; typing this in the Message Box would produce the square root of 10:
put sqrt(10)
Now that you are armed with the given information, try to add a square root feature to the calculator.