User Interface
 

 < Home   < Developers   < Development Support   < Documentation

5 User Interface


 Table of Contents  |  < Previous  |  Next >  |  Index
   
   

Title -
Palm OS® Programmer's Companion
vol. I

5 User Interface

Palm OS Resource Summary

Drawing on the Palm OS Device

The Draw State

Drawing Functions

Forms, Windows, and Dialogs

Alert Dialogs

Progress Dialogs

Controls

Buttons

Popup Trigger

Selector Trigger

Repeating Button

Push Buttons

Check Boxes

Sliders and Feedback Sliders

Fields

Menus

Dynamic Menus

Menu Shortcuts

Tables

Table Event

Lists

Categories

Initializing Categories in a Database

Initializing the Category Popup Trigger

Managing a Category Popup List

The Default Application Category

Bitmaps

Versions of Bitmap Support

Drawing a Bitmap

Color Tables and Bitmaps

Labels

Scroll Bars

Custom UI Objects

Dynamic UI

Dynamic User Interface Functions

Color and Grayscale Support

Indexed Versus Direct Color Display

Color Table

UI Color List

Direct Color Functions

Pixel Reading and Writing

Direct Color Bitmaps

Insertion Point

Text

Working With Text As Strings

Fonts in Palm OS 3.0 and Later

Receiving User Input

The Graffiti Manager

The Key Manager

The Pen Manager

The Keyboard Dialog

Application Launcher

Summary of User Interface API

       

This chapter describes the user interface (UI) elements that you can use in your application. To create a user interface element, you create a resource that defines what that element looks like and where it is displayed. You interact with the element programmatically as a UI object. A Palm OS UI object is a C structure that is linked with one or more items on the screen. Note that Palm UI objects are just structures, not the more elaborate objects found in some systems. This is useful because in general a C structure is more compact than these other objects.

This chapter introduces each of the user interface objects. It also describes Palm system managers that aid in working with the user interface. The chapter covers:

Palm OS Resource Summary

Drawing on the Palm OS Device

Forms, Windows, and Dialogs

Controls

Fields

Menus

Tables

Lists

Categories

Bitmaps

Labels

Scroll Bars

Custom UI Objects

Dynamic UI

Color and Grayscale Support

Insertion Point

Text

Receiving User Input

Application Launcher

For guidelines on creating a user interface, see the chapter "Good Design Practices" earlier in this book.

Palm OS Resource Summary

The Palm OS development environment provides a set of resource templates that application developers use to implement the buttons, dialogs, and other UI elements. Table 5.1 maps user interface elements to resources. The ResEdit name is included for developers using that tool. It is not relevant for Palm OS Constructor users.

All resources are discussed in detail in the chapter "Palm OS Resources" of the Palm OS Programmer's API Reference. Specific design recommendations for some of the elements are provided in the chapter "Good Design Practices" in "User Interface Guidelines."

Table 5.1 UI resource summary 
UI Element and Functionality
Example
Resource(s)
Command button-
Execute command.
Button (tBTN)
Push button (also called radio button)-
Select a value

Push button (tPBN)
Hot text entry-
Invoke dialog that changes text of the button.

Selector trigger (tSLT)
Increment arrow-
Increment/decrement values, or scroll.

Button (tBTN) or repeating button (tREP)
Check box-
Toggle on or off.
Checkbox (tCBX)
Popup list-
Choose a setting from a list.
Popup trigger (tPUT)
Popup list (tPUL)
List (tLST)
Menu-
Execute commands not found on screen as buttons and so on.
Menu Bar (MBAR)
Menu (MENU)
Text field-
Display text (single or multiple lines).
Field (tFLD)
Scroll bar-
Use together with fields or tables.

Scroll bar (tSCL)

Drawing on the Palm OS Device

The first Palm OS platform devices have an LCD screen of 160x160 pixels. The built-in LCD controller maps a portion of system memory to the LCD. This controller can support 2 bits/pixel grayscale; however, the Palm OS software only supported 1 bit/pixel monochrome graphics until version 3.0. Two bits/pixel support was added in Palm OS 3.0 and 4 bits/pixel in Palm OS 3.3. Palm OS 3.5 introduces support for both grayscale and color displays, with system palettes of either 1, 2, 4, or 8 bits/pixel. Palm OS 4.0 introduces support for 16 bits/pixel color.(See "Color and Grayscale Support" for more information.) Hardware may still limit the actual displayable depths.

Usually, the form manager handles all necessary drawing and redrawing to the screen when it receives certain events. (In Palm OS, a form is analogous to a window in a desktop application, and a window is an abstract drawing region.) You don't have to explicitly call drawing routines. However, if you're performing animation or if you have any custom user interface objects (known as gadgets), you might need to use the drawing functions provided by the window manager.

The window manager defines a window object and provides functions for drawing to windows. A window is a drawing region that is either onscreen or offscreen. The window's data structure contains a bitmap that contains the actual data displayed in the window. Windows add clipping regions over the top of bitmaps.

The Draw State

The window manager also defines a draw state: pen color, pattern, graphics state, and so on. The draw state is handled differently depending on the operating system version.

On pre-3.5 versions of Palm OS, the system maintains several individual global variables that each track an element of the draw state. If you want to change some aspect of the draw state, you use a WinSet... function (such as WinSetUnderlineMode). Each WinSet... function returns the old value. It's your responsibility to save the old value returned by the function and to restore the variable's value when you are finished by calling the function again. Using such routines can be inconvenient because it means using application stack space to track system state. Further, if a caller forgets to restore the value, the entire look and feel of the device may be altered.

Palm OS 3.5 introduces two improvements to make tracking changes to the draw state easier. First, it groups the drawing-related global variables and treats them as a single unit. This draw state is the Palm OS implementation of a pen. It contains the current transfer (or draw) mode, pattern mode and pattern data for WinFill... routines, and foreground and background colors. It also contains text-related drawing information: the font ID, the font pointer, the underline mode, and the text color. (Palm OS does not currently support other common pen-like concepts such as line width, pen shape, or corner join.) Only one draw state exists in the system.

Second, Palm OS 3.5 can track changes to the draw state by storing states on a stack. Your application no longer needs to use its own stack for pieces of the draw state. Instead, use WinPushDrawState to push a copy of the current draw state on the top of the stack. Then use the existing WinSet... functions to make your changes. When you've finished your drawing and want to restore the draw state, call WinPopDrawState.

The new drawing state stack allows for additional debugging help. If an application exits without popping sufficiently or it pops too much, this is detected and flagged on debug ROMs. When switching applications, the system pops to a default state on application exit, guaranteeing a consistent draw state when a new application is launched.

Drawing Functions

The window manager can draw rectangles, lines, characters, bitmaps, and (starting in version 3.5) pixels. The window manager supports five flavors of most calls:

Table 5.2 Window manager drawing operations 
Mode
Operation
Draw
Render object outline only, using current foreground color and pattern. For a bitmap, draws the bitmap.
Fill
Render object internals only, using current foreground color and pattern.
Erase
Erase object outline and internals to window background color.
Invert
Swap foreground and background colors within region defined by object.
Paint
Supported only in version 3.5 and higher. Render object using all of the current draw state: transfer mode, foreground and background colors, pattern, font, text color, and underline mode.

The drawing functions always draw to the current draw window. This window may be either an onscreen window or an offscreen window. Use WinSetDrawWindow to set the draw window before calling these functions.

Forms, Windows, and Dialogs

A form is the GUI area for each view of your application. For example the Address Book offers an Address List view, Address Edit view, and so on. Each application has to have one form, and most applications have more than one. To actually create the view, you have to add other UI elements to the form; either by dragging them onto the form from the catalog or by providing their ID as the value of some of the form's fields.

Figure 5.1 shows an example of a form. Typical forms are as large as the screen, as shown here. Other forms are modal dialogs, which are shorter than the screen but just as wide.

Figure 5.1 Form

A window defines a drawing region. This region may be on the display or in a memory buffer (an off-screen window). Off-screen windows are useful for saving and restoring regions of the display that are obscured by other UI objects. All forms are windows, but not all windows are forms.

The window object is the portion of the form object that determines how the form's window looks and behaves. A window object contains viewing coordinates of the window and clipping bounds.

When a form is opened, a frmOpenEvent is triggered and the form's ID is stored. A winExitEvent is triggered whenever a form is closed, and a winEnterEvent is triggered whenever a form is drawn.

The following two sections describe special types of forms:

Alert Dialogs

Progress Dialogs

Alert Dialogs

If you want to display an alert dialog (see Figure 5.2) or prompt the user for a response to a question, use the alert manager. The alert manager defines the following functions:

FrmAlert

FrmCustomAlert

Figure 5.2 Alert dialog

Given a resource ID that defines an alert, the alert manager creates and displays a modal dialog box. When the user taps one of the buttons in the dialog, the alert manager disposes of the dialog box and returns to the caller the item number of the button the user tapped.

There are four types of system-defined alerts:

Question

Warning

Notification

Error

The alert type determines which icon is drawn in the alert window and which sound plays when the alert is displayed.

When the alert manager is invoked, it's passed an alert resource (see the chapter "Palm OS Resources" in the Palm OS Programmer's API Reference) that contains the following information:

The rectangle that specifies the size and position of the alert window

The alert type (question, warning, notification, or error)

The null-terminated text string; that is, the message the alert displays

The text labels for one or more buttons

Progress Dialogs

If your application performs a lengthy process, such as data transfer during a communications session, consider displaying a progress dialog to inform the user of the status of the process. The progress manager provides the mechanism to display progress dialogs.

You display a progress dialog by calling PrgStartDialog. Then, as your process progresses, you call PrgUpdateDialog to update the dialog with new information for the user. In your event loop you call PrgHandleEvent to handle the progress dialog update events queued by PrgUpdateDialog. The PrgHandleEvent function makes a callback to a textCallback function that you supply to get the latest progress information.

Note that whatever operation you are doing that is the lengthy process, you do the work inside your normal event loop, not in the callback function. That is, you call EvtGetEvent and do work when you get a nilEvent. Each time you get a nilEvent, do a chunk of work, but be sure to continue to call EvtGetEvent frequently (like every half second), so that pen taps and other events get noticed quickly enough.

The dialog can display a few lines of text that are automatically centered and formatted. You can also specify an icon that identifies the operation in progress. The dialog has one optional button that can be a cancel or an OK button. The type of the button is automatically controlled by the progress manager and depends on the current progress state (no error, error, or user canceled operation).

Progress textCallback Function

When you want to update the progress dialog with new information, you call the function PrgUpdateDialog. To get the current progress information to display in the progress dialog, PrgHandleEvent makes a callback to a function, textCallback, that you supplied in your call to PrgStartDialog.

The system passes the textCallback function one parameter, a pointer to a PrgCallbackData structure. To learn what type of information is passed in this structure, see the chapter "Progress Manager" in the Palm OS Programmer's API Reference.

Your textCallback function should return a Boolean. Return true if the progress dialog should be updated using the values you specified in the PrgCallbackData structure. If you specify false, the dialog is still updated, but with default status messages. (Returning false is not recommended.)

In the textCallback function, you should set the value of the textP buffer to the string you want to display in the progress dialog when it is updated. You can use the value in the stage field to look up a message in a string resource. You also might want to append the text in the message field to your base string. Typically, the message field would contain more dynamic information that depends on a user selection, such as a phone number, device name, or network identifier, etc.

