H O M E

Jonathan Cooper
Manager of Information,
Art Gallery of New South Wales, Sydney, AUSTRALIA

Writing About HyperCard

Target Practice

Originally published in MACinations (Club Mac, Sydney, Australia) August 1994

If you wanted an object, say a button, to respond in a certain way to an event, say a mouse-click (specifically, a mouseUp message), common sense would tell you to write an appropriate handler for that event and put it in the script of that object. E.g.:

 

 Script of card button "Addresses":

on mouseUp
  go to stack "Addresses"
end mouseUp

Clicking on this button will take you to a stack called "Addresses". However, let's say you had a number of card buttons on the one card and each one simply took you to another stack. Then, it would make more sense to have a single handler in the card's script that responded appropriately to a mouse-click on any of these buttons. But how do we know which button (or object) was originally clicked? The answer is the built-in function "the target".

Try this experiment on a 'blank' card: (If one of your first five Home cards still has no buttons on it, you could use that. Otherwise, just create a new, blank stack.)

1. Create a number of card buttons (three will do for now).

2. Give each button exactly the same name as a stack on your hard disk, but leave each script completely empty.

3. Open the card script (command-option-C is the short-cut) and type the following:

on mouseUp
  get the target
  if "card button" is not in it then pass mouseUp
  put the short name of it into stackName
  if there is a stack stackName then go to stack stackName
end mouseUp

4. Click on any button. Assuming you had named it correctly, it will take you to its corresponding stack, even though it has no script of its own. Such is the power of "the target"!

 

Let's look at the handler line by line:

get the target
- ... puts the full name of the object that originally received the mouseUp message into the special variable "it", so we don't have to ask for it again.

if "card button" is not in it then pass mouseUp
- If the target was not a card button, then let the mouseUp message pass.

put the short name of it into stackName
- The short name of "card button "Addresses"" would simply be "Addresses".

if there is a stack stackName then go to stack stackName
- May as well check that there really is a stack with this name. If so, go to it.

Question: What if I wanted to have a card button on the same card that didn't act like this?

Answer: Easy. Just put a mouseUp handler in its script. But make sure there is no "pass mouseUp". Even the script...

on mouseUp
  --
end mouseUp

... would do the trick. Then, of course the button wouldn't do anything! (unless it had a mouseDown handler or a mouseEnter handler or whatever...)

Another application of "the target": Itty bitty fields

   Sometimes, a field has to be very small for some reason, which makes editing difficult. For example, it may only need to contain one word most of the time but occasionally extra text needs to be added (see Fig. 2). In this case, a scrolling field would be impractical.

Two solutions would be to:

a) "toggle" the field between its normal, small size and a larger size and
b) edit the field with a dialog box.

The following handlers, if typed into the card, background or stack script, will give any field without its own script special properties: typing command-E while the insertion point is within the field will toggle the field between two sizes and positions and typing command-D will allow you to edit the field in a dialog box. Additionally, typing command-I will display the "Field Info" dialog box.

on commandKeyDown which
  put the target into targ
  if "field" is not in targ then pass commandKeyDown
  put script of targ into temp
  if which = "E" then
    if number of items in line 1 of temp <> 4 or
    number of items in line 2 of temp <> 4 then pass commandKeyDown
    put line 1 of temp is a rect into cond1
    put line 2 of temp is a rect into cond2
    if not (cond1 and cond2) then pass commandKeyDown
    toggleRect (targ),line 1 of temp,line 2 of temp
  else if which = 1 or which = 2 and "on" is not in temp then
    answer "Set rectangle #" & which && "of" && targ && "to its current" &&
    "rectangle? (" & the rect of targ & ")?" with "Cancel" or "OK"
    if it = "Cancel" then exit to HyperCard
    put the rect of targ into line which of temp
    set script of targ to temp
  else if which = "D" then
    dialogEdit targ
  else if which = "I" then
    put the selectedChunk into selectedChars
    choose field tool
    select targ
    doMenu "Field Info..."
    choose browse tool
    select selectedChars
  else pass commandKeyDown
end commandKeyDown

on toggleRect objectName,rect1,rect2
  put the selectedChunk into selectedChars
  if rect of objectName = rect1
  then set rect of objectName to rect2
  else set rect of objectName to rect1
  select selectedChars
end toggleRect

on dialogEdit objectName
  put the selectedChunk into selectedChars
  if length of value of objectName > 200 then
    answer objectName && "is too long to edit in this way." &&
    "Edit first 200 characters?" with "Cancel" or "OK"
    if it = "Cancel" then exit dialogEdit
    ask objectName with (char 1 to 200 of the value of objectName) & ""
    if it = "" then
      beep
      answer "Delete first 200 characters of" && objectName & "?"
      with "OK" or "Cancel"
      if it = "Cancel" then exit dialogEdit
      do "put it into char 1 to 200 of" && objectName
    else
      if last char of it = "" then delete last char of it
      do "put it into char 1 to 200 of" && objectName
      select selectedChars
    end if
  else
    ask objectName with the value of objectName
    do "put it into" && objectName
    select selectedChars
  end if
end dialogEdit

To make the toggleRect process work, type command-1 into the field when it is set to the smaller rectangle then drag it to its larger rectangle and type command-2 into it. The co-ordinates of these two rectangles will then be stored as the first two lines of the field's script. (This is why the fields should not have their own scripts.)

The dialogEdit process has two drawbacks:

1. There is a limit (set here to 200 characters) to the amount of text that will fit into an "ask" dialog box.
2. Any special formatting will be lost as the edited text gets put back into the field.

However, at least you don't have to worry about other fields "getting in the way", as you do with the toggleRect method.

Notice also how in each process triggered by command-E, -1, -2, -D or -I, the insertion point (or selection) gets restored to its previous position. This is done by putting the selectedChunk (e.g. "char 5 to 15 of bkgnd field "City"") into the variable selectedChars, then when all is finished, selecting selectedChars.

Conclusion

So, the next time you are doing some HyperTalking, remember how valuable "the target" is. A little bit of forward planning can save you from having to type basically the same lines of code over and over again. Also, if you ever have to change something (like applying an "iris open" visual effect before going to another stack in our first example) you can do it in one step instead of, say, ten.

Writing About HyperCard
Top