|
Jonathan
Cooper |
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 |
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.