For example, the PrgUpdateDialog function might have been called with a stage of 1 and a messageP parameter value of a phone number string, "555-1212". Based on the stage, you might find the string "Dialing" in a string resource, and append the phone number, to form the final text "Dialing 555-1212" that you place in the text buffer textP.

Keeping the static strings corresponding to various stages in a resource makes it easier to localize your application. More dynamic information can be passed in via the messageP parameter to PrgUpdateDialog.


NOTE: The textCallback function is called only if the parameters passed to PrgUpdateDialog have changed from the last time it was called. If PrgUpdateDialog is called twice with exactly the same parameters, the textCallback function is called only once.

Controls

Control objects allow for user interaction when you add them to the forms in your application. Events in control objects are handled by CtlHandleEvent. There are several types of control objects, which are all described in this section.


NOTE: Palm OS 3.5 and higher support graphical controls for all control types other than check box. Graphical controls behave the same as their non-graphical counterparts, but they display a bitmap instead of a text label. On releases prior to Palm OS 3.5, you can create a graphical control by setting the text label to the empty string and placing the control on top of a bitmap.

Buttons

Buttons (see Figure 5.3) display a text label in a box. The default style for a button is a text string centered within a rounded rectangle. Buttons have rounded corners unless a rectangular frame is specified. A button without a frame inverts a rectangular region when pressed.

When the user taps a button with the pen, the button highlights until the user releases the pen or drags it outside the bounds of the button.

Table 5.3 shows the system events generated when the user interacts with the button and CtlHandleEvent's response to the events.

Figure 5.3 Buttons

Table 5.3 Event flow for buttons 
User Action
System Response
CtlHandleEvent Response
Pen goes down on a button.
penDownEvent with the x and y coordinates stored in EventType.
Adds the ctlEnterEvent to the event queue.


ctlEnterEvent with button's ID number.
Inverts the button's display.
Pen is lifted from button.
penUpEvent with the x and y coordinates stored in EventType.
Adds the ctlSelectEvent to the event queue.
Pen is lifted outside button.
penUpEvent with the x and y coordinates stored in EventType.
Adds the ctlExitEvent to the event queue.

Popup Trigger

A popup trigger (see Figure 5.4) displays a text label and a graphic element (always on the left) that signifies the control initiates a popup list. If the text label changes, the width of the control expands or contracts to the width of the new label plus the graphic element.

Table 5.4 shows the system events generated when the user interacts with the popup trigger and CtlHandleEvent's response to the events. Because popup triggers are used to display list objects, also see the section "Lists" in this chapter.

Figure 5.4 Popup trigger

Table 5.4 Event flow for popup triggers 
User Action
System Response
CtlHandleEvent Response
Pen goes down on the popup trigger.
penDownEvent with the x and y coordinates stored in EventType.
Adds the ctlEnterEvent to the event queue.


ctlEnterEvent with popup trigger's ID number.
Inverts the trigger's display.
Pen is lifted from button.
penUpEvent with the x and y coordinates stored in EventType.
Adds the ctlSelectEvent to the event queue.

ctlSelectEvent with popup trigger's ID number.
Adds a winEnterEvent for the list object's window to the event queue. Control passes to FrmHandleEvent, which displays the list. Control then passes to LstHandleEvent.
Pen is lifted outside button.
penUpEvent with the x and y coordinates stored in EventType.
Adds the ctlExitEvent to the event queue.

Selector Trigger

A selector trigger (see Figure 5.5) displays a text label surrounded by a gray rectangular frame. If the text label changes, the width of the control expands or contracts to the width of the new label.

Table 5.5 shows the system events generated when the user interacts with the selector trigger and CtlHandleEvent's response to the events.

Figure 5.5 Selector trigger

Table 5.5 Event flow for selector triggers 
User Action
System Response
CtlHandleEvent Response
Pen goes down on a selector trigger.
penDownEvent with the x and y coordinates stored in EventType.
Adds the ctlEnterEvent to the event queue.


ctlEnterEvent with selector trigger's ID number.
Inverts the button's display.
Pen is lifted from the selector trigger.
penUpEvent with the x and y coordinates stored in EventType.
Adds the ctlSelectEvent to the event queue.

ctlSelectEvent with selector trigger's ID number.
Adds a frmOpenEvent followed by a winExitEvent to the event queue. Control is passed to the form object.

Repeating Button

A repeat control looks like a button. In contrast to buttons, however, users can repeatedly select repeat controls if they don't lift the pen when the control has been selected. The object is selected repeatedly until the pen is lifted.

Table 5.6 shows the system events generated when the user interacts with the selector trigger and CtlHandleEvent's response to the events.

Table 5.6 Event flow for repeating buttons 
User Action
System Response
CtlHandleEvent Response
Pen goes down on a repeating button.
penDownEvent with the x and y coordinates stored in EventType.
Adds the ctlEnterEvent to the event queue.


ctlEnterEvent with button's ID number.
Adds the ctlRepeatEvent to the event queue.
Pen remains on repeating button.
Tracks the pen for a period of time, then sends another ctlRepeatEvent if the pen is still within the bounds of the control.
Pen is dragged off the repeating button.

No ctlRepeatEvent occurs.
Pen is dragged back onto the button.
See above.
Pen is lifted from button.
penUpEvent with the x and y coordinates stored in EventType.
Adds the ctlExitEvent to the event queue.

Push Buttons

Push buttons (see Figure 5.6) look like buttons, but the frame always has square corners. Touching a push button with the pen inverts the bounds. If the pen is released within the bounds, the button remains inverted.

Table 5.7 shows the system events generated when the user interacts with the push button and CtlHandleEvent's response to the events.

Figure 5.6 Push buttons

.

Table 5.7 Event flow for push buttons 
User Action
System Response
CtlHandleEvent Response
Pen goes down on a push button.
penDownEvent with the x and y coordinates stored in EventType.
Adds the ctlEnterEvent to the event queue.


ctlEnterEvent with push button's ID number.
If push button is grouped and highlighted, no change. If push button is ungrouped and highlighted, it becomes unhighlighted.
Pen is lifted from push button.
penUpEvent with the x and y coordinates stored in EventType.
Adds the ctlSelectEvent to the event queue.

Check Boxes

Check boxes (see Figure 5.7) display a setting, either on (checked) or off (unchecked). Touching a check box with the pen toggles the setting. The check box appears as a square, which contains a check mark if the check box's setting is on. A check box can have a text label attached to it; selecting the label also toggles the check box.

Push buttons and check boxes can be arranged into exclusive groups; one and only one control in a group can be on at a time.

Table 5.8 shows the system events generated when the user interacts with the check box and CtlHandleEvent's response to the events.

Figure 5.7 Check boxes

Table 5.8 Event flow for check boxes 
User Action
Event Generated
CtlHandleEvent Response
Pen goes down on check box.
penDownEvent with the x and y coordinates stored in EventType.
Adds the ctlEnterEvent to the event queue.

ctlEnterEvent with check box's ID number.
Tracks the pen until the user lifts it.
Pen is lifted from check box.
penUpEvent with the x and y coordinates stored in EventType.

If the check box is unchecked, a check appears.

If the check box is already checked and is grouped, there is no change in appearance.

If the check box is already checked and is ungrouped, the check disappears.

Adds the ctlSelectEvent to the event queue.

Pen is lifted outside box.
penUpEvent with the x and y coordinates stored in EventType.
Adds the ctlExitEvent to the event queue.

Sliders and Feedback Sliders

Starting in Palm OS 3.5, slider controls (see Figure 5.8) are supported. Sliders represent a value that falls within a particular range. For example, a slider might represent a value that can be between 0 and 10.

Figure 5.8 Slider

There are four attributes that are unique to slider controls:

The minimum value the slider can represent

The maximum value the slider can represent

The current value

The page jump value, or the amount by which the value is increased or decreased when the user clicks to the left or right of the slider thumb

Palm OS supports two types of sliders: regular slider and feedback slider. Sliders and feedback sliders look alike but behave differently. Specifically, a regular slider control does not send events while the user is dragging its thumb. A feedback slider control sends an event each time the thumb moves one pixel, whether the pen has been lifted or not.

Table 5.9 shows the system events generated when the user interfaces with a slider and how CtlHandleEvent responds to the events.

Table 5.9 Event flow for sliders 
User Action
System Response
CtlHandleEvent Response
Pen tap on slider's background.
penDownEvent with the x and y coordinates stored in EventType.
Adds the ctlEnterEvent to the event queue.

ctlEnterEvent with slider's ID number.
Adds or subtracts the slider's page jump value from its current value, and adds a ctlSelectEvent with the new value to the event queue.
Pen goes down on the slider's thumb.
penDownEvent with the x and y coordinates stored in EventType.
Adds the ctlEnterEvent to the event queue.

ctlEnterEvent with slider's ID number.
Tracks the pen.
Pen drags slider's thumb to the left or right.

Continues tracking the pen.
Pen is lifted from slider.
penUpEvent with the x and y coordinates stored in EventType.
Adds the ctlSelectEvent with the slider's ID number and new value if the coordinates are within the bounds of the slider.

Adds the ctlExitEvent if the coordinates are outside of the slider's bounds.

Table 5.10 shows the system events generated when the user interacts with a feedback slider and CtlHandleEvent's response to the events.

Table 5.10 Event flow for feedback sliders 
User Action
System Response
CtlHandleEvent Response
Pen tap on slider's background.
penDownEvent with the x and y coordinates stored in EventType.
Adds the ctlEnterEvent to the event queue.

ctlEnterEvent with slider's ID number.
Adds or subtracts the slider's page jump value from its current value and then sends a ctlRepeatEvent with the slider's new value.

Adds or subtracts the slider's page jump value from its current value repeatedly until the thumb reaches the pen position or the slider's minimum or maximum. Then sends a ctlSelectEvent with slider's ID number and new value.
Pen goes down on the slider's thumb.
penDownEvent with the x and y coordinates stored in EventType.
Adds the ctlEnterEvent to the event queue.

ctlEnterEvent with slider's ID number.
Tracks the pen and updates the display.
Pen drags slider's thumb to the left or right.
ctlRepeatEvent with slider's ID number and new value.
Tracks the pen. Each time pen moves to the left or right, sends another ctlRepeatEvent if the pen is still within the bounds of the control.
Pen is dragged off the slider vertically.

ctlRepeatEvent with the slider's ID number and old value.
Pen is dragged back onto the slider.

ctlRepeatEvent with the slider's ID number and new value.
Pen is lifted from slider.
penUpEvent with the x and y coordinates stored in EventType.
Adds the ctlExitEvent to the event queue.

Sliders are drawn using two bitmaps: one for the slider background, and the other for the thumb. You may use the default bitmaps to draw sliders, or you may specify your own bitmaps when you create the slider.

The background bitmap you provide can be smaller than the slider's bounding rectangle. This allows you to provide one bitmap for sliders of several different sizes. If the background bitmap isn't as tall as the slider's bounding rectangle, it's vertically centered in the rectangle. If the bitmap isn't as wide as the slider's bounding rectangle, the bitmap is drawn twice. First, it's drawn left-justified in the left half of the bounding rectangle and clipped to exactly half of the rectangle's width. Then, it's drawn right-justified in the right half of the bounding rectangle and clipped to exactly half of the rectangle's width. (See Figure 5.9.) Note that this means that the bitmap you provide must be at least half the width of the bounding rectangle.

