ViewKit Preference Item Classes

The following sections describe preference item classes provided by ViewKit ObjectPak. In addition to the specific member functions listed, each class also supports all functions provided by the VkPrefItem class.

Text Fields

The VkPrefText class supports text field preference items, allowing users to enter text strings. Figure 31. shows a simple preference dialog containing a text field preference item.

Figure 31. Example of a Text Field Preference Item

The VkPrefText constructor has the following form:

VkPrefText(const char *name, int columns = 5)

The VkPrefText constructor expects as its first argument the name of the preference item. You can optionally provide as a second argument an integer value specifying the default number of columns for the text field.

For example, creating the text field shown in Figure 31. requires only the following line:

VkPrefText *name = new VkPrefText("name");

To set the label for the text field, you must set the XmNlabelString resource of the preference item's label widget. Therefore, to set the label as shown in Figure 31., you must set the following resource:

*nameLabel.labelString: Enter your name:

Refer to "Preference Item Labels" for more information on setting the label of a preference item.

Retrieving text field value

To retrieve the internally-stored text field value, use the getValue() function:

char *getValue()

getValue() duplicates the internal value and then returns a pointer to the duplicate string. (You should free this string when you no longer need it.) For example, the following line retrieves the value of the name text field shown above:

userName = name->getValue();

Setting text field value

To programmatically set the text field value, use the setValue() function:

void setValue(const char *str)

setValue() copies the string that you pass as an argument, sets the internally-stored value to that string, and updates the value displayed by the text field. For example, the following line sets the value of the name text field shown above to "John Doe:"

name->setValue("John Doe");

Toggle Buttons

The VkPrefToggle class supports a single toggle button preference item. You can group multiple toggle buttons using a VkPrefGroup or VkPrefList item, and you can enforce radio-style behavior on a group of toggles by grouping them in a VkPrefRadio item. These classes are discussed later in this chapter.

Figure 32. shows a simple preference dialog containing a single toggle button preference item.

Figure 32. Example of a Toggle Button Preference Item

The VkPrefToggle constructor has the following form:

VkPrefToggle(const char *name, Boolean forceLabelFormat = FALSE)

The first argument the VkPrefToggle constructor expects is the name of the preference item. For example, creating the toggle button shown in Figure 32. requires only the line:

VkPrefToggle *erase = new VkPrefToggle("erase");

You can provide an optional Boolean value as a second argument to the VkPrefToggle constructor. A TRUE value forces the VkPrefToggle object to create and use a label widget as described in "Preference Item Labels" . Otherwise, if the value is FALSE, the behavior of the label is determined as described below in "Toggle Buttons." The default value is FALSE.

Setting toggle preference item labels

Setting the label for a toggle preference item is more complex than with other preference items. Unlike many of the other preference items, the ToggleButton widget that is the base widget of the VkPrefToggle item includes a text label. Therefore, to set that label, you must set the XmNlabelString resource of the preference item's base widget instead of its label widget. For example, to set the label as shown in Figure 32., you must set the resource:

*eraseBase.labelString: History Erase

This works for all cases except for when a toggle is an item in a vertical VkPrefGroup or VkPrefRadio item that contains items other than toggles. (A group that contains more than one type of preference item is a non-homogenous group; a group that contains only one type of preference item is a homogenous group.) To understand why this is done, consider first a simple vertical VkPrefGroup containing only two toggles, as shown in Figure 33. In this case, the labels appear to the right side of the buttons as they normally do.

Figure 33. Toggle Preference Items in a Homogenous Vertical Group

When toggle items appear in a homogenous group like the one shown in Figure 33., you should set the XmNlabelString resources for the base widgets of the toggle items. For example:

*firstToggleBase.labelString: Toggle One
*secondToggleBase.labelString: Toggle Two

However, the labels for most other preference items appear to the left of the items. Left uncorrected, if a vertical, non-homogenous VkPrefGroup or VkPrefRadio contained a toggle item, the label for the toggle would not align with the other labels.

Therefore, in the case of a non-homogenous vertical VkPrefGroup or VkPrefRadio, ObjectPak sets the XmNlabelString resource of all toggle items' base widgets to NULL and instead displays their label widgets.

The result is that all of the preference items' labels correctly align, as shown in Figure 34.:

Figure 34. Toggle Preference Items in a Non-Homogenous Vertical Group

When toggle items appear in a non-homogenous, vertical group like the one shown in Figure 34., you should set the XmNlabelString resources for the label widgets of the toggle items rather than the base widgets. For example:

