TweetFollow Us on Twitter

September 95 - Multipane Dialogs

Multipane Dialogs

Norman Franke

As applications grow in power and complexity, so does the tendency to present users with numerous cluttered dialog boxes. To simplify the user interface, developers are moving increasingly to dialogs with multiple panes. This article describes how to implement multipane dialogs that users navigate by clicking in a scrolling list of icons.

Dialog boxes with multiple panes ("pages" of controls) are an increasingly popular element of the Macintosh user interface. Like simple dialogs, multipane dialogs can be presented when users need to indicate preferences, set attributes of text or graphic objects, or give specifications for complex operations such as searches or formatting, among other things. By grouping related options and providing a single point of interaction for manipulating them, multipane dialogs simplify life for the user and the developer.

Five different kinds of controls for navigating multipane dialogs are in general use: the scrolling list of icons, the pop-up menu, index tabs (simulating the look of tabs on the tops of file folders in a file cabinet), Next/Previous buttons, and icon button sets. Although there aren't any hard-and-fast rules about when you should use one over another, these considerations (suggested by Elizabeth Moller of Apple's Human Interface Design Center) generally apply:

  • Novice users have trouble with pop-up menus, so choose a different kind of control if your target audience includes large numbers of these users.

  • Index tabs work well for small numbers of panes, but they may not work well when the tabs start overlapping or the number of panes is variable.

  • Next/Previous buttons are a good choice when there's more than one mandatory pane. They make it easy for users to step through mandatory and optional panes in sequence.
The sample application MPDialogs on this issue's CD demonstrates the use of a multipane preferences dialog navigated by clicking in a scrolling list of icons, similar to the Control Panel in System 6 and print dialogs in QuickDraw GX. After describing the user interface presented by this sample program, I'll go into the details of how to implement a similar multipane dialog in your own application. Source code for the routines I'll discuss is also included on the CD. This code requires System 7 and is compatible with both black-and-white and color displays.

WHAT THE USER INTERFACE LOOKS LIKE

To experience how multipane dialogs work, run the sample program MPDialogs. When you choose Preferences from the File menu, you'll be presented with the interface shown in Figure 1. This is a good illustration of the elements of a multipane dialog.

Figure 1. The Communications pane of the sample multipane dialog

The long vertical rectangle on the left side of the dialog box contains the pane selection icon list. Each icon in this scrolling list has a one-word label under it for identification and represents one pane of the dialog, which is displayed when the user clicks the icon. If you click the Defense icon, for instance, you'll see the pane shown in Figure 2. The arrow and tab keys on the keyboard can also be used to change the pane selection; however, if the current pane contains multiple editable text fields, the tab key will work as in a normal dialog and move the cursor to the next text field.

Figure 2. The Defense pane of the sample multipane dialog

The bottom portion of the dialog below the line contains two buttons that act on the dialog as a whole: Cancel and OK. The OK button accepts the settings and Cancel aborts all changes and closes the dialog. The two buttons above the line act only on the current pane and are optional: Revert restores the control values in the current pane to what they were when that pane was last opened, and Use Defaults resets the control values in that pane to factory defaults.

The large region above the buttons is where the pane's controls are placed. The sample code supplied on the CD handles actions for checkboxes, radio button groups, and pop-up menus. Command-key equivalents can be used to toggle checkboxes and radio buttons, in addition to the standard keyboard equivalents for OK (Return/Enter) and Cancel (Escape/Command-period). After experimenting with making changes to the control values in the sample program, you can choose Display from the File menu to see the results of your changes.

A couple of custom capabilities can be added to a pane through optional procedures:

  • taking special action such as dimming or undimming other controls when items are clicked

  • performing data validation such that if validation fails, the user isn't permitted to change panes or exit the dialog with the OK button
These two capabilities are demonstrated in the sample multipane dialog. When you click the Enable Self-Destruct checkbox in the Defense pane, the Self-Destruct checkbox is undimmed. When you enter nondigits in the editable text field in the Communications pane, data validation fails and you're unable to change panes or click OK.

Note that multipane dialogs, like simple dialogs, can take one of three forms:

  • standard modal dialog -- a dialog that has a border around it and no title bar, that can't be moved around on the screen, and that stays frontmost as long as it's open

  • movable modal dialog -- a dialog that has a border around it and a title bar, that can be moved around on the screen, and that stays frontmost as long as it's open and the application is frontmost

  • modeless dialog -- a dialog that looks and behaves like a normal document window with a title bar and a close box, and that isn't always frontmost
