Overview of ViewKit ObjectPak Preference Dialogs

Preference dialogs allow users to customize the behavior of an application, but often involve large numbers of text input fields, labels, toggle buttons, and other controls. Without high-level support, these dialogs can take considerable time and effort to write. Also, a user expects preference dialogs to work in a specific way. Typically, a user sets a number of preferences and clicks on an Apply button or an OK button to apply all changes at once. A user also expects to be able to click on Cancel and return all preferences to their previous state, regardless of the number of changes made.

ViewKit ObjectPak supports an easy-to-use collection of classes for building preference dialogs. Rather than dealing directly with widgets and their placement, callbacks, and so forth, you can simply create groups of preference items. These items maintain their own states, allowing an application to query each item for changes. ObjectPak handles layout automatically and provides the ability to apply or revert all preferences to their previous state.

ViewKit ObjectPak Preference Dialog Class

In ViewKit ObjectPak, preference dialogs are implemented as a specialized class of dialog. Specifically, the base preference dialog class, VkPrefDialog, is a subclass of VkGenericDialog, which is in turn a subclass of VkDialogManager. Thus, the VkPrefDialog class inherits all of the functions and data members provided by these base classes.

However, the way you use preference dialogs in your programs differs significantly from to way you use other dialog classes. A single, reusable instance of each type of dialog is sufficient for the other dialog classes. Details such as the message, button labels, or dialog title change from posting to posting, but general dialog behavior remains the same.

VkPrefDialog

On the other hand, individual postings of preference dialogs often vary significantly. Usually, they have different preference items and data structures associated with each preference item. Unlike the other dialog classes, VkPrefDialog does not create a global instance of a preference dialog. Instead, you must create a separate instance of VkPrefDialog for each preference dialog you want to display in your program. For very simple preference dialogs (such as a few toggle buttons), you might be able to directly instantiate a VkPrefDialog object. However, in most cases you should create a separate subclass of VkPrefDialog for each preference dialog in your application.

For each preference dialog, you create a collection of preference items and associate them with the dialog. Each preference item maintains its own state or value, and your program can query the value of preference items as needed. Users can change the values associated with any number of preference items, then click on the Apply button to apply all changes and keep the dialog up, or the OK button to apply all changes and dismiss the dialog. Users can also click on the Cancel button to return all preferences to their last applied values and dismiss the dialog.

The VkPrefDialog class also supplies an ObjectPak callback named prefCallback. The preference dialog activates this callback whenever the user clicks on the dialog's Apply, OK, or Cancel button.

ViewKit ObjectPak Preference Item Classes

The basis for all ViewKit ObjectPak preference item classes is the abstract class VkPrefItem, which is derived from VkComponent. All preference items are derived from the base class VkPrefItem, which provides a common set of manipulation functions.

Preference items can be divided into three groups: those that implement various controls such as text fields, toggles, and option menus; those that are "ornamental"; and those that arrange other preference items and manage them as a group.

Control

The following table describes the preference items that implement controls:

 

 

Preference Item

Description

VkPrefText

A text field.

VkPrefToggle

A single toggle button (you can group multiple toggle buttons into a VkPrefRadio item to enforce radio-style behavior of the buttons).

VkPrefOption

An option menu.

 

 

Ornamental

The following table describes preference items that are ornamental:

 

 

Preference Item

Description

VkPrefLabel

A text label.

VkPrefSeparator

A separator.

VkPrefEmpty

A "null" item that you can use to add extra space between other items.

 

 

Groups

The following table describes preference items that create groups of items:

 

 

Preference Item

Description

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.

VkPrefRadio

A subclass of VkPrefGroup for managing a group of toggle items in a radio box style. You can specify either vertical or horizontal layout; the default is vertical. Items are always padded so that they take equal space. You have the option of displaying a label for the group.

VkPrefList

Defines a group of related items. The VkPrefList class arranges its items vertically. Unlike VkPrefGroup, items are not padded so that they take equal space; instead, each item takes only as much space as it needs. Also in contrast to VkPrefGroup, VkPrefList does not display any label for the group.

 

 

Each preference item maintains its own state or value, and your program can query the value of preference items as needed. Preference items automatically update their stored values when the user clicks on the preference dialog's Apply or OK button, and revert to their previous values when the user clicks on the dialog's Cancel button.

Example 37. Creating a ViewKit Preference Dialog

This example demonstrates how to create the preference dialog shown in Figure 30. using the ObjectPak classes.