*firstToggleLabel.labelString: Toggle One
*secondToggleLabel.labelString: Toggle Two

Note: If you provide the Boolean value TRUE as a second argument to the VkPrefToggle constructor, the VkPrefToggle object always creates and uses a label widget instead of using the base widget's text label.


Refer to "Preference Item Labels" for more information on setting the label of a preference item.

Getting and setting toggle preference item values

Use the getValue() function to retrieve the Boolean value of the toggle:

Boolean getValue()

For example, the following line retrieves the value of the firstToggle toggle shown above:

toggleSet = firstToggle->getValue();

Use the setValue() function to programmatically set the value of the toggle:

void setValue(Boolean value)

setValue() sets the internally-stored value to the Boolean value you pass as an argument, and updates the value displayed by the toggle. For example, the following line sets the value of the secondToggle toggle shown above to TRUE:

secondToggle->setValue(TRUE);

Option Menus

The VkPrefOption class supports option menu preference items, allowing users to select an option from a menu. Figure 35. shows a simple preference dialog containing an option menu preference item.

Figure 35. Example of an Option Menu Preference Item

The VkPrefOption constructor has the following form:

VkPrefOption(const char *name, int numEntries)

The VkPrefOption constructor expects as its first argument the name of the preference item. The second argument is an integer value specifying the number of entries in the option menu.

For example, you can create the option menu shown in Figure 35. with the line:

VkPrefOption *align = new VkPrefOption("align", 3);

Setting option menu preference item labels

To set the label for the option menu you must set the XmNlabelString resource of the preference item's label widget. Therefore, to set the label as shown in Figure 35., you must set the resource:

*alignLabel.labelString: Alignment

Refer to "Preference Item Labels" for more detailed information.

To set the labels for the individual items in the option menu, use the setLabel() function:

void setLabel(int index, const char *label)

setLabel() expects two arguments. The first is an integer value specifying the index of the of the menu item. Menu items are numbered starting with 0.

The second setLabel() argument is a character string, first treated as a resource name looked up relative to the menu item's widget. If the resource value exists, it is used as the label. If no resource is found, or if the string contains spaces or newline characters, the string itself is used as the label.

For example, the following lines set the labels for the option menu items shown in Figure 35. directly:

align->setLabel(0, "Align Left");
align->setLabel(1, "Align Center");
align->setLabel(2, "Align Right");

On the other hand, the following lines set the labels using resource values:

align->setLabel(0, "alignLeft");
align->setLabel(1, "alignCenter");
align->setLabel(2, "alignRight");

In the second case, you would also have to set the appropriate resource values. You could do so using the setDefaultResources() function, or you could include the following lines in a resource file:

*align*alignLeft: Align Left
*align*alignCenter: Align Center
*align*alignRight: Align Right

You can retrieve the label for a given item using the getLabel() function:

char *getLabel(int index)

index is the index of the menu item.


Note: getLabel() returns the same string that you passed to setLabel() when setting the item's label. Therefore, if you set the item's label by specifying a resource name, getLabel() returns the resource name, not the value of the resource.


Dynamically changing the number of option menu items

In the VkPrefOption constructor, you must provide an argument specifying the number of elements in the option menu. However, after creating an option menu preference item, you can resize it as needed using the setSize() function:

void setSize(int numEntries)

setSize() accepts an integer argument specifying the new size of the option menu. If the new size is smaller than the old size, setSize() automatically deletes all unneeded widgets. If the new size is larger, setSize() automatically creates and manages any additional widgets needed.

You can determine the current size of an option menu preference item using the size() function:

int size()

You can access any of the button widgets contained in the option menu with the getButton() function:

Widget getButton(int index)

Simply specify the index of the button you want and getButton() returns the appropriate widget.

Getting and setting option menu preference item values

Use the getValue() function to retrieve the internally-stored value of the option menu:

int getValue()

getValue() returns an integer value specifying the index of the selected menu entry. For example, the following line retrieves the value of the align text field shown above:

alignment = align->getValue();

Use the setValue() function to programmatically set the value of the option menu:

void setValue(int index)

setValue() sets the internally-stored value to the index value you pass as an argument, and updates the value displayed by the option menu. For example, the following line sets the value of the alignment text field shown above to 1, corresponding to the "Align Center" option:

align->setValue(1);

Labels

The VkPrefFigure 36.Label class supports text labels for preference dialogs.


