The Nokia 9000i contains has a very specific look and feel which is created through the use of a specific user interface developed for the device. The specific UI contains not only visual representations for GEOS objects, but also additional objects that are particularly tailored for the Nokia 9000i device.
Most of these objects have been grouped into the "Foam" library. This library is a special collection of classes, objects and routines specifically applicable to the Nokia 9000i device. Because of its multi-faceted nature, the Foam library is not a coherent library so much as a "toolbox" of useful widgets.
We will not attempt to cover every piece of the Foam library within this chapter. Instead, we provide a brief overview of the foam UI classes, then delve into the objects which are particularly useful for creating your application.
These objects are:
0 Foam UI Classes Overview
1 FoamSubApplicationClass
1.1 FoamSubApplicationClass Instance Data
1.2 Using a FoamSubApplication Object
2 ComplexMonikerClass
2.1 ComplexMoniker Instance Data
2.2 ComplexMoniker Usage
2.3 ComplexMoniker Messages
3 Convenient Dialog Routines
4 FlashingNoteClass
4.1 FlashingNote Instance Data
4.2 Setting Up the Template
4.3 Initiating and Destroying the Flashing Note
5 FoamProgressDialog
5.1 FoamProgressDialog Instance Data
5.2 Setting Up the Template
5.3 Using a FoamProgressDialog
6 Routines for Lists
The foam library includes many new UI classes. This page lists these classes, briefly describes each class' utility, and displays an annotated snapshot of each UI class.
Inherits:
GenFileSelectorClass
Use a FFileSelectorClass when you do not need a controller and the associated ComplexMoniker UI to select a file but only want to display a list of files (if you do want a full controller with complete UI, use FileOpenControlClass). FFileSelectorClass objects allow you to get and set the directory path using the FDocumentDir enum values for the directories which are specific to the Nokia 9000i Communicator.

