(Translate this site)

Search this site

Site web log(s)

First aid for broken links

HyperCard Headstart, Part Two

ORIGINAL PUBLICATION DATE: FALL 1994

Please help us keep this site online


GOOGLE CACHE INDEX

Site map

Latest site updates

Site author

Back to HyperCard Headstart, Part One

Getting to know HyperCard

HyperCard is like a deck of playing cards ...


...that you can manipulate on screen and build programs in and around. A single HyperCard program is called a "stack", and essentially comprises the deck of cards available to a user at any given time. Such a deck of cards (or stack) might contain as few as a single card, or as many as thousands. The author of a particular stack or deck of cards assumes the role of 'dealer' for that deck/stack, pretty much making up the rules of the game as they go along. The rules for a HyperCard stack can be wildly different from one stack to another-- its all up to the author of the stack.
The card deck model HyperCard's based on actually works pretty good for many purposes, since practically all programs often need several different screens available for presentation to users (cards), and you might want to access them in a variety of ways (sequentially, randomly, via particular button or menu command), all of which you can do with HyperCard's screens.

Hiding cards and why



The author may elect to keep some cards forever hidden from users, in order to provide the stack with its own internal, protected memory space. Such memory space can allow a stack to be more intelligent than would otherwise be the case. For instance, this memory might be used to remember user preferences from a previous session. Why hidden cards for memory space? Because the only non-volatile memory a HyperCard stack enjoys lies within its scripts, its artwork, and its text fields. This means if you have variables that might change in value from one session to another, based on something 'learned' by your stack over time, the only practical place to store them is in text fields; and text fields require a card to reside on. Ergo, the hidden memory card (or cards-- you might need more than one to contain all the fields required).

The main three HyperCard modes of operation


Browse mode is the default. Many HyperCard users may never exit this mode to another, as this is the one you're typically in to move through a stack, read and scroll through text, type in information, click buttons, and more.

Button mode is really a development tool for authoring and scripting HyperCard stacks. Button mode allows you to move and resize buttons, as well as access via double-clicks their Info dialog boxes, and from there their scripts.

Field mode is another development tool, except in this case for text fields. In this mode you can move and resize text fields, and edit their scripts or other properties.


Using Fonts in HyperCard


Theres two kinds of font usage in HyperCard-- paint and text.

Paint font usage

Paint font images pose little problem for distribution in stacks, as they are simple bitmap-style imagery, and don't require that an end-user's system possess the font resource with which the image was created. This allows you, the author, great latitude in how your stack looks font-wise, so long as you can adequately get by with simple, paint-type images. However, there are some disadvantages to using fonts in this manner:

1. As you develop your stack, it can be difficult and time consuming to revise text embedded in your stack as paint images. Because it's often necessary to manually move individual words or phrases about to get the revisions to fit in properly, as well as spend substantial time trying to figure out which font you originally used to create the text, so that you can use it again to create new text that matches the old. If this text were instead within a text field, you could simply type in the new text, with HyperCard automatically rearranging the rest to accept it, and select a section of text and examine the font menu to see which font was being used, as necessary.

2. Paint-style font images can consume a lot more disk space than their text field counterparts. The amount of extra space required varies with many factors, but in general paint fonts require maybe a third more disk space than text field fonts.

Text field font usage

When you use fonts in text fields of stacks you plan to distribute widely, you should limit your usage to fonts generally available on most Macs. Otherwise when someone else looks at your stack, and their system doesn't contain the same font, HyperCard will make the best choice it can for a match from what's available-- usually making your text look rather garish as a result. From the few near universal fonts available on Macs these days, something like 12 point Geneva seems the best overall choice for legibility, compatibility, and easy-to-stomach appearance. Unfortunately, there are times that more latitude in font usage seems essential for a presentation. And since the Mac's few universal fonts are lacking in such flexibility, the only other choice is to use non-universal fonts in the creation of paint-style text in your screens.


HyperCard shorthand or abbreviations


The more you script the more you'll use and appreciate HyperCard's shorthand, or abbreviations for its commands.

Abbreviations you're likely to use most often are:

      	bg = background
      	cd = card
      	btn = button
      	fld = field
      	loc = location
      	char = character
      	chars = characters

Command shorthand you might often use:

      	lock screen = set the lockscreen to true
      	unlock screen = set the lockscreen to false

      	lock messages = set the lockmessages to true
      	unlock messages = set the lockmessages to false



HyperCard comments, notes, and asides...



...can come in handy. During development or debug of fairly complex scripts you'll often want to make notes to yourself about what's happening in a particular statement, or perhaps place an informative comment for the benefit of your future self who might not look at the same section of code again for years. Or, you might wish to remove a statement from the executing script temporarily as a test, without having to remove it entirely from the listing. All these things can be done with comments in HyperCard scripts. HyperCard will usually ignore any statement with two dashes (--) in front of it; so you can safely park your comments or temporarily out-of-the-running script behind these dashes, as you pursue other matters.

Other ways to get scripts out of your face temporarily while still keeping them relatively handy include storing them elsewhere, like in the script of another object. You can even place them inside a handler so named that it will never be activated by any command from HyperCard or your own scripts-- a handler devoted purely to storage, but maintaining your statements in their original format (any scripts you store without a proper handler name or comment dashes (--) will not retain their format structure, and may also cause a script error under some conditions, if HyperCard tries to act on them).

Below is an example of using comment dashes:

      	on mouseUp
         		-- here I've placed a comment on its own separate line in a handler
         		go to next cd  -- here I've placed a comment after a command
      	end mouseUp


Playing with the pointer


Showing a busy cursor is no more difficult than typing
set the cursor to busy
in a script. This changes the cursor to the beachball shape many Mac users will be familiar with from past incarnations of MacDraw and other programs.

However, a single statement of this type won't make the beachball cursor move or rotate as you might expect, to indicate the stack is working (as opposed to being crashed or hung up).

