HyperActive Software

Home What's New Who We Are What We Do Solutions Resources

We make software for humans. Custom Mac, Windows, iOS and Android solutions in HyperCard, MetaCard, and RunRev LiveCode


Converting a HyperCard stack to LiveCode

Optimizing the stack for LiveCode

While the converted Tech Support TimeSaver runs fine now, there are some things that will optimize it for LiveCode which will make the scripts run more efficiently and provide additional features that HyperCard doesn't offer. None of these changes are required, but adding them will improve the functionality of the stack.

Use send to instead of idle handlers

As mentioned elsewhere, the idle message is supported for compatibility with HyperCard but is extremely inefficient, tying up the CPU and creating a great deal of overhead. It is highly recommended that idle handlers be avoided in scripts. LiveCode offers many other messages and commands to do what HyperCard users traditionally use idle to do. Take a look, for example, at the grab command, which makes an object follow the mouse, or the move command which puts objects into animated motion. But one of the most useful structures for replacing idle is the send to object command, which sends a message repeatedly to an object at an interval specified by the script.

Both the title card and the timer card of the Tech Support TimeSaver stack use an idle handler; in the first case to implement the repeated sound of a watch ticking, and in the second to update a timer display showing elapsed seconds. We will change both of these.

Changing the title card script

Go to the title card of the stack and open its card script. Delete or comment out the idle handler. Enter this handler in its place:

on doTicks
  play "Tick.rev"
  send "doTicks" to me in 1 second
end doTicks
Now comment out the line in the openCard handler that sets the idleRate, and comment out or delete the entire closeCard handler as well. Insert the command doTicks just before the pass openCard command in the openCard handler. Finally, add a new closeCard handler:
on closeCard
  repeat for each line l in the pendingmessages
    if "rev" is not in item 3 of l then cancel item 1 of l
  end repeat
  pass closeCard
end closeCard
The entire script of the title card should now look like this (changes are in red):
on openCard
  global gShowDialog
  -- set the idleRate to 800
  if gShowDialog is "Yes" then
    put "No" into gShowDialog
    -- play "Bell"
    answer "This program is $5 shareware." & return & return & \
        "NOTICE: Do not distribute this stack except in its original," \
        && "unaltered form as a HyperCard file. See the About card" && \
        "for details." with "More Info" or "OK"
    if it is "More Info" then
      lock screen
      go next card
      set scroll of card field "Info" to 0
      unlock screen with visual effect dissolve fast
    end if
  end if
  pass openCard
end openCard


on doTicks play "Tick.rev" send "doTicks" to me in 1 second end doTicks

-- on idle play "Tick.rev" pass idle end idle

on closeCard repeat for each line l in the pendingmessages if "rev" is not in item 3 of l then cancel item 1 of l end repeat pass closeCard end closeCard

Close the script editor. If you leave the card and then return, you will hear a steady ticking about once per second. What did we do?

The doTicks handler simply plays the sound and then instructs itself to call its own handler name again 1 second later. The doTicks command we inserted into the openCard script is the trigger that starts the process initially; after that, doTicks repeats itself on its own. When the card is closed, the closeCard handler examines the pendingMessages, which is a list of messages that are queued up waiting to be sent, and it loops through the list, canceling each one that is not one of LiveCode's own internal messages. All of LiveCode's internal messages begin with "rev", and it is important to test for the existence of that string before a script cancels any pending message. If it doesn't, the stack will error whenever LiveCode's own handlers are running. The loop could optionally test for any other condition too, if there were several different handlers queueing up lots of different kinds of pending messages, but in this case our stack has only one type of pending message so we just cancel them all.

The advantage to using this approach instead of idle is that while pending messages are being sent and executed, LiveCode continues to be fully operational; the user has full control of the mouse and keyboard, other messages are sent normally, and there is no slowdown while the system waits for an idle handler to finish before moving on to the next task.

Changing the Timer card script

Go to the Timer2 card now and open its script. Change every instance of the word idle to checkTime. Delete the pass idle line in the idle script completely. Insert the line send checkTime to me in 200 milliseconds at the end of the checkTime handler, and insert the command checkTime just before the pass openCard command in the openCard handler.

In addition, add the same closeCard handler we used before so that all pending messages will be canceled when the user leaves the Timer card.

The revised card script looks like this:

on openCard
  global gTimerOpenOrClosed
  put "Open" into gTimerOpenOrClosed
  pass openCard
end openCard

on checkTime global gStartTime,gTimerOn,gTemp get gTimerOn if it is empty then put "0:00" into card field "Elapsed Time" if it is "yes" then put (the seconds - gStartTime) into gTemp put gTemp div 60 into wholeMinutes put gTemp mod 60 into remainingSeconds if remainingSeconds < 10 then put "0" before remainingSeconds if wholeMinutes > 59 then put (wholeMinutes div 60) into wholeHours put (wholeMinutes mod 60) into wholeMinutes if wholeMinutes < 10 then put "0" before wholeMinutes put wholeHours &":"& wholeMinutes & ":" & remainingSeconds \ into card field "Elapsed Time" exit checkTime end if put wholeMinutes &":"& remainingSeconds into cd fld "Elapsed Time" end if send "checkTime" to me in 200 milliseconds end checkTime

on closeCard repeat for each line l in the pendingMessages if "rev" is not in item 3 of l then cancel item 1 of l end repeat end closeCard

Leave the card and return again to trigger the openCard handler. Then try the timer.

Up to top | Converting Stacks to LiveCode - TOC | Next Page