Figure 30. Example of an ViewKit ObjectPak Preference Dialog

Code

/////////////////////
// DocPrefDialog.h
/////////////////////
#include <Vk/VkPrefDialog.h>
#include <Vk/VkPrefItem.h>
class DocPrefDialog: public VkPrefDialog {
protected:
VkPrefLabel *dialogName;
VkPrefSeparator *sep1;
VkPrefGroup *numberGroup;
VkPrefSeparator *sep2;
VkPrefRadio *paginationGroup;
VkPrefGroup *textGroup;
VkPrefGroup *horizGroup;
VkPrefList *docList;
static String _defaultResources[];
virtual Widget createDialog(Widget parent);
public:
VkPrefText *firstPageNumber;
VkPrefOption *firstPageSide;
VkPrefToggle *paginSingleSide;
VkPrefToggle *paginDoubleSide;
VkPrefToggle *textQuotes;
VkPrefToggle *textSpaces;
DocPrefDialog ( const char *name );
~DocPrefDialog();
virtual const char* className();
};
///////////////////////
// DocPrefDialog.C
///////////////////////
String DocPrefDialog::_defaultResources[] = {
"*dialogNameBase.labelString: Document Properties",
"*numberGroupLabel.labelString: Numbering:",
"*firstPageNumberLabel.labelString: 1st Page #:",
"*firstPageSideLabel.labelString: 1st Page:",
"*firstPageRight: Right",
"*firstPageLeft: Left",
"*paginationGroupLabel.labelString: Pagination:",
"*paginSingleSideBase.labelString: Single-sided",
"*paginDoubleSideBase.labelString: Double-sided",
"*textGroupLabel.labelString: Text:",
"*textQuotesBase.labelString: Smart Quotes",
"*textSpacesBase.labelString: Smart Spaces",
NULL
};
DocPrefDialog::DocPrefDialog (const char *name) : VkPrefDialog (name)
{
// Empty
}
Widget DocPrefDialog::createDialog(Widget parent) {
setDefaultResources(parent, _defaultResources);
dialogName = new VkPrefLabel("dialogName");
sep1 = new VkPrefSeparator("sep1");
firstPageNumber = new VkPrefText("firstPageNumber");
firstPageSide = new VkPrefOption("firstPageSide", 2);
firstPageSide->setLabel(0, "firstPageRight");
firstPageSide->setLabel(1, "firstPageLeft");
numberGroup = new VkPrefGroup("numberGroup");
numberGroup->addItem(firstPageNumber);
numberGroup->addItem(firstPageSide);
sep2 = new VkPrefSeparator("sep2");
paginSingleSide = new VkPrefToggle("paginSingleSide");
paginDoubleSide = new VkPrefToggle("paginDoubleSide");
paginationGroup = new VkPrefRadio("paginationGroup");
paginationGroup->addItem(paginSingleSide);
paginationGroup->addItem(paginDoubleSide);
textQuotes = new VkPrefToggle("textQuotes");
textSpaces = new VkPrefToggle("textSpaces");
textGroup = new VkPrefGroup("textGroup");
textGroup->addItem(textQuotes);
textGroup->addItem(textSpaces);
horizGroup = new VkPrefGroup("horizGroup", TRUE, TRUE);
horizGroup->addItem(paginationGroup);
horizGroup->addItem(textGroup);
docList = new VkPrefList("docList");
docList->addItem(dialogName);
docList->addItem(sep1);
docList->addItem(numberGroup);
docList->addItem(sep2);
docList->addItem(horizGroup);
setItem(docList);
Widget base = VkPrefDialog::createDialog(parent);
return(base);
}
DocPrefDialog::~DocPrefDialog()
{
delete firstPageNumber;
delete firstPageSide;
delete paginSingleSide;
delete paginDoubleSide;
delete textQuotes;
delete textSpaces;
delete dialogName;
delete sep1;
delete numberGroup;
delete sep2;
delete paginationGroup;
delete textGroup;
delete horizGroup;
delete docList;
}
const char* DocPrefDialog::className()
{
return "DocPrefDialog";
}

To post this dialog, create an instance of the DocPrefDialog class and use one of the post() functions described in "Posting Dialogs" . For example:

DocPrefDialog *docPref = new DocPrefDialog("docPref");
// ...
docPref->post();

Retrieve the value of a preference item with the getValue() function, as described in "Obtaining and Setting Preference Item Values" . For example:

Boolean smartSpaces;
// ...
smartSpaces = docPref->textSpaces->getValue();