Figure 5.9 Drawing a slider background

Fields

A field object displays one or more lines of text. Figure 5.10 is an underlined, left-justified field containing data.

Figure 5.10 Field

The field object supports these features:

Proportional fonts (only one font per field)

Drag-selection

Scrolling for multiline fields

Cut, copy, and paste

Left and right text justification

Tab stops

Editable/noneditable attribute

Expandable field height (the height of the field expands as more text is entered)

Underlined text (each line of the field is underlined)

Maximum character limit (the field stops accepting characters when the maximum is reached)

Special keys (Graffiti strokes) to support cut, copy, and paste

Insertion point positioning with pen (the insertion point is positioned by touching the pen between characters)

Scroll bars

The field object does not support overstrike input mode; horizontal scrolling; numeric formatting; or special keys for page up, page down, left word, right word, home, end, left margin, right margin, and backspace. On Palm OS Versions earlier than 3.5, the field object also does not support word selection. Starting in version 3.5, double-tapping a word selects that word, and triple-tapping selects the entire line.


NOTE: Field objects can handle line feeds-\0A-but not carriage returns-\0D. PalmRez translates any carriage returns it finds in any Palm OS resources into line feeds, but doesn't touch static data.

Events in field objects are handled by FldHandleEvent. Table 5.11 provides an overview of how FldHandleEvent deals with the different events

Table 5.11 Event flow for fields 
User Action
Event Generated
FldHandleEvent Response
Pen goes down on a field.
penDownEvent with the x and y coordinates stored in EventType.
Adds the fldEnterEvent to the event queue.

fldEnterEvent with the field's ID number.
Sets the insertion point position to the position of the pen and tracks the pen until it is released. Drag-selection and drag-scrolling are supported.


Starting in Palm OS release 3.5, double-tapping in a field selects the word at that location, and triple-tapping selects the line.
Pen is lifted.
penUpEvent with the x and y coordinates.
Nothing happens; a field remains selected until another field is selected or the form that contains the field is closed.
Enters characters into selected field.
keyDownEvent with character value in EventType.
Character added to field's text string.
Presses up arrow key
Moves insertion point up a line.
Presses down arrow
Moves insertion point down a line; the insertion point doesn't move beyond the last line that contains text.
Presses left arrow
Moves insertion point one character position to the left. When the left margin is reached, move to the end of the previous line.
Presses right arrow
Moves insertion point one character position to the right. When the right margin is reached, move to the start of the next line.
Cut command
Cuts the current selection to the text clipboard.
Copy command
Copies the current selection to the text clipboard.
Paste command
Inserts clipboard text into the field at insertion point.

Menus

A menu bar is displayed whenever the user taps a menu icon. Starting in Palm OS 3.5, the menu bar is also displayed when the user taps in a form's titlebar. The menu bar, a horizontal list of menu titles, appears at the top of the screen in its own window, above all application windows. Pressing a menu title highlights the title and "pulls down" the menu below the title (see Figure 5.11).

Figure 5.11 Menu

User actions have the following effect on a menu:

When...
Then...
User drags the pen through the menu.
Command under the pen is highlighted.
Pen is released over a menu item.
That item is selected and the menu bar and menu disappear.
Pen is released outside both the menu bar and the menu.
Both menu and menu bar disappear and no selection is made.
Pen is released in a menu title.
Menu bar and Menu remain displayed until a selection is made from the menu.
Pen is tapped outside menu and menu bar.
Both menu and menu bar are dismissed.
User selects a separator with the pen.
Menu is dismissed but no event is posted.

A menu has the following features:

Item separators, which are lines to group menu items.

Keyboard shortcuts; the shortcut labels are right justified in menu items.

A menu remembers its last selection; the next time a menu is displayed the prior selection appears highlighted.

The bits behind the menu bar and the menus are saved and restored by the menu routines.

When the menu is visible, the insertion point is turned off.

Menu events are handled by MenuHandleEvent. Table 5.12 describes how user actions get translated into events and what MenuHandleEvent does in response.

Table 5.12 Event flow for menus 
User Action
Event Generated
MenuHandleEvent Response
Pen enters menu bar.
winEnterEvent identifying menu's window.
Tracks the pen.
User selects a menu item.
penUpEvent with the x and y coordinates.
Adds a menuEvent with the item's ID to the event queue.

Dynamic Menus

In releases of Palm OS prior to release 3.5, the menu was loaded from a menu resource (created with Constructor or some other tool) and could not be modified in code. Starting in Palm OS 3.5, you can add, hide, or unhide menu items while the menu resource is being loaded.

A menuOpenEvent is sent when the menu resource is loaded. (Note that this event is new in version 3.5. Previous releases do not use it.) In response to this event, you can call MenuAddItem to add a menu item to one of the pull-down menus, MenuHideItem to hide a menu item, or MenuShowItem to display a menu item.

You might receive menuOpenEvent several times during an application session. The menu resource is loaded each time the menu is made the active menu. A menu becomes active the first time the user either requests that the menu be displayed or enters the command keystroke on the current form. That menu remains active as long as the form with which it is associated is active. A menu loses its active status under these conditions:

When FrmSetMenu is called to change the active menu on the form.

When a new form, even a modal form or alert panel, becomes active.

Suppose a user selects your application's About item from the Options menu then clicks the OK button to return to the main form. When the About dialog is displayed, it becomes the active form, which causes the main form's menu state to be erased. This menu state is not restored when the main form becomes active again. The next time the user requests the menu, the menu resource is reloaded, and a new menuOpenEvent is queued.

You should only make changes to a menu the first time it is loaded after a form becomes active. You should not add, hide, or show items based on user context. Such practice is discouraged in the Palm OS user interface guidelines.

Menu Shortcuts

As an alternative to selecting a menu command through the user interface, users can instead enter a menu shortcut. This support is present in all versions of the Palm OS, but it has been extended in Palm OS 3.5.

On all versions of Palm OS, the user can enter a Graffiti command keystroke followed by another Graffiti character. If the next character matches one of the shortcut characters for an item on the active menu, a menuEvent with that menu item is generated. To support this behavior, you simply specify a shortcut character when you create a menu item resource. The default behavior of Palm OS handles this shortcut appropriately.

Starting in Palm OS 3.5, entering the Graffiti command character displays the command toolbar (see Figure 5.12). This toolbar is the width of the screen. (Previous versions of Palm OS simply display the string "Command:" in the lower-left portion of the screen.) The command toolbar displays a status message on the left and buttons on the right. After entering the command character, the user has the choice of entering a Graffiti character or of tapping one of the buttons on the command toolbar. Both of these actions cause the status message to be briefly displayed and (in most cases) a menuEvent to be added to the event queue.

Figure 5.12 Command Toolbar

The buttons displayed on the toolbar depend on the user context. If the focus is in an editable field, the field manager displays buttons for cut, copy, and paste on the command toolbar. If there is an action to undo, the field manager also displays a button for undo.

The active application may also add its own buttons to the toolbar. To do so, respond to the menuCmdBarOpenEvent and use MenuCmdBarAddButton to add the button. Listing 5.1 shows some code from the Memo application that adds to the command toolbar a button that displays the security dialog and then prevents the field manager from adding other buttons.

Listing 5.1 Responding to menuCmdBarOpenEvent


else if (event->eType == menuCmdBarOpenEvent) { 
  
   MenuCmdBarAddButton(menuCmdBarOnLeft,  
      BarSecureBitmap, menuCmdBarResultMenuItem,  
      ListOptionsSecurityCmd, 0); 
  
   // Tell the field package to not add buttons  
   // automatically; we've done it all ourselves. 
   event->data.menuCmdBarOpen.preventFieldButtons =  
      true; 
  
   // Don't set handled to true; this event must  
   // fall through to the system. 
} 

The system contains bitmaps that represent such commands as beaming and deleting records. If your application performs any of these actions, it should use the system bitmap. Table 5.13 shows the system bitmaps and the commands they represent. If you use any of these, you should use them in the order shown, from right to left. That is, BarDeleteBitmap should always be the rightmost of these bitmaps, and BarInfoBitmap should always be the leftmost.

Table 5.13 System command toolbar bitmaps 
Bitmap
Command
BarDeleteBitmap
Delete record.
BarPasteBitmap
Paste clipboard contents at insertion point.
BarCopyBitmap
Copy selection.
BarCutBitmap
Cut selection.
BarUndoBitmap
Undo previous action.
BarSecureBitmap
Show Security dialog.
BarBeamBitmap
Beam current record.
BarInfoBitmap
Show Info dialog (Launcher).

You should limit the buttons displayed on the command toolbar to 4 or 5. There are two reasons to limit the number of buttons. You must leave room for the status message to be displayed before the action is performed. Also, consider that the toolbar is displayed only briefly. Users must be able to instantly understand the meaning of each of the buttons on the toolbar. If there are too many buttons, it reduces the chance that users can find what they need.

Note that the field manager already potentially displays 4 buttons by itself. If you want to suppress this behavior and display your own buttons when a field has focus, set the preventFieldButtons flag of the menuCmdBarOpenEvent to true as is shown in Listing 5.1.

Tables

Tables support multi-column displays. Examples are:

the List view of the ToDo application

the Day view in the Datebook

The table object is used to organize several types of UI objects. The number of rows and the number of columns must be specified for each table object. A UI object can be placed inside a cell of a table. Tables often consist of rows or columns of the same object. For example, a table might have one column of labels and another column of fields. Tables can only be scrolled vertically. Tables can't include bitmaps.

A problem may arise if non-text elements are used in the table. For example, assume you have a table with two columns. In the first column is an icon that displays information, the second column is a text column. The table only allows users to select elements in the first column that are as high as one row of text. If the icon is larger, only a narrow strip at the top of the column can be selected.

Table Event

The table object generates the event tblSelectEvent. This event contains:

The table's ID number

The row of the selected table

The column of the selected table

When tblSelectEvent is sent to a table, the table generates an event to handle any possible events within the item's UI object.

Lists

The list object appears as a vertical list of choices in a box. The current selection of the list is inverted.

Figure 5.13 List

A list is meant for static data. Users can choose from a predetermined number of items. Examples include:

the time list in the time edit window of the datebook

the Category popup list (see "Categories" in this chapter)

If there are more choices than can be displayed, the system draws small arrows (scroll indicators) in the right margin next to the first and last visible choice. When the pen comes down and up on a scroll indicator, the list is scrolled. When the user scrolls down, the last visible item becomes the first visible item if there are enough items to fill the list. If not, the list is scrolled so that the last item of the list appears at the bottom of the list. The reverse is true for scrolling up. Scrolling doesn't change the current selection.

Bringing the pen down on a list item unhighlights the current selection and highlights the item under the pen. Dragging the pen through the list highlights the item under the pen. Dragging the pen above or below the list causes the list to scroll if it contains more choices than are visible.

When the pen is released over an item, that item becomes the current selection. When the pen is dragged outside the list, the item that was highlighted before the penDownEvent is highlighted again if it's visible. If it's not, no item is highlighted.

An application can use a list in two ways:

Initialize a structure with all data for all entries in the list and let the list manage its own data.

Provide list drawing functions but don't keep any data in memory. The list picks up the data as it's drawing.

