What I Did With the !Locate Command

On My Summer Vacation

by Tom Nally

Newsletter Home

Card No. 1

Okay, so I didn't write LBCard on my Summer vacation! I wrote it during February, 2003. But since this is the last article in the newsletter, I needed a "hook" to get you to click to this article!

So sue me.

The Predecessors of LBCard

It wasn't too long ago that I owned one of the early versions of the black-and-white MacIntosh Computers, a Mac Plus. When I acquired this cute little computing machine, it didn't have [HyperCard] on the hard drive, but I was soon able buy the HyperCard 800K installation disks from serious Mac users who were upgrading to modern MacIntosh systems.

I was interested in HyperCard because it was billed as an incredibly easy application development environment, simple and engaging for the novices, and sophisticated enough for the [professionals].

HyperCard allows users to develop and deploy applications using what might be called the "card metaphor". That is, controls (called "objects" in HyperCard) reside on identically-sized virtual "cards" that are assembled in a "stack". A stack is the generic name for a HyperCard-built application. Users interact with the application by navigating through the cards in the stack.

Over the years, Apple stopped developing HyperCard because it no longer fit in with their business strategy. (Though MacOS still comes with a HyperCard player, and one can still purchase HyperCard 2.4 through the Apple Store.)

Other software companies, seeing the commercial potential of the intensely loyal HyperCard community, began producing competitor products to HyperCard in the late 1980's. Some of these products, like [SuperCard], are Mac-only development environments. Others, like [MetaCard] and [Runtime Revolution], are cross-platform. There are other card-type products occupying the shareware niche that are Windows-only. Among the latter are [Multimedia Builder] and [Neobook]. Still other products, like [Macromedia Director], have become successful by adopting and extending (and sometimes recharacterizing) the card metaphor. In order to avoid testing your patience any further, suffice it to say that a few others have come and gone.

What LBCard Is, and Ain't

Card No. 2

LBCard is an attempt to emulate the appearance and behavior of a HyperCard stack as developed and made ready for the user. LBCard is a 10-card stack, featuring navigation controls on the left, and fun stuff on the right.

The navigation controls include the ListBox, and the four buttons below the ListBox: First, Prev, Next and Last. These navigation controls reside on all cards. This attribute puts them in a category called "background controls", which will be discussed below. The controls on the right are "card controls", meaning that they reside on a single card.

Understand that LBCard is a "stack" in the HyperCard sense of the term, or at least an attempt to emulate a stack. LBCard is not an IDE for developing a stack. That would be a much more ambitious project for which there are no current plans.

Using !Locate to Achieve the Card Effect

Card No. 5

On the first card of the stack, if you push the Next button this will bring the second card to the top of the stack. Both cards are pictured upward and on the right. Notice that the left-hand sides of the cards are identical, while the right-hand sides of the cards are different. Specifically, the large bitmap button on the first card has been shifted somewhere off window, while the large StaticText of the second card has made an appearance on the window. Because the window size remains the same while the content of the window changes, one might characterize this as flipping to a new card in the stack.

This effect is achieved by using LB's !Locate command. The purpose of the !Locate command is to change the position and/or the size of a control on the control's parent window. If we were to use the !Locate command for a Button and a RadioButton, the code might looks something like this:

Print  #main.Button01,  "!locate 245  180  150  25"
Print  #main.Radio01,   "locate 435  215  129  25"
Print  #main, "refresh"

Card No. 6

If the !Locate command is used to move an entire group of controls off window, and used again to move a new group of controls on window, this will produce the effect of flipping to new cards in a stack. Indeed, this is the procedure used in LBCard.

In the code above, note that a "refresh" command must be sent to the window after the !Locate commands are issued.

Also note that the syntax for the !Locate command is slightly different for the RadioButton compared to the normal Button. When used with a normal Button, the !Locate command is preceeded by an exclamation point. When used with the RadioButton control, no exclamation point preceeds Locate.

There is logic behind this. Some controls (Buttons, TextBoxes, StaticText) can have their label or contents altered by the Print command. For these controls, the !Locate command must be preceeded by the exclamation point so that Liberty BASIC will know that the developer is not just trying to alter the label of the control. Consult Liberty BASIC Help to find out which controls require exclamation points with !Locate, and which do not.

An exception to the usability of the !Locate command should be noted here: an LB GroupBox control does not respond to the !Locate command. Instead, developers must use the the MoveWindow API function as described in the Liberty BASIC Help System.

Background Controls and Window Controls

Card No. 7

As mentioned above, some of the controls in LBCard will reside on each and every card. Drawing from the language of HyperCard, these will be referred to as "background controls". The persistent character of these controls as one browses through a stack gives one the impression that they reside on the background of the stack, rather than on any particular card. Hence the name. Background controls are easy to implement: one merely avoids using the !Locate command to reposition them off the window! Any Liberty BASIC control can be used as a background control.