To make the beachball cursor spin or rotate, simply repeat the original statement elsewhere in your script. One great way to accomplish this with a single line of code is to place the statement inside a repeating loop. This will spin the cursor like we're talking about, as the statement will be executed anew with each cycle of the loop.

The beachball is the default busy cursor. But what if you want the wristwatch cursor instead? And you want its hand to spin? Sorry, but you'll have to create your own custom icons to depict a spinning watch. HyperCard has a static (unmoving) watch cursor you can use, but doesn't supply the fodder for animating its hands like it does for animating the beachball.


HyperCard sleight-of-hand



If you're a magic aficionado you'll appreciate HyperCard's own bag of tricks for fooling stack users. First and foremost, HyperCard lets you freeze time for the end user, while it (time) continues running normally for you and your program internally. A seventies-style movie about a magic watch sometimes appears on TV illustrating how powerful this principle would be if applicable to the entire world. When you freeze time in HyperCard, all the normal screen updates don't occur-- so you can perform amazing manipulations of your stack without the user seeing them-- moving between cards, cutting and pasting, deleting cards, etc. When you UNfreeze time again, all the user sees are the end results of your machinations-- not the messy intermediate stage. The command for freezing time in HyperCard is lock screen; the command to unfreeze it is unlock screen.

The long winded ways to say these things are:

      	set the lockscreen to true
      	set the lockscreen to false



Other sleight-of-hand tricks are illustrated in HyperSavvy HOT v1.0, the companion stack to this article series, published as part of the Summer 94 issue. Therein are given functional examples of the
lock screen
described above, as well as other techniques, such as pre-loading text fields to make them appear to be rapidly changing on-the-fly, and how to use a combination of buttons and fields to mimic the functionality of a PopUp menu in your stack. There's also examples of using button icons and outlines to create animation effects, in various progress gauge dialogs in the stack.

And while we're on the subject of object handling sometimes being faster than the eye...

Each card can have many layers of objects, some visible, some invisible, some shared with other cards, some not.



The pure graphic imagery seen on each card in HyperCard can possess both a background and foreground aspect, much like a painting. The background is referred to inside HyperCard by the name you'd expect ("background"), while the foreground is not-- usually being referred to as a "card".

Whatever artwork exists in the card layer will usually take precedence over images in the background layer; that is, if you have a picture of a clown in the card layer, and an elephant in the background layer, youll see only the clown if they're both located in the same two dimensional region of the HyperCard window. This will be the case where the clown graphic is opaque; you might make it transparent, in which case a user will see the elephant through the clown. Many cards may share the same background. So on another card the user might see the elephant through transparent balloons rather than the clown.

Text fields have a layer of their own, which is always in front of any graphics they share a card or background with. A background text field will always be in front of a background graphic, and a card text field always in front of a card graphic. A card text field will always be in front of a background text field.

Buttons too have their own layer, which is in front of any text fields they share a card or background with. So a background button is always in front of any background text field or graphic, and a card button always atop a card field or graphic.

A card button can cover up a background button on screen, and all the buttons and fields in a background layer can be hidden by an opaque graphic in the card layer.

Often you'll have several buttons and text fields occupying the same card or background layer.
In such a case as this, you may shuffle the buttons or text fields amongst themselves, within their respective groups and layers, like a deck of cards. The way you do this is use the Bring Closer and Send Farther commands in HyperCard's Objects menu, after you've selected the particular button or field you want to move. These commands are incremental-- that is, you may have to use them several times to get the object where you want it. If you're moving a text field from behind three others to the front of its field layer you'll need to use Bring Closer three times.

How does HyperCard determine where a button or field is in its respective layer and object group? By order of creation (until you change the order by a Bring Closer or Send Farther command). The first button created in a layer will be the farthest back, the latest button the one in front. The same goes for text fields.


Scripting in HyperCard's object oriented environment


Great, humongous chunks of a HyperCard stack are programmable by the user. And each chunk is pretty much an independent object, so there's not as much to worry about in programming as there would be in a language like C or BASIC.

If you're used to certain other languages, you've seen program listings that were tens or even hundreds of pages long, since often much or all the programming is done in one place, creating something like a book worth of text you can scroll through for hours, and in which it can be very difficult to locate bugs or other items, simply because everything's all in one, contiguous form.

In HyperCard, each piece of a stack is a separate individual, with its own programming. This means each button, each card, each background, each text field, all possess their own potential programming text, in their own editing window.

This fact can seem intimidating to the beginning scripter, even if they are otherwise experienced with a variety of languages. At least it was for me, and I did possess considerable experience with other languages before arriving at HyperCard.

I guess the best advice is: don't worry so much. As long as you keep to a fairly reasonable backup routine for whatever serious work you're attempting with HC, you should feel free to try just about anything with the program. After all, that's one big reason kids usually learn stuff faster than we adults-- they worry less, and experiment more.




HyperCard object names, and other remote identification matters


One great thing about HyperCard is you can name everything with as descriptive a title as you wish in a stack. And then refer to that name in your programming rather than using the ID numbers or other references available for the object in question-- because HyperCard will recognize the name!

You can have a card named "H.G. Wells", where it's the screen in your database that holds his biography in a text field. Also sitting there on your "H.G. Wells" card you can have two buttons, one named War of the Worlds, and the other Time Machine, because each button leads, respectively, to cards detailing those two works by the author.

Naming your objects this way is a good habit to get into, as it'll make it more convenient for you to cut and paste objects from one stack into another-- because that way you won't have to change ID or sequence numbers in your scripts in a following clean-up procedure.

However, you don't want to name objects indiscriminately, as this can lead to problems on a par with not naming them at all; mainly because you'll be unable to remember the names, or tend to use the same name more than once. So be careful when naming your objects to make the name something meaningful to you, that you'll easily remember in later script references, and be unlikely to use again with a different object.

