Documentation  |   Table of Contents   |  < Previous   |  Next >   |  Index

9    Applications and the Dynamic Input Area

Palm OS® Programmer's Companion

Volume I

     

On most existing Palm Powered handhelds, Palm OS® applications are drawn in a fixed space that is 160 X 160 pixels or 320 X 320 pixels in size, depending on the device's screen density. The input area, where the user enters characters, is silkscreened onto such devices. Some Palm Powered handhelds have dynamic input areas, as shown in Figure 9.1, that users can close when they do not need to enter characters. (Tapping the arrow in the lower right closes the input area, leaving a smaller control bar visible.)

On these devices, the application area is not fixed—it is the traditional square size while the input area is opened, and it is a rectangular size when the input area is closed, giving more space to the application.

Figure 9.1  Closable Dynamic Input Area

A control bar at the bottom of the screen, shown in Figure 9.2, contains various buttons, including one called the trigger (the arrow at the right in this example), that opens the input area when it is closed. A trigger also typically appears in the input area to provide a way for the user to close the input area.

Figure 9.2  Control Bar

The control bar is typically closed when the input area is open, except on double density screens, when it is always shown; however, licensees can change this behavior.

To take advantage of the additional screen space, your application must respond when the input area is opened or closed and redraw the current form in the available application space. This chapter describes how to do so.

To make your application work with a dynamic input area, do the following:

  1. Check the feature to make sure that the API described in this document is available. (See "The Dynamic Input Area Feature.")
  2. Call WinSetConstraintsSize to set the size constraints for each form in response to the frmLoadEvent or frmOpenEvent. (See "Size Constraints.")
  3. Set up each form in your application to work with the Pen Input Manager in response to the frmLoadEvent or frmOpenEvent, and the winEnterEvent. This involves calling FrmSetDIAPolicyAttr, PINSetInputTriggerState, and PINSetInputAreaState. (See "Input Area Policy.")
  4. Respond to the sysNotifyDisplayResizedEvent notification by posting a winDisplayChangedEvent and then in this event handler, redraw the form in the available space. (See "Resizing a Form.")

NOTE: If an application does not call FrmSetDIAPolicyAttr before a form is drawn, the system assumes it is a legacy form that doesn't support a closable input area. In this case, the input area is drawn without a trigger.

The Dynamic Input Area Feature ^TOP^

Before you can use any of the API described in this chapter, you must make sure that the dynamic input area API is available. Test the pinFtrAPIVersion feature as shown in Listing 9.1

Listing 9.1  Checking the dynamic input area feature


err = FtrGet(pinCreator, pinFtrAPIVersion, &version); 
if (!err && version) { 
//PINS exists 
} 

If this feature is defined, a new manager called the Pen Input Manager controls the input area and notifies the application of any changes in the input area state.


NOTE: Version 1.1 (pinAPIVersion1_1) of the Pen Input Manager is slightly different from version 1.0 (pinAPIVersion1_0). It doesn't matter which version you find; you should write your application to be compatible with both, as described in the following sections.

Size Constraints ^TOP^

After you've determined that the Pen Input Manager is available, you need to let it know the size constraints for each form in your application. You do so by calling the function WinSetConstraintsSize when the form is loaded; that is, in response to the frmLoadEvent. (Alternately, you can do this on a frmOpenEvent.)

The WinSetConstraintsSize function takes seven parameters: the handle to the form's window, the minimum, preferred, and maximum heights for the form, and the minimum, preferred, and maximum widths for the form. The Pen Input Manager uses this information to determine whether the form supports a closed input form.

If you don't specify size constraints, the Pen Input Manager assumes that the minimum, maximum, and preferred height and width are all 160 standard coordinates. In this way, legacy applications are always sized appropriately when the input area is open.

Listing 9.2 shows how you might call WinSetConstraintsSize for an application with three forms: a main form, an edit form, and a password dialog. WinSetConstraintsSize must be called in response to the frmLoadEvent or frmOpenEvent. You typically handle the frmLoadEvent in your application's AppHandleEvent, so you would place this code in your application's AppHandleEvent function.

Listing 9.2  Setting the size constraints


