[comp.sys.mac] HyperCard Linking Routines

keith@apple.UUCP (Keith Rollin) (10/19/87)

[Chuq...Where's comp.sys.mac.hypercard?]

While developing a HyperCard stack to track new 3rd party products, 
I discovered I needed to have a more powerful linking facility than 
the one provided by Hypercard. My idea was to create circular links 
among all similar products (e.g. all Mac II monitors). However, under 
the old system, this was very difficult. Not only was the actual 
linking of new objects into an existing circle awkward, but deleting 
items was virtually impossible.

Imagine a stack linked like the one below. This linking system is 
similar to the one used in the Clip Art stack on the Home card:

                          +--------+
                   +------| card 4 |<-------+
                   |      +--------+        |
                   v                        |
              +--------+              +--------+
              | card 1 |------------->| card 3 |
              +--------+              +--------+

                          +--------+
                          | card 2 |
                          +--------+

Card #2 is a newly created card that you want to insert into this 
chain somehow. Under the old system, you would have to break the 
link between cards 1 and 3, and then create 2 new links between 1->2 
and 2->3. This is awkward and time consuming, especially with 
having to toggle between the button tool and browse tool all the 
time.

To speed up the process, I wrote the following button and 
background scripts. In addition to making linking a one step process, 
it adds a facility for resolving links when a card is deleted.

I am submitting these routines for 2 reasons: 

1) They are handy, and will hopefully help you in your own 
endeavors, and 

2) They could do with a bit of help themselves. For example, I have to 
keep a list of backward links to facilitate deleting cards. I do this by 
adding a comment line at line 2 of my button script that holds the 
card ID of the card that points to it. However, my routines don't 
handle circular lists that do NOT have this additional comment line. 
Therefore, I am posting these routines so that the collective genius of 
this group can add to their efficiency and functionality.

(Note: in these listings, I have substituted "++" for the funny "option-
return" character).

In order to implement these scripts in my stack, I created 2 
background buttons. The first one is called "Similar Products". This 
button contains the script that moves us from one card to the next 
one in the chain. It looks something like this:


on MouseUp
  -- Linked from card id <####>
  go to card id <####>
end MouseUP


 This script is created and modified by the second button, called 
"Link To". Here is its script:


on mouseUp  -- "Link to" button was hit
  global LinkFromCard
  Show field "Link To"
  Show background button "Move to card to Link"
  Show background button "to and press:"
  Show background button "OK"
  Show background button "or"
  Show background button "Cancel"
  put the ID of this card into LinkFromCard
end mouseUp


Clicking on this button makes visible a background field and 2 
background buttons -- well, actually 5. I use buttons to contain text 
that I want carried from card to card. If I put the text in a 
background field, it will not be carried. 

The "window" looks like this, and appears on top of everything else 
(like the normal Link window):

            +--------------------------------------+
            |  Move to card to link to and press:  |
            |  +----------+        +------------+  |
            |  |    OK    |   or   |   Cancel   |  |
            |  +----------+        +------------+  |
            +--------------------------------------+

In addition to making this window visible, the button also stores the 
ID of the new card in the global variable LinkFromCard.

The Cancel button of the "link window" is straightforward; it simply 
hides all the buttons and the field:


on mouseUp  -- Cancel button was hit
  hide background button "OK"
  hide background button "or"
  hide background button "Cancel"
  hide background button "Move to card to Link"
  hide background button "to and press:"
  hide field "Link To"
end mouseUp


The OK button is where the action is. After pressing the "Link to" 
button to show the "link window", we can move anywhere within the 
circular link (using any means, such as arrows or command-F). 
Pressing the OK button will form the new links, using the following 
script:


on mouseUp  -- OK button was hit
  Global LinkFromCard
  -- check to see that we aren't linking to ourselves
  if LinkFromCard is the ID of this card then
    answer "Sorry, I won't link this card to itself." with "Cancel"
  else
    put word 3 of LinkFromCard into LinkID -- Actual card number
    Get script of button "Similar Products"
    if it is not empty then  -- insert into cycle
      -- move the link script from this card (1) to our new card (2)
      -- and change the backlink
      Get script of button "Similar Products"
      put the ID of this card into word 4 to 6 of line 2 of it
      Set script of button "Similar Products" of card id LinkID to it
      Put word 5 of line 3 of it into TempID  -- for later
      --
      -- Create forelink from this card (1) to new card (2)
      Get script of button "Similar Products"
      put LinkID into word 5 of line 3 of it
      Set script of button "Similar Products" to it
      --
      -- Modify backlink of card (3) to new card (2)
      Get the script of button "Similar Products" of card id TempID
      put LinkID into word 6 of line 2 of it
      Set the script of button "Similar Products" of ++
      card id TempID to it
    else  -- link the two together (no previous link in this card)
      -----------
      Set script of button "Similar Products" to ++
      "on mouseUp" & RETURN & ++
      "-- Linked from " & LinkFromCard & RETURN & ++
      "go to " & LinkFromCard & RETURN & ++
      "end mouseUp" & RETURN
      -----------
      Set script of button "Similar Products" of card id LinkID to ++
      "on mouseUp" & RETURN & ++
      "-- Linked from " & the id of this card & RETURN & ++
      "go to " & ID of this card & RETURN & ++
      "end mouseUp" & RETURN
      -----------
    end if
  end if
  hide background button "OK"
  hide background button "or"
  hide background button "Cancel"
  hide background button "Move to card to Link"
  hide background button "to and press:"
  hide field "Link To"
end mouseUp


Got it? Fine. For those those that missed it, here's what happened:

1) First a check is made to see if we are trying to the link the new 
card (referred to in the script as card #2) to itself. 

2) If so, then we say "Sorry, I won't link this card to itself", hide the 
buttons, and exit. 

3) If not, we check if we are linking into an existing circular link. 

4) If so, we break the chain, modify card #1 to point to card #2, point 
the backlink of card #3 to card #2, and insert a script into card #2 
that points forward to card #3 and backwards to card #1. 

5) If we are not inserting the new card into a current link, then we 
are essentially creating a new circular link, and the appropriate 
scripts are inserted. 

6) After all is said and done, the buttons are hidden.

All that remains is to resolve links when a card is deleted. The 
following background script accomplishes that:


on DeleteCard  -- in background script
  -- Resolve links in "Similar Products" button
  get the script of button "Similar Products"
  put word 6 of line 2 of it into BackLink
  put word 5 of line 3 of it into ForeLink
  if BackLink is not empty then
    if BackLink <> ForeLink then
      Get script of button "Similar Products" of card id ForeLink
      Put BackLink into word 6 of line 2 of it
      Set script of button "Similar Products" of card id ForeLink to it
      Get script of button "Similar Products" of card id BackLink
      Put ForeLink into word 5 of line 3 of it
      Set script of button "Similar Products" of card id BackLink to it
    else
      Set script of button "Similar Products" of card id BackLink ++
      to empty
    end if
  end if
end DeleteCard


This script first checks to see if this card's linking button has a script. 
If so, it identifies the cards on either side of the "to-be-nuked" card, 
patches their scripts, and exits to HyperCard, which will then delete 
the card.

-----

Keith Rollin
Technical Communications
Sales Tech Support
-- 

Keith Rollin                                               amdahl\
Sales Technical Support                               pyramid!sun !apple!keith
Apple Computer                                             decwrl/

Disclaimer: I read this board for fun, not profit. Anything I say is from the
            result of reading magazines, hacking, and soaking my head in acid.