In this way object names are similar to variable names-- for you don't want to name your variables indiscriminately either, for pretty much the same reasons. Fortunately however, HyperCard's usage of global and local variables gives you much more slack in this regard than you tend to enjoy with object naming.

All this extra consideration required for naming objects can often slow up a project-- so many times you might not go to the trouble. That's OK, since HyperCard doesn't usually require a name for an object. But remember that copying and pasting your buttons, fields, and cards into another stack later will entail lots of ID number changes, if formal names are lacking from your objects' descriptions.

the target
is a HyperCard synonym for whatever object received the last message. For example, let's say you had six radio buttons you wanted to use the same handler for in their shared card script. Your goal might be to have only one button hilited at a time. If you're to use the same handler for all the buttons, you type its name into the
mouseUp
handler of each button's script. Then in the card script, where the special wholesale button handler is, you first turn off the hilites of all the buttons, so as to prevent more than one ever being seen hilited at the same time-- that's easy. The harder part is next turning on the hilite of the single button that the user just clicked. Or, at least it would be harder if HyperCard didn't offer
the target
as a remedy. Since
the target
always contains the identity of the last object to receive a message from the user, it'll hold the identity of the button clicked upon. So after turning off the hilites of all the various buttons, we can turn on the hilite of
the target
in our script, and that's that.

Users of HyperCard v2.2/2.3 may know that the above work is redundant for them, since HyperCard takes care of such things automatically, with button families. However,
the target
can still be used in this way with other HyperCard objects by 2.2/2.3 users, and users of older HyperCard versions will still require it for radio buttons too.

Names are optional for objects-- but addresses aren't. If you don't name an object, HyperCard will still recognize it by a unique ID number HyperCard assigns to it when you first create the object. But providing HyperCard with the proper address of the object, or where it lives in the stack, is mandatory where you're referring to anything not present on the card where the acting script is running from. For example, if your script is inside a button on card ID 342, and it needs to refer to a field existing on the same card, then your script may get by just referring to the field as
cd fld ID 23
. But if the field in question were on a different card entirely from the button whose script is calling on it, you'd have to give the field's address too when identifying it.

When you add the field's address to its identification,
cd fld ID 23
changes to something like
cd fld ID 23 of cd ID 8946
. If the field and card have been assigned names by you, this expression might instead look like
cd fld "George" of cd "Carlsons".


Actually, the prefix
cd
in the field's identification is also a part of its address, since this informs HyperCard you're talking about a field in the card layer, and not the background layer; two very different locations in terms of objects.

this [object], me, cousin it, and the message box.

Though I mention elsewhere how HyperCard understands names given to objects like buttons and cards, it's often unnecessary to use a name in your scripts. If you write a line inside a button program that refers to the same button housing the script, rather than using the button's name you can just say
me
, and the button program will know you mean the button itself. Just remember though that
me
works as a reference only inside the program of the very object you're referring to.

A variation on
me
is
this [object]
. However, the two can't always be used interchangeably. If you say
this card
in a script, the script will interpret this as the card on-screen , or the card that's supposed to be onscreen at this time (if the lock screen command has been invoked, HyperCard could have been ordered to move to a particular card by script command, but the lock screen order prevented that card from replacing the last one displayed on screen).
this stack, this card,
and
this background
may be the full range of possible uses for this expression.
me
might be applied to the full range of HyperCard objects.

The Addams Family on TV had a cousin "it", and HyperCard does too, sort of. If you do much of any HyperCard programming at all you'll become very familiar with cousin "it". In HyperCard
it
is a temporary variable you'll often use in your scripts, and which HyperCard uses automatically for its own use, in the course of its operations. You'll often put
it
into a variable of your own to get free info from HyperCard, and other useful tasks, sort of like drawing water from a public well.

The
message box
is sort of the opposite of cousin
it
, in that it's dedicated wholly to your own use, rather than the way
it
may be used casually either by HyperCard or a scripter. Whenever you put something into the
message box
by script, like the value of a variable or a character string, the message box appears on-screen, displaying what you put into it. Sometimes the
message box
is useful for checking a certain variable inside a program, and more convenient and useful than things like the "variable watcher" which came with HyperCard 2.1. Let's say you suspected your variable "
thinGie
" contained an erroneous value at a critical point in your script. You can check this by displaying its value in the
message box
from the very spot suspect in your script. Just type the line
put thinGie into message box
immediately following the line that sets its value, or immediately after your program has made a decision based on "
thinGie
", and the next time your program runs it'll display
thinGie's
value in the
message box,
allowing you to verify if anything is amiss.

Another great thing about the message box is you can type in one-line programs or commands to get immediate results, rather than having to set up a button to do the same thing. If you type into the message box the following...

go to cd 3


...and then press your return key, you're immediately transported to card 3 in the stack (if there is one).



HyperCard variables and lists (known in HyperTalk as containers)


Given the previous information about objects and object-naming, it might seem difficult to get all the parts of a stack to work together. But it's easier than it appears. For one thing, in something like a BASIC program you have to be pretty careful about assigning variable names, since using the same one for two different things could really screw up your entire program. In older BASIC languages the problem was made even worse by the fact that you were restricted to using only very short variable names; so, as in the recent history of DOS with filenames, it was very easy to become redundant or too cursory in the names used, to the point that you either didn't know what a particular abbreviated name stood for, or ruined a lot of work by mistakenly using the wrong one at the wrong time. In HyperCard though, you can often use the same variable name in all of your different program listings throughout a stack, for lots of different purposes, with no problem at all. This is because HyperCard has two kinds of variables: local and global. Local variables are used and forgotten by HyperCard immediately, being remembered only long enough to perform the task which fathered them. So using "
ButtFlip
" as a local variable in the program for card 113 doesn't interfere at all with using "
ButtFlip
" again in the next program you run, that might exist in the background of the very same card!

