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.