You can have Director execute different Lingo code in response to various conditions. Any non-zero expression (including negative numbers) is considered
TRUE, and only an expression that evaluates to zero is considered
FALSE. Refer to Chapter 5 for details on evaluating comparisons, including compound expressions. (These example multi-line code fragments must be placed in a handler for testing.)
if statement will execute different Lingo code based on the value of the specified expression. This allows you to, say, use a single Director movie on both Macintosh and Windows but branch to different code depending on the playback platform, as determined by
the platform property, such as:
if (the platform starts "Windows") then -- Do Windows-specific stuff here else -- Do Macintosh-specific stuff here end if
if statement has many possible forms, but I recommend only these. Items shown in curly braces are optional. Note the correct indentation:
else if and
else clauses are optional:
if x = 1 then go frame "Slide1" else if x = 2 then go frame "Slide2" else if x = 3 then go frame "Slide3" else go frame "End" end if
The following forms are theoretically valid, but they often misbehave in Projectors and within nested
if statements, so I don’t recommend them:
Where I use the one-line form of
if...then in the examples throughout the book, I do so only for brevity. The Lingo compiler occasionally makes errors when evaluating one-line and two-line
Use the following three-line form even for simple
if statements, especially when nesting
By always using an
end if statement, and by always including a carriage return after the
then keyword, Director won’t get confused and neither will you. The auto-indenting will work reliably and it also makes the code easier to read and debug. See Chapter 3.
You can nest
if statements to create the desired logic. It is crucial that you use the three-line
if...end if construct, rather than the one-line or two-line form. An
end if always pairs up with the most recent
if from the inside out. Let Lingo’s auto-indentation be your guide.
expression1then if expression2 then
action2end if else
Example 1-20 is a typical usage of a nested
There must be one
end if for each
if statement. Watch for this, especially with nested
ifs, such as is shown in Example 1-21.
Example 1-21. Common If Statement Errors
if x > 5 then if x < 7
statementsend if -- You are is missing an "end if" here
If you omit the
then keyword, you’ll also have problems:
if x > 5 -- the keyword"then" is missing
if...else if...end if statement instead of a series of
The following is inefficient because if
x equals 5, it will never equal 6, and vice versa:
if x = 5 then -- Do something end if if x = 6 then -- Do something different end if
This is more efficient (see also "Case Statements" later in this chapter):
if x = 5 then -- Do something else if x = 6 then -- Do something different end if
The incorrect order of comparison can lead to the wrong code being executed. Some code may never be executed, or code may be executed unintentionally.
In this example, both
if statements will be executed if
x equals 5. This may be what you want, but it is more likely a logic error:
if x > 0 then
statementsend if if x > 4 then
In this erroneous example, the second branch will never be executed because the first branch is taken in every case where the second condition would be
if x > 0 then
statementselse if x > 4 then alternative statements (never reached) end if
In this corrected example, the second branch will be executed only if
x is less than 4 but greater than 0:
if x > 4 then
statementselse if x > 0 then alternative statements end if
The innermost conditional clauses in this example are never executed.
Example 1-22. Nesting If Statements Properly
if x = 3 then
alert "Executed option 3"-- This is never executed; if x is 3, it's not 4
if x = 4 then
alert "Executed option 4"-- This is never executed; if x is 4, it's not 5
if x = 5 then
alert "Executed option 5"
The correct construct is:
if x = 3 then
alert "Executed option 3"
else if x = 4 then
alert "Executed option 4"
else if x = 5 then
alert "Executed option 5"
end if only for each
if, not for each
else if (sometimes Director won’t complain, but the results won’t be what you wanted). Example 1-23 is wrong.
Example 1-23. Using End If Improperly
if x = 3 then alert "Executed option 3" else if x = 4 then alert "Executed option 4" else if x = 5 then alert "Executed option 5" end if end if -- This is not needed end if -- This is not needed
end ifs can change your logic unintentionally. Contrast the following with the earlier nested
if example. It will always execute the last
alert command because it follows the last
if field "name" <> EMPTY then -- These five lines of code are a nested "if". if length(field "name") > 10 then alert "Enter only the first ten letters" else alert welcome & field "name" end if -- This terminate the inner "if" statement end if -- This terminate the outer "if" statement -- This will always be executed alert "Please enter your name"
if statement must have a matching
end if. Erroneous structures at the end of a preceding handler will trickle into the next handler and corrupt the indentation. Note the incorrect indentation in the
mouseDown handler caused by the missing
end if in the preceding
on mouseUp if the clickOn = 3 then if rollover(7) then put "Yahoo!" end if put "whatever" -- This is missing an "end if" end on mouseDown put "Hello" -- Note incorrect indentation end
on mouseUp if the clickOn = 3 then if rollover(7) then put "Yahoo!" end if put "whatever" end if -- That's better! end on mouseDown put "Hello" end
Look for ways to reduce the number of
if clauses. Here we’ve modified the example shown under "Multiple-Clause If...Then...Else If...Else...End If.” We’ve reduced the number of clauses by using the value of
x to construct the name of the destination marker (“Slide1,” “Slide2,” or “Slide3”).
if x >= 1 and x <= 3 then go frame ("Slide" & x) else go frame "End" end if
case statement conditionally executes Lingo statements based on the value of an item. It is often easier to implement than multiple
if...then statements, but long
case statements can be slower than the corresponding
if...then constructs. Director executes the statement(s) following the first
value that matches the
case clause. The colon after
otherwise is optional, and multiple statements can be included after each value to be matched. Once a match is found and its statements executed, subsequent values and their statements are ignored, and execution continues after the
end case statement.
Example 1-24 shows a
case statement and the equivalent
Example 1-24. Case Statements
on keyDown case (the key) of RETURN: go frame "done" TAB, BACKSPACE: beep otherwise: pass end case end keyDown
case statement is equivalent to the following
if ... then statement:
on keyDown if (the key = RETURN) then go frame "done" else if (the key = TAB) or (the key = BACKSPACE) then beep else pass end if end keyDown
on keyDown case (TRUE) of (the keyCode >= 123 and the keyCode <= 126): -- The user pressed an arrow key statements (the keyCode = 122): -- The user pressed F1 statements (the keyCode = 118): -- The user pressed F4 statements otherwise: alert "Please press an arrow key, F1 or F4" end case end keyDown
Repeat loops repeat any statements within the body of the loop. They are used to cycle through a series of items, such as elements in a list, or to repeat an operation a specific number of times (they are equivalent to so-called for...next loops used in some languages). When the
end repeat command is reached, execution begins again at the top of the
repeat loop until some condition causes the loop to terminate. Execution continues at the statement following the
end repeat command. Use the Debugging window, described in Chapter 3, to examine the exact flow of Lingo as Director executes the steps in the
Don’t use repeat loops that monopolize Director’s attention for more than a few seconds.
In Shockwave, you can’t check whether an operation completed with
netDone() from within a repeat loop because Director doesn’t perform network operations during a repeat loop. Likewise, Director doesn’t update all system properties or update the Stage automatically during a repeat loop.
The repeat loop has four forms (3 forms of
repeat with plus
repeat while), as shown earlier in Table 1-3. The example multi-line code fragments must be placed in a handler for testing.
repeat while command repeats as long as an expression is
TRUE. If the expression never becomes FALSE, it will be an infinite loop.
Example 1-25. Repeat Loops
repeat while (the stillDown = TRUE) put "The mouse is still down" end repeat
repeat with commands loop through a range of values. Although not necessarily apparent, the three forms of the
repeat with loop all use an index variable (counter) that changes automatically each time the loop is executed.
In this example, the index variable (
i) starts at the initial value (in this case 1) and increments each time through the loop until it hits the upper bound (in this case 100). If the initial value is greater than the upper limit, the statement(s) within the loop are never executed.
repeat with i = 1 to 100 put "The next number is" && i end repeat
The following is the equivalent
repeat while loop to the above
repeat with loop. You can see that
repeat with loops are more convenient.
set i = 1 repeat while i <= 100 put "The next number is" && i set i = i + 1 end repeat
repeat with...down to command repeats for a decreasing range of values. In this case, the index variable (
i) is decremented (not incremented) each time through the loop.
repeat with i = 100 down to 1 put string(i) && "Bottles of beer on the wall..." end repeat
repeat with...in command cycles once through all the items in a list. (Refer to Chapter 6 or ignore this example for now.) Each time through the loop,
i is automatically set to the next item in the list. Use the following to loop through an irregular set of numbers:
set myList = [12, 17, 52, 43] repeat with i in myList put "The next item in the list is" && i end repeat
i is not an integer in the previous example; it is actually the contents of the next item in the list. The previous example can be simulated with a standard
repeat with loop, as follows:
set myList = [12, 17, 52, 43] repeat with j = 1 to count (myList) set i = getAt (myList , j) put "Item number:" && j put "The next item in the list is" && i end repeat
In the last example, note that the index variable
j is an integer and can be used to print a list element’s position within the list. You must manually intialize and increment an index variable to obtain a similar counter if using a
repeat with...in loop, such as:
set myList = [12, 17, 52, 43] set j = 1 repeat with i in myList put "Item number:" && j put "The next item in the list is" && i set j = j + 1 end repeat
repeat with x = 1 to the number of members if the memberType of member x = 0 then next repeat end if put "Item" && x && "is type" && the memberType of member x end repeat
exit repeat to exit the current repeat loop immediately. Program execution continues with the statement following the
end repeat statement.
Exit repeat exits only the current (innermost) repeat loop, and it will not exit nested
repeat loops. Use
abort, or a flag to exit multiple loops, as shown in Example 1-26. (Again, use the Debugging window to examine the exact flow of Lingo as Director executes the following code.)
Example 1-26. Nested Repeat Loops
on findIt global gFoundIt set gFoundIt = FALSE -- Search for a #shape cost member repeat with y = 1 to the number of castLibs repeat with x = 1 to the number of members of castLib y set thisItem = the memberType of member x of castLib y if thisItem = #shape then set gFoundIt = member x of castLib y exit repeat -- exit the innermost loop end if end repeat -- exit the outermost loop too if gFoundIt then exit repeat end if end repeat -- Execution continues here after loop if gFoundIt then put "Found shape cast member at" && gFoundIt else put "Shape cast member not found." end if end
Lingo does not precalculate the number of iterations it will perform for a
repeat...with loop. Rather, it reevaluates the expression each time through the loop. In the following example, we manually increment the index variable (
i) to step by two rather than one. Note that we add only 1 to
i, not 2, because Lingo will automatically increment
i once each time the loop is executed.
Example 1-27. Customized Repeat Loops
on printEvenNumbers repeat with i = 0 to 100 put i set i = i + 1 end repeat end printEvenNumbers
Avoid manually setting the index variable within a
repeat loop unless you need to change the number of loop iterations. Setting it incorrectly can lead to an infinite loop.
After a loop completes, the index normally is one greater than the ending value:
on testRepeat repeat with i = 1 to 100 put i end repeat put "The ending value for i is" && i end testRepeat testRepeat -- 1 -- 2 -- <etc.> -- 99 -- 100 -- "The ending value for i is 101"
An infinite loop is a
repeat loop that will never be exited because the conditional expression never turns
FALSE. (Apple’s street address in Cupertino, California, is One Infinite Loop). An infinite loop will appear to hang the computer, and you must abort the Projector or halt the movie to stop it.
The most simple infinite loop is shown in Example 1-28.
Unless you add an
exit repeat, Lingo will never exit such a
startTimer repeat while TRUE if the timer > 60 then exit repeat else -- do something end if end repeat
But this would be better written as:
startTimer repeat while the timer <= 60 -- do something end repeat
It is easy enough to create an infinite loop accidentally. The following will loop forever, assuming the loop takes less than 60 ticks to execute, because
startTimer is within the
repeat loop and keeps resetting the timer.
startTimer repeat while the timer <= 60 startTimer -- do something end repeat
The following would lead to an infinite loop as well. The variable
x is unintentionally set to 5; the programmer did not realize that
x is also being used as the loop’s index variable.
repeat with x = 1 to 10 put "x" && x set x = 5 end repeat
A loop will also be infinite if some condition you expect to become
TRUE forever. Suppose you are waiting for a sound to start:
puppetSound "mySound" repeat while not soundBusy(1) nothing end repeat
If the sound never starts (in this case, you need to add
updateStage after the
puppetSound command), Director will loop forever because
soundBusy(1) will never become TRUE, so
not soundBusy(1) will always remain
Use the Debugger to diagnose infinite loops and similar problems. See Chapter 3.