if (eventP->eType == frmLoadEvent) { 
// Load the form resource. 
formId = eventP->data.frmLoad.formID; 
frmP = FrmInitForm(formId); 
FrmSetActiveForm(frmP); 
 
// Set the same policy for each form in application.  
err = FrmSetDIAPolicyAttr(frmP, frmDIAPolicyCustom); 
 
// Enable the input trigger 
err = PINSetInputTriggerState(pinInputTriggerEnabled); 
 
formWinH = FrmGetWindowHandle (frmP); 
// Set the event handler for the form, and set each form's  
// size requirements.  
switch (formId) { 
case MainForm: 
FrmSetEventHandler(frmP, MainFormHandleEvent); 
WinSetConstraintsSize(formWinH, 80, 160, 225,  
160, 160, 160); 
break; 
 
case EditForm: 
FrmSetEventHandle(frmP, EditFormHandleEvent); 
WinSetConstraintsSize(formWinH, 100, 160, 225,  
160, 160, 160); 
break; 
 
case PasswordDialog: 
FrmSetEventHandler(frmP, PasswordDialogHandleEvent); 
FrmSetDIAPolicyAttr(frmPolicyStayOpen); 
break; 
 
default: 
break; 
} 
return true; 
} 

In Listing 9.2, WinSetConstraintsSize is called once for each form in the application. There is currently nothing that should resize a form's width, so each of these calls uses 160 for all of the width parameters. The full-screen forms prefer to be 160 pixels high because the application uses these same forms when running on older devices that use static input areas; however, it's acceptable for the main form to be as short as 80 pixels and the Edit form to be as short as 100 pixels if the input area needs more space. Finally, the input area should not be closable for the password dialog because it is needed to enter the password.

Input Area Policy ^TOP^

To set up your application's forms to work with the Pen Input Manager, you must do the following for each form:

  • Set an input area policy using the function FrmSetDIAPolicyAttr to let the system know that the form will resize itself when the input area is opened and closed. Do so in response to the frmLoadEvent or frmOpenEvent.
  • Enable the input trigger, which is what the user uses to open and close the input area, using the function PINSetInputTriggerState. An example of the trigger is the lower right arrow shown in Figure 9.1 and Figure 9.2.

Setting the Input Area Policy ^TOP^

The input area policy that you set with FrmSetDIAPolicyAttr specifies whether your form supports a dynamic input area. Listing 9.2 shows how you might call FrmSetDIAPolicyAttr in your application's AppHandleEvent.

Most forms should use a policy of frmDIAPolicyCustom. If not, the system treats your form as it does all forms in a legacy application. It opens the input area when the form is opened so that the form has the normal square area in which to draw, and it disables the input trigger so that the user cannot close the input area while your form is being displayed.


NOTE: Future Palm OS versions might not disable the input trigger for legacy applications or forms.

The input area policy is set on a form-by-form basis rather than an application-by-application basis because each form might have different requirements for the input area. A form that relies heavily on user input might need to ensure that the input area is opened while the form is active. However, a form that has no editable fields, like an address list, may want to keep the input area closed so that more information is visible.

Enabling the Input Trigger ^TOP^

For each form in your application that uses the policy frmDIAPolicyCustom, you can enable the input area's input trigger. Use the function PINSetInputTriggerState to enable the trigger (see Listing 9.2).

You must enable the input trigger for each form because a system dialog might disable it. System dialogs appear on top of your application's forms. When the dialog is dismissed and control returns to your application, the input trigger may be disabled. You won't receive a frmLoadEvent or frmOpenEvent because your form is already loaded and opened. Instead, you get the winEnterEvent. Therefore, to make sure your users can open and close the input area while your application is active, even after a system dialog is displayed, you must enable the trigger in response to the winEnterEvent.

Note that the key code associated with the input trigger button is vchrInputAreaControl, so a keyDownEvent with this character is enqueued whenever the trigger is tapped.

Setting an Input Area State ^TOP^

You can set the input area state with the function PINSetInputAreaState. Most forms should set the input area state to pinInputAreaUser, which lets the user decide whether the input area is open or closed, in response to the frmOpenEvent.

In rare cases, it may be beneficial for the form to decide whether the input area is opened or closed. For example, you might have a tall form that closes the input area so that the user can see the entire form without scrolling. f you explicitly set the input area state to opened or closed, you may need to do so in winEnterEvent because a system dialog may appear on top of your form and reset the input area state.

Be careful not to set the input area state too much. If the input area is opened and closed automatically in too many instances, the result may be a jumpy user interface that produces a jarring user experience. It is probably best to let your users decide what they want to do.

Resizing a Form ^TOP^

When the Pen Input Manager opens or closes the input area or control bar or changes the display orientation, it broadcasts the sysNotifyDisplayResizedEvent notification to all applications that have registered for it.

When the application receives the sysNotifyDisplayResizedEvent, it must post a winDisplayChangedEvent (using EvtAddUniqueEventToQueue), which forms can handle to resize themselves.

Listing 9.3  Posting a winDisplayChangedEvent