Controls which reside on a single card may be called "card controls". As discussed in the section above, we create the sense that these controls are attached to a card by using the !Locate command to move them on and off the window.

Putting a Card Application Together

Card No. 8

What coding components are required to create a card application in Liberty BASIC?

First, the developer has to create controls for each card. I used Alyce Watson's [Liberty Basic Workshop] to create the 10 cards for LBCard. Using LBW's GUI Builder, I created a "template" card. The template card contained the background controls on the left side of the card, while the right side of the card remained empty for the card controls. I kept reloading the template card each time I wanted to build a new card.

When I created a new group of card controls, I would give each control in that group the same 3-character prefix. This prefix would identify those controls as belonging to a particular card. Look at the code shown below. Note that the two controls for Card 02 have the prefix "c02" in the control name, while the two controls for Card 03 have the prefix "c03" in the control name.

'''''''c02 Controls'''''''''
GoSub [Assign.c02.StaticText]
Statictext  #main.c02StaticID, "002", 2000, 325, 25, 20
Statictext  #main.c02Static01, c02Static01$, 2000, 50, 345, 260

'''''''c03 Controls'''''''''
GoSub [Assign.c03.StaticText]
Statictext  #main.c03StaticID, "003", 2000, 325, 25, 20
Statictext  #main.c03Static01, c03Static01$, 2000, 50, 345, 260

Note in the code above that all controls have an initial x-value of 2000. This effectively locates all of these controls off window. This is how it must be for these controls. Since cards 02 and 03 are not at the top of the stack when the window opens, all card 02 and 03 controls must initially reside off window.

Card No. 9

The developer must also have a way of tracking the card currently at the top of the stack, as well as a way of identifying the next card to come to the top of the stack as the user browses the stack. I use the variables "CurrentCard" and "NextCard". As a user clicks a button to move a new card to the top of the stack, all of the controls associated with "CurrentCard" must be relocated off window. Then, all the controls associated with "NextCard" must be relocated to the window. After the relocation is done and the "refresh" command is issued, then the value of "CurrentCard" takes on the value of "NextCard", and the program waits for the next navigation command from the user.

The card application developer must also have subroutines of some sort to perform the actual work of moving groups of controls on and off the windows. To move card 09 controls off window, I used the following subroutine,

    Print  #main.c09StaticID, "!locate 2000  325  25   20"
    Print  #main.c09BB01,     "locate  2000  60   373  250"
    Print  #main, "refresh"

while I used this one to move card 09 controls back on window:

    Print  #main.c09StaticID, "!locate 590  325  25   20"
    Print  #main.c09BB01,     "locate  240  60   373  250"
    Print  #main, "refresh"

Through clever use of variables, one could actually use the same subroutine to move groups of controls both on and off the window. That seemed harder to me, however, and I chose not to venture down that road.

Understand also that card 09 only has two card controls, so the code shown only needs to relocate two controls. Card 06, on the other hand, has forty-one controls: 20 BitMap buttons, and 21 StaticText. Understandably, the two subroutines needed to move those controls are huge!

What Is the Potential of the Card Metaphor With LB?

Card No. 10

There is no doubt that applications using the card metaphor provide the end user with a simple and fun way to interact with all of the information that an application may provide. In the LBCard demo, for example, no instructions are needed. The end user will naturally start clicking away, and observe how the navigation controls allow him to browse all of the cards in the stack.

Though simple for the end user, the construction of this card application was very tedious. Each new card required no less than five independent steps:

  1. Laying out the card controls with the GUI builder and the template;
  2. Copying the control definitions into the LBCard code, and giving them initial x-values which will locate them off window;
  3. Building the subroutine to move the controls, as a group, on window;
  4. Building the subroutine to move the controls, as a group, off window; and
  5. Updating the code of each button or other control which enables card navigation.

So, does the card metaphor provide so much value to the user that it's worth the burden that must be born by the developer? That can only be answered on an application-by-application basis. Certainly, a five-card application would be pretty easy to construct. However, a one-hundred-card application would probably be too much for the developer to endure.

A tool or two, specifically for the creation of LB card applications, would certainly make the card metaphor a more attractive option. I'm not envisioning a whole new IDE necessarily. LBW's GUI Builder and Freeform would remain essential tools in the construction of a card application.

What I'm thinking about is something that might be called an "intermediate processor". This tool would take the card control definitions output by GUI Builder, for example, and create the subroutines for moving the controls on and off window.

Valuable, yes, but a project for another day.

NewsLetter TOC

Newsletter Home



OS Editor

LBW Review

Fast Data



Begin Prog II