Of course, sometimes you'll want variables HyperCard remembers from one object's program to another: global variables. Whenever you use these in a program, you tell HyperCard your intentions by putting a statement like
global johnHenry,Henrietta,stopBit,whoA
as the first (or near first) line in your program listing (where
johnHenry,Henrietta,stopBit,whoA
are all global variables with names you yourself made up).

Any variable in HyperCard can be made into a list by simply distributing various punctuation marks or other signals inside it. Inside lists such marks are called
itemDelimiters,
and any words or characters inbetween the marks are called
items.
The delimiter used most often and by default is the comma. So the usual HyperCard list variable will contain something like
Peggy,Anne,Sue,Terri,Melinda
(commas included). To order HyperCard to take note of
Peggy
in the list, you'd say in a script
item 1 of listOfGirls
(if listOfGirls was the name of the variable).
You can change the
itemDelimiter
if you wish, to something like a colon for special purposes, like interpreting file pathnames obtained from the Mac operating system. For example,
Hard disk:Applications:HyperCard:FLUX Summer 94
might be the pathname you'd get for FLUX residing on your hard drive, if the magazine is inside a folder named "HyperCard", inside another folder named "Applications"-- and your hard drive is simply named "Hard disk". Pathnames are really just one of the ways the Mac keeps track of where things are, and you might never fool around with them much in your scripting. But you can if you want, by telling HyperCard to recognize colons as itemDelimiters, with the statement
set itemDelimiter to colon
.

Like lots of HyperCard elements, the identity of the
itemDelimiter
changes back automatically to the default value the next time HyperCard gets to idle. This means you can change the
itemDelimiter
in your script to a
colon
or something else out of the ordinary, use it to do whatever it is you need, then forget about it-- and HyperCard will put that toy away for you when you're done. But remember HyperCard won't reset this while your script's still busy. So if your script first does work with a colon delimited list, and then switches to work on a comma delimited list, you must reset the itemDelimiter yourself inbetween lists-- or face the wrath of the mighty Script Error.









HyperCard's nervous system, chain of command, and message hierarchy



You might be surprised to know HyperCard possesses something eerily similar to a living nervous system, that constantly pulses with messages streaming from HyperCard's extremities to its brain.

By typing "mw" into HyperCard's message box and pressing your return key, you can bring onscreen a small window that displays this pulse of information always traveling through an open and active HyperCard stack.

As you'll see in the message watcher window, most of these pulses are
idle
messages, meaning that nothing is happening, that HyperCard is waiting for the user (or a user-written script) to tell it something to do.



Message passing, handlers, and interception

Trickle up information flow; the natural or default message flow in HyperCard (bottom up). Typically a system message will begin its journey in an encounter with a button or text field, and if not intercepted along the way by a handler, proceed to the card underlying that button or text field, go on to the background behind the card, then to the host stack. If the message still finds no handler designed to cope with it, it will go on to the local Home stack, and from there, to the HyperCard application itself. If HyperCard has no built-in predilection for actively responding to this particular message in some way, the message will then simply drop out of the HyperCard universe, into a sort of 'black hole', from which nothing ever returns.

One big reason handlers are named as they are is because the main thing they do is intercept and handle messages as such signals travel through the HyperCard system.

The majority of messages intercepted by the handlers of a typical stack are standard HyperCard system messages, consisting of things like
mouseUp, openCard, 
and
openBackground
. But handlers can be written to intercept custom messages too. In fact, you could write handlers to intercept almost any message you might care to create-- and this is exactly what you'll do in order to create your own custom capabilities in a stack.

You'll want to use HyperCard's standard system messages as a skeleton for your efforts, as they conveniently cover most of the events you'd want to respond to in your stack, such as the end-user clicking on a button, making a menu selection, or moving to a new card. If you had a custom handler you'd written for a fantastic animated display inside your stack, named
SpectacularEffects
, you might utter just the name of the handler inside the
mouseUp
handler of a trigger button, to invoke the special display. Then when the user clicked the button, the name would move through the stack as a message, looking for your handler to intercept it.

Where would be a good place for your
SpectacularEffects
handler to be, in order to intercept the message? Well, the most straightforward place for it would be inside the script of the trigger button itself, just after the
mouseUp
handler which calls upon it. Everything would work fine with this arrangement.

But the very best placement of the
SpectacularEffects
handler would depend on several factors. For instance, what if you wanted another button on the same card to use the
SpectacularEffects
handler too? In that case, you might want to place the
SpectacularEffects
handler not in any one button's script, but inside the script of the card which all the buttons shared. This way all the buttons could easily access the handler, and you'd save space in your stack by not having several redundant copies of the handler spread among several different scripts.

What if there were other buttons, on different cards, that you wanted to use the handler with? Well, if all or most of the cards in question shared the same background, you could place the handler in that single background's script, rather than the scripts of multiple cards, saving space by bumping the
SpectacularEffects
handler up from a card script to a background script.

Note that this technique does more than just save space in your script; it also helps speed development and reduce the potential for bugs. How? It can speed development because you can improve the functionality of all the buttons dependent on the same handler by modifying that single handler in its single script, rather than having to edit several different scripts to accomplish the same purpose. Plus, the fewer copies of the handler in your stack you must edit, the less chance for making mistakes or mistyping within any one of them and not catching your error in testing-- which makes for a reduction in potential bug creation. Further, the fewer examples of the handler you must hunt down in your stack when a correction is deemed necessary, the less likely you'll accidentally overlook one for revision, creating a bug for your end-users to find later.

HyperCard's Chain of Command; Top-Down and Horizontal Messaging. Sending a message down or sideways through a stack is accomplished, logically enough, with the
send
command. This command is quite powerful, allowing you to (among other things) get around HyperCard's limitations on the size of individual object scripts. The 30,000 character or roughly 6000 word limit can hit developers especially hard in the area of stack scripts, because so much of a complex stack's functionality can be dependent on that single script, since it's often the only one which many important features of your stack can all share simultaneously.