case sysAppLaunchCmdNotify: 
if (((SysNotifyParamType*) cmdPBP)->notifyType ==  
sysNotifyDisplayResizedEvent) 
{ 
EventType resizedEvent;
MemSet(&resizedEvent, sizeof(EventType), 0); 
//add winDisplayChangedEvent to the event queue 
resizedEvent.eType = winDisplayChangedEvent; 
EvtAddUniqueEventToQueue(&resizedEvent, 0, true); 
} 
break; 

It's possible for the input area to change state while a menu is open. To handle this case, an application should also enqueue a winDisplayChangedEvent (using code similar to Listing 9.3) when it receives a winEnterEvent.

The notification contains a rectangle specifying the new bounds for the current form. In general, forms should respond to the closing of the input area by moving any command buttons to the bottom of the new rectangle and by resizing the data area of the display.

Listing 9.4 shows a simple example of handling the winDisplayChangedEvent.

Listing 9.4  Handling winDisplayChangedEvent


// Input area was opened or was closed. Must resize form.  
case winDisplayChangedEvent: 
// get the current bounds for the form 
frmP = FrmGetActiveForm(); 
WinGetBounds (FrmGetWindowHandle(frmP), &curBounds); 
 
// get the new display window bounds 
WinGetBounds(WinGetDisplayWindow(), &displayBounds); 
 
EditFormResizeForm(frmP, &curBounds, &displayBounds); 
WinSetBounds(FrmGetWindowHandle(frmP), &displayBounds); 
FrmDrawForm(frmP); 
handled = true; 
break; 

This example is for a form containing one multi-line text field, a scroll bar, and several command buttons at the bottom of the form. It responds to the winDisplayChangedEvent by passing the form's current bounds and new bounds to a function named EditFormResizeForm, which is shown in Listing 9.5. This function determines the difference between the current height and width and the new height and width and then applies that difference to the objects in the form. For the command buttons, it changes their position so that they always appear at the bottom of the form. For the text field and scroll bar, it resizes them so that more text lines are displayed on the screen.

Note that after resizing a form with a text field, it is a good idea to call FldRecalculateField to update the word-wrapping for the field's new size.

Listing 9.5  Resizing a form


void EditFormResizeForm(FormType *frmP,  
RectangleType* fromBoundsP, RectangleType* toBoundsP)  
{ 
Int16 heightDelta, widthDelta;  
UInt16 numObjects, i; 
Coord x, y; 
RectangleType objBounds; 
 
heightDelta = widthDelta = 0; 
numObjects = 0; 
x = y = 0; 
FieldType* fldP; 
 
// Determine the amount of the change 
heightDelta=(toBoundsP->extent.y - toBoundsP->topLeft.y) -  
(fromBoundsP->extent.y - fromBoundsP->topLeft.y); 
widthDelta=(toBoundsP->extent.x - toBoundsP->topLeft.x) -  
(fromBoundsP->extent.x - fromBoundsP->topLeft.x); 
 
// Iterate through objects and re-position them.  
// This form consists of a big text field and  
// command buttons. We move the command buttons to the  
// bottom and resize the text field to display more data. 
numObjects = FrmGetNumberOfObjects(frmP); 
for (i = 0; i < numObjects; i++) { 
switch (FrmGetObjectType(frmP, i)) { 
case frmControlObj: 
FrmGetObjectPosition(frmP, i, &x, &y); 
FrmSetObjectPosition(frmP, i, x + widthDelta, y +  
heightDelta); 
break; 
case frmFieldObj: 
case frmScrollBarObj: 
FrmGetObjectBounds(frmP, i, &objBounds); 
objBounds.extent.x += widthDelta; 
objBounds.extent.y += heightDelta; 
FrmSetObjectBounds(frmP, i, &objBounds); 
fldP = (FieldType*) FrmGetObjectPtr(frmP, i); 
FldRecalculateField(fldP, false); 
break; 
} 
} 
} 

Hiding and Showing the Control Bar ^TOP^

There are two functions that applications can use to hide and show the control bar: StatHide and StatShow.

It's best not to manually hide or show the control bar, but there may be some situations in which an application needs to draw to the entire display area and thus must hide the control bar. However, if the control bar is hidden, this prevents users from exiting to the Launcher or opening the input area. If the control bar is hidden, you must provide a mechanism for the user to exit the application or to show the control bar.

To determine if the control bar is hidden or showing, you can call StatGetAttribute with the statAttrBarVisible selector. You can obtain the bounds of the control bar by using the statAttrDimension selector.

Note that the Stat... functions are available only in Pen Input Manager version 1.1.

Pen Input Manager Compatibility ^TOP^

