The XmNdialogType resource can take the value XmDIALOG_TEMPLATE in Motif 1.2. This value creates a
TemplateDialog, which is basically an empty MessageDialog that can be modified by the programmer. By default, the
dialog only contains a Separator child. By setting various resources on a TemplateDialog when it is created, you can
cause the dialog to create other standard children. If you set a string or callback resource for an action area button, the
button is created. If you set the XmNmessageString resource, the message is displayed in the standard location. If
you set the XmNsymbolPixmap resource, the specified symbol appears in its normal location. If you don't set a
particular resource, then that child is not created, which means that you cannot modify the resource later with
XtSetValues(), set a callback for the child with XtAddCallback(), or retrieve the child with
XmMessageBoxGetChild().
8.1.2 Modifying SelectionDialogs
The Motif SelectionDialog supports the same types of modifications as the MessageDialog. With Motif 1.2, you can
provide additional action area buttons, a work area child, and a MenuBar. Unlike the MessageDialog, the first widget
that is added is taken as the work area, regardless of whether it is a PushButton or a MenuBar. The fact that the first
child is always considered the work area is a bug. As a result of the bug, you need to be careful about the order in
which you add children to a SelectionDialog. If you want to add a PushButton to the action area of a SelectionDialog,
you need to add an unmanaged work area widget first, so that the PushButton is placed in the action area, rather than
used as the work area. After you add a work area, if you add a MenuBar, it is placed along the top of the dialog, and
PushButton children are inserted after the OK button. The position of the work area child is controlled by the
XmNchildPlacement resource, which can take the following values:
XmPLACE_ABOVE_SELECTION
XmPLACE_BELOW_SELECTION
XmPLACE_TOP
The SelectionDialog only supports the addition of one work area; the layout of multiple work area children is
undefined. In Motif 1.1, only a single work area child can be added to a SelectionDialog. This child is always placed
between the list and the text entry area.
Consider providing additional controls in a PromptDialog like the one used in the program prompt_dlg from
Chapter 6, Selection Dialogs. In this program, the dialog prompts the user for a new label for the PushButton that
activated the dialog. By adding another widget to the dialog, we can expand its functionality to prompt for either a
label name or a button color. The user enters either value in the same text input area and the RadioBox controls how
the text is evaluated. the source code shows the new program. XtSetLanguageProc() is only available in
X11R5; there is no corresponding function in X11R4. XmStringCreateLocalized() is only available in -Motif
1.2; XmStringCreateSimple() is the corresponding function in -Motif 1.1. XmFONTLIST_DEFAULT_TAG
replaces XmSTRING_DEFAULT_CHARSET in -Motif 1.2.
/* modify_btn.c −− demonstrate how a default Motif dialog can be
* modified to support additional items that extend the usability
* of the dialog itself. This is a modification of the prompt_dlg.c
* program.
*/
#include <Xm/SelectioB.h>
#include <Xm/RowColumn.h>
#include <Xm/PushB.h>
main(argc, argv)
char *argv[];
{
XtAppContext app;
Widget toplevel, rc, button;
void pushed();
8 Custom Dialogs 8.1.2 Modifying SelectionDialogs
168
XtSetLanguageProc (NULL, NULL, NULL);
/* Initialize toolkit and create toplevel shell */
toplevel = XtVaAppInitialize (&app, "Demos", NULL, 0,
&argc, argv, NULL, NULL);
/* RowColumn managed both PushButtons */
rc = XtVaCreateWidget ("rowcol", xmRowColumnWidgetClass, toplevel,
NULL);
/* Create two pushbuttons −− both have the same callback */
button = XtVaCreateManagedWidget ("PushMe 1",
xmPushButtonWidgetClass, rc, NULL);
XtAddCallback (button, XmNactivateCallback, pushed, NULL);
button = XtVaCreateManagedWidget ("PushMe 2",
xmPushButtonWidgetClass, rc, NULL);
XtAddCallback (button, XmNactivateCallback, pushed, NULL);
XtManageChild (rc);
XtRealizeWidget (toplevel);
XtAppMainLoop (app);
}
/* pushed() −−the callback routine for the main app's pushbuttons.
* Create a dialog that prompts for a new button name or color.
* A RadioBox is attached to the dialog. Which button is selected
* in this box is held as an int (0 or 1) in the XmNuserData resource
* of the dialog itself. This value is changed when selecting either
* of the buttons in the ToggleBox and is queried in the dialog's
* XmNokCallback function.
*/
void
pushed(pb, client_data, call_data)
Widget pb;
XtPointer client_data;
XtPointer call_data;
{
Widget dialog, toggle_box;
XmString t, btn1, btn2;
extern void read_name(), toggle_callback();
Arg args[5];
int n = 0;
/* Create the dialog −− the PushButton acts as the DialogShell's
* parent (not the parent of the PromptDialog). The "userData"
* is used to store the value
*/
t = XmStringCreateLocalized ("Enter New Button Name:");
XtSetArg (args[n], XmNselectionLabelString, t); n++;
XtSetArg (args[n], XmNautoUnmanage, False); n++;
XtSetArg (args[n], XmNuserData, 0); n++;
dialog = XmCreatePromptDialog (pb, "notice_popup", args, n);
XmStringFree (t); /* always destroy compound strings when done */
/* When the user types the name, call read_name() ... */
XtAddCallback (dialog, XmNokCallback, read_name, pb);
/* If the user selects cancel, just destroy the dialog */
XtAddCallback (dialog, XmNcancelCallback, XtDestroyWidget, NULL);
/* No help is available... */
8 Custom Dialogs 8.1.2 Modifying SelectionDialogs
169
XtUnmanageChild (XmSelectionBoxGetChild (dialog, XmDIALOG_HELP_BUTTON));
/* Create a toggle box −− callback routine is toggle_callback() */
btn1 = XmStringCreateLocalized ("Change Name");
btn2 = XmStringCreateLocalized ("Change Color");
toggle_box = XmVaCreateSimpleRadioBox (dialog,
"radio_box", 0 /* inital value */, toggle_callback,
XmVaRADIOBUTTON, btn1, 0, NULL, NULL,
XmVaRADIOBUTTON, btn2, 0, NULL, NULL,
NULL);
XtManageChild (toggle_box);
XtManageChild (dialog);
XtPopup (XtParent (dialog), XtGrabNone);
}
/* callback for the items in the toggle box −− the "client data" is
* the item number selected. Since the function gets called whenever
* either of the buttons changes from true to false or back again,
* it will always be called in pairs −− ignore the "False" settings.
* When cbs−>set is true, set the dialog's label string accordingly.
*/
void
toggle_callback(toggle_box, client_data, call_data)
Widget toggle_box;
XtPointer client_data;
XtPointer call_data;
{
Widget dialog = XtParent(XtParent(toggle_box));
XmString str;
int n = (int) client_data;
XmToggleButtonCallbackStruct *cbs =
(XmToggleButtonCallbackStruct *) call_data;
if (cbs−>set == False)
return; /* wait for the one that toggles "on" */
if (n == 0)
str = XmStringCreateLocalized ("Enter New Button Name:");
else
str = XmStringCreateLocalized ("Enter Text Color:");
XtVaSetValues (dialog,
XmNselectionLabelString, str,
XmNuserData, n, /* reset the user data to reflect new value */
NULL);
XmStringFree (str);
}
/* read_name() −−the text field has been filled in. Get the userData
* from the dialog widget and set the PushButton's name or color.
*/
void
read_name(dialog, client_data, call_data)
Widget dialog;
XtPointer client_data;
XtPointer call_data;
{
char *text;
int n;
Widget push_button = (Widget) client_data;
XmSelectionBoxCallbackStruct *cbs =
(XmSelectionBoxCallbackStruct *) call_data;
8 Custom Dialogs 8.1.2 Modifying SelectionDialogs
170
/* userData: n == 0 −> Button Label, n == 1 −> Button Color */
XtVaGetValues (dialog, XmNuserData, &n, NULL);
if (n == 0)
XtVaSetValues (push_button, XmNlabelString, cbs−>value, NULL);
else {
/* convert compound string into regular text string */
XmStringGetLtoR (cbs−>value, XmFONTLIST_DEFAULT_TAG, &text);
XtVaSetValues (push_button,
XtVaTypedArg, XmNforeground,
XmRString, text, strlen (text) + 1,
NULL);
XtFree (text); /* must free text gotten from XmStringGetLtoR() */
}
}
The new dialog is shown in the figure.
Output of modify_btn.c
We add a RadioBox as the work area child of the PromptDialog. The ToggleButtons in the RadioBox indicate whether
the input text is supposed to change the label of the PushButton or its text color. To determine which of these
attributes to change, we use the callback routine toggle_callback().
Rather than storing the state of the RadioBox in a global variable, we store the value in the XmNuserData resource
of the dialog widget. Using this technique, we can retrieve the value anytime we wish and minimize the number of
global variables in the program. The XmNuserData resource is available for all Motif widgets except shells, so it is
a convenient storage area for arbitrary values. The type of value that XmNuserData takes is any type whose size is
less than or equal to the size of an XtPointer, which is typically defined as a char pointer. As a result, storing an
int works just fine. If you want to store a data -structure in this resource, you need to store a pointer to the structure.
The size or type of the structure is irrelevant, since pointers are the same size. You might run into problems with
unusual architectures where pointers of different types are not the same size, like DOS.
8 Custom Dialogs 8.1.2 Modifying SelectionDialogs
171

Get Volume 6A: Motif Programming Manual now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.