This document is a single-page version of a a multi-page document, suitable for easy printing.

Communicator UI

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:


Communicator UI: 0 Foam UI Classes Overview

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.

FFileSelectorClass

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.


An example of a FFileSelectorClass file selector.

Include: foam.goh

Reference: FileOpenControlClass, FFileSelectorClass.

ExtendedFileSelectorClass

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.

ComplexMonikerClass

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:

While each of the above items behaves quite differently, they all share the ComplexMonikerClass behavior of displaying a text and icon moniker.

Include: foam.goh

Reference: ComplexMonikerClass, GenTriggerClass, GenInteractionClass, GenItemGroupClass, GenItemClass, GenBooleanGroupClass, GenDynamicListClass, or ContactListClass.

TwoLevelTriggerClass

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

FoamSubApplicationClass

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.

GreyFrameClass

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.

ListWithUserDefinedClass

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.

RepeatingGenGlyphClass

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.


Dialogs

FlashingNoteClass

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.

SelfDestroyingDialogClass

Inherits: GenInteractionClass

The SelfDestroyingDialogClass is used to put up a dialog box that self-destructs upon dismissal.

Include: foam.goh

Reference: SelfDestroyingDialogClass, GenInteractionClass.

FoamProgressDialogClass

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.


Indicator Classes

The indicator classes exist in the foam library to facilitate drawing the status indicator at the left of the Nokia 9000i Communicator screen. As such, they are usually not as useful as Gen classes. Below is a brief listing of these classes followed by a screen shot of several UI objects which instantiate these classes.

GreyGenInteractionClass

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 .

IndicatorClass

Inherits: GenGlyphClass

An IndicatorClass object is a GenGlyph that draws an etched border around itself.

Include: foam.goh

Reference: IndicatorClass, GenGlyphClass .

IconIndicatorClass

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.

LevelIndicatorClass

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.

IndicatorInteractionClass

Inherits: IndicatorClass

This makes a GenInteraction with an etched border.

Include: foam.goh

Reference: IndicatorInteractionClass, GenInteractionClass.


Filter Lists

FilterListClass

Inherits: GenDynamicListClass

See below for description.

FilterTextClass

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.


Underlined Text

UnderlinedGenTextClass

Inherits: GenTextClass

See below for description.

UnderlinedVisTextClass

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.


Text Style Controllers

FoamTextStyleControlClass

Inherits: GenControlClass

See below for description.

FoamFontControlClass

Inherits: GenControlClass

See below for description.

FoamPointSizeControlClass

Inherits: GenControlClass

See below for description.

FoamJustificationControlClass

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.


Communicator UI: 1 FoamSubApplicationClass

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 .


Communicator UI: 1.1 FoamSubApplicationClass: FoamSubApplicationClass Instance Data

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:

FA_SERVICES_APP
FA_SYSTEM_APP
FA_EXTRAS_APP

Communicator UI: 1.2 FoamSubApplicationClass: Using a FoamSubApplication Object

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;
}

Communicator UI: 2 ComplexMonikerClass

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.


Communicator UI: 2.1 ComplexMonikerClass: ComplexMoniker Instance Data

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;

The ComplexMoniker Keyword

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.

The ComplexMoniker Text

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.

CMT_NULL
Never set a moniker to this value. It exists purely as a placeholder.
Basic strings:
CMT_OK
CMT_CLOSE
CMT_CANCEL
CMT_YES
CMT_NO
Command strings:
CMT_CLEAR
CMT_CLEAR_ALL
CMT_CHANGE
CMT_RENAME
CMT_COPY
CMT_SETTINGS
CMT_OPEN
CMT_CREATE_NEW "New"
CMT_DELETE
CMT_ROTATE
CMT_SELECT
CMT_START
CMT_GO
CMT_INSTALL
CMT_DEINSTALL "Remove"
CMT_NEXT
CMT_PREVIOUS
CMT_USER_DEFINED "User defined:"
CMT_ZOOM
CMT_ZOOM_IN
CMT_ZOOM_OUT
CMT_VIEWING_TOOLS
CMT_OPTIONS
Communication strings:
CMT_PHONE "On"
CMT_CALL
CMT_CALL_LOWERCASE "Call"
CMT_SEND
CMT_SEND_OPTIONS
CMT_CONNECT
CMT_CALLS
CMT_FAXES
CMT_DATA_CALLS
CMT_MESSAGES
CMT_RECENT_CALLS
CMT_RECENT_FAXES "Recent numbers"
CMT_RECENT_MESSAGES "Recent numbers"
CMT_RECEIVED_CALLS
CMT_RECEIVED_FAXES "Received fax numbers"
CMT_RECEIVED_MESSAGES "Received message numbers"
CMT_MISSED_CALLS
CMT_LAST_DIALED_CALLS "Dialed calls"
CMT_TO_COLON "To:"
CMT_FROM_COLON "From:"
CMT_TEXT_SEND "Send text"
CMT_TEXT_CAPTURE "Capture text"
CMT_CAPTURE
CMT_STOP_CAPTURE
CMT_FORWARD_FAX "Forward"
CMT_SELECT_RECEIVER "Recipient"
CMT_HANGUP
CMT_FORWARD
CMT_REPLY
Miscellaneous commands:
CMT_CLEAR_LIST
CMT_NO_CONTACT_INFORMATION "No log information"
CMT_CONTACT_CARD
CMT_NONE
CMT_CLEAR_ALL_COMMAND
CMT_ACCEPT
CMT_RESET
CMT_STOP
CMT_ACTIVATE
CMT_DISABLE
CMT_HELP
CMT_BACK
CMT_SPECIAL_KEYS_COMMAND "Keys"
CMT_SPECIAL_KEYS
CMT_TEXT
CMT_TEXTS
CMT_ZOOM_PLUS "Zoom in"
CMT_ZOOM_MINUS "Zoom out"
CMT_INSERT
CMT_OFF
CMT_ON
CMT_MENU /* Not available on build 4.8.8 or earlier versions of the Communicator */
CMT_SEARCH /* Not available on build 4.8.8 or earlier versions of the Communicator */

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;
}