Not keeping data in memory avoids unacceptable memory overhead if the list is large and the contents of the list depends on choices made by the user. An example would be a time conversion application that provides a list of clock times for a number of cities based on a city the user selects. Note that only lists can pick up the display information on the fly like this; tables cannot.

Formatting can be an issue for lists: While it's possible to imitate a multi-column display, lists really consist of rows of text.

The LstHandleEvent function handles list events. Table 5.14 provides an overview of how LstHandleEvent deals with the different events.

Table 5.14 Event flow for lists 
User Action
System Response
LstHandleEvent Response
Pen goes down on popup trigger button.
winEnterEvent identifying list's window.
Adds the lstEnterEvent to the event queue.

lstEnterEvent with list's ID number and selected item.
Tracks the pen.
Pen goes down on a list box.
penDownEvent with the x and y coordinates stored in EventType.
Highlights the selection underneath the pen.

Pen is lifted from the list box.
penUpEvent with the x and y coordinates stored in EventType.
Adds the lstSelectEvent to the event queue.

lstSelectEvent with list's ID number and number of selected item.
Stores the new selection. If the list is associated with a popup trigger, adds a popSelectEvent to the event queue. with the popup trigger ID, the popup list ID, and the item number selected in EventType. Control passes to FrmHandleEvent.
Pen is lifted outside the list box.
penUpEvent with the x and y coordinates stored in EventType.
Adds winExitEvent to event queue.

Categories

Categories allow you to group records logically into manageable lists. In the user interface, categories typically appear in a popup list in a form's titlebar and in dialogs that allow you to edit a single database record.

You create a category popup list the same way you create any other popup list: create the list resource, create the popup trigger control resource with a width of 0, and set the trigger's list ID to be the ID of the list. You manage the category popup list using the category API described in the chapter "Categories" of the Palm OS Programmer's API Reference.

For the most part, you can handle a category popup list using only these calls:

Call CategoryInitialize when you create a new database as described in "Initializing Categories in a Database" below).

Call CategorySetTriggerLabel to set the category popup trigger's label when the form is opened (as described in "Initializing the Category Popup Trigger").

Call CategorySelect when the user selects the category popup trigger (as described in "Managing a Category Popup List").

You typically don't need to use the other functions declared in Category.h unless you want more control over what happens when the user selects the category trigger.

This section focuses on the user interface aspects of categories. For information on how categories are stored and how to manage categories in a database, read Chapter 7, "Files and Databases."

Initializing Categories in a Database

Before you can use the category API calls, you must set up the database appropriately. The category functions expect to find information at a certain location. If the information is not there, the functions will fail.

Category information is stored in the AppInfoType structure within the database's application info block. As described in the chapter titled "Files and Databases" in this book, the application info block may contain any information that your database needs. If you want to use the category API, the first field in the application info block must be an AppInfoType structure.

The AppInfoType structure maps category names to category indexes and category unique IDs. Category names are displayed in the user interface. Category indexes are used to associate a database record with a category. That is, the database record's attribute word contains the index of the category to which the record belongs. Category unique IDs are used when synchronizing the database with the desktop computer.

To initialize the AppInfoType structure, you call CategoryInitialize, passing a string list resource containing category names. This function creates as many category indexes and unique IDs as are necessary. You only need to make this call when the database is first created or when you newly assign the application info block to the database.

The string list resource is an appInfoStringsRsc ('tAIS') resource. It contains predefined categories that new users see when they start the application for the first time. Note that the call to CategoryInitialize is the only place where you use an appInfoStringsRsc. Follow these guidelines when creating the resource:

Place any categories that you don't want the user to be able to change at the beginning of the list. For example, it's common to have at least one uneditable category named Unfiled, so it should be the first item in the list.

The string list must have 16 entries. Typically, you don't want to predefine 16 categories. You might define one or two and leave the remaining entries blank. The unused slots should have 0 length.

Keep in mind that there is a limit of 16 categories. That includes both the predefined categories and the categories your users will create.

Each category name has a maximum length defined by the dmCategoryLength constant (currently, 16 bytes).

Don't include strings for "All" or "Edit Categories." While these two items often appear in category lists, they are not categories, and they are treated differently by the category functions.

Listing 5.2 shows an example function that creates and initializes a database with an application info block. Notice that because the application info block is stored with the database, you allocate memory for it using DmNewHandle, not with MemHandleNew.

Listing 5.2 Creating a database with an app info block


typedef struct { 
   AppInfoType appInfo; 
   UInt16 myCustomAppInfo; 
} MyAppInfoType; 
  
Err CreateAndOpenDatabase(DmOpenRef *dbPP, UInt16 mode) 
{ 
   Err error = errNone; 
   DmOpenRef dbP; 
   UInt16 cardNo; 
   MemHandle h; 
   LocalID dbID; 
   LocalID appInfoID; 
   MyAppInfoType *appInfoP; 
  
   // Create the database.  
   error = DmCreateDatabase (0, MyDBName, MyDBCreator, MyDBType,  
      false); 
   if (error) return error; 
  
   // Open the database.  
   dbP = DmOpenDatabaseByTypeCreator(MyDBType, MyDBCreator,  
      mode); 
   if (!dbP) return (dmErrCantOpen); 
  
   // Get database local ID and card number. We need these to  
   // initialize app info block. 
   if (DmOpenDatabaseInfo(dbP, &dbID, NULL, NULL, &cardNo, NULL)) 
      return dmErrInvalidParam; 
  
   // Allocate app info in storage heap.  
   h = DmNewHandle(dbP, sizeof(MyAppInfoType)); 
   if (!h) return dmErrMemError; 
  
   // Associate app info with database.  
   appInfoID = MemHandleToLocalID (h); 
   DmSetDatabaseInfo(cardNo, dbID, NULL, NULL, NULL, NULL, NULL,  
      NULL, NULL, &appInfoID, NULL, NULL, NULL); 
  
   // Initialize app info block to 0.  
   appInfoP = MemHandleLock(h); 
   DmSet(appInfoP, 0, sizeof(MyAppInfoType), 0);  
  
   // Initialize the categories. 
   CategoryInitialize ((AppInfoPtr) appInfoP,  
      MyLocalizedAppInfoStr); 
  
   // Unlock the app info block. 
   MemPtrUnlock(appInfoP); 
  
   // Set the output parameter and return.  
   *dbPP = dbP; 
   return error; 
} 

Initializing the Category Popup Trigger

When a form is opened, you need to set the text that the category popup trigger should display. To do this, use CategoryGetName to look up the name in the AppInfoType structure and then use CategorySetTriggerLabel to set the popup trigger.

For the main form of the application, it's common to store the index of the previously selected category in a preference and restore it when the application starts up again.

Forms that display information from a single record should show that record's category in the popup list. Each database record stores the index of its category in its attribute word. You can retrieve the record attribute using DmRecordInfo and then AND it with the mask dmRecAttrCategoryMask to obtain the category index.

Listing 5.3 shows how to set the trigger label to match the category for a particular database record.

Listing 5.3 Setting the category trigger label


   UInt16 attr, category; 
   Char categoryName [dmCategoryLength]; 
   ControlType *ctl; 
  
   // If current category is All, we need to look  
   // up category. 
   if (CurrentCategory == dmAllCategories) { 
      DmRecordInfo (AddrDB, CurrentRecord, &attr,  
         NULL, NULL);    
      category = attr & dmRecAttrCategoryMask; 
   } else  
      category = CurrentCategory; 
   CategoryGetName (AddrDB, category, 
      categoryName); 
   ctl = FrmGetObjectPtr(frm,  
      FrmGetObjectIndex(frm, objectID)); 
   CategorySetTriggerLabel (ctl, categoryName); 

Managing a Category Popup List

When the user taps the category popup trigger, call CategorySelect. That is, call CategorySelect in response to a ctlSelectEvent when the ID stored in the event matches the ID of the category's trigger. The CategorySelect function displays the popup list, manages the user selection, displays the Edit Categories modal dialog as necessary, and sets the popup trigger label to the item the user selected.

Calling CategorySelect

The following is a typical call to CategorySelect:

categoryEdited = CategorySelect (AddrDB, frm,  
  ListCategoryTrigger, ListCategoryList, true,  
  &category, CategoryName, 1,  
  categoryDefaultEditCategoryString); 

This example uses the following as parameters:

AddrDB is the database with the categories to be displayed.

frm, ListCategoryTrigger, and ListCategoryList identify the form, popup trigger resource, and list resource.

true indicates that the list should contain an "All" item. The "All" item should appear only in forms that display multiple records. It should not appear in forms that display a single record because selecting it would have no meaning.

category and CategoryName are pointers to the index and name of the currently selected category. When you call this function, these two parameters should specify the category currently displayed in the popup trigger. Unfiled is the default.

The number 1 is the number of uneditable categories. CategorySelect needs this information when the user chooses the Edit Categories list item. Categories that the user cannot edit should not appear in the Edit Categories dialog.

Because uneditable categories are assumed to be at the beginning of the category list, passing 1 for this parameter means that CategorySelect does not allow the user to edit the category at index 0.

categoryDefaultEditCategoryString is a constant that means include an Edit Categories item in the list and use the default string for its name ("Edit Categories" on US English ROMs).