One example is FLUX magazine itself, which is capable of so many different and strange things, compared to most other stacks you might encounter. First off, each issue [from the second year of publication, was] essentially two entirely different programs in one: a magazine with educational, speculative, and/or entertaining articles and imagery, AND a Super Stack, which amounts pretty much to a full-blown application program, dedicated to creating complex, interactive presentations to be published in future issues of the magazine. The magazine transforms itself to a Super Stack at the click of a button, thereby deleting and rearranging huge chunks of its functionality, sort of like a hero from one of those Japanese transformer kid shows. As if this wasn't enough, the transformed Super Stack then offers users a wide array of tool palettes, above and beyond those provided by the basic HyperCard application. Not least among these palettes is the new Magic Palette, which pretty much gives HyperCard Player users a big piece of the full-blown HyperCard application program, within the environment of the Super Stack (providing much of the functionality of userLevels 4 and 5).

It's no surprise that many experienced HyperCard scripters might find all this to be quite amazing, considering what they know of HyperCard's limitations. Especially when they discover that no custom XCMDs or XFCNs are involved in the majority of these capabilities.

Much of the credit for all this has to go to HyperCard's
send
command. It allows me to send all the dozens of different commands originating from the wealth of palettes to a single card script in the stack, rather than burdening the stack script with them. Other tasks too are offloaded from the stack script via this method. In other words, FLUX as we know it today could not exist without the
send
command.

Believe it or not, all the above represents only a small part of the power of HyperCard's
send
command-- and not even the part you're most likely to use in your own efforts!

No, the way you'll probably use the
send
command most is in things like sending a
mouseUp
message to a button on a particular card. Yes, the
send
command can be used to send HyperCard's own system messages to objects! At least sometimes. Some messages work better with
send
than others. Anyway, why might you want to send a
mouseUp
to a button this way? Well, in v2.1 of HyperCard and earlier, there was no way to set up a default button automatically-- you know, the kind with extra lines drawn around it, that signify it will be the button activated if you press your return key? In these older HyperCards, you had to set such things up manually. One way was to place a
returnKey
handler in the card script that looked like this:

         	on returnKey
            	send "mouseUp" to cd btn ID 3
         	end returnKey

This script (along with the appropriate lines drawn around the button onscreen) makes card button ID 3 a default button, activated automatically by the press of the return key.

There's still other facets to the
send
command, but as they pertain to highly advanced subjects like inter-stack communications, and even network communications, they're not really appropriate in this article. Most scripters are unlikely to need or want to use those advanced functions in their own efforts for the first two or three years of stack development, as it could easily take that long for them to become proficient enough in other, more practical Hyper matters, to even want to exploit such things.


Turning off the message system

Sometimes you'll want to turn off HyperCard's normal message broadcasting system. I've personally found myself in the situation of needing a script to:

1. Move to a particular card to get something.
2. Return to the original card to deposit the object retrieved.

However, an
openCard
handler in the interim destination card was programmed to do something else, and that something interfered with the above described process, which I was adding later. The interfering script was there for a good reason, unrelated to the new process I was creating, and so I didn't want to remove or disable the older script. The solution was to temporarily turn off HyperCard's messaging system while my newer script was running, so that the
openCard
handler never got the signal to act on its own script. Turning off the message system is always a temporary thing, as it automatically turns itself back on as soon as the active stack is idling again.

The command to turn off HyperCard's messaging system is
lock messages
. Its opposite is
unlock messages
, but the system automatically goes back on-line anyway as soon as your scripted processes are finished, and HyperCard's able to return to an 'idling' condition.


HyperCard's subroutines (called "handlers" in HyperTalk)



"Handlers" is the term HyperCard uses for subroutines or message trapping routines. Many handlers can be named whatever you want. Maybe you need to access the same subroutine from the scripts of several different objects, so you decide to have just one subroutine in a place accessible to all, to save space in your stack. Maybe you have six cards, all with a button called "Order Form", which your customers will click to go to a screen designed for accepting orders. In this case, you might want all six buttons to use the same subroutine. Here, each button's program might look something like this:

      	on mouseUp
         		orderForm
      	end mouseUp

In this handler, the phrase
on mouseUp
tells the button to grab the
mouseUp
system message that shoots through the HyperCard program when a user lets go of his mouse button, just after the user has clicked on the screen button with his pointer.

on mouseUp
makes the button object stand up and pay attention when the
mouseUp
message comes its way. The button then looks at whatever instructions you've listed inside the handler-- here it's just
orderForm
. The button object sees
orderForm
, but doesn't understand it, since you've put the handler for
orderForm
somewhere else in the stack. So the button just passes the message
orderForm
on up the chain of command in the stack, to see if anybody else knows what you're talking about.

The message
orderForm
next travels to the script of the card the button lives on. The card object checks its its own script to see if you put something there about
orderForm
, and finding nothing, just passes the message on again.

orderForm
is next passed to the card's background, which also knows nothing about it, and so passes it on up to the stack object.

Here, finally, the stack object recognizes the command, as you've placed the handler below in its program listing (please excuse the formatting below; it's slightly inaccurate):

      	on orderForm
         		global howManyTimes
         		add 1 to howManyTimes
         		put howManyTimes into cd fld "Order Form Check Out" of cd "Surveillance"
         		go to cd "Form"
      	end orderForm

The
on orderForm
and
end orderForm
expressions tell HyperCard where your instructions for this particular message begin and end.

global howManyTimes
tells the stack you want to use the global variable
howManyTimes
here.

add 1 to howManyTimes
adds one to the number already in the global variable.

put howManyTimes into cd fld "Order Form Check Out" of cd "Surveillance"
tells the stack to put the number that's inside the global variable
howManyTimes
into a text field named
Order Form Check Out
, that exists on the card you've named
Surveillance
, hidden somewhere in your stack.

go to cd "Form"
tells the stack to move the user from the present card where he clicked the button to the order form card, which is named
Form
.