Pen Input Manager version 1.1 was introduced with Palm OS Garnet version 5.3SC. There are some differences between Pen Input Manager version 1.1 and version 1.0.

The version of the Pen Input Manager is returned in the version parameter of the following FtrGet call:


err = FtrGet(pinCreator, pinFtrAPIVersion, &version); 

We recommend writing your application to be compatible with all versions of the Pen Input Manager. It will be compatible if you follow the guidelines in this book.

This section documents the differences in version 1.1 so that you know the details. They include:

New sysFtrNumInputAreaFlags Support ^TOP^

The presence of the Pen Input Manager in version 1.1 does not indicate the capabilities of the device. In version 1.0, the device supports all of the features in the following sections (listed immediately above), and the flags are not implemented.

In version 1.1, you must test another feature, sysFtrNumInputAreaFlags, to determine if the device supports a dynamic input area, live ink, and a closable dynamic input area.


err = FtrGet(sysFtrCreator, sysFtrNumInputAreaFlags, &flags) 

A selector is available to determine if the OS supports the dynamic input area. If the grfFtrInputAreaFlagDynamic flag is set to 0, or FtrGet returns an error, then the dynamic input area is not supported. Likewise, if the grfFtrInputAreaFlagCollapsible flag is set to 0, or if FtrGet returns an error, then a closable dynamic input area is not supported.

The flags argument is initialized using bits defined in Graffiti.h:


#define grfFtrInputAreaFlagDynamic 0x00000001 
#define grfFtrInputAreaFlagLiveInk 0x00000002 
#define grfFtrInputAreaFlagCollapsible 0x00000004 

Additional winDisplayChangedEvent ^TOP^

Version 1.1 of the Pen Input Manager uses an additional mechanism for notifying applications that the input area or control bar has opened or closed. Version 1.0 sends the sysNotifyDisplayResizedEvent notification, while version 1.1 sends this notification and also the winDisplayChangedEvent.

To be compatible with both versions, an application should post a winDisplayChangedEvent (using EvtAddUniqueEventToQueue) when the sysNotifyDisplayResizedEvent notification is received. Listing 9.3 shows how to do this.

Restoration of Input Trigger State ^TOP^

With Pen Input Manager version 1.1, if you set an input area policy of frmDIAPolicyCustom but don't call PINSetInputTriggerState to enable or disable the trigger or call PINSetInputAreaState to open or close the input area, then the system automatically restores the last user-selected input area state and enables the trigger (1.0 doesn't do this). If PINSetInputAreaState and/or PINSetInputTriggerState is called by the application, however, then the form's resulting state is restored when the form is updated due to a call to FrmDrawForm or a WinEnterEvent.

With Pen Input Manager version 1.0, you must enable the input trigger for each form because a system dialog might disable it. System dialogs appear on top of your application's forms. System dialogs use the same input area policy as legacy applications do: the input area is opened and the user is not allowed to close it. When the dialog is dismissed and control returns to your application, the input trigger will still be disabled. You won't receive a frmLoadEvent or frmOpenEvent because your form is already loaded and opened. Instead, you get the winEnterEvent. Therefore, to make sure your users can open and close the input area while your application is active, even after a system dialog is displayed, you must enable the trigger in response to the winEnterEvent.

New pinInputAreaUser Input Area State ^TOP^

Pen Input Manager version 1.1 implements a new input area state: pinInputAreaUser. However, you can use this state in applications designed to run in both 1.0 and 1.1 environments, because it will simply be ignored in 1.0.

New Stat... Functions ^TOP^

The following new functions are implemented in Pen Input Manager version 1.1, but not in version 1.0:

StatGetAttribute, StatHide, and StatShow

It's best not to use these functions in order to be compatible with devices running Pen Input Manager version 1.0.

New Support for Changing Display Orientation ^TOP^

Pen Input Manager version 1.1 implements support for changing the display orientation between portrait, landscape, and the reverse of each. This allows the display to be rotated to any of the four possible directions.

The following functions support the display orientation feature: SysGetOrientation, SysSetOrientation, SysGetOrientationTriggerState, SysSetOrientationTriggerState.

Not all devices support changing the display orientation. For devices that don't support changing the display orientation, the only valid orientation is portrait.


NOTE: Orientation support is implemented only in Pen Input Manager version 1.1 in Palm OS Garnet version 5.3 and later. Pen Input Manager version 1.1 is available on earlier OS versions, but depending on licensee support, it may or may not include this feature. To check if this function is implemented in Pen Input Manager 1.1 in a Palm OS version earlier than 5.3, you must use SysGlueTrapExists.