Note: VkPrefLabel is useful only in conjunction with VkPrefList. Do not use VkPrefLabel with either VkPrefGroup or VkPrefRadio; VkPrefLabel does not create a label widget and, therefore, it does not align properly with other items contained in a VkPrefGroup or VkPrefRadio item.


Figure 36. shows a preference dialog that contains a label preference item.

Figure 36. Example of a Label Preference Item

The VkPrefLabel constructor expects the name of the preference item as a value:

VkPrefLabel(const char *name)

For example, creating the label shown in Figure 36. requires only the line:

VkPrefLabel *dialogName = new VkPrefLabel("dialogName");

Many other ObjectPak preference items include label widgets in addition to their base widget; however, in the case of the VkPrefLabel item, the label is the base widget. Therefore, in preference item groups, a VkPrefLabel item aligns with other base widgets, not with other label widgets.

Because the label that is displayed for a VkPrefLabel item is the base widget, you set the label's text by setting the XmNlabelString resource of the item's base widget. Therefore, to set the label as shown in Figure 36., you must set the resource:

*dialogNameBase.labelString: Document Properties

Refer to "Preference Item Labels" for more detailed information.

Separators

The VkPrefSeparator class supports a simple separator for use in preference dialogs.


Note: VkPrefSeparator is useful only in conjunction with VkPrefList. You should not use VkPrefSeparator with either VkPrefGroup or VkPrefRadio; VkPrefSeparator does not create a label widget and therefore it does not align properly with other items contained in a VkPrefGroup or VkPrefRadio item.


The only argument the VkPrefSeparator constructor expects is the name of the preference item:

VkPrefSeparator(const char *name)

For example:

VkPrefSeparator *sep = new VkPrefSeparator("sep");

Empty Space Preference Items

The VkPrefEmpty class provides a "null" item that you can use to add extra space between other items. This preference item is useful only in conjunction with one of the grouping preference items: VkPrefGroup, VkPrefRadio, or VkPrefList.

The VkPrefEmpty constructor accepts no arguments:

VkPrefEmpty()

For example:

VkPrefEmpty *space = new VkPrefEmpty();

Groups of Preference Items

ViewKit ObjectPak provides three classes for creating groups of items: VkPrefGroup, VkPrefRadio, and VkPrefList. Both VkPrefRadio and VkPrefList are implemented as subclasses of VkPrefGroup.

Comparison of group preference items

VkPrefGroup defines a group of related items. You can specify either vertical or horizontal layout; the default is vertical. With a vertical layout, VkPrefGroup pads items so that they take equal space. You have the option of displaying a label for the group.

Figure 37. shows an example of a vertical VkPrefGroup item with a label. The label is the group item's label widget, not a VkPrefLabel item. The VkPrefGroup item right-aligns the labels for all of the items it contains. (Because the VkPrefToggle items are part of a non-homogenous VkPrefGroup item, you must set the XmNlabelString resources of their label widgets instead of their base widgets, as described in "Toggle Buttons" .) Also, all items are allocated the same amount of vertical space. If you were to add a larger item to this group, the group item would allocate for each item the same amount of vertical space.

Figure 37. Example of a Vertical VkPrefGroup Item with Label

Figure 38. shows the same preference items grouped by a horizontal VkPrefGroup item with a label.

Figure 38. Example of a Horizontal VkPrefGroup Item with Label

VkPrefList is similar to VkPrefGroup; however, it supports only a vertical orientation and it does not support displaying a group label. Unlike VkPrefGroup, VkPrefList does not pad its items so that they take equal space; instead, each item takes only as much space as it needs. Typically, you use a VkPrefList item to group other group items. For example, in Example 37., the top-level VkPrefList item contained a VkPrefLabel item and two VkPrefGroup items--one vertical and one horizontal--separated by two VkPrefSeparator items.

VkPrefList is also the only grouping item to which you should add VkPrefLabel or VkPrefSeparator items. You should not use VkPrefLabel or VkPrefSeparator with either VkPrefGroup or VkPrefRadio; they do not create label widgets and therefore do not align properly with other items contained in a VkPrefGroup or VkPrefRadio item.

Figure 39. shows an example of a VkPrefList.

Figure 39. Example of a VkPrefList Item


Note: The VkPrefList item does not contain a group label; if you want to provide a label for a VkPrefList item, you can include a VkPrefLabel item in it. Also. the VkPrefList item does not align the labels of the items it contains. (Because the VkPrefToggle items are part of a VkPrefList item, you must set the XmNlabelString resources of their base widgets instead of their label widgets, as described in "Toggle Buttons" on page 230.) Each item is allocated only as much vertical space as it needs. If you were to add a larger item to this group, it would not affect the vertical spacing of the other items.