In the
orderForm
handler I did several things:

I updated a global variable to keep track of how many times the user looked at the order form. If I can ever get my hands on this information later I can analyze it statistically, along with other data, to find out things like the percentage of users who looked at the order form, that actually ordered something-- you know, customer surveys sort of, except subtle. It's kind of like a telephone survey except without the inconvenience of a ringing phone to get the information-- it all happens automatically and transparently. This tidbit provides a real world example of the greater marketing power and consumer research potential available in interactive media over the old forms.
But back to the
orderForm
handler....I told the stack to remember the global variable by storing it in a text field on a hidden data card I have in my stack. This is necessary because otherwise my stack will forget the updated number when the user quits out of the stack, and start from scratch when the stack is reopened. The only permanent way to get a stack to remember things is to either install a fixed value inside the stack's scripts somewhere, or store values inside text fields inside the stack-- global variables have to be reset each time the stack is opened, and are RAM based, while the contents of text fields are saved to disk as part of the stack file.

HyperCard now returns to the original buttons
mouseUp
handler, to perform any other tasks that might be listed after
orderForm
. In this case however, there are no other tasks-- just the phrase
end mouseUp.


end mouseUp
informs the button that this is the end of its instructions for this particular event, and so HyperCard starts twiddling its thumbs by pulsing with
idle
messages, waiting for something to happen...


Text Processing in Scripts


Dealing with user cursoring and typing, scrolling, justification, fonts, styles, re-formatting, and word wrap in the text fields inside your stack

Surprise! You don't have to deal with these things at all in most cases, because HyperCard will do it for you automatically! Anyone who's been forced to program text processing from scratch in C or other languages will really appreciate the way you can just plunk down a HyperCard text field and expect it to pretty much take care of itself most of the time. Of course, sooner or later you'll get into fairly advanced stack building, where playing with the text fields may become necessary after all-- but you'll be starting your work from a much better position than most programmers throughout history enjoyed in this area.


Translating text into HyperTalk strings

Literal strings . If you place a quote before and after a string of alphanumeric characters, HyperCard will see the string not as a programming instruction, but as a linear list of characters meant to be held in storage, displayed in an object, compared to another string, or installed somewhere in the stack.
The quoted phrase "The ship sank with all hands." is an example of the material HyperCard will treat in the manner just described.

If you want HyperCard to do more with a bit of text than what's discussed above, such as make dynamic changes in a text string based on current circumstances, you have to get more complicated.

In those cases the literal strings described before will be only a small part of the text processing you and HyperCard will be working on together.

Displaying quote marks in text fields. Let's say you wanted to display quotes in a text field, both before and after a text string you place there. Using the script statement...

 put "The ship sank with all hands" into cd fld ID 4 


...will NOT include quotes in what's placed inside the field. In fact, it won't put any quotes at all into the field. It'll only place the words between the quotes into the field.
To add visible quotes to the text, you'd have to tell HyperCard to place something like
quote&"The ship sank with all hands."&quote
into the field. You see? You have to actually spell the word q-u-o-t-e for HyperCard to understand you want the punctuation mark added to the sentence. Why is it so complicated a process to add a simple quote? Well, to answer that question I'd have to get into all the trade offs involved in designing any programming language, and especially those involved in creating HyperCard's own scripting language. Suffice it to say that HyperCard's developers tried their best to make everything as easy and straightforward as possible for scripters-- but at some point you always get backed into a corner, and have to nail down a compromise to pay for everything else. To my mind this quote thing is one of the compromises made by the developers. Actually, considering the power and ease of use the developers bought with the handful of compromises they made, I believe they did a great job.

The ampersand symbol; HyperCard Glue for Strings. Anyway, now we come to the ampersand (&) symbol. The ampersand is like smart glue in HyperCard. You use it to tie together text strings and their modifiers so that HyperCard will understand what you're talking about. In the example above I used ampersands to tie together my literal text string and the quote marks I wanted to appear to either side of the string. If you place two ampersands side-by-side (&&), they not only glue together any string and modifier you put into a statement, but insert a space character smack between the two string pieces so joined, too.

Inserting changing values into a string. Sometimes you'll want to display a message to your user showing a changeable value. Maybe you want to keep them up-to-date on some lengthy process they've initiated in your stack. You might wish to display something to the effect of "14 items remaining to be processed". How would you make a single text string allow a regular update of the value here expressed as "14"?
Well, let's say "14" is a momentary value contained in a variable named
whatsLeft
. If
whatsLeft
can be depended upon to always hold the value you want the user to see in the string, you can use ampersand glue to attach it to your string, like so:

           whatsLeft&&"items remaining to be processed."

Place the statement displaying this string into the same repeat loop performing your process, and it will update the value displayed regularly onscreen-- as long as the variable
whatsLeft
is updated in the script too, somewhere.

How hard is it to display more than one changing value in a text string? Not hard at all, with ampersand glue. Let's say we wanted to display a bit more information than the previous example did. Maybe say "14 items of a total of 28" remaining to be processed.

The way we'd build the string is to begin by breaking the literal part into two, inserting the appropriate extra variable, and then gluing it all back again with ampersands.

If the variable containing "28" is named
total
, the end result of our rearranging would look like so:

   whatsLeft&&"items of a total of"&&total&&"remaining to be processed."

You may have noticed that we actually have a variable here with the same spelling as part of the literal text string it follows. Those of you with programming experience might ask if this could cause a problem for HyperCard. The answer is no. The "total" inside the literal text string is regarded as completely different from the variable named
total
, because of the placing of the quotation marks in the expression.

Storing, changing, and deleting text

Characters, chunks, words, and lines. Characters are individual letters or numbers in a text field or variable/container. "2" and "e" are considered single characters or chars by HyperCard.