To use a different name (for example, if you don't have enough room for the default name), pass the ID of a string resource containing the desired name.

In some cases, you might not want to include the Edit Categories item. If so, pass the constant categoryHideEditCategory.


NOTE: The categoryDefaultEditCategoryString and categoryHideEditCategory constants are only defined if 3.5 New Feature Set is present. See the CategorySelect function description in the Palm OS Programmer's API Reference for further compatibility information.

Interpreting the Return Value

The CategorySelect return value is somewhat tricky: CategorySelect returns true if the user edited the category list, false otherwise. That is, if the user chose the Edit Categories item and added, deleted, or changed category names, the function returns true. If the user never selects Edit Categories, the function returns false. In most cases, a user simply selects a different category from the existing list without editing categories. In such cases, CategorySelect returns false.

This means you should not rely solely on the return value to see if you need to take action. Instead, you should store the value that you passed for the category index and compare it to the index that CategorySelect passes back. For example:

Int16 category; 
Boolean categoryEdited; 
  
category = CurrentCategory; 
  
categoryEdited = CategorySelect (AddrDB, frm,  
  ListCategoryTrigger, ListCategoryList, true,  
  &category, CategoryName, 1,  
  categoryDefaultEditCategoryString); 
  
if ( categoryEdited ||  
    (category != CurrentCategory)) { 
  /* user changed category selection or  
    edited category list. Do something. */ 
} 

If the user has selected a different category, you probably want to do one of two things:

Update the display so that only records in that category are displayed. See the function ListViewUpdateRecords in the Address Book example application for sample code.

Change the current record's category from the previous category to the newly selected category. See the function EditViewSelectCategory in the Address Book example application for sample code.

Note that the CategorySelect function handles the results of the Edit Categories dialog for you. It adds, deletes, and renames items in the database's AppInfoType structure. If the user deletes a category that contains records, it moves those records to the Unfiled category. If the user changes the name of an existing category to the name of another existing category, it prompts the user and, if confirmed, moves the records from the old category to the new category. Therefore, you never have to worry about managing the category list after a call to CategorySelect.

The Default Application Category

You can store an application's category in a 'taic' resource (symbolically named defaultCategoryRscType) with the ID 1000 in the .prc file. Starting in Palm OS 3.5, the Launcher application installs your application into the specified category. In Constructor, you can specify the 'taic' resource by providing a value for the Default App Category field in the main window.

Most applications should not specify a 'taic' resource. By default, Launcher installs applications in the Unfiled category, and each user chooses where to file the application.

Only specify a 'taic' resource in these instances:

Your application is intended for consumers and clearly belongs to one of the Launcher predefined categories (see Table 5.15).

Always specify the Launcher predefined categories in US English in ASCII characters. Launcher provides the appropriate translations for localized ROMs.

Your application is intended for a vertical market or you've created a suite of custom applications that work together to provide a complete custom solution.

In this case, you might define a 'taic' resource with a custom category name. Launcher creates the category if it doesn't already exist in the Launcher database. When you're not identifying one of Launcher's predefined categories, you may identify the category in any language.

Table 5.15 Launcher predefined categories 
Default Launcher Category
Description
Games
Any game.
Main
Applications that would be used on a daily basis, such as Date Book or Address Book.
System
Applications that control how the system behaves, such as the Preferences, HotSync, and Security.
Utilities
Applications that help the user with system management.
Unfiled
The default category.

Do not treat the default application category as something analogous to the Microsoft Windows Start menu category. On a Palm OS device, the user is limited to 16 categories including Unfiled. Obviously, that limit would be quickly reached if each application defines its own category. Only assign a default category where it is a clear benefit to your users.

Bitmaps

A bitmap is a graphic displayed by Palm OS. There are several ways to create a bitmap resource in Constructor:

If you simply want to display a bitmap at a fixed location on a form, drag a Form Bitmap object to the form. Assign a resource ID in the Bitmap ID field, and you can then create a bitmap resource. The bitmap resource is a 'Tbmp' resource, and the Form Bitmap object that contains it is a 'tFBM' resource.

If you want to create a bitmap for some other purpose (for example, to use in animation or to display a gadget), create either a Bitmap resource or a Bitmap Family resource in the main project window. In this case, Constructor creates a 'tbmf' resource, and the PalmRez post linker converts it and its associated PICTs to a 'Tbmp' resource. (Constructor creates PICT format images on both the Macintosh and Microsoft Windows operating systems.)

A 'Tbmp' resource defines either a single bitmap or a bitmap family. A bitmap family is a group of bitmaps, each containing the same drawing but at a different pixel depth (see Figure 5.14). When requested to draw a bitmap family, the operating system chooses the version of the bitmap with the pixel depth equal to the display. If such a bitmap doesn't exist, the bitmap with the pixel depth closest to but less than the display depth is chosen. If there are no bitmaps less than the display depth, then the bitmap with the pixel depth closest to the display depth is used.

Programmatically, a bitmap or bitmap family is represented by a BitmapType structure. This structure is simply a header. It is followed by the bitmap data in the same memory block. Bitmaps in Palm OS 3.0 and higher are also allowed to have their own color tables. When a bitmap has its own color table, it is stored between the bitmap header and the bitmap data.

Figure 5.14 Bitmap family

Versions of Bitmap Support

There are three different bitmap encodings:

Version 0 encoding is supported by all Palm OS releases.

Version 1 encoding is supported on Palm OS 3.0 and higher. PalmRez creates version 1 bitmaps unless you've explicitly specified a transparency index or a compression type when creating the bitmap in Constructor.

Version 2 encoding is supported on Palm OS 3.5 and higher. This encoding supports transparency indices and RLE compression.

With a version 2 bitmap, you can specify one index value as a transparent color at creation time. The transparency index is an alternative to masking. The system does not draw bits that have the transparency index value.

When a bitmap with a transparency index is rendered at a depth other than the one at which it was created, the transparent color is first translated to the corresponding depth color, and the resulting color is named transparent. This may result in a group of colors becoming transparent.

Drawing a Bitmap

If you use a Form Bitmap object, your bitmap is drawn when the form is drawn. No extra coding is required on your part.

If you're not using a Form Bitmap object, to draw the bitmap you obtain it from the resource database and then call either WinDrawBitmap or WinPaintBitmap. (The form manager code uses WinDrawBitmap to draw Form Bitmap objects.) If passed a bitmap family, these two functions draw the bitmap that has the depth equal to the current draw window depth or the closest depth that is less than the current draw window depth if available, or the closest depth greater than the current draw depth if not.

MemHandle resH =  
  DmGetResource (bitmapRsc, rscID); 
BitmapType *bitmap = MemHandleLock (resH); 
WinPaintBitmap(bitmap, 0, 0); 

If you want to modify a bitmap, starting in Palm OS 3.5 you can create the bitmap programmatically with BmpCreate, create an offscreen window wrapper around the bitmap using WinCreateBitmapWindow, set the active window to the new bitmap window, and use the window drawing functions to draw to the bitmap:

BitmapType *bmpP; 
WinHandle win; 
Err error; 
  
bmpP = BmpCreate(10, 10, 8, NULL, &error); 
if (bmpP) { 
  win = WinCreateBitmapWindow(bmpP, &error); 
  if (win) { 
    WinSetDrawWindow(win); 
    WinDrawLines(win, ...); 
    /* etc */ 
  } 
} 

BmpCreate always creates a version 2 bitmap, even if you don't specify a transparency or compression.

To learn how to modify a bitmap in releases prior to Palm OS 3.5, download the Signatures example application from the Knowledge Base on the Palm OS Developer website.

Color Tables and Bitmaps

As mentioned previously, bitmaps can have their own color tables attached to them. A bitmap might have a custom color table if it requires a palette that differs from the default system palettes. If a bitmap has its own color table, the system must create a conversion table to convert the color table of the current draw window before it can draw the bitmap. This conversion is a drain on performance, so using custom color tables with bitmaps is not recommended if performance is critical.

As an alternative, if your bitmap needs a custom palette, use the WinPalette function to change the system palette that is currently in use, then draw your bitmap. After the bitmap is no longer visible, use WinPalette again to set the system palette back to its previous state.

Labels

You can create a label in a form by creating a label resource.

The label resource displays noneditable text or labels on a form (dialog box or full-screen). It's used, for example, to have text appear to the left of a checkbox instead of the right.

You don't interact with a label as a programmatic entity; however, you can use Form and Control API to create new labels or to change labels dynamically. See the "Summary of User Interface API" at the end of this chapter.

Scroll Bars

Palm OS 2.0 and later provides vertical scroll bar support. As a result, you can attach scroll bars to fields, tables, or lists, and the system sends the appropriate events when the end user interacts with the scroll bar (see Figure 5.15).

Figure 5.15 Scroll bar

Here's what you have to do to include a scroll bar in your user interface:

1. Create a scroll bar (tSCL) UI resource.

Provide the ID and the bounds for the scroll bar rectangle. The height has to match the object you want to attach it to. The width should be 7.

2. Provide a minimum and maximum value as well as a page size.

Minimum is usually 0.

Maximum is usually 0 and set programmatically.

The page size determines how many lines the scroll bar moves when the text scrolls.

3. Make the scroll bar part of the form.

When you compile your application, the system creates the appropriate scroll bar UI object. (See the chapter "Scroll Bars" in the Palm OS Programmer's API Reference for more information on the scroll bar UI object.)

There are two ways in which the scroll bar and the user interface object that it's attached to need to interact:

When the user adds or removes text, the scroll bar needs to know about the change in size.

To get this functionality, set the hasScrollbar attribute of the field, table, or list. (For tables, you must set this programmatically with the function TblHasScrollBar.)

If hasScrollbar is set for a field, you'll receive a fldChangedEvent whenever the field's size changes. Your application should handle these events by computing new values for the scroll bar's minimum, maximum, and current position and then use SclSetScrollBar to update it.

If hasScrollbar is set for a table, you should keep track of when the table's size changes. Whenever it does, you should compute new values for the scroll bar's minimum, maximum, and current position and then use SclSetScrollBar to update it.

Lists are intended for static data, so you typically don't have to worry about the size of a list changing.

You should also call SclSetScrollBar when the form is initialized to set the current position of the scroll bar.

When the user moves the scroll bar, the text needs to move accordingly. This can either happen dynamically (as the user moves the scroll bar) or statically (after the user has released the scroll bar).

The system sends the following scroll bar events:

- sclEnterEvent is sent when a penDownEvent occurs within the bounds of the scroll bar.

- sclRepeatEvent is sent when the user drags the scroll bar.

- sclExitEvent is sent when the user lifts the pen. This event is sent regardless of previous sclRepeatEvents.

Applications that want to support immediate-mode scrolling (that is, scrolling happens as the user drags the pen) need to watch for occurrences of sclRepeatEvent. In response to this event, call the scrolling function associated with the UI object (FldScrollField, LstScrollList, or your own scrolling function in the case of tables).

Applications that don't support immediate-mode scrolling should ignore occurrences of sclRepeatEvent and wait only for the sclExitEvent.

Custom UI Objects

A gadget resource lets you implement a custom UI object. The gadget resource contains basic information about the custom gadget, which is useful to the gadget writer for drawing and processing user input.

You interact with gadgets programmatically using the Form API. See the "Summary of User Interface API" at the end of this chapter.

A gadget is best thought of as simply a reserved rectangle at a set location on the form. You must provide all drawing and event handling code. There is no default behavior for a gadget.

Starting in Palm OS 3.5, you can create an extended gadget. An extended gadget is simply a gadget with a callback routine (FormGadgetHandler) that provides drawing and event handling code for the gadget. Use FrmSetGadgetHandler to set the callback function. (A pointer to the gadget is passed to the callback, so you can use the same function for multiple gadgets.) When the form receives certain requests to draw itself, delete itself, or to hide or show a gadget object, the form manager calls the gadget handler function you provide. When the form receives events intended for the gadget, it passes those to the gadget handler function as well.

In versions prior to 3.5, gadgets do not have a callback function. Instead, you must write code to draw the gadget and respond to pen down events in the form's event handler. Listing 5.4 shows the event handler for the main form in the Rock Music sample application. This code makes calls to draw the gadget in response to a frmOpenEvent or frmUpdateEvent, and if there is a penDownEvent within the bounds of the gadget, it calls a function to handle that event as well. Listing 5.5 shows how a gadget handler function might be written for Rock Music.

Listing 5.4 Pre-Palm OS 3.5 gadget example


Boolean MainViewHandleEvent(EventPtr event) 
{ 
   Boolean handled = false; 
   Word objIndex; 
   FormPtr frm; 
   RectangleType r; 
  
   switch (event->eType) { 
      case frmOpenEvent: 
         MainViewInit(); 
         frm = FrmGetActiveForm (); 
         FrmDrawForm (frm); 
         DrawGadget(); 
         handled = true; 
         break; 
       
      case frmUpdateEvent: 
         frm = FrmGetActiveForm (); 
         FrmDrawForm (frm); 
         DrawGadget(); 
         handled = true; 
         break; 
          
      case penDownEvent: 
         frm = FrmGetActiveForm (); 
         objIndex = FrmGetObjectIndex (frm,  
            RockMusicMainInputGadget); 
         FrmGetObjectBounds (frm, objIndex, &r); 
         if (RctPtInRectangle (event->screenX,  
            event->screenY, &r)) { 
            GadgetTapped (); 
            handled=true; 
         } 
         break; 
      ... 
   } 

Listing 5.5 Palm OS 3.5 gadget example


Boolean GadgetHandler (struct FormGadgetType *gadgetP, UInt16 cmd, void *paramP) 
{ 
   Boolean handled = false; 
  
   switch (cmd) { 
      case formGadgetDrawCmd: 
      //Sent to active gadgets any time form is  
      //drawn or redrawn. 
         DrawGadget(); 
         gadgetP->attr.visible = true; 
         handled = true; 
         break; 
       
      case formGadgetHandleEventCmd: 
      //Sent when form receives a gadget event.  
      //paramP points to EventType structure.  
         if (paramP->eType == frmGadgetEnterEvent) { 
         // penDown in gadget's bounds.  
            GadgetTapped (); 
            handled = true; 
         } 
         if (paramP->eType == frmGadgetMiscEvent) { 
            //This event is sent by your application 
            //when it needs to send info to the gadget 
         } 
         break; 
      case formGadgetDeleteCmd:  
         //Perform any cleanup prior to deletion. 
         break; 
      case formGadgetEraseCmd:  
      //FrmHideObject takes care of this if you  
      //return false.  
         handled = false; 
         break; 
   } 
   return handled; 
} 

Dynamic UI

Palm OS 3.0 and later provides functions that can be used to create forms and form elements at runtime. Most applications will never need to change any user interface elements at runtime-the built-in applications don't do so, and the Palm user interface guidelines discourage it. The preferred method of having UI objects appear as needed is to create the objects in Constructor and set their usable attributes to false. Then use FrmShowObject and FrmHideObject to make the object appear and disappear as needed.

Some applications, such as forms packages, must create their displays at runtime-it is for applications such as these that the Dynamic UI API is provided. If you're not absolutely sure that you need to change your UI dynamically, don't do it-unexpected changes to an application's interface are likely to confuse or frustrate the end user.

Dynamic user interface objects are subject to the following limitations:

You cannot create tables or Graffiti Shift indicators.

You cannot create buttons (or repeating buttons) having frames or non-bold frames.

You can use the FrmNewForm function to create new forms dynamically. Palm's UI guidelines encourage you to keep popup dialogs at the bottom of the screen, using the entire screen width. This isn't enforced by the routine, but is strongly encouraged in order to maintain a look and feel that is consistent with the built-in applications.

The FrmNewLabel, FrmNewBitmap, FrmNewGadget, LstNewList, FldNewField and CtlNewControl functions can be used to create new objects on forms.

It is fine to add new items to an active form, but doing so is very likely to move the form structure in memory; therefore, any pointers to the form or to controls on the form might change. Make sure to update any variables or pointers that you are using so that they refer to the form's new memory location, which is returned when you create the object.

The FrmRemoveObject function removes an object from a form. This function doesn't free memory referenced by the object (if any) but it does shrink the form chunk. For best efficiency when removing items from forms, remove items in order of decreasing index values, beginning with the item having the highest index value. When removing items from a form, you need to be mindful of the same concerns as when adding items: the form pointer and pointers to controls on the form may change as a result of any call that moves the form structure in memory.

When creating forms dynamically, or just to make your application more robust, use the FrmValidatePtr function to ensure that your form pointer is valid and the form it points to is valid. This routine can catch lots of bugs for you-use it!

Dynamic User Interface Functions

The following API can be used to create forms dynamically:

CtlNewControl

CtlValidatePointer

FldNewField

FrmNewBitmap

FrmNewForm

FrmNewGadget

FrmNewLabel

FrmRemoveObject

FrmValidatePtr

LstNewList

WinValidateHandle

FrmNewGsi (available only if 3.5 New Feature Set is present)

Color and Grayscale Support

Starting in Palm OS version 3.5, the operating system supports system palettes of 1, 2, 4, or 8 bits-per-pixel, as follows:

1-bit: white (0) and black (1)

2-bit: white (0), light gray (1), dark gray (2), and black (3)

4-bit: 16 shades of gray, from white (0) to black (0xF)

8-bit: 216 color "Web-safe" palette, which includes all combinations of red, green, and blue at these levels: 0x00, 0x33, 0x66, 0x99, 0xCC, and 0xFF. Also, it includes all 16 gray shades at these levels: 0x00, 0x11, 0x22, ... 0xFF. Finally, it includes these extra named HTML colors: 0xC0C0C0 (silver), 0x808080 (gray), 0x800000 (maroon), 0x800080 (purple), 0x008000 (green), and 0x008080 (teal). The remaining 24 entries (indexes 0xE7 through 0xFE) are unspecified and filled with black. These entries may be defined by an application.

Generalized support for color tables in all bit depths is included, with performance degrading if the color tables are not standard.

Starting in Palm OS version 4.0, the operating system supports 16-bit color. However, support is not provided to allow the UI layer of the OS to utilize 16-bit color mode. Buttons, controls, and other gadgets continue to be displayed with a color bit depth of no more than 8-bits.

Indexed Versus Direct Color Display

Displays that support 1, 2, 4, or 8 bits per pixel rely on a color lookup table in the display hardware in order to map pixel values into colors. The only colors that can be displayed on the screen at any given time are those that are found in the display's color lookup table.

Direct color displays on the other hand, do not rely on a color lookup table because the value stored into each pixel location specifies the amount of red, green, and blue components directly. For example, a 16-bit direct color display could have 5 bits of each pixel assigned as the red component, 6 bits as the green component, and 5 bits as the blue component. With this type of display, the application is no longer limited to drawing with a color that is in the color lookup table.

The color indexed mode for setting the foreground, background, and text colors used previous to Palm OS release 4.0 continues to work even with direct color displays because the system uses a translation table for mapping color index values into direct colors.

When the screen is a direct color display, the color lookup table for the screen is present only for compatibility with the indexed mode color calls. The lookup table has no effect on the display hardware, since the hardware derives the color from the red, green, and blue bits stored in each pixel location of the frame buffer.

Color Table

The system color table is stored in a 'tclt' resource (symbolically named colorTableRsc). The color table is a count of the number of entries, followed by an array of RGBColorType colors. An RGBColorType struct holds 8 bits each of red, green, and blue plus an "extra" byte to hold an index value.

A color's index is used in different ways by different software layers. When querying for a color or doing color fitting, the index holds the index of the closest match to the RGB value in the reference color table. When setting a color in a color table, the index can specify which slot the color should occupy. In some routines, the index is ignored.

Generally, the drawing routines and the operating system use indexed colors rather than RGB. Indexed colors are used for performance reasons; it allows the RGB-to-index translation to be skipped for most drawing operations.

Care should be taken not to confuse a full color table (which includes the count) with an array of RGB color values. Some routines operate on entire color tables, others operate on lists of color entries.

Color Translation Table

When rendering requires a translation from one depth to another, a color translation table is used. For example, suppose you are trying to display an 8-bit color bitmap image on a 2-bit display. Palm OS must translate the color bitmap to a grayscale bitmap in order to display it. To do so, it creates the translation table by stepping through each element of the source color table (the 8-bit bitmap) and finding the best fit for the RGB value in the destination color table (which has exactly 4 values). This table is generated once and is reused for all drawing operations until it is no longer valid.

Palm OS uses one of two algorithms to build the translation table:

Luminosity fitting if the destination color table is grayscale.

Shortest distance in the RGB space if the destination color table is color.

Although shortest distance RGB fitting does not always produce the best perceptual match, it is fast, and it works well for the available palettes on Palm OS.

Color Table Management

If you want to change the color table used by the current draw window, you can do so with the WinPalette function. If the current draw window is onscreen, the palette for the display hardware is also changed. For more information see the WinPalette function description in the Palm OS Programmer's API Reference.

If your application needs to know which RGB color corresponds to which index color in the current palette, it can do so with the function calls WinRGBToIndex and WinIndexToRGB. When calling WinRGBToIndex, an exact match may not be available. That is, you may be calling WinRGBToIndex with an RGB value that is not in the palette and thus does not have an index. If there is no exact RGB match, the best-fit algorithm currently in place is used to determine the index value. For WinIndexToRGB, the RGB value returned is always the exact match. (An error is displayed on debug ROMs if the index is out of range.)

UI Color List

The system builds a UI color list in addition to the system color table. The UI color list contains the colors used by the various user interface elements. Each UI color is represented by a symbolic color constant. See Table 5.16 for a list of colors used.

Each bit depth has its own list of UI colors, allowing for a different color scheme in monochrome, grayscale, and color modes. This is important because even with a default monochrome look and feel, highlighted field text is black-on-yellow in color and white-on-black in other modes.

To obtain the color list, the system first tries to load it from the synchronized preferences database using the value sysResIDPrefUIColorTableBase plus the current screen depth. The use of a preference allows for the possibility that individual users could customize the look using a third party "personality" or "themes" editor. If the preference is not defined, it loads the default color table from the system color table resource plus the current screen depth.

Using a list allows easy variation of the colors of UI elements to either personalize the overall color scheme of a given Palm device or to adjust it within an application. Defining these as color classes ensures that the user interface elements are consistent with each other.

Table 5.16 UI objects and colors 
UI Object
Symbolic Colors Used
Forms
UIFormFrame, UIFormFill
Modal dialogs
UIDialogFrame, UIDialogFill
Alert dialogs
UIAlertFrame, UIAlertFill
Buttons (push button, repeating button, check boxes, and selector triggers)
UIObjectFrame, UIObjectFill, UIObjectForeground, UIObjectSelectedFill, UIObjectSelectedForeground
Fields
UIFieldBackground, UIFieldText, UIFieldTextLines, UIFieldTextHighlightBackground, UIFieldTextHighlightForeground
Menus
UIMenuFrame, UIMenuFill, UIMenuForeground, UIMenuSelectedFill, UIMenuSelectedForeground
Tables
Uses UIFieldBackground for the background, other colors controlled by the object in the table cell.
Lists and popup triggers
UIObjectFrame, UIObjectFill, UIObjectForeground, UIObjectSelectedFill, UIObjectSelectedForeground
Labels
Labels on a control and noneditable fields use UIObjectForeground, and text written to a form using WinDrawChars or WinPaintChars use the current text setting in the draw state.
Scroll bars
UIObjectFill, UIObjectForeground, UIObjectSelectedFill, UIObjectSelectedForeground
Insertion point
UIFieldCaret
Front-end processor (currently only used on Japanese systems)
UIFieldFepRawText, UIFieldFepRawBackground, UIFieldFepConvertedText, UIFieldFepConvertedBackground, UIFieldFepUnderline

Should your application need to change the colors used by the UI color list, it can do so with UIColorSetTableEntry. If you need to retrieve a color used, it can do so with UIColorGetTableEntryIndex or UIColorGetTableEntryRGB.

If you change the UI color list, your changes are in effect only while your application is active. The UI color list is reset as soon as control switches to another application. When control switches back to your application, you'll have to call UIColorSetTableEntry again.

Direct Color Functions

The direct color function calls are more generic than their indexed forms and can be used with both indexed (1, 2, 4, or 8 bit) or direct 16-bit color displays. The system automatically looks up the color index value of the closest color if necessary.

The direct color functions are: WinSetForeColorRGB, WinSetBackColorRGB, WinSetTextColorRGB, and WinGetPixelRGB

Because these calls are only available on systems with the direct color enhancements present, applications should generally stick to using the indexed form of these calls: WinSetForeColor, WinSetBackColor, WinSetTextColor, and WinGetPixel unless they need finer control over the choice and dynamic range of colors.

Pixel Reading and Writing

The Palm OS 3.5 API call for reading a pixel value, WinGetPixel, is designed to return a color index value. When this call is performed on a direct color display, it must first get the actual pixel value (a 16 or 24 bit direct color value). The system then looks up the closest color from the system's virtual 8-bit color lookup table, and returns the index of the closest color from that table. This mode of operation ensures compatibility for applications that take the return value from WinGetPixel and use it as an indexed color to WinSetForeColor, WinSetBackColor, and WinSetTextColor.

Applications that need to copy pixels exactly from one location to another on direct color displays should use WinGetPixelRGB instead of WinGetPixel. If you use WinGetPixel on a direct color display, it can result in a loss of color because of the closest-match color table lookup operation that WinGetPixel performs.

WinGetPixelRGB returns the pixel as an RGBColorType with a full 8 bits each of red, green, and blue, assuring no loss of color resolution. This call is more generic than the WinGetPixel call and can be used with both indexed (1, 2, 4, or 8 bit) or direct color modes. The system automatically looks up the RGB components of indexed color pixels as necessary.

The pixel setting API calls (WinPaintPixel, WinDrawPixel, and so on) all rely on using the current foreground and background colors and do not require new forms for the direct color mode. An application can simply pass in the return RGBColorType from WinGetPixelRGB to WinSetForeColorRGB and then call WinDrawPixel in order to copy a direct color pixel.

Direct Color Bitmaps

In Palm OS release 4.0 the Window manager supports16 bits per pixel direct color bitmaps, as well as the previously supported 1, 2, 4, and 8 bit indexed color bitmaps. A direct color bitmap is indicated by the new directColor bit in the BitmapFlagsType bit-field of the BitmapType data structure. In addition to this flag, a direct color bitmap must also include the BitmapDirectInfoType fields: redBits, greenBits, blueBits, reserved, and transparentColor.

The redBits, greenBits, and blueBits fields indicate the number of bits in each pixel for each color component. The current implementation only supports 16 bits per pixel, with 5 bits of red, 6 bits of green, and 5 bits of blue:

R R R R  R G G G  G G G B  B B B B 
MSB                           LSB 

The transparentColor field contains the red, green, and blue components of the transparent color of the bitmap. For direct color bitmaps, this field is used instead of the transparentIndex field to designate the transparent color value of the bitmap, because the transparentIndex field is only 8 bits wide and can only represent an indexed color. The transparentColor field, like the transparentIndex field, is ignored unless the hasTransparency bit is set in the bitmap's flags field.

With Palm OS 4.0, a 16-bit direct color bitmap can always be rendered, regardless of the actual screen depth. The 16-bit color functions automatically perform the necessary bit depth conversion to render the bitmap into whatever depth the destination is in.

Bitmap resources can be built to contain multiple depth images in the same bitmap resource, one image for each possible depth. A potential incompatibility could arise if an application includes only a direct color version of a bitmap. Therefore, applications need to either check that version 4.0 of Palm OS is present before drawing a direct color bitmap, or they must always include a 1, 2, 4, or 8 bit per pixel image of the bitmap in the bitmap resource along with the direct color version.

Special Drawing Modes

The special drawing modes of winErase, winMask, winInvert, and winOverlay introduce a complication when it comes to direct color models. These drawing modes were originally designed for use with monochrome bitmaps where black is designated by 1 bits and white is designated by 0 bits. With these color assignments, these various modes can be described as:

WinErase becomes an AND operation (black pixels in the source leave the destination alone whereas white pixels in the source make the destination white).

WinMask becomes an AND NOT operation (black pixels in the source make the destination white whereas white pixels leave the destination alone)

WinInvert becomes an XOR operation (black pixels in the source invert the destination whereas white pixels leave the destination alone)

WinOverlay becomes an OR operation (black pixels in the source make the destination black, white pixels in the source leave the destination alone)

In a direct color bitmap, black is designated by all 0s and white is designated by all 1s. Because of this, if all the drawing modes were implemented as logical operations in the same way as they are for indexed color modes, the desired effect would not be achieved.

The assumption made by direct color functions is that the desired effect is more important to the caller than the actual logical operation that is performed. Thus, the various drawing modes, when drawing to a direct color bitmap, become:

WinErase becomes an OR operation (black pixels in the source leave the destination alone whereas white pixels in the source make the destination white).

WinMask becomes an OR NOT operation (black pixels in the source make the destination white whereas white pixels leave the destination alone)

WinInvert becomes an XOR NOT operation (black pixels in the source invert the destination whereas white pixels leave the destination alone)

WinOverlay becomes an AND operation (black pixels in the source make the destination black, white pixels in the source leave the destination alone)

As long as the source and destination bitmaps contain only black and white colors, the new interpretations of the drawing modes in direct color modes produce the same effects as they would have with an indexed color mode.

With non-black and white pixels however, an application may get unexpected results from these drawing modes if they assume that the direct color function calls perform the same logical operation in direct color mode as they do in indexed color mode.

Insertion Point

The insertion point is a blinking indicator that shows where text is inserted when users write Graffiti characters or paste clipboard text.

In general, an application doesn't need to be concerned with the insertion point; the Palm OS UI manages the insertion point.

Text

This section describes how to work with text in the user interface-whether it's text the user has entered or text that your application has created to display on the screen.


NOTE: If you application is going to be localized, you must take special care when working with text. See the chapter "Localized Applications" for more information.

Working With Text As Strings

The string manager provides a set of string manipulation functions. The string manager API is closely modeled after the standard C string-manipulation functions like strcpy, strcat, etc.

Applications should use the functions built into the string manager instead of the standard C functions because doing so makes the application smaller:

When your application uses the string manager functions, the actual code that implements the function is not linked into your application but is already part of the operating system.

When you use the standard C functions, the code for each function you use is linked into your application and results in a bigger executable.

In addition, many standard C functions don't work on the Palm OS device at all because the OS doesn't provide all basic system functions (such as malloc) and doesn't support the subroutine calls used by most standard C functions.


NOTE: If your application is going to be localized, be careful when using string functions. Where possible, use the functions described in the chapter "Localized Applications" instead.

Using the StrVPrintF Function

Like the C vsprintf function, the StrVPrintF function is designed to be called by your own function that takes a variable number of arguments and passes them to StrVPrintF for formatting. This section gives a brief overview of how to use StrVPrintF. For more details, refer to vsprintf and the use of the stdarg.h macros in a standard C reference book.

When you call StrVPrintF, you must use the special macros from stdarg.h to access the optional arguments (those specified after the fixed arguments) passed to your function. This is necessary, because when you declare your function that takes an optional number of arguments, you declare it using an ellipsis at the end of the argument list:

MyPrintF(CharPtr s, CharPtr formatStr, ...); 

The ellipsis indicates that zero or more optional arguments may be passed to the function following the formatStr argument. Since these optional arguments don't have names, the stdarg.h macros must be used to access them before they can be passed to StrVPrintF.

To use these macros in your function, first declare an args variable as type va_list:

va_list args; 

Next, initialize the args variable to point to the optional argument list by using va_start:

va_start(args, formatStr); 

Note that the second argument to the va_start macro is the last required argument to your function (last before the optional arguments begin). Now you can pass the args variable as the last parameter to the StrVPrintF function:

StrVPrintF(text, formatStr, args); 

When you are finished, invoke the macro va_end before returning from your function:

va_end(args); 

Note that the StrPrintF and StrVPrintF functions implement only a subset of the conversion specifications allowed by the ANSI C function vsprintf. See the StrVPrintF function reference for details.

Fonts in Palm OS 3.0 and Later

Palm OS 3.0 and later provides a new font (largeBoldFont), two new font manipulation routines (FontSelect and FntDefineFont), and support for the use of custom fonts.

To use the large, bold font, pass the largeBoldFont selector to the FntSetFont function. Under Palm OS 3.0 and later, if you try to draw with a font that isn't installed, the system uses the standard font by default. Previous versions of Palm OS can crash if told to use a nonexistent font.

The FontSelect function displays a dialog box in which the user can specify the use of one of the three primary fonts stdFont, boldFont, or largeBoldFont. For more information, see the description of FontSelect in the Palm OS Programmer's API Reference.

The FntDefineFont function makes a custom font available to your application. For more information, see the description of FntDefineFont in the Palm OS Programmer's API Reference.

Currently, Palm has not made available any tools or specifications to convert desktop fonts for use on Palm OS 3.0 or later. If you have an urgent need for such support, send email to devsupp@palm.com for updated information.

Receiving User Input

The five ways that a user interacts with an application are:

by entering Graffiti

by pressing a hardware button on the device

by tapping the pen on a control in a form or dialog

by tapping on an onscreen keyboard in the keyboard dialog.

by tapping in the menu bar or in a particular menu.

For the first three types of input, the Palm OS provides a dedicated manager: The Graffiti Manager, The Key Manager, and The Pen Manager, respectively. Most applications do not need to access these managers directly; instead, applications receive events from these managers and respond to the events. There are cases, however, where you might need to interact with one of these managers. The following pages describe each of these managers and when you might need to use them. To learn how to obtain user input from a UI object, refer to the section in this chapter that covers that object.

The keyboard dialog allows users to input characters into a text field by tapping an onscreen keyboard. When the keyboard dialog is closed, the amended text is automatically displayed in the original field. As with the three managers just mentioned, you will probably not need to access the keyboard dialog directly. The user can open the keyboard from any text field. In certain limited circumstances, however, you may wish to display the keyboard dialog programmatically. For more information, see "The Keyboard Dialog."

The Menu Manager handles taps that display a menu and those that select an item from a menu. For details, see "Menus."

The Graffiti Manager

The Graffiti manager provides an API to the Palm OS Graffiti recognizer. The recognizer converts pen strokes into key events, which are then fed to an application through the event manager.

Most applications never need to call the Graffiti manager directly because it's automatically called by the event manager whenever it detects pen strokes in the Graffiti area of the digitizer.

Special-purpose applications, such as a Graffiti tutorial, may want to call the Graffiti manager directly to recognize strokes in other areas of the screen or to customize the Graffiti behavior.

Using GrfProcessStroke

GrfProcessStroke is a high-level Graffiti manager call used by the event manager for converting pen strokes into key events. The call

Removes pen points from the pen queue

Recognizes the stroke

Puts one or more key events into the key queue

GrfProcessStroke automatically handles Graffiti ShortCuts and calls the user interface as appropriate to display shift indicators in the current window.

An application can call GrfProcessStroke when it receives a penUpEvent from the event manager if it wants to recognize strokes entered into its application area (in addition to the Graffiti area).

Using Other High-Level Graffiti Manager Calls

Other high-level calls provided by the Graffiti manager include routines for

Getting and setting the current Graffiti shift state (caps lock on/off, temporary shift state, etc.)

Notifying Graffiti when the user selects a different field. Graffiti needs to be notified when a field change occurs so that it can cancel out of any partially entered shortcut and clear its temporary shift state if it's showing a potentially accented character.

Special-Purpose Graffiti Manager Calls

The remainder of Graffiti manager API routines are for special-purpose use. They are basically all the entry points into the Graffiti recognizer engine and are usually called only by GrfProcessStroke. These special-purpose uses include calls to add pen points to the Graffiti recognizer's stroke buffer, to convert the stroke buffer into a Graffiti glyph ID, and to map a glyph into a string of one or more key strokes.

Accessing Graffiti ShortCuts

Other routines provide access to the Graffiti ShortCuts database. This is a separate database owned and maintained by the Graffiti manager that contains all of the shortcuts. This database is opened by the Graffiti manager when it initializes and stays open even after applications quit.

The only way to modify this database is through the Graffiti manager API. It provides calls for getting a list of all shortcuts, and for adding, editing, and removing shortcuts. The ShortCuts screen of the Preferences application provides a user-interface for modifying this database.

Note on Auto Shifting

The Palm OS 2.0 and later automatically uses an upper-case letter under the following conditions:

Period and space or Return.

Other sentence terminator (such as ? or !) and space

This functionality requires no changes by the developer, but should be welcome to the end user.

Note that the auto-shifting rules are language-specific, since capitalization differs depending on the region. These rules depend on the version of the ROM, the market into which the device is being sold, and so on.

Note on Graffiti Help

In Palm OS 2.0 and later, applications can pop up Graffiti help by calling SysGraffitiReferenceDialog or by putting a virtual character-graffitiReferenceChr from Chars.h-on the queue.

Graffiti help is also available through the system Edit menu. As a result, any application that includes the system Edit menu allows users to access Graffiti Help that way.

The Key Manager

The key manager manages the hardware buttons on the Palm OS device. It converts hardware button presses into key events and implements auto-repeat of the buttons. Most applications never need to call the key manager directly except to change the key repeat rate or to poll the current state of the keys.

The event manager is the main interface to the keys; it returns a keyDownEvent to an application whenever a button is pressed. Normally, applications are notified of key presses through the event manager. Whenever a hardware button is pressed, the application receives an event through the event manager with the appropriate key code stored in the event record. The state of the hardware buttons can also be queried by applications at any time through the KeyCurrentState function call.

The KeyRates call changes the auto-repeat rate of the hardware buttons. This might be useful to game applications that want to use the hardware buttons for control. The current key repeat rates are stored in the key manager globals and should be restored before the application exits.

The Pen Manager

The pen manager manages the digitizer hardware and converts input from the digitizer into pen coordinates. The Palm OS platform device has a built-in digitizer overlaid onto the LCD screen and extending about an inch below the screen. This digitizer is capable of sampling accurately to within 0.35 mm (.0138 in) with up to 50 accurate points/second. When the device is in doze mode, an interrupt is generated when the pen is first brought down on the screen. After a pen down is detected, the system software polls the pen location periodically (every 20 ms) until the pen is again raised.

Most applications never need to call the pen manager directly because any pen activity is automatically returned to the application in the form of events.

Pen coordinates are stored in the pen queue as raw, uncalibrated coordinates. When the system event manager routine for removing pen coordinates from the pen queue is called, it converts the pen coordinate into screen coordinates before returning.

The Preferences application provides a user interface for calibrating the digitizer. It uses the pen manager API to set up the calibration which is then saved into the Preferences database. The pen manager assumes that the digitizer is linear in both the x and y directions; the calibration is therefore a simple matter of adding an offset and scaling the x and y coordinates appropriately.

The Keyboard Dialog

The keyboard dialog is an onscreen keyboard on which the user taps to input information into a text field. When the insertion point is in a text field, the user can open the onscreen keyboard by tapping on the silk-screen letters ("abc" or "123") in the lower corners of the Graffiti area. The keyboard dialog appears:

Figure 5.16 The Keyboard Dialog

The keyboard dialog's text field contains the full text of the original field, with the insertion point in the same position as in the original field. Users can start inserting and deleting characters immediately, or they can scroll up or down and then insert and delete. When one of the software keys is tapped, the corresponding character is inserted in the text field of the keyboard dialog.

As the user taps, the keyboard dialog code captures pen events, maps them to characters, and posts keyDownEvents. The text field in the keyboard dialog handles each keyDownEvent, displaying the character onscreen and inserting it into the memory chunk associated with the field. Since the keyboard dialog has its own event loop, you cannot handle the key events yourself. If you need to capture the key events, you should consider creating a custom version of the onscreen keyboard dialog, as outlined in "Creating a Custom Keyboard Layout."

The keyboard code edits the text string of the original field in-place. Each field has a text handle that points to the memory chunk containing the text string for the field. When the keyboard dialog is opened, the association between the text handle and the original field is removed. The text handle is then assigned to the text field of the keyboard dialog and edited according to user input. When the keyboard dialog is closed, the text handle is reassigned to the original field.

For details on how FldHandleEvent manipulates the memory chunk that holds a field's text string, see Chapter 9, "Fields," in the Palm OS Programmer's API Reference. Read about the FldGetTextHandle and FldSetText functions.

Opening the Keyboard Dialog Programmatically

In most applications, the keyboard dialog appears only when explicitly opened by the user. There are occasions, however, when you may wish to force the user to input characters via the onscreen keyboard. For example, the service activation application shipped with all Palm VIIs displays the keyboard dialog automatically. Palm made this choice because the activation application must be usable by completely new Palm users, who may not know how to write Graffiti or open the keyboard dialog themselves. Other reasons for imposing the keyboard dialog include accurate input of passwords or account numbers.

To display the keyboard dialog programmatically, use one of the following functions:

SysKeyboardDialog

SysKeyboardDialogV10

Normally, use SysKeyboardDialog only. SysKeyboardDialogV10 is for compatibility with Palm OS 1.0.

See keyboard.h for the function prototypes and the KeyboardType they use. Note that the rest of the functions listed in keyboard.h are for system use only and do not form part of the Palm OS API.

Keyboard Layouts

The keyboard dialog has three views, one for each of the pre-defined layouts: the English alphabet, numerals and punctuation, and Latin characters with diacritic marks. The default is the English alphabet. To display a particular layout, call the sysKeyboardDialog function and pass it one of the following constants, which are defined in an enumeration named KeyboardType:
Table 5.17 Constants Defined in KeyboardType
Constant
Character Set
kbdAlpha
The English language character set.
kbdNumbersAndPunc
A set containing numbers and some advanced punctuation.
kbdAccent
The International character set, made up of Latin characters with diacritic marks.
kbdDefault
The value of kbdDefault is the same as kdbAlpha and cannot be changed.

Creating a Custom Keyboard Layout

You cannot add an extra keyboard layout or modify an existing one. You can, however, create your own keyboard dialog module that implements the functionality outlined below.

First, your application should intercept the keyDownEvent generated when the user taps the "abc" or "123" silk-screen letters in the Graffiti area. Create a custom keyboard dialog loader routine to handle it. Your keyboard code should then do the following:

Get the text handle of the original field and save it in a variable. Use FldGetTextHandle.

Remove the association between the text handle and the original field. Use FldSetTextHandle or FldSetText, passing NULL as the second argument.

Assign the text handle to the text field of the keyboard dialog.

Define a Keyboard event handler that:

- captures pen events in your onscreen keyboard region, which may be a bitmap of a keyboard or may consist of individual push buttons,

- maps pen events to characters,

- creates keyDownEvents and posts them to the event queue so that the dialog's text field can automatically handle them and insert them in its text chunk.

When the dialog is closed, remove the association between the text handle and keyboard's field, and then re-assign the text handle to the original text field.

Finally, if you wish more than one layout, your custom keyboard dialog must contain a button to open each layout.

Application Launcher

The Application Launcher (accessed via the silk-screen "Applications" button) presents a window or menu from which the user can open other applications present on the Palm device. Applications installed on the Palm device (resource databases of type 'appl') appear in the Application Launcher automatically.


NOTE: Versions of Palm OS prior to 3.0 implemented the Launcher as a popup. The SysAppLauncherDialog function, which provides the API to the old popup launcher, is still present in Palm OS 3.0 for compatibility purposes, but it has not been updated and, in most cases, should not be used.

The Launcher application can beam applications to other Palm devices. Only the application itself is beamed; associated storage databases and preferences are not transmitted. To suppress the beaming of your application by the Launcher, you can set the dmHdrAttrCopyPrevention bit in your database header. (For a runtime code example, see the "Dr McCoy" sample application. Note that you can also use compile-time code to suppress beaming.)

Normally, the Launcher represents installed applications graphically as icons that appear in the Launcher window. The Launcher application also provides a list mode that allows the user to see more applications at once than are normally visible in its default viewing mode. You can use the Constructor tool to provide a small icon for the list mode-you'll need to create a tAIB resource having 1001 as the value of its ID.

The Launcher displays a version string from each application's tver resource, ID 1000. This short string (usually 3 to 6 characters) is displayed in the "Info" dialog.

Situations in which you need to open the Application Launcher programmatically are rare, but the system does provide an API for doing so. To activate the Launcher from within your application, enqueue a keyDownEvent that contains a launchChr, as shown in Listing 5.6.


WARNING! Do not use the SysUIAppSwitch or SysAppLaunch functions to open the Application Launcher application.

Listing 5.6 Opening the Launcher


EventType newEvent; 
newEvent.eType = keyDownEvent;
newEvent.data.keyDown.chr = launchChr;
newEvent.data.keyDown.modifiers = commandKeyMask; 
EvtAddEventToQueue (&newEvent); 

For information on launching other applications programmatically, see "Launching Applications Programmatically" in the chapter "Application Startup and Stop."

Summary of User Interface API

Progress Manager Functions

Form Functions

Initialization


Event Handling

Displaying a Form

Displaying a Modal Dialog
Updating the Display

Form Attributes
Accessing a Form Programmatically
Accessing Objects Within a Form
Title and Menu
Labels

Controls
Gadgets

Bitmaps


Coordinates and Boundaries
Removing a Form From the Display
Releasing a Form's Memory

Window Functions

Initialization


Making a Window Active

Accessing a Window Programmatically
Offscreen Windows

Displaying Characters

Bitmaps

Lines

Rectangles

Pixels

Clipping Rectangle

Setting the Drawing State
Coordinates and Boundaries
Working with the Screen

Removing a Window From the Display

Releasing a Window's Memory

Working with Colors

Control Functions

Displaying a Control

Control's Value

Label

Enabling/Disabling
Event Handling


Setting up controls

Debugging

Field Functions

Obtaining User Input
Updating the Display

Displaying Text


Editing Text

Cut/Copy/Paste

Scrolling

Field Attributes
Text Attributes
Working With the Insertion Point
Releasing Memory

Event Handling

Dynamic UI

Menu Functions

Table Functions

Drawing Tables

Updating the Display

Retrieving Data

Displaying Data

Retrieving a Row

Table Information
Row Information

Masked Records

Column Information

Removing a Table From the Display

Event Handling


Private Record Functions

List Functions

Displaying a List

Updating the Display

List Data and Attributes

Removing a List From the Display

Event Handling

Category Functions

Bitmap Functions

Scroll Bar Functions

UI Color List Functions

UI Controls

Insertion Point Functions

String Manager Functions

Length of a String


Comparing Strings

Changing Strings

Searching Strings

Converting

Localized Numbers

Font Functions

Changing the Font
Accessing the Font Programmatically
Wrapping Text

String Width

Character Width

Height

Scrolling


Creating a Font


Graffiti Manager Functions

Translate a Stroke into Keyboard Events

Shift State

Point Buffer

Working with Macros

Key Manager Functions

Pen Manager Functions

Keyboard Dialog Functions