The ComplexMoniker Icon Bitmap

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:

CMB_LEFT_FINGER
CMB_RIGHT_FINGER
CMB_CONTACT_CARD
CMB_CONTACT_LIST
CMB_SPEED_DIAL
CMB_SETTINGS_TITLE_ICON
CMB_SERVICES_VIEW
CMB_SERVICES_DEFINE
CMB_QUESTION_ICON
CMB_OPEN_FOLDER
CMB_DRAWER
CMB_RENAME_COPY
CMB_FOLDER
CMB_SECURITY_SUCCESS
CMB_SECURITY_ERROR
CMB_PC_ICON
CMB_INPUT_TITLE_ICON
CMB_WARNING_TITLE_ICON
CMB_SEARCH /* Not available on build 4.8.8 or earlier versions of the Communicator */
CMB_SMS_CARD_ICON /* Not available on build 4.8.8 or earlier versions of the Communicator */

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:

@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, ...
};

Text Styles

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:

TS_BOLD (default)
TS_OUTLINE
TS_ITALIC
TS_SUPERSCRIPT
TS_SUBSCRIPT
TS_STRIKE_THRU
TS_UNDERLINE

Font Sizes

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.

ComplexMoniker Vardata

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.


Communicator UI: 2.2 ComplexMonikerClass: ComplexMoniker Usage

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:

(If you are not creating a command trigger, set CMI _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!";

Communicator UI: 2.3 ComplexMonikerClass: ComplexMoniker Messages

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.


Communicator UI: 3 Convenient Dialog Routines

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()
These routines present a dialog box notifying the user about an action. The user may dismiss the dialog, but may not cancel the action. The function takes one argument, the optr of a string buffer to display. This function has no return value.
FoamDisplayError() , FoamDisplayErrorNoBlock()
These routines present a dialog box notifying the user that an error has occurred. The user may dismiss the dialog via the OK button. The function takes one argument: the optr of the string buffer containing the text to display. The function has no return value.
FoamDisplayOkCancelWarning()
This function presents the user with a warning in an OK/Cancel dialog. The function takes one argument: the optr of the string buffer to display. This function returns an InteractionCommand value; if the user presses the OK button, the function returns IC_APPLY.
FoamDisplayQuestion()
This routine presents a Yes/No dialog. It takes one argument, the optr of the text buffer containing the string to display. If the user presses the Yes button, the function will return IC_YES.
FoamDisplayNote() , FoamDisplayNoteNoBlock()
These functions display an OK dialog box displaying a text message to the user. The function takes one argument, the optr to a string buffer with the text to display.
FoamDisplayDeleteWarning()
This routine presents an OK/Cancel dialog box asking for a file deletion confirmation. This function takes three arguments: a pointer to a string buffer containing the file name, and optrs to two string chunks: one to display before the file name, and one to display after. If the function returns IC_YES, the user has confirmed that the file should be deleted.
FoamDisplayDeleteWarningNoBlock()
This routine presents an OK/Cancel dialog box asking for a file deletion confirmation. This function takes three arguments: the optr of the text string asking the user for confirmation, the message to send if the Delete button is pressed, and the object to send that message to. This function has no explicit return value. If the user Cancels the dialog, it won't send any message.

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.


Communicator UI: 4 FlashingNoteClass

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.


Communicator UI: 4.1 FlashingNoteClass: FlashingNote Instance Data

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.


Communicator UI: 4.2 FlashingNoteClass: Setting Up the Template

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:

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;

Communicator UI: 4.3 FlashingNoteClass: Initiating and Destroying the Flashing Note

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).


Communicator UI: 5 FoamProgressDialog

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.


Communicator UI: 5.1 FoamProgressDialog: 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);
 
FPDI _descriptionText contains text to display to the user, informing them of the task being performed.
FPDI_ statusText contains text to display next to the status indicator.
FPDI _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.
FPDI_ 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.

Communicator UI: 5.2 FoamProgressDialog: Setting Up the Template

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:

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;

Communicator UI: 5.3 FoamProgressDialog: Using a FoamProgressDialog

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);
}

Communicator UI: 6 Routines for Lists

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:

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() .


This document is a single-page version of a a multi-page document, suitable for easy printing.