Words, to HyperCard, are pretty much the same thing they are to you and me-- groups of characters separated from others by spaces or punctuation marks. However, there is one difference between HyperCard's perceptions and ours when it comes to words: HyperCard will accept things like "gffpt" as a word, so long as it meets the previous criteria, where you and I wouldn't.
When might you use the term
words
in your scripts? Well you might have HyperCard count the number of words in a text field for you, like so:

put the number of words in cd fld ID 3 into totalWrds

Chunks are ranges of characters, like
char 23 to 45 of cd fld ID 5
(translated: the 23rd through 45th characters in text field ID 5) which can include any or all of the other types named here. The term
chunk
is usually used in scripts as part of functions like
the foundChunk,
which provides you with information about the location of text inside a text field, after you've initiated a search for same. Things like
the foundChunk
come in handy when you want do custom search and replace operations in a field.



Lines are usually words, phrases, or numbers separated by a return, which will tend to arrange them vertically in a container like a text field.

Just one thing
lines
are useful for are creating clickable vertical lists in scrolling text fields, like those seen in the Preferences screen of Pathfinder HC v1.0. Because HyperCard will return to your scripts information about which
line
was clicked on, via
the clickLine,
allowing you to hilite that line, and carry out commands based on what the line displays onscreen to the user.
the clickChunk 
and
 the clickText functions,
and grouped text properties all are related to this.



Specifying a single character in a container .

put char 5 of "red hair" into shoThis 


...puts the character "h"
 
into the variable "shoThis".

Deleting a single character in a container.

  put "red hair" into shoThis
  delete char 5 of shoThis


...puts the words "red hair" into the variable "shoThis", then deletes the "h" inside the variable, leaving only "red air" remaining.

Specifying a single word in a container .

  put word 2 of "flaming red hair" into shoThis


...puts the word "red" into the variable "shoThis".

Deleting a single word in a container.

  put "flaming red hair" into shoThis
  delete word 2 of shoThis



...puts the words "flaming red hair" into the variable "shoThis", then deletes the word "red" inside the variable, leaving only "flaming hair" remaining.

Designating a range of text

Elsewhere in this article I talk about giving HyperCard an address for a text field-- informing HyperCard about whether it exists on a card or background, and which one.

When working with text, you not only often require similar address information, but must add still more-- such as the address of a particular character within the text of a field or variable.

word 1 to 3 of myStory
identifies to HyperCard the first three words contained in the variable
myStory
.

line 3 of cd fld ID 14 of cd ID 342677
identifies to HyperCard the text between the second and third return characters in card field ID 14, which is located on cd ID 342677.


HyperCard functions


Some folks will say that functions are the real subroutines in HyperCard, because they act a little more like the BASIC gosub command lots of folks are used to, often returning a new value to the handler which called upon them.

HyperCard functions can use both the global and local variables discussed before, as well as store and retrieve data in text fields. But functions also make use of a different form of variable, called parameters, to make them a bit more flexible than the standard handler in a script.

Parameter variables



Between local variables which you want forgotten immediately after usage, and global variables which you want to remember always, are parameter values.

By parameter values I mean values passed from one handler to another, or from a handler to an function, or other routine, and maybe back again.

Unlike global variables, you can declare parameters 'on-the-fly' in a script, without any prior warning to HyperCard, much as you can local variables. But there are a couple of rules you must subscribe to in their usage:

One, you must list any parameters used in your handler or function upfront, in the
on [handler name]
header, or very first line of a function script. For example, a
doMenu
handler often uses a parameter containing the menu option a user has chosen, by its header being written something like
on doMenu command
, where
command
may then be used within the body of the handler script as a container holding the specific option a user indicated with their pointer. The name you use for the parameter doesnt matter much-- HyperCard will accept just about whatever you feel like using.

Two, in functions that you want to return a value to the handler which called them, you must instruct HyperCard as to this desire. For example, the last statement before the closing line of a function might say
return aardvark,
and whatever value had been placed in
aardvark
within the function will be made available to the handler which called upon the function in the first place. An example would be the passing of a simple "true" or "false" value from a function back to the handler which called it, like below:

In a
closeStack
handler I have the statement...

            if FLUXDiff() then

...which calls upon the function below...

            function FLUXDiff
            	return not(there is a card "Comic Relief Init")
            end FLUXDiff 

In this case the call upon the function in the
closeStack
handler will cause HyperCard to read
FLUXDiff()
as the function's returned result rather than the word
FLUXDiff()
. As the function returns a true or false value only, one of those values is what HyperCard sees when it looks at the function call in the
closeStack
script.

Here,
FLUXDiff()
returns "true" if there's NOT a card named "Comic Relief Init" in the current stack. And returns "false" if there IS such a card. This may seem confusing, and I must admit I myself have to think about it a little each time I examine it, to fully understand it. It's the Boolean
not
that's included in the function statement, that throws us. If you don't know what "Boolean" means, don't fret; it's just a label used in mathematics and programming for the use of logical ideas like "and, not", and "or",which all come in handy when you're talking to computers, since they readily understand such things. For example, in the statement
if tryVegas = 10 and tryLA = 12 then go next cd,
the computer will understand you only want to go to the next card if BOTH variables contain the stated values; which here means both variables must contain the correct value for anything to happen. Change the statement by replacing
and
with
or,
and the computer will take you to the next card if either of the variables contain the desired value. As for the Boolean
not,
an example was given previously in the explanation of the
FLUXDiff()
function.

But getting back to passing parameters:
What if you need to pass something more substantial than "true" or "false" from a function to a handler? What then?

Essentially you do the same thing, only substituting a variable name for the expression we used above of
not(there is a card "Comic Relief Init").


Heres an example:

Let's say I'm going to use a button script to change the script of another object. In the button script I have the line...

   put scripObject() into bullsEye


...and so somewhere else I must have a function
scripObject
, which performs some work concerning the variable
bullsEye
, returning the results of that work to the commanding button script. Near the end of the
scripObject
function I say...

           	return interMediateValue

...which contains the result of the functions calculations..