The sample program displays a movable modal dialog, but the code provided supports all three forms.

That's all there is to the interface. For some words of wisdom about things to take into account as you design your own multipane dialogs, see "Tips for Designing Multipane Dialogs." Now we'll move along to the details of how to incorporate the multipane dialog routines on the CD into your own application: the resources you need to define, the calls to make to the main routines to open the dialog and handle events, and the customizing you can do with optional procedures.

TIPS FOR DESIGNING MULTIPANE DIALOGS

BY ELIZABETH MOLLER OF APPLE'S HUMAN INTERFACE DESIGN CENTER

A multipane dialog is appropriate only when the panes you're presenting are obviously related to one another in some way. With that caveat in mind, here are some suggestions for making your multipane dialogs easy to understand and use:

  • Provide a sentence or title to help clarify your intent. For example, you might precede a scrolling list of icons in a preferences dialog with a sentence like "Select items from this list to set your SurfWriter preferences."

  • If you use an icon list, label the icons in your list to help users recognize them.

  • Visually separate buttons that apply only to the current pane from those that work on all panes (like OK and Cancel in a modal dialog).

  • Don't change the size of the dialog or window as the user navigates from pane to pane. Pick a size that accommodates the pane with the most controls.

  • Design the dialog so that changing the settings in one pane doesn't change the settings in another. For example, clicking a checkbox in one pane shouldn't disable a checkbox in another pane, because the user won't see the latter action occur and thus won't understand the cause and effect.

  • Be consistent in your use of controls. If you use a particular type of control to mean "choose a setting," for instance, don't use the same type of control to mean "navigate between panes" in the same dialog. Users should be able to easily distinguish controls that navigate through multiple panes from controls that make choices in the dialog.

  • Order the panes from mandatory to optional, by frequency of use, from general to specific, or, when no other order is apparent, alphabetically. If there are mandatory fields and controls, be sure to put them in the first pane or step the user through mandatory panes before optional ones.

  • When the dialog is closed, remember the pane that was last used, unless there are mandatory controls in a pane. If there is a mandatory pane, it should always be displayed when the dialog reopens.

DEFINING NEEDED RESOURCES

The first step in incorporating the multipane dialog routines is to define the custom resources the code needs. You'll find ResEdit TMPL templates for all the needed resources on the CD. You can put these in the ResEdit Preferences file to make them available at all times or leave them in the application you're editing.

The first resource that needs to be created is the main DLOG and its associated DITL, which will form the basis for the dialog. A sample is provided in the file MPDialogs Resources that you can simply copy into a new project's resource file. The DITL should include six items, numbered as follows:

  • OK button
  • Cancel button
  • Revert button
  • Use Defaults button
  • a user item that defines the icon list rectangle
  • a hidden static text field for default Command-key equivalents
