.KEYWORD controls
.FLYINGHEAD PROGRAMMING POWER
.TITLE Programming controls in PalmOS
.DEPT
.SUMMARY In programmer-speak, "controls" are the doodads you use to interact with the Palm device. A button is a control. So is a checkbox. But if you’re a programmer building some new nifty-neato Palm application, how do you control the controls? In the latest installment of his highly-regarded Programming Power column, Programming Technology Editor Alan Jay Weiner shows you how to become your very own control freak.
.AUTHOR Alan Jay Weiner
We looked at resources in June, and started looking at forms and controls. Last month, I provided several utility routines for working with controls. This month, let’s take a look at several different types of controls–what we can do with them, and how they work.
.H1 What are controls?
Just to clarify what we’re talking about, what are controls? They’re the user-interface elements with which we interact–they’re the buttons we push, the pull-down lists, check boxes, and so forth. Officially, the PalmOS documentation defines control objects as buttons, pop-up trigger, selector trigger, repeat controls, pushbuttons, and check boxes.
Some of the controls are actually the "triggers" for other user interface (UI) objects. For example, the popup trigger tells a list to display itself on the screen. Pop-up lists have two controls: the trigger and the list itself. More on that in a bit.
You’ve already used these controls; they’re used on the forms in the built-in applications and third-party programs. So you’re familiar with using them. Let’s take a look at how to work with them in our programs.
.H1 How do the controls work?
When we build a form and place various controls on it, the program contains the parameters we specify; the position of each control, its height and width, and so forth. When the form is used, the operating system keeps track of each control using a special data structure. As things happen which change the control, those changes are reflected within that data structure and on the screen.
Most of the time, users cause these changes by tapping on the screen–pressing a button or selecting something. Other times, some other event causes a change (for example, the tap on the pop-up trigger changing the pop-up list status so it will appear on the screen). Initially, only the trigger is displayed; the actual list is "unusable" so it won’t show up. Once the user taps the trigger, the list changes to usable and is displayed.
Since PalmOS knows about the standard controls, most of the events related to these controls are handled by the operating system. When the user presses a button, the application ignores the pen-down and pen-up events and just lets PalmOS do the proper "pressing on button" actions. Our event loop sees these events, so if we wanted to intercept them for some special reason we can. But normally, we just ignore them. They ripple their way through the event handlers and finally the default form handler (within the OS) does what it should to make the control work properly. The button handler inverts the button when it’s pressed, and returns it to normal when it’s released.
.H1 How does the OS keep track of controls?
Listing A (at http://www.component-net.com/pp-extras/control1.html) shows a section of the include file CONTROL.H. This is the structure the OS uses to keep track of the controls.
This structure shows the general capabilities of the controls, and shows the common functionality between the controls. There’s little difference between a checkbox and a button for example; visually, they do a bit different when they’re tapped, but the structure defining them is nearly the same.
Let’s look at the pieces of the ControlType structure.
The first element, id, is the ID number assigned by you when you design the form, either in Constructor or PilRC’s script.
The RectangleType structure, bounds, contains an upper-left corner coordinate (0,0 is the top left) and a width and height (160, 160 would be the full screen). We’ll deal with RectangleTypes a lot; they show up in lots of APIs. It’s used here to set the position and size of the control.
The CharPtr, text, points to the text label for the control.
The ControlAttrType, attr, contains the control’s attributes, whether the control is usable or not, enabled or not, etc.
The ControlAttrStyle, style, says what type of control it is, a button, checkbox, etc.
FontID specifies which font to use to draw the control’s text label.
Finally, group contains a group id number if that particular control is part of a group. You might have two buttons to select "Fahrenheit" or "Celsius" in an application. By making the two pushbuttons a group the OS’s pushbutton-handling routines should know to only allow one button to be on at a time. When you press Fahrenheit, it will turn off Celsius, and vice-versa. Unfortunately, the group indicator appears to be useless; the program must turn off other buttons itself if it wants to enforce the "only one at a time" rule. I haven’t bothered with grouping buttons. When I wish to do such things, I just do it by knowing the range of the control IDs.
Actually, having the application do this is more flexible. You might want to allow multiple selections in a pushbutton bar, or only allow certain combinations.
When an application manipulates a control, changing the text on a button for example, it uses one of the PalmOS APIs to do so. Looking at last month’s utility routines, the ChangeButtonText routine calls the CtlSetLabel API to change a button’s text. These APIs take a pointer to the ControlType structure so they know which control to change. The ControlPtr data type is defined as a pointer to a ControlType. Because we frequently need to refer to a control by a ControlPtr (pointer to its data structure), it’s easier to use last month’s GetObjectPointer routine; the example programs from Palm define do this. In fact, I took this routine directly from those examples.
.H1 How do we work with controls in our program?
As I mentioned, the OS handles most of the work with the controls. So what do we do when we’re working with the controls? How do we know when they change, or when a user selects them?
Well, that depends on the type of control. For a button, we get a ctlSelectEvent event when the user taps and releases the button. We saw in the "hello world" application how a button works: it’s drawn when the form is drawn, and when the user presses it, the ctlSelectEvent message triggered the application to do some function. Listing B (at http://www.component-net.com/pp-extras/control2.html) shows that section of the form event handler. For the full program, see the May 1998 issue.
Repeating buttons use a similar event, the ctlRepeatEvent. One thing to remember: the ctlRepeatEvent handler needs to return "not handled" so the event will be passed on to the handler within the OS. If you don’t, the button won’t repeat. Normally, the section in the form handler which deals with the control’s selection returns "handled", since it did do something with that event.
The controls generate several other events; we can act on these events if we want to do something special. The ctlEnterEvent indicates that the user has tapped on a control; at this point the pen is still down. The ctlExitEvent indicates the pen was dragged outside of the control. If it’s dragged back into the control, there will be another ctlEnterEvent. These allow activity to occur when a user presses on a control, rather than upon the release.
Sometimes I prefer to let the OS track the control’s settings and then get the value when I close a form. I do this in my application’s preferences screen. The user can select his or her preferences, and rather than acting on each ctlSelectEvent, I wait for the form to exit, and then query the OS for the current state of each control. Naturally, this doesn’t work for buttons. They’re only "set" as long as the user is pressing on them. But it works fine for pushbuttons and checkboxes. It has the added advantage of delaying any real changes until the form exits, so I can implement a Cancel button on the form. This way, when the user presses the Ok button, the exiting-form routine gets the value of each control and remembers whatever information it should. If the user presses Cancel the form just exits without updating getting any control settings or changing any of the application’s information.
.H1 Next month
We’ll keep digging into controls as time goes on, and we’ll get into other UI objects, especially fields; they tend to not work as you’d expect. But I think next month we’ll start playing with some more code. My 3-year-old son’s been clamoring to play with my PalmPilot, so why don’t we write a simple game? Let’s see