...and so when HyperCard sees the line...

           	put scripObject() into bullsEye

... it sees the returned value of
interMediateValue
when it looks at the word
scripObject()
. And thereby places this value into the variable
bullsEye
, there inside the handler which called upon the function in the first place.




Escapes and aborts; extricating yourself from messy situations and avoiding unnecessary scripting


Often inside a handler you may find yourself figuratively painted into a corner, in that you've reached a circumstance where you'd like the routine to stop, but there's still another apparent 25 script lines following it to be gone through by HyperCard. How can you just say to HyperCard "Never mind the rest of the script if such and such happens"? With an
exit
command. The
exit
command is flexible, allowing a scripter several options: it can be used to escape only a repeat loop inside a handler, but still allow the execution of any remaining commands in that handler; it can also provide escape from the handler altogether, immediately and completely. The first two examples below illustrate those two actions. The third example is an
exit to HyperCard
, and is used when the doo-doo is extra deep; your script is very complex, execution might be inside a handler called by another handler called by another handler, or you've got HyperCard jumping through some loops at the time that seem particularly difficult to get the program to break away from cleanly. Though the
exit to HyperCard
may be the most powerful version of the command, you should be careful where you use it, as it effectively will stop any and all on-going processes in your stack at the time-- and only an
idle
handler or manual user action can start them up again.

      	exit repeat
      	exit [handler name]
      	exit to HyperCard


Warning Signs



When you're first starting out programming in HyperCard, one warning sign that you're getting off track could be excessive complexity and length in your scripts. For often these things will signal that you're laboring under some gross misconceptions in HyperCard syntax, variable usage, program loops, or available commands. If your script begins to get intimidating looking (or starts running noticeably slower), here's some things to check for that might allow you to improve matters:

Are you using several repeat loops when one would do?

Is there a lot of redundant statements in your script? Where you do the same thing many times, with only an ID number or object name changing between statements? If so, you might be able to drastically shorten your script with a simple repeat loop. If the numbers that change are sequential, you can easily let the repeat loop's counter variable stand for them in a single statement. You can use a modified version of the counter value if it's larger or smaller than what you require, by subtracting or adding a constant value to it before inserting it into a statement (Just be careful that your repeating loop still gets the right counter value for its own work!) If you're using names for your objects, or you require random, non-sequential ID numbers, you can put these into a comma-delimited container, or item list, and feed them to the repeating statement using the loop counter as an index to the values.

Many times you can replace an entire section of code in a script with a single handler name, and then install that script under that new handler name elsewhere in your stack. In some cases this maneuver will allow you to substitute the new handler name for the identical script at many places in your original listing, making the whole thing much easier to examine and understand-- not to mention much more compact on disk.

Making use of scripts found in other stacks



Both novice and expert scripters should do this on a pretty regular basis. Though you must avoid outright plagiarizing of someone else's copyrighted code, this will be an unlikely scenario for most scripters, for the following reasons:

One, rarely will you find a script that does exactly what you want it to, as written. Perhaps the found script performs on a text field what you'd rather do on a button. Maybe your idea requires a lot more functionality than the found script provides, necessitating considerable rewriting and experimentation to make it work. Maybe the found script is far too complex, and you need only a small piece of it. Any of these possibilities, as well as innumerable others, will force you to change a found script so extensively that the best HyperCard experts in the world would have a tough time saying your finished script infringed on the original.

Two, in order to make a found script work with scripts you've already created, it will often be necessary to change all or many of the variables in the found script to match your other code elements. This change alone can make for substantial modifications.

Three, major changes in the repetitive loops of a script will often be in order. You may have to remove nested loops, or add some, in order to get the effects you want. You may have to adjust counters and high end or low end limits on the number of times a loop repeats.

Four, you might want to make a lot of changes simply to make the look of the found script consistent with how you personally do things, in order to avoid later confusion for yourself. For instance, many scripters make variable names stand out in scripts by capitalizing a central letter-- by typing "doThis " rather than "dothis". Or by using "repeat until" rather than "repeat while" or "repeat with"; others may use only two letter handler names like "cs, nm, vc" , and so on, rather than more descriptive identifications.

Five, you'll probably want to add some comments as you work.

Six, many stack authors may welcome your use of their code-- as long as you add substantially to its quality, speed, and/or flexibility-- and make it available to them to continue tweaking themselves....it all adds to the strength of the brighter side of the Force, Luke...


What if you DO find a piece of script that's already "just right"?

In many cases the original author will have stated in his stack that it's OK to use his scripts in this manner, so long as you subscribe to certain conditions, like maybe mentioning his name in your stack's credits or whatever (it's good manners to do this even if they don't specifically request it). Whatever the stated conditions are, be sure to follow them-- otherwise you could end up like those guys "Milli Vinilli", who were revealed to be lip synching their songs, instead of really singing. Nobody wants to become the Milli Vinilli of HyperCard scripting.

So what if the original author's requirements are too stiff? Say, they demand a $1000 licensing fee for you to use their stuff? Or a $10 commission on each stack you sell with their script excerpt included? Ouch!
In this case you have only two choices: bite the bullet and pay them as they demand-- or give it up, and try to replace their script with your own work, or a script available from a more economical source. Of course, if your project is destined to be the next Myst-style CD ROM hit, you can easily afford to pay someone a hefty licensing fee upfront. But few folks will be in that position, and so will want a more balanced arrangement with the author.

Forward to HyperCard Headstart, Part Three


Copyright © 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 by J.R. Mooneyham. All rights reserved.

So who is J.R. Mooneyham, and just what are his qualifications for speculating about the future of government, business, technology, and society?

You can find out by clicking here...(and also send FEEDBACK)


Back to the Table of Contents of the Signposts Timeline

Back to J.R.'s WebFLUX Page (the magazine)

Back to J.R.'s WebWork Page (A hefty catalog of links to almost everything)

Site Map for the WebFLUX and WebWork pages