VkPrefRadio is almost identical to VkPrefGroup except that you use it only for enforcing radio-style behavior on the VkPrefToggle items that it contains. You should add only VkPrefToggle items to a VkPrefRadio item. Otherwise, VkPrefRadio supports the same functionality as VkPrefGroup.

Figure 40. shows an example of a vertical VkPrefRadio item with a label. The label is the group item's label widget, not a VkPrefLabel item. Because the VkPrefToggle items are part of a homogenous VkPrefRadio item, you must set the XmNlabelString resources of their base widgets instead of their label widgets, as described in "Toggle Buttons" .

Figure 40. Example of a Vertical VkPrefRadio Item with Label

Creating group preference items

The VkPrefGroup constructor has the following form:

VkPrefGroup(const char *name,
Boolean horizOrientation = FALSE,
Boolean noLabel = FALSE)

The VkPrefGroup constructor expects as its first argument the name of the preference item. The second argument is an optional Boolean value that determines the orientation of the group; FALSE, the default value, specifies a vertical orientation and TRUE specifies a horizontal orientation. The third argument is an optional Boolean value that determines whether or not to display a label for the group; FALSE, the default value, specifies that the group should display the label and TRUE specifies that the group should not display the label.

For instance, Example 37. contained the following constructor:

VkPrefGroup *numberGroup = new VkPrefGroup("numberGroup");

This created a new VkPrefGroup item named "numberGroup" with a vertical orientation and a visible label. Example 37. also contained the following constructor:

VkPrefGroup *horizGroup = new VkPrefGroup("horizGroup",
TRUE, TRUE);

This created a new VkPrefGroup item named "horizGroup" with a horizontal orientation and no visible label.

The VkPrefRadio constructor accepts the same arguments as the VkPrefGroup constructor:

VkPrefRadio(const char *name,
Boolean horizOrientation = FALSE,
Boolean noLabel = FALSE)

For instance, Example 37. contained the following constructor:

VkPrefRadio *paginationGroup = new VkPrefRadio("paginationGroup");

This created a new VkPrefRadio item named "paginationGroup" with a vertical orientation and a visible label.

VkPrefList accepts only one argument, a character string specifying the name of the item:

VkPrefList(const char *name)

As noted earlier, all VkPrefList items have a vertical orientation and do not display a label. Example 37. created a VkPrefList item as the top-level preference item to contain all other preference items:

VkPrefList *docList = new VkPrefList("docList");

Adding and deleting preference items from a group item

After creating a group item, you can add other items to it with the addItem() function:

void addItem(VkPrefItem *item)

Preference items appear in the order in which you add them. Example 37. added five preference items to the docList preference item:

docList->addItem(dialogName);
docList->addItem(sep1);
docList->addItem(numberGroup);
docList->addItem(sep2);
docList->addItem(horizGroup);

Once you have added items to a group item, you can access an individual child item with the item() function:

VkPrefItem *item(int item)

Provide an integer index value as an argument and item() returns a pointer to the desired preference item. The numbering of preference items within a group begins with 0, so to retrieve a pointer to the numberGroup item added above to docList, you could use the line:

item = docList->index(2);

The size() function returns the number of preference items currently associated with a group item:

int size()

The deleteChildren() function deletes all the items contained by a group item:

virtual void deleteChildren()

Note that this function does not just disassociate the items from the parent group item, it actually deletes the items. This is useful for freeing memory in a destructor. ObjectPak does not provide any means of disassociating preference items without deleting them or of deleting individual items in a group. This should not pose a problem as most applications create preference dialogs at startup and almost never need to modify them afterwards.

Monitoring preference item values

The group preference items provide a changed() function just like all other preference items; however changed() operates differently with group items than it does with individual preference items. In group items, changed() calls the changed() functions of all child items in the group and returns TRUE if any of the child items have changed.

Setting group item labels

To set the label for a VkPrefGroup or VkPrefRadio item, you must set the XmNlabelString resource of the preference item's label widget. (Remember that VkPrefList items do not display labels.) Example 37. illustrated this by setting the labels for numerous group items:

*numberGroupLabel.labelString: Numbering:
*paginationGroupLabel.labelString: Pagination:
*textGroupLabel.labelString: Text:

Refer to "Preference Item Labels" for more information on setting the label of a preference item.