FFileSelectorClass file selector.
Include: foam.goh
Reference: FileOpenControlClass, FFileSelectorClass.
Inherits:
GenFileSelectorClass, but is a variant class.
This class is not available on build 4.8.8 or earlier versions of the Communicator.
The ExtendedFileSelectorClass expands the functionality of any subclass of GenFileSelectorClass, usually FFileSelectorClass. It allows multiple files to be selected, optionally provides the user with a search box that narrows the list of files to match the text typed in the search box, and can find files in any directory or subdirectory, not just the directories represented by the enumerated type FDocumentDir.
Include: foam.goh
Reference: ExtendedFileSelectorClass, FFileSelectorClass.
Inherits:
GenClass, but is a variant class.
The ComplexMonikerClass allows developers to create a moniker that contains both text and a bitmap icon. Since the text and icon are referred to generically, it is easy to localize the moniker. A complex moniker is a variant class - its parent class is dynamically created at runtime - so it can assume a variety of forms. The superclass of a ComplexMonikerClass object may be any child of GenClass. This allows complex monikers to be:
ComplexMonikerClass behavior of displaying a text and icon moniker.
Include: foam.goh
Reference: ComplexMonikerClass,
GenTriggerClass,
GenInteractionClass,
GenItemGroupClass,
GenItemClass,
GenBooleanGroupClass,
GenDynamicListClass, or
ContactListClass.
Inherits:
ComplexMonikerClass
Applications that require more than four triggers may establish two panes of triggers. The user can toggle between these two panes using two TwoLevelTriggerClass trigger objects which usually have the monikers "More" or "Back". They are typically put in the fouth slot (slot 3). Since the "More" and "Back" triggers take up two slots, an application which uses two panes of triggers may define up to six of its own triggers.
Include: foam.goh
Reference: TwoLevelTriggerClass, ComplexMonikerClass, Nokia 9000i Communicator Topics: UI Conventions
Inherits:
GenApplicationClass
Since the Nokia 9000i Communicator does not have a file manager per se, applications added to the device must be launched through a currently existing application. The FoamSubApplicationClass specifies in which pre-existing application an add-on application should reside.
Include: foam.goh
Reference: FoamSubApplicationClass, GenApplicationClass.
Inherits:
GenInteractionClass
Draws a gray beveled box around its children. It can be used with the
ComplexMoniker variant class to add a moniker label (see FilterListClassexample).
Include: foam.goh
Reference: GreyFrameClass, GenInteractionClass.
Inherits:
GenItemGroupClass
GenItemClass and GenItemGroupClass work together to display a list of static monikers that the user may choose from. ListWithUserDefinedClass
expands this to allow the user to navigate to an object and input information.
The additional item may be a UnderlinedTextWithListClass,
TextWithListClass, or GenValueWithListClass.
Include: foam.goh
Reference: ListWithUserDefinedClass, GenItemGroupClass.
Inherits:
GenGlyphClass
RepeatingGenGlyphClass is used to create animations. It works be replacing the visMoniker of GenGlyphClass with the application-defined sequence of bitmapped icons, which it then cycles through. One common use of RepeatingGenGlyphClass is in dialog boxes which are opened with PutUpDialogViaUIThread(). This is done so that the animation is processed by another thread and thus doesn't burden the application.
Include: foam.goh
Reference: RepeatingGenGlyphClass, FoamProgressDialogClass.
Inherits:
GenInteractionClass
The FlashingNoteClass is used to flash a note on the screen for a set length of time. The application specifies the minimum and maximum time the note will remain on the screen. If the user presses a key after the note has been on screen for the minimum duration, the note dialog box is dismissed. This dialog runs on its own thread and takes the responsibility for dismissing and destroying itself.
Include: foam.goh
Reference: FlashingNoteClass, GenInteractionClass.
Inherits:
GenInteractionClass
The SelfDestroyingDialogClass is used to put up a dialog box that self-destructs upon dismissal.
Include: foam.goh
Reference: SelfDestroyingDialogClass, GenInteractionClass.
Inherits:
GenControlClass
When an application starts a process that may take a while, it is good practice to put up a FoamProgressDialogClass dialog which notifies the user that the application is working and which indicates the status of the process. This dialog is put up on its own thread. The process is indicated by an animation of gears grinding away and by the status text which the application may append. If the user chooses the provided "Cancel" trigger a message is sent which indicates that the process should be terminated.
Include: foam.goh
Reference: FoamProgressDialogClass, GenControlClass.
Inherits:
GenPrimaryClass
This class creates a primary window with a gray background. It is an inappropriate base for most applications because it only draws properly when placed against the left edge of the screen and it puts a gray background behind the trigger menu, thus making them look different from all other Communicator applications.
Include: foam.goh
Reference: GreyGenInteractionClass, GenPrimaryClass .
Inherits:
GenGlyphClass
An IndicatorClass object is a GenGlyph that draws an etched border around itself.
Include: foam.goh
Reference: IndicatorClass, GenGlyphClass .
Inherits:
IndicatorClass
This class is a GenGlyph that can draw one or two icons within etched borders from a list of bitmaps. The displayed icons can be changed dynamically.
Include: foam.goh
Reference: IconIndicatorClass, IndicatorClass.
Inherits:
IndicatorClass
The LevelIndicatorClass draws a bitmap followed by a sequence of bitmaps. This is used for displaying a level indicator such as the battery charge. The number of levels or the bitmap label can be changed dynamically.
Include: foam.goh
Reference: LevelIndicatorClass, IndicatorClass.
Inherits:
IndicatorClass
This makes a GenInteraction with an etched border.
Include: foam.goh
Reference: IndicatorInteractionClass, GenInteractionClass.
Inherits:
TextWithListClass, which in turn inherits GenTextClass.
FilterListClass and FilterTextClass objects work together to provide the appropriate UI for interactive searches.
Include: foam.goh
Reference: FilterListClass, FilterTextClass, TextWithListClass, GenTextClass.
Inherits:
VisTextClass
UnderlinedGenTextClass and UnderlinedVisTextClass objects behave like the associated TextClass objects except that the text area has a dotted underline. These classes are used extensively for text-entry fields on the Nokia 9000i Communicator.
Include: foam.goh
Reference: UnderlinedGenTextClass, UnderlinedVisTextClass, GenTextClass, VisTextClass.
Inherits:
GenControlClass
The controllers FoamTextStyleControlClass, FoamFontControlClass, FoamPointSizeControlClass, and/or
FoamJustificationControlClass attach to a text object and allow the user to change the displayed text styles. These controllers are functionally equivalent to the standard
text object controllers (TextStyleControl, FontControl, etc.), but they have UI and features customized for the Nokia 9000i Communicator.
Include: foam.goh
Reference: FoamTextStyleControlClass, FoamFontControlClass, FoamPointSizeControlClass, FoamJustificationControlClass, GenControlClass.
Applications may be written to be incorporated into the
Nokia 9000i Communicator as part of a special release.
The Nokia 9000i Communicator does not have a file manager,
per se, to enable launching these applications. The applications
must be launched through a currently existing application.
FoamSubApplicationClass
allows you to indicate under which pre-existing application the new application should reside.
"Add-on" applications for the Nokia 9000i Communicator device, whether included on the device as part of a value-added release, or developed as an aftermarket product, will fall into one of three categories:
For each of these cases, there is an application already on the device that launches the sub-application. Service applications are launched using the SVCAPPS launcher; system applications use the SYSAPPS launcher; extra applications use the EXTRAPPS launcher.
Add-on applications are declared using the FoamSubApplication object, and an instance data field is set within the object indicating the "main" application it should be tied with.
Because a sub-application is not a separate application, special care needs to be taken when the sub-application is closed. This is discussed in Using a FoamSubApplication Object .
FoamSubApplicationClass Instance Data
Using a FoamSubApplication Object
There is only one instance data field in a
FoamSubApplicationClass
object. This field is noted below.
Code Display 2-1 FoamSubApplicationClass Instance Data
@instance FApplication FSAI_launcherApp;
FSAI
_launcherApp
stores an
FApplication
type referring to the application it should reside under.
For FoamSubApplication objects, the following
FApplication
values are the only values that are relevant:
MSG_FSA_RETURN_TO_LAUNCHER
FoamSubApplication objects do not close like other applications. Because of this, they need to provide their own special "Close" trigger. However, FoamSubApplication objects should not simply "close" when the user presses this trigger. Instead, they should send MSG_FSA_RETURN_TO_LAUNCHER to this FoamSubApplication object.
This message changes the
[hardIconBar]
entry of the .INI file for the sub-application to be the launcher application (stored in FSAI_
launcherApp
). This allows the sub-application to seemingly close without closing the parent application. It is the responsibility of the application to provide a "Close" trigger that sends this message to the
FoamSubApplicationClass
object.
The "Close" trigger is declared as a
ComplexMonikerClass
object of type CMT_CLOSE. The ComplexMoniker is discussed more fully in ComplexMonikerClass
.
Code Display 2-2 Using the FoamSubApplicationClass Object
/* * Declare the FoamSubApplication object as you would a normal GenApplication * object. This sub-app will be launched from the Extras application. */
@start AppResource
@object FoamSubApplicationClass MyApp = {
GI_comp = @MyPrimary;
FSAI_launcherApp = FA_EXTRAS_APP;
gcnList(MANUFACTURER_ID_GEOWORKS, GAGCNLT_WINDOWS) = @MyPrimary;
GI_visMoniker = list { @MyTextMoniker };
}
@visMoniker MyTextMoniker = "Nokia UI\rSample App";
@end AppResource;
/* * Somewhere in your sub-app, create a CMT_CLOSE trigger. */
@object ComplexMonikerClass CloseTrigger = {
ComplexMoniker = GenTriggerClass;
CMI_topText = CMT_CLOSE;
GTI_actionMsg = MSG_FSA_RETURN_TO_LAUNCHER;
GTI_destination = @TemplateApp;
HINT_SEEK_MENU_BAR;
HINT_SEEK_REPLY_BAR;
/*
* Close Command triggers should always be in the fourth position (3 because
* HINT_SEEK_SLOT refers to zero-based slot positions).
*/
HINT_SEEK_SLOT = 3;
}
ComplexMonikerClass
is a versatile class that provides powerful behavior with little overhead. A complex moniker serves two purposes. First, it allows a developer to easily create a moniker containing both graphics and text. Second, it allows both text and graphics to be easily localized by referring to both items "generically."
A complex moniker may take a variety of forms.
ComplexMonikerClass
is what's known in GEOS as a "variant" class, which means that the object's parent class is dynamically assigned when the object is visually built.
A complex moniker may contain both a text string and a bitmap. The text string may be either a single line or two lines (separated by a `\r' character in the text buffer). If the text is two lines, it will be right-justified; this allows text strings in the command bar to align properly.
ComplexMonikerClass
contains the following instance data:
Code Display 2-3 ComplexMonikerClass Instance Data
ComplexMoniker ClassName
@instance TextStyle CMI_textStyle = (TS_BOLD);
@instance word CMI_topText;
@instance word CMI_iconBitmap;
@instance byte CMI_fontSize;
Because
ComplexMonikerClass
is a variant class, it needs to have its superclass assigned when it is built. The
ComplexMoniker
keyword represents the parent class of the complex moniker. By setting this keyword to a class name the parent class is changed from the default superclass GenClass to the specified class. Any child of GenClass may be a complex moniker superclass. The following are commonly used superclasses:
GenTriggerClass
GenInteractionClass
GenItemGroupClass
GenItemClass
GenBooleanGroupClass
GenDynamicListClass
ContactListClass
Each of these classes will behave quite differently, but all will exhibit the same characteristics in displaying their text and icon monikers that are gained through using
ComplexMonikerClass.
Note that using a ComplexMoniker object will cause the specific UI to ignore any moniker stored in the GI_
visMoniker
instance data field in the above classes.
CMI
_topText
stores the "text" to display. This may be either a Chunkhandle to a text string, or a
ComplexMonikerText
identifier. If the value is a
ComplexMonikerText
identifier, the specific UI will determine what exact text is displayed.
As noted, the text may contain two lines. The top text is limited to COMPLEX_MONIKER_MAX_TOP_TEXT_LENGTH while the bottom is limited to COMPLEX_MONIKER_MAX_BOTTOM_TEXT_LENGTH.
Below is a complete list of types; in most cases the (English) text on the Nokia 9000i device is similar, if not identical, to the text alluded to by the identifier's name. Those cases where the actual text is noticeably different are noted. Using such an identifier is beneficial for localization purposes.
Code Display 2-4 Setting a Complex Moniker's Text
/* * The text in a complex moniker is stored within the CMI_topText instance field. * This text may either be referenced by a ChunkHandle ... */
@object ComplexMonikerClass MyMoniker = {
ComplexMoniker = GenTriggerClass;
CMI_topText = @MyText;
}
/* Use the TCHAR type to ensure the text is DBCS-compliant. */
@chunk TCHAR MyText[] = "Sample Text";
/* * ... or CMI_topText can store a ComplexMonikerText type which indicates the text * generically. */
@object ComplexMonikerClass MyClearTrigger = {
ComplexMoniker = GenTriggerClass;
CMI_topText = CMT_CLEAR;
}
CMI_
iconBitmap
stores the bitmap to display within this moniker. This may either be a ChunkHandle to a Bitmap structure or a member of the
ComplexMonikerBitmap
types. These types are enumerated below:
Again, using a generic identifier eases localization.
You can create your own bitmaps by using the GEOS Icon Editor. To do so, perform the following steps:
BMFormat
of BMF_4BIT). You may also create simple monochrome bitmaps (
BMFormat
of BMF_MONO).|
Icon Editor Color |
Nokia 9000i |
|---|---|
|
WHITE |
WHITE |
|
BLACK |
BLACK |
|
LIGHT_VIOLET |
LIGHT GRAY |
|
DARK_GREEN |
DARK GRAY |
filename
.goh using the following options:@visMoniker Moniker ={
@chunk byte YourIconName[] = {
size = <...>;
style = <...>;
color = <...>;
aspectRatio = <...>;
cachedSize = <...,...>;
gstring { GSFillBitmapAtCP(<...>),
GSEndString() }
Your resulting bitmap, ready for inclusion in your app, should look like this:
@chunk byte MyIconName[] = {
Bitmap (32,20,BMC_PACKBITS,
(BMT_MASK|BMF_4BIT)),
0xfd, 0xff, 0x03, 0xbf, ...
};
CMI_
textStyle
stores a GEOS
TextStyle
, defined in
graphics.h
. By default, text is shown as TS_BOLD. The full list of styles appears below:
CMI
_fontSize
stores a font size (in points). There are four pre-established font sizes that you should choose from:
#define FOAM_LARGE_FONT_SIZE 20 #define FOAM_NORMAL_FONT_SIZE 18 #define FOAM_LIGHT_FONT_SIZE 17 #define FOAM_SMALL_FONT_SIZE 16
The large font size is best reserved for commands and title bar monikers. In most other cases, use the normal font size.
The default font can be obtained by those routines or objects that demand a font name by using the
VisTextDefaultFont
value VTDF_RESPONDER.
There are several vardata attributes that you may attach to the Complex Moniker. These are noted below:
Code Display 2-5 ComplexMoniker Vardata
@vardata void ATTR_COMPLEX_MONIKER_PLACE_BITMAP_AT_LEFT;
@vardata void HINT_COMPLEX_MONIKER_DRAW_SEPARATOR; @vardata void HINT_COMPELX_MONIKER_DONT_DRAW_SEPARATOR;
ATTR_COMPLEX_MONIKER_PLACE_BITMAP_AT_LEFT will position the icon bitmap (if any) to the left of the text.
HINT_COMPLEX_MONIKER_DRAW_SEPARATOR
draws a single-line separator below the complex moniker.
HINT_COMPLEX_MONIKER_DONT_DRAW_SEPARATOR
prevents the drawing of a single-line separator below the complex moniker.
MSG_COMPLEX_MONIKER_GET_MONIKER, MSG_COMPLEX_MONIKER_REPLACE_MONIKER
In most cases, you will want to use a ComplexMoniker when you create Command triggers. Command triggers on the Nokia 9000i appear along the right edge of the screen, and correspond to the four off-screen buttons that they abut.
To create a ComplexMoniker command trigger, follow these steps:
ComplexMoniker
keyword to
GenTriggerClass
.
_fontSize
to something other than FOAM_LARGE_FONT_SIZE.)
Code Display 2-6 Complex Moniker Example (GenInteraction)
@object ComplexMonikerClass AboutBox = {
/* This object will behave as a GenInteration (grouping) object */
ComplexMoniker = GenInteractionClass;
CMI_topText = @AboutBoxTitle;
CMI_iconBitmap = @AboutIcon;
GI_comp = @AboutText;
/* Geometry Hints */
HINT_DRAW_IN_BOX;
HINT_DRAW_SHADOW;
HINT_PLACE_MONIKER_TO_LEFT;
HINT_EXPAND_WIDTH_TO_FIT_PARENT;
HINT_EXPAND_HEIGHT_TO_FIT_PARENT;
/* ComplexMoniker Hints */
HINT_COMPLEX_MONIKER_DRAW_SEPARATOR;
ATTR_COMPLEX_MONIKER_PLACE_BITMAP_AT_LEFT;
}
@chunk TCHAR AboutBoxTitle[] = "CmplxMon Sample Application";
Code Display 2-7 ComplexMoniker Example (GenDynamicList)
@object ComplexMonikerClass CMTextsList = {
ComplexMoniker = GenDynamicListClass;
CMI_topText = @CMTextsListTitle;
CMI_fontSize = FOAM_NORMAL_FONT_SIZE;
CMI_iconBitmap = CMB_OPEN_FOLDER;
GIGI_destination = process;
GIGI_applyMsg = MSG_CMPLXMON_PROCESS_SHOW_CURRENT_CMTEXT;
GDLI_queryMsg = MSG_CMPLXMON_PROCESS_GET_CMTEXT;
/* GDLI_numItems will be set at app-launch time. */
HINT_DRAW_IN_BOX;
HINT_DRAW_SHADOW;
HINT_PLACE_MONIKER_ABOVE;
HINT_PLACE_MONIKER_TO_LEFT;
HINT_COMPLEX_MONIKER_DRAW_SEPARATOR;
HINT_MINIMIZE_CHILD_SPACING;
HINT_EXPAND_WIDTH_TO_FIT_PARENT;
HINT_EXPAND_HEIGHT_TO_FIT_PARENT;
HINT_ITEM_GROUP_SCROLLABLE;
ATTR_COMPLEX_MONIKER_PLACE_BITMAP_AT_LEFT;
ATTR_GEN_SEND_APPLY_MSG_ON_APPLY_EVEN_IF_NOT_MODIFIED;
ATTR_GEN_ITEM_GROUP_STATUS_MSG =
MSG_CMPLXMON_PROCESS_SHOW_CURRENT_CMTEXT;
}
}
Code Display 2-8 ComplexMoniker Example (Command Trigger)
@object ComplexMonikerClass MyCommandTrigger = {
ComplexMoniker = GenTriggerClass;
CMI_topText = @CommandTextTitle;
GTI_actionMsg = MSG_GEN_INTERACTION_INITIATE;
GTI_destination = @DialogThatThisTriggerBringsUp;
HINT_SEEK_MENU_BAR;
HINT_SEEK_REPLY_BAR;
HINT_SEEK_SLOT = 0;
}
@chunk byte CommandTextTitle[] = "I Commeand Thee!";
MSG_COMPLEX_MONIKER_GET_MONIKER, MSG_COMPLEX_MONIKER_REPLACE_MONIKER
To retrieve a complex moniker, send the ComplexMoniker
MSG_COMPLEX_MONIKER_GET_MONIKER
. This message takes a single argument, a pointer to a structure of type
GetComplexMoniker
. The structure will be filled in with the relevant information by the message.
typedef struct {
TextStyle GCM_textStyle;
byte GCM_fontSize;
ComplexMonikerText GCM_topText;
ComplexMonikerBitmap GCM_iconBitmap;
} GetComplexMoniker;
Send
MSG_COMPLEX_MONIKER_REPLACE_MONIKER
to replace a complex moniker with a new moniker.
This message takes two arguments: a
ReplaceComplexMoniker
structure and a
ReplaceComplexMonikerChunkHandles
structure.
The
ReplaceComplexMoniker
structure should hold the parameters for the new moniker.
typedef struct {
TextStyle RCM_textStyleSet;
TextStyle RCM_textStyleClear;
word RCM_fontSize;
dword RCM_topTextSource;
dword RCM_iconBitmapSource;
ComplexMonikerSourceType RCM_topTextSourceType;
ComplexMonikerSourceType RCM_iconBitmapSourceType;
word RCM_iconBitmapSize;
RCMOverwrite RCM_overwrite;
} ReplaceComplexMoniker;
RCM_
textStyleSet
stores a
TextStyle
record of styles that should be set (masked) on top of any currently existing styles.
RCM
_textStyleClear
stores a
TextStyle
record of styles that should be cleared if they are set among the currently existing styles.
RCM
_fontSize
stores the new font size. Pass 0 to indicate no change.
RCM
_topTextSource
stores a dword value containing, or pointing to, the source for the new text. The type of value stored here is indicated in RCM
_topTextSourceType
.
RCM
_iconBitmapSource
stores a dword value containing, or pointing to, the source for the new bitmap. The type of value stored here is indicated in RCM
_iconBitmapSourceType.
RCM_
topTextSourceType
stores the type of text reference contained in RCM_
topTextSource
.
RCM
_iconBitmapSourceType
stores the type of bitmap reference contained in RCM_
iconBitmapSource
.
RCM_iconBitmapSize
stores the size of the icon bitmap, in bytes.
RCM
_overwrite
indicates whether the existing complex moniker chunks should be overwritten. Pass TRUE if you wish this occur.
MSG_COMPLEX_MONIKER_REPLACE_MONIKER
also passes a
ReplaceComplexMonikerChunkHandles
structure. This structure is used to place returned chunk handles of the text and bitmap.
typedef struct {
ChunkHandle RCMCH_topText;
word RCMCH_unusedCX;
ChunkHandle RCMCH_iconBitmap;
word RCMCH_unusedBP;
} ReplaceComplexMonikerChunkHandles;
RCMCH
_
topText
contains the ChunkHandle of the text portion of the new complex moniker.
RCMCH
_iconBitmap
contains the ChunkHandle of the bitmap (graphics) portion of the new complex moniker.
The Foam library provides a number of routines useful for displaying simple dialog boxes to the user. Each of these displays a dialog box. The dialog box will have one or more buttons. Most of the functions have a return value; the function's return value will be an
InteractionCommand
value corresponding to which button the user pressed to dismiss the dialog. The
FoamDisplay...NoBlock()
routines don't have an explicit return value; they send a message if the user presses the OK button.
The following routines are available:
FoamDisplayWarning()
,
FoamDisplayWarningNoBlock()
FoamDisplayError()
,
FoamDisplayErrorNoBlock()
FoamDisplayOkCancelWarning()
InteractionCommand
value; if the user presses the OK button, the function returns IC_APPLY.
FoamDisplayQuestion()
FoamDisplayNote()
,
FoamDisplayNoteNoBlock()
FoamDisplayDeleteWarning()
FoamDisplayDeleteWarningNoBlock()
For dialog box types not provided by these functions, you will have to set up your UI, using GenInteraction objects in the usual way--or you may use the
FlashingNoteClass
or
FoamProcessDialogClass
, described later in this chapter.
Sometimes, you may want to send a notification to a user without requiring the user to respond. Ideally, you would like a dialog box to appear on screen for a few seconds, and then go away, or automatically disappear once any key is pressed. You can get this behavior with a
FlashingNoteClass
object.
You can provide the following parameters to a Flashing Note object:
A Flashing Note should be placed as the root of an unattached tree within its own UI block (resource). In this manner, it will act as a template. To initiate the flashing note, call the routine
PutUpDialogViaUIThread(),
passing the optr of the dialog box template. This routine will copy the template resource, attach it to the application tree, and manage its thread of execution. The dialog will be run within the specific UI thread to avoid blocking the application thread.
Initiating and Destroying the Flashing Note
FlashingNoteClass
only contains one piece of instance data, but it also changes the defaults for its superclass,
GenInteractionClass
.
Code Display 2-9 FlashingNoteClass Instance Data
#define FLASHING_NOTE_DEFAULT_DURATION (3*60) /* 3 seconds */ #define FLASHING_NOTE_DEFAULT_MINIMUM_DURATION (1*60) /* 1 second */
@instance word FNI_duration;
@default GII_attrs = GIA_NOT_USER_INITIATABLE | GIA_SYS_MODAL); @default GII_visibility = GIV_DIALOG; @default GII_type = GIT_MULTIPLE_RESPONSE; @default FNI_duration = FLASHING_NOTE_DEFAULT_DURATION;
@vardata word HINT_FLASHING_NOTE_DESTROY_SELF_AFTER_DISMISS; @vardata word ATTR_FLASHING_NOTE_MINIMUM_DURATION;
FNI
_duration
stores the maximum duration (in ticks -- 1/60ths of a second) for the dialog to remain on-screen. Do not set this to zero; doing so will make the dialog box "permanent" and incapable of dismissal.
Usually, a
FlashingNoteClass
object (and its children) should be contained within their own resource. The resource should remain unattached to the application tree. The routine
PutUpDialogViaUIThread()
will take care of copying and attaching the group of objects.
To set up your template, perform the following steps:
notDetachable
.
FlashingNoteClass
object.
duration
instance field to the number of ticks (1/60ths of a second) you wish to have the dialog box on-screen. By default, this is 180 ticks (3 seconds).
ATTR_FLASHING_NOTE_MINIMUM_DURATION
and set it to the number of ticks (1/60ths of a second) to remain on-screen. By default, this is 60 ticks (one second).
HINT_FLASHING_NOTE_DESTROY_SELF_AFTER_DISMISS
if you don't want to manually destroy it.
HINT_WINDOW_NOT_TITLE_BAR
and
HINT_DRAW_IN_BOX
.Code Display 2-10 FlashingNote Template
@start FlashingNoteTemplateResource, notDetachable;
@object FlashingNoteClass FlashingNoteTemplate = {
GI_states = @default & ~GS_USABLE;
GI_comp = @DialogBoxTemplate;
FNI_duration = 600; /* 10 seconds */
HINT_DRAW_IN_BOX;
HINT_FLASHING_NOTE_DESTROY_SELF_AFTER_DISMISS;
HINT_WINDOW_NO_TITLE_BAR;
ATTR_FLASHING_NOTE_MINIMUM_DURATION = 300; /* 5 seconds */
}
/* * We want a separator, so we will create a sub-group interaction as a complex * moniker. */
@chunk TCHAR DialogTemplateText[] = "Flashing Note";
@object ComplexMonikerClass DialogBoxTemplate = {
ComplexMoniker = GenInteractionClass;
CMI_topText = @DialogTemplateText;
CMI_fontSize = FOAM_NORMAL_FONT_SIZE;
GI_comp = @DialogText;
HINT_PLACE_MONIKER_ABOVE;
HINT_COMPLEX_MONIKER_DRAW_SEPARATOR;
HINT_FIXED_SIZE = { SST_PIXELS | FOAM_DEFAULT_BUBBLE_WIDTH, 0 };
}
@chunk TCHAR DialogTextText[] = "This particular flashing note will stay up a minimum \r of 5 seconds, and will dismiss itself if you press any key after that.\r\r\ It will dismiss itself automatically after 10 seconds.\r";
@object GenTextClass DialogText = {
GTXI_text = @DialogTextText;
GI_attrs = @default | GA_READ_ONLY;
}
@end FlashingNoteTemplateResource;
Initiating the flashing note is simple. Simply call
PutUpDialogViaUIThread()
, passing the optr of the root Flashing Note object.
If that object contains
HINT_FLASHING_NOTE_DESTROY_AFTER_DISMISS
, the dialog will be automatically detached and destroyed after it disappears from view (though the template block will remain untouched, of course).
When performing a time-consuming task, it is wise to prevent user frustration and use a FoamProcessDialogClass which informs the user of the task's progress and offers much-appreciated feedback.
The FoamProgress dialog provides the following functionality:
As with a Flashing Note, a FoamProgress dialog should be placed as the root of an unattached tree within its own UI block (resource). To initiate the Foam Progress dialog, call the routine
PutUpDialogViaUIThread(),
passing the optr of the dialog box template. This routine will copy the template resource, attach it to the application tree, and manage its thread of execution. The dialog will be run within the specific UI thread, avoiding blocking the application thread.
The dialog can be taken down with
TakeDownDialogViaUIThread()
or by placing
HINT_FOAM_PROGRESS_DIALOG_DESTROY_SELF_AFTER_DISMISS
on the object.
FoamProgressDialog Instance Data
FoamProgressDialogClass
contains several pieces of instance data, and also alters the defaults of its superclasses,
GenControlClass
and
GenInteractionClass
.
Code Display 2-11 FoamProgressDialogClass Instance Data
@instance ChunkHandle FPDI_descriptionText = NullChunk; @instance ChunkHandle FPDI_statusText = NullChunk; @instance optr FPDI_cancelDestination = NullOptr; @instance word FPDI_cancelActionMsg = 0;
@vardata void HINT_FOAM_PROGRESS_DIALOG_DESTROY_SELF_AFTER_DISMISS; @vardata void ATTR_FOAM_PROGRESS_DIALOG_DONT_DISMISS_ON_CANCEL;
@default GII_visibility = GIV_POPUP; @default GII_type = GIT_MULTIPLE_RESPONSE; @default GII_attrs = (GIA_NOT_USER_INITIATABLE | GIA_MODAL); @default GI_attrs = GA_SIGNAL_INTERACTION_COMPLETE; @default GI_states = (@default | GS_ENABLED);
_descriptionText
contains text to display to the user, informing them of the task being performed.
statusText
contains text to display next to the status indicator.
_cancelDestination
contains the object that should receive notification (via FPDI
_cancelActionMsg
) if the action is cancelled by the user. The object must be capable of handling cancellation in a clean manner.
cancelActionMsg
stores the message to send if the user cancels the operation. This message will be sent to the FPDI_
cancelDestination
, where it should be handled appropriately.
HINT_FOAM_PROGRESS_DIALOG_DESTROY_SELF_AFTER_DISMISS
indicates that the resource block containing this dialog should be destroyed after the dialog is dismissed. This hint indirectly calls
UserDestroyDialog();
do not use this hint if you will use
TakeDownDialogViaUIThread()
instead.
ATTR_FOAM_PROGRESS_DIALOG_DONT_DISMISS_ON_CANCEL
indicates that the dialog will not be dismissed if the user presses "Cancel." The application is responsible for handling this situation, and eventually dismissing the dialog.
A
FoamProgressDialogClass
object (and its children) should be contained within its own resource. The resource should remain unattached to the application tree. The routine
PutUpDialogViaUIThread()
will take care of copying and attaching the group of objects.
To set up your template, perform the following steps:
notDetachable
.
FoamProgressDialogClass
object.
descriptionText
instance field with text describing the action.
statusText
with text to reside along the status indicator.Code Display 2-12 FoamProgressDialog Template
@start FoamProgressDialogTemplate, notDetachable;
@chunk TCHAR DescriptionText[] = "While, we're waiting a series of dots will appear below."
@chunk TCHAR StatusText[] = "Here are the dots: ";
@object FoamProgressDialogClass ProgressSample = {
FPDI_descriptionText = @DescriptionText;
FPDI_statusText = @StatusText;
GII_attrs = (@default | GIA_SYS_MODAL) & ~GIA_MODAL;
GI_states = (@default) & ~GS_USABLE;
HINT_DRAW_IN_BOX;
}
@end FoamProgressDialogTemplate;
MSG_FOAM_PROGRESS_DIALOG_APPEND_STATUS_TEXT
Code Display 2-13 Using a FoamProgressDialog
static ShowProgressDialog ()
{
optr progressDialog;
word i;
SemaphoreError semResult;
TCHAR statusAppendStr[] = " . ";
progressDialog = PutUpDialogViaUIThread(@FoamProgressDialogTemplate);
for ( i=0; i<5; i++) {
semResult = ThreadPTimedSem(cancelSemaphore, 0);
if (semResult == SE_TIMEOUT) {
@send ProgressDialog::MSG_MY_PROGRESS_DIALOG_CANCEL_RECEIVED();
break;
}
else (
ThreadVSem(cancelSempahore);
TimerSkeep(30);
@call progressDialog::MSG_FOAM_PROGRESS_DIALOG_APPEND_STATUS_TEXT(
statusAAppendStr);
}
}
TimerSleep(30);
TakeDownDialogViaUIThread(progressDialog);
}
/* Handler for MSG_MY_PROGRESS_DIALOG_CANCEL_TRIGGERED */
@method MyProgressDialogClass, MSG_MY_PROGRESS_DIALOG_CANCEL_TRIGGERED
{
SemaphoreError semResult;
semResult = ThreadPSem(cancelSemaphore);
EC_ERROR_IF( (semResult == SE_TIMEOUT), CANNOT_GRAB_SEMAPHORE_CANCELPROGDIALOG); }
/* Handler for MSG_MY_PROGRESS_DIALOG_CANCEL_RECEIVED */
@method MyProgressDialogClass, MSG_MY_PROGRESS_DIALOG_CANCEL_RECEIVED
{
ThreadVSem(cancelSemaphore);
}
There are two routines useful for presenting the user with a list that is alphabetically sorted and/or presents has multi-column items.
The
FoamGetLexicalOrder()
routine is used for alphabetically ordering strings. It takes a char value and returns a byte-size number. This number represents that character's position in a sorted multi-language "alphabet". If you are presenting the user with a sorted list of strings, this is the routine to use to sort the list.
The
CreateVisMonikerLine()
routine puts together a multi-column visual moniker. It puts the moniker together from an array of strings and/or bitmaps you supply. It returns the optr of the new moniker. It takes the following arguments:
VisMonikerColumn
structures: This data contains the data which will be combined into the multi-column moniker.
The
VisMonikerColumn
structure is defined:
typedef struct {
byte VMC_width; /* 0 for bitmaps */
const void * VMC_ptr;
Justification VMC_just;
TextStyle VMC_style;
ColumnBorder VMC_border;
} VisMonikerColumn;
For each field, pass a
VMC_width
to specify the number of pixels to allow to draw the text, or 0 to signal that this column is a bitmap.
VMC_ptr
should point to a string buffer if the column contains text; it should point to a simple bitmap if the column contains a bitmap.
When you are done using the multi-column moniker, it is up to you to free its memory. Get the memory block handle from the optr and pass that handle to
MemFree()
.