The Revert and Use Defaults buttons can be moved offscreen to make either of them unavailable. (Alternatively, the buttons can be removed and the control #defines in the main header file, MPDialogs.h, can be changed to reflect the new numbering.) The icon list is always displayed vertically, and the rectangle doesn't include the scroll bar. The sample application provides the standard Command-key equivalents for OK and Cancel. The standard equivalents for OK are handled in the code; those for Cancel are handled by means of the hidden static text field, which defines default Command-key equivalents for the rest of the controls in the dialog as well.

A DITL needs to be created for each pane. The first item is a hidden static text field that defines Command-key equivalents for the items in the pane; this is in addition to the default list in the main DITL. See "Code for Dialog Command-Key Equivalents" for details of the syntax.

CODE FOR DIALOG COMMAND-KEY EQUIVALENTS

The Command-key equivalent code I provide in the sample uses a modified version of KeyEquivFilter, a routine in Utilities.c, which is part of DTS Lib on the CD. It takes these two additional parameters:

  • The ID of the static text item that contains the mappings. My dialog code calls this routine twice, once for the bottom buttons and a second time for the items in the pane.

  • An offset to add to the item numbers when a hit occurs. This allows the code to use relative item numbering for easier specification of Command-key equivalents in panes.

The static text item is an item-match string that follows the general format =cxxyyzz or ccxxyyzz. The =c matches the character c, and cc matches the character by its ASCII value. The next number, xx (a flag byte with the bits set to specify the modifier keys you're checking for), is logically ANDed with the modifier flags from the key-down event and compared to yy (a flag byte with the bits set to specify the values of the modifier keys -- for example, you can force the Control key to be up). If this comparison is true and if the character c matches the character the user typed, the item zz is returned as being hit.

Each item-match string is eight characters long and is separated from other such strings that follow by a comma. The numbers in the strings are hexadecimal and case is significant for character matches.

For example, the hidden static text field that's checked for each pane in the sample application is

=.190102,1B190102,1B190002
The first item-match string checks for a period and for the Control, Option, and Command keys. If only the Command key has been pressed, item 2 is returned as being hit. Similarly, the next item-match string handles Command-Escape (Escape is 1B) and the last item-match string handles Escape by itself.


The items are numbered local to each DITL, so that, for example, the first control would be item 2. All user items in the DITL are set to the DrawGray procedure, which outlines the item's rectangle with either the gray color or a stippled gray pattern, depending on the user's monitor.

Next, a DTL# resource should be created with the same resource ID as the main DLOG resource. It contains a list of the resource IDs of the DITLs that comprise a specific multipane dialog and the text displayed under each icon in the list. Then the icon groups are created; they have the same resource ID as the DITL to which they correspond. Small versions of the icons aren't needed, but color versions should be created for display on color-capable Macintosh computers.

Optional DGRP resources can be created for specifying radio button groups. The resource ID is the same as that of the corresponding pane's DITL. Each DGRP can contain multiple groups per pane, if desired; however, a particular radio button should only be used in a single group. Like the per-pane Command-key equivalent strings, items are numbered local to the DITL.

You should also copy the following:

  • the pseudo-CDEF with resource ID 251, which provides support for using the icon list as a control (in the file MPDialogs Resources)

  • the LDEF with resource ID 130, which implements the icon list definition for the List Manager (in the file Icon LDEF in the LDEF folder)

  • optionally, the 'hdlg' resource and corresponding STR# resource for Balloon Help support (in the file MPDialogs Resources)
You can add Balloon Help to a multipane dialog by adding two help items to the individual DITL resources that make up each pane. One is for the controls in the main DITL and uses an 'hdlg' resource and an STR# resource with the same ID. The second help item is an 'hdlg' resource for each pane's DITL; it should start at item 8 for the first control in the pane. See the file MPDialogs.u.rsrc on the CD for a sample 'hdlg' resource for the first pane.

CALLING THE MAIN ROUTINES

Now we'll review the calls your application needs to make to the main routines in order to open and close the multipane dialog, handle events, and access the values of the controls in the dialog. But first, let's look at the data your application needs to maintain.

POINTERS AND HANDLES

Your application must maintain a DialogPtr for each dialog used. You also need to declare a handle for storing the returned settings. Passing a pointer to NULL causes the code to allocate a new handle and return it to the caller; otherwise, a handle to an existing record must be provided. For a preferences dialog, this data should be maintained in the application's preferences file in the Preferences folder.
    Implementing preferences files is discussed in the article "The Right Way to Implement Preferences Files" in develop Issue 18.*
The sample code internally allocates an MPDHdl for each open multipane dialog for storing state information. The handle is stored in the refCon of the dialog.

OPENING, HANDLING EVENTS, AND CLOSING

Your application should call OpenMPDialog for each desired multipane dialog, taking any actions necessary when a dialog is opened, such as disabling menus. This call is passed the resource ID of the DLOG for the dialog, a reference to the handle that stores the returned settings, and four optional parameters, which are described later. Here's an example:
DialogPtr prefDlog = NULL;
Handle thePrefs = NULL;

prefDlog = OpenMPDialog (kPrefDLOG, NULL, NULL, NULL, NULL,
                        &thePrefs);
if (prefDlog) SetMenusBusy();
// If NULL, the dialog couldn't be opened. 

The main event loop should call DoMPDialogEvent after each event is returned from WaitNextEvent. If DoMPDialogEvent returns true, the multipane dialog routines have handled the event; your application should inspect the DialogPtr to determine whether the dialog has been closed, so that the application can recover from the dialog state. A return value of false indicates that your application should process the event as it would normally. For example:
if (DoMPDialogEvent(&prefDlog, &mainEventRec)) {
   // A NULL DialogPtr means the dialog has been closed. 
   if (!prefDlog)
      SetMenusIdle();
} else {
   // Process the event as usual. 
   ...
}
To dispose of the dialog without user interaction, your application can call CloseMPDialog:
CloseMPDialog(prefDlog);
After the dialog has been closed, it's the application's responsibility to dispose of or save the data handle created with the call to OpenMPDialog. The code I've provided assumes this handle is maintained by the application after creation.

ACCESSING CONTROL VALUES

The following two routines are provided for accessing the control values stored in the data handle:
  • GetMPDItem retrieves the value of the control corresponding to the pane and item specified and stores it in a buffer.

  • SetMPDItem stores in the handle a value retrieved from a buffer.
Both of these routines assume that the caller knows the length and type of the control's data representation. Items are numbered differently from in the DITL resource -- only items that have a value are included, and the values for radio button groups come after those for all other controls in the data. The values of checkboxes, enabled buttons in radio button groups, and pop-up menus are stored as 16-bit integers. Return codes are defined in the header file. Errors are returned for invalid pane and item numbers and buffer lengths.

The routines are declared as follows:

short GetMPDItem (Handle theData, short pane, short item, Ptr ptr,
                  short len)
short SetMPDItem (Handle theData, short pane, short item, Ptr ptr,
                  short len)
The sample application, in the code for DialogDisplay, provides a basic example of the use of these routines to display the current settings of the controls in the previously closed dialog.

Normally, these routines should be sufficient to access the data in the handle. However, those applications for which it would be more efficient to manipulate the handle directly can use the following format:

Last Open Pane
Offset to Pane 1, Offset to Pane 2, ..., Offset to Pane n, NULL
(Pane 1) Length of Item 1, Data for Item 1, ..., Length of Item m,
   Data for Item m, NULL
...
(Pane n) Length of Item 1, Data for Item 1, ..., Length of Item m,
   Data for Item m, NULL
The Last Open Pane and the Offset to Pane fields are all long integers and the Length of Item fields are all short integers. The Length of Item value doesn't include the length of itself; to get to the next field you would add
Length of Item + sizeof(short)
to the pointer. The Last Open Pane field allows the multipane dialog code to display the dialog with the last pane the user had open as the current pane.

That's all you need to know to make basic use of my multipane dialog code. But you can also go a step further: you can customize certain aspects of a multipane dialog by using the four optional parameters to OpenMPDialog mentioned above.

CUSTOMIZING WITH OPTIONAL PROCEDURES

The second through fifth parameters to OpenMPDialog can indicate action procedures that customize dialog behavior by responding to certain events. A value of NULL for any of these parameters tells the application to use the default behavior. To provide custom behavior, you would pass a universal procedure pointer instead of NULL. The procedures can also be changed dynamically, with the InstallAction routine.

The action procedures and the default actions are as follows:

  • The Set Defaults action procedure (parameter 2) provides factory defaults for controls. The default action is to set them to 0.

  • The Click action procedure (parameter 3) enables you to customize the actions resulting from clicking a control, such as dimming or undimming other controls or performing data validation. The default action is to toggle checkboxes and handle radio buttons via the Radio Group action procedure.

  • The Edit action procedure (parameter 4) enables special handling of editable text fields, such as converting the string to an integer. The default action is to store the entire string as a Str255.

  • The Radio Group action procedure (parameter 5) enables you to customize the behavior of radio button groups, such as how the values are stored. The default action is to store the value as the index number of the radio button that's enabled in the group; the default value is 1 (the first radio button in the group).
All the action procedure pointers are declared as UniversalProcPtrs for compatibility in case of PowerPC compilation, so they must be allocated before use. The sample program does this by declaring a UniversalProcPtr for each desired action procedure. For example, the one for the Click action procedure is declared as follows:
ClickActionUPP myClickAction = NULL;
It's initialized in the main routine of the application like this:
myClickAction = NewClickActionProc(MyClickAction);
Depending on what you want to do in the action procedures, you may need to make use of the MPDHdl stored in the dialog's refCon, mentioned earlier. This is a handle to an MPDRec (shown in Listing 1), which is the main data structure used by the multipane dialog code for state information. None of the elements of this structure should be modified by user code. The four UPP fields can be manipulated via calls to InstallAction and RemoveAction.

Listing 1. The MPDRec structure

typedef struct MPDRec {
  short           numPanes;    // Number of panes in the dialog
  short           currentPane; // Current pane being displayed 
  short           baseItems;   // Item number of first item in panes
  short           *paneIDs;    // List of IDs for the pane's DITLs
  short           paneDirty;   // Whether Revert should be enabled
  RadioGroupPt    radio;       // Linked list of radio button groups
  Handle          theData;     // Actual storage for dialog values
  Handle          tmpData;     // Temporary storage for dialog values
  Handle          *IconHandles;// List of icon suites
  ListHandle      theList;     // List Manager list for the icon list
  ClickActionUPP  ClickAction; // Action procedures
  EditActionUPP   EditAction;
  GroupActionUPP  GroupAction;
  DefActionUPP    DefAction; 
} MPDRec, *MPDPtr, **MPDHdl;
The baseItems field will be the most useful in the action procedures. It holds the item number of the first item in the pane, which is the hidden static text item used for Command-key equivalents. Thus, if dataH is of type MPDHdl, the index of the first real control (the second DITL entry) in the pane will be (*dataH)->baseItems + 1.

Now let's take a closer look at each of the action procedures.

THE SET DEFAULTS ACTION PROCEDURE

The Set Defaults action procedure provides factory defaults for checkboxes and other controls, except for radio button groups (handled in the Radio Group action procedure). It's called with a pointer to -- and the length of -- a buffer holding the internal representation of the value of a single control corresponding to a specific pane and item number. You can call DefaultAction to take the default action for items your code doesn't handle. The procedure is declared like this:
void MySetDefAction (Ptr theData, short len, short iType, short pane,
                    short item)
The Set Defaults action procedure's defaults for radio buttons apply only to those that aren't part of a radio button group. But using single radio buttons is definitely not advised; all radio buttons should be in groups to be consistent with the Macintosh Human Interface Guidelines.

THE CLICK ACTION PROCEDURE

The Click action procedure enables you to customize the actions resulting from clicking a control. For instance, this procedure can handle dimming or undimming other items when certain controls are clicked. It can also provide validation for control settings when the user tries to change the pane or click OK, to ensure that the entered settings make sense. The procedure receives a DialogPtr and the pane and item numbers. It's declared as follows:
short MyClickAction(short mType, DialogPtr dlog, short pane,
                    short item)
The mType parameter specifies the message to process when the action procedure is called. The procedure is called with a kInitAction message right after the control is set when the pane is first displayed; this gives you an opportunity to set up the initial state of the dialog. The procedure is called with a kClickAction message after the user has released the mouse button in a control. A kValidateAction message is received for data validation; it's the responsibility of the Click action procedure to put up an alert to notify the user if a setting is unacceptable.

Listing 2 is a Click action procedure from the sample application that undims the third checkbox in the Defense pane (Self-Destruct) if the second checkbox (Enable Self-Destruct) is checked. It also ensures that the editable text field in the Communications pane contains only digits; if this field contains nondigits, the validation fails and the user can't change panes or click OK.

Listing 2. A sample Click action procedure

short MyClickAction(short mType, DialogPtr dlog, short pane,
                    short item)
{
   MPDHdl   dataH;
   short    iType, val = 0;
   Rect     iRect;
   Handle   iHandle;

   // Obtain multipane dialog state record.
   dataH = (MPDHdl) GetWRefCon(dlog);

   // Handle the second item validation.
   if (mType == kValidateAction) {
      // Validation fails if nondigits are in the field.
      if (pane == kCommPane &&
         item == kFrequency + (*dataH)->baseItems) {
         GetDialogItem(dlog, item, &iType, &iHandle, &
                       iRect);
         GetDialogItemText(iHandle, theStr);
         val = VerifyDigits(theStr);
         if (val)
            StopAlert(ALERT_Invalid, NULL);
      }
      // All other items validate OK.
      return val;
   }

   // If this isn't the second checkbox, handle things the default
   // way.
   if (pane != kMiscellaneousPane ||
         item != kEnableSelfDestruct + (*dataH)->baseItems)
      return (DefaultClickAction(mType, dlog, pane, item));

   // Initialize and Click messages are handled almost the same.
   // Dim the third checkbox based on the value of the second.
   GetDialogItem(dlog, item, &iType, &iHandle, &iRect);
   val = GetControlValue((ControlHandle) iHandle);
   switch (mType) {
      // Toggle the item in response to the user click.
      case kClickAction:
         val = !val;
         SetControlValue((ControlHandle) iHandle, val);
         // Fall through!
      // In either case, enable/disable next checkbox.
      case kInitAction:
         AbleDItem(dlog, kSelfDestruct + (*dataH)->baseItems, val);
         break;
   }

   // Initialize and Click messages should never fail.
   return 0;
}
The default Click action procedure, DefaultClickAction, calls the Radio Group action procedure to handle buttons in a radio button group; thus, actions in response to a click in a radio button group should be handled there. Call DefaultClickAction to inherit default functionality for controls not handled in your customization procedure.

THE EDIT ACTION PROCEDURE

The Edit action procedure enables special handling of editable text fields. A common implementation is to store the field's string as a long integer, converting the string value to and from this form as needed.

This procedure receives a pointer to a buffer for storage of the control's internal value, a handle to the control, and the pane and item numbers; it returns the length of the space required for the text field. The first parameter is a message that informs the procedure whether to calculate the storage size for this field, initialize the value, or copy the value to or from the field.

The procedure is declared as follows:

short MyEditAction(short mType, Ptr hPtr, Handle iHandle, short pane,
                   short item)
The kCalcAction message requests the amount of storage required for the representation of the field value in memory. The kInitAction message requests that the value of the field be initialized. The kP2TAction message requests that the code retrieve the value of the field and store it in memory (in other words, that the permanent storage value be transferred to the temporary storage area -- P2T is shorthand for "permanent to temporary"). Conversely, the kT2PAction message ("temporary to permanent") requests that the code set the field to the value indicated by the representation in memory. Default behavior can be maintained by calling DefaultEditAction, if desired.

Listing 3 is an Edit action procedure from our sample application. Normally, the procedure should check the item and pane numbers to distinguish between different text fields, but the sample application has only one such field.

Listing 3. A sample Edit action procedure

short MyEditAction(short mType, Ptr hPtr, Handle iHandle, short pane,
                   short item)
{
   short      ret = 0;
   long      val;
   Str255   textStr;

   Assert(hPtr != NULL);
   switch (mType) {
      case kP2TAction:      // Save value of control.
         GetItemDialogText(iHandle, textStr);
         StringToNum(textStr, &val);
         *(long *) hPtr = val;
         ret = sizeof(long);
         break;
      case kT2PAction:      // Set value of control.
         val = *(long *) hPtr;
         NumToString(val, textStr);
         SetIText(iHandle, textStr);
         ret = sizeof(long);
         break;
      case kInitAction:      // Initialize value.
         *(long *) hPtr = 0;
         ret = sizeof(long);
         break;
      case kCalcAction:      // How much storage do we need for this?
         ret = sizeof(long);
         break;
   }
   return ret;
}

THE RADIO GROUP ACTION PROCEDURE

To simplify using radio button groups, a single value is stored for the entire group. This value is the relative item number of the enabled button in the group. For example, the value of a group of three radio buttons with the second one enabled would be 2.

In the sample program, radio button groups are stored in a linked list starting from the radio field of the MPDRec structure. The RadioGroup structure is defined as shown in Listing 4.

Listing 4. The RadioGroup structure

typedef struct RadioGroup {
   struct RadioGroup *next;
   short pane;
   short num;
   short items[1]; 
} RadioGroup, *RadioGroupPtr;
The next field points to the next radio button group, to enable traversing the linked list of groups. The pane field is the pane number this group belongs to. The num field holds the number of items that make up this radio button group. The relative item numbers of these radio buttons are stored in the items array.

The Radio Group action procedure enables you to customize the behavior of radio button groups. For instance, an application could choose to store radio button group values differently from the default or handle dimming or undimming of items in response to the user's actions. The Radio Group action procedure receives the same messages as the Edit action procedure. It returns the length of the space required for the radio button group's internal storage; the default is four bytes per group, two for the number of radio buttons and two for the value as a short integer.

Like the Edit action procedure, the Radio Group action procedure is called with the kInitAction and kCalcAction messages. However, these messages occur before the dialog is opened, so the DialogPtr will be NULL at that time. The procedure is declared like this:

short MyGroupAction(short mType, RadioGroupPtr group, Handle dataH,
                    DialogPtr dlog, Ptr hPtr, short pane, short item)
Note that in response to the kInitAction message, the action procedure is expected to store the number of radio buttons in the group in the first two bytes of the internal storage. Here's an example from the default Radio Group action procedure (dataH is of type MPDHdl):
for (i = 0; i < group->num; i++) {
  if (GetCheckOrRadio(dlog, group->
        items[i] + (*dataH)->baseItems - 1))*(short *) hPtr = i + 1;
}
To obtain the actual item number for the control in the dialog, you just add
(*dataH)->baseItems - 1
to the relative number stored in the items array, as shown in the above code. As mentioned earlier, the baseItems field of dataH is the number of the first pane-specific item in the dialog.

NOW WHAT?

The code that accompanies this article on this issue's CD provides an easy-to-implement method for adding icon-selected multipane dialogs to any application. (The routines for managing radio button groups could be extracted without much difficulty and used elsewhere.) The sample program also provides an example of using the AppendDITL and ShortenDITL routines. So experiment with the sample application and then try out multipane dialogs as a way of simplifying the user interface in your own application.

NORMAN FRANKE misses the large electrical storms and green things of his native Pennsylvania, but not the humidity. He's using the B.S. in computer science he earned from Carnegie Mellon as he writes Macintosh software for a large national laboratory in northern California. Now working on an M.S. in computer science at Stanford, he enjoys writing sound manipulation software for his Macintosh and watching classic and action/adventure movies in his spare time.*

Thanks to our technical reviewers Tim Craycroft, Nitin Ganatra, C. K. Haun, and Elizabeth Moller. Thanks also to Eric Soldan for ListControl and KeyEquivFilter from DTS Lib.*

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

EtreCheck 3.1.5 - For troubleshooting yo...
EtreCheck is an app that displays the important details of your system configuration and allow you to copy that information to the Clipboard. It is meant to be used with Apple Support Communities to... Read more
WALTR 2 2.0.8 - $39.95
WALTR 2 helps you wirelessly drag-and-drop any music, ringtones, videos, PDF, and ePub files onto your iPhone, iPad, or iPod without iTunes. It is the second major version of Softorino's critically-... Read more
Carbon Copy Cloner 4.1.12 - Easy-to-use...
Carbon Copy Cloner backups are better than ordinary backups. Suppose the unthinkable happens while you're under deadline to finish a project: your Mac is unresponsive and all you hear is an ominous,... Read more
Dropbox 16.3.27 - Cloud backup and synch...
Dropbox is an application that creates a special Finder folder that automatically syncs online and between your computers. It allows you to both backup files and keep them up-to-date between systems... Read more
Microsoft OneNote 15.29 - Free digital n...
OneNote is your very own digital notebook. With OneNote, you can capture that flash of genius, that moment of inspiration, or that list of errands that's too important to forget. Whether you're at... Read more
Spotify 1.0.44.100. - Stream music, crea...
Spotify is a streaming music service that gives you on-demand access to millions of songs. Whether you like driving rock, silky R&B, or grandiose classical music, Spotify's massive catalogue puts... Read more
SpamSieve 2.9.27 - Robust spam filter fo...
SpamSieve is a robust spam filter for major email clients that uses powerful Bayesian spam filtering. SpamSieve understands what your spam looks like in order to block it all, but also learns what... Read more
VueScan 9.5.62 - Scanner software with a...
VueScan is a scanning program that works with most high-quality flatbed and film scanners to produce scans that have excellent color fidelity and color balance. VueScan is easy to use, and has... Read more
Fantastical 2.3.2 - Create calendar even...
Fantastical 2 is the Mac calendar you'll actually enjoy using. Creating an event with Fantastical is quick, easy, and fun: Open Fantastical with a single click or keystroke Type in your event... Read more
PCalc 4.4.4 - Full-featured scientific c...
PCalc is a full-featured, scriptable scientific calculator with support for hexadecimal, octal, and binary calculations, as well as an RPN mode, programmable functions, and an extensive set of unit... Read more

Latest Forum Discussions

See All

Galaxy on Fire 3 and four other fantasti...
Galaxy on Fire 3 - Manticore brings the series back for another round of daring space battles. It's familiar territory for folks who are familiar with the franchise. If you've beaten the game and are looking to broaden your horizons, might we... | Read more »
The best apps for your holiday gift exch...
What's that, you say? You still haven't started your holiday shopping? Don't beat yourself up over it -- a lot of people have been putting it off, too. It's become easier and easier to procrastinate gift shopping thanks to a number of apps that... | Read more »
Toca Hair Salon 3 (Education)
Toca Hair Salon 3 1.0 Device: iOS Universal Category: Education Price: $2.99, Version: 1.0 (iTunes) Description: | Read more »
Winter comes to Darkwood as Seekers Note...
MyTona, based in the chilly Siberian city of Yakutsk, has brought a little festive fun to its hidden object game Seekers Notes: Hidden Mystery. The Christmas update introduces some new inhabitants to players, and with them a chance to win plenty of... | Read more »
Bully: Anniversary Edition (Games)
Bully: Anniversary Edition 1.03.1 Device: iOS Universal Category: Games Price: $6.99, Version: 1.03.1 (iTunes) Description: *** PLEASE NOTE: This game is officially supported on the following devices: iPhone 5 and newer, iPod Touch... | Read more »
PINE GROVE (Games)
PINE GROVE 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: A pine grove where there are no footsteps of people due to continuous missing cases. The case is still unsolved and nothing has... | Read more »
Niantic teases new Pokémon announcement...
After rumors started swirling yesterday, it turns out there is an official Pokémon GO update on its way. We’ll find out what’s in store for us and our growing Pokémon collections tomorrow during the Starbucks event, but Niantic will be revealing... | Read more »
3 reasons why Nicki Minaj: The Empire is...
Nicki Minaj is as business-savvy as she is musically talented and she’s proved that by launching her own game. Designed by Glu, purveyors of other fine celebrity games like cult favorite Kim Kardashian: Hollywood, Nicki Minaj: The Empire launched... | Read more »
Clash of Clans is getting its own animat...
Riding on its unending wave of fame and success, Clash of Clans is getting an animated web series based on its Clash-A-Rama animated shorts.As opposed to the current shorts' 60 second run time, the new and improved Clash-A-Rama will be comprised of... | Read more »
Leaks hint at Pokémon GO and Starbucks C...
Leaked images from a hub for Starbucks employees suggests that a big Pokémon GO event with the coffee giant could begin this very week. The images appeared on Reddit and hint at some exciting new things to come for Niantic's smash hit game. | Read more »

Price Scanner via MacPrices.net

Never Settle for Low Performing Wifi With iOS...
AppYogi Software has announced the release of WiFi Signal Strength Status App 1.0, the company’s new utility developed exclusively for macOS. WiFi Signal Strength Status App features a unique, single... Read more
New 2016 13-inch Touch Bar MacBook Pros in st...
B&H Photo has stock of new 2016 Apple 13″ Touch Bar MacBook Pro models, each including free shipping plus NY sales tax only: - 13″ 2.9GHz/512GB Touch Bar MacBook Pro Space Gray: $1999 - 13″ 2.... Read more
New 2016 15″ Touch Bar MacBook Pros in stock...
B&H Photo has new 2016 Apple 15″ Touch Bar MacBook Pro models in stock today including free shipping plus NY sales tax only: - 15″ 2.7GHz Touch Bar MacBook Pro Space Gray: $2799 - 15″ 2.7GHz... Read more
DietSensor App Targeting Diabetes and Obesity...
DietSensor, Inc., a developer of smart food and nutrition applications designed to fight diabetes and obesity and help improve overall fitness, has announced the launch of its DietSensor app for... Read more
Holiday 2016 13-inch 2.0GHz MacBook Pro sales...
B&H has the non-Touch Bar 13″ MacBook Pros in stock today for $50-$100 off MSRP. Shipping is free, and B&H charges NY sales tax only: - 13″ 2.0GHz MacBook Pro Space Gray (MLL42LL/A): $1449 $... Read more
Holiday sale: Apple TVs for $51-$40 off MSRP,...
Best Buy has dropped their price on the 64GB Apple TV to $159.99 including free shipping. That’s $40 off MSRP. 32GB Apple TVs are on sale right now for $98 on Sams Club’s online store. That’s $51 off... Read more
12-inch Retina MacBooks, Apple refurbished, n...
Apple has restocked a full line of Certified Refurbished 2016 12″ Retina MacBooks, now available for $200-$260 off MSRP. Refurbished 2015 models are available starting at $929. Apple will include a... Read more
Holiday sale: 12-inch Retina MacBook for $100...
B&H has 12″ Retina MacBooks on sale for $100 off MSRP as part of their Holiday sale. Shipping is free, and B&H charges NY sales tax only: - 12″ 1.1GHz Space Gray Retina MacBook: $1199 $100... Read more
Apple refurbished 13-inch MacBook Airs availa...
Apple has Certified Refurbished 13″ MacBook Airs available starting at $849. An Apple one-year warranty is included with each MacBook, and shipping is free: - 13″ 1.6GHz/8GB/128GB MacBook Air: $849 $... Read more
Apple refurbished iMacs available for up to $...
Apple has Certified Refurbished 2015 21″ & 27″ iMacs available for up to $350 off MSRP. Apple’s one-year warranty is standard, and shipping is free. The following models are available: - 21″ 3.... Read more

Jobs Board

*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
US- *Apple* Store Leader Program - Apple (Un...
…Summary Learn and grow as you explore the art of leadership at the Apple Store. You'll master our retail business inside and out through training, hands-on Read more
Automotive Detailer - *Apple* Used Autos -...
We are currently conductinginterviews and will be accepting applications for a part-time detailer. Apple Used Autos is a great place to work andstart a career. We Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Retail - Multiple Positions- Trumbul...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.