A custom dialog
In this dialog, the Help button is the only one with a label recommended by Motif. Since the other common actions
did not effectively represent the actions of the dialog, we chose our own labels. We decided not to use the Cancel
action because we didn't want to combine the actions of Reset and Close in one button. Instead, we separated the
functionality into two actions. The Clear button resets the controls without closing the window and the Done button
closes the window. While Cancel, the recommended Motif label, implies that the action specified by the dialog should
not be taken, Done merely suggests that the dialog be dismissed. Selecting Done does not cancel anything, it just
dismisses the dialog. Close might be more appropriate, but since the dialog is part of an electronic mail application
where the term "close" is used to describe the action of closing a folder, we are not using that label to avoid ambiguity.
We do not use the OK action in the dialog because it doesn't work with the desired usage of the dialog. Let's say the
user selects a date to search for messages and then presses the OK button to start the search. By definition, OK should
perform the action and dismiss the dialog. If that were to happen here, the user would never see the results of the
search. While Apply might be more appropriate for our desired action, we decided to use Search instead because it is
more descriptive of the action being taken by the dialog.
8.3 Building a Dialog
Now that we've explained the design process for a dialog, let's create a real dialog and identify each of the steps in the
process. Consider the problem of providing help. While the Motif InformationDialog is adequate for brief help
8 Custom Dialogs 8.3 Building a Dialog
176
messages, a customized dialog may be more appropriate for displaying large amounts of text. Our custom dialog
displays the text in a scrolling region which is capable of handling arbitrarily large amounts of data.
the source code shows a program that uses a main application window as a generic backdrop. The MainWindow
widget contains a MenuBar that has two menus: File and Help. The Help menu contains several items that, when
selected, pop up a dialog window that displays the associated help text. The text that we provide happens to be
predefined in the program, but you could incorporate information from other sources, such as a database or an external
file. 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.
/* help_text.c:
* Create a simple main window that contains a sample (dummy) work
* area and a menubar. The menubar contains two items: File and Help.
* The items in the Help pulldown call help_cb(), which pops up a
* home−made dialog that displays predefined help texts. The purpose
* of this program is to demonstrate how one might approach the
* problem displaying a large amount of text in a dialog box.
*/
#include <stdio.h>
#include <ctype.h>
#include <Xm/DialogS.h>
#include <Xm/MainW.h>
#include <Xm/RowColumn.h>
#include <Xm/Form.h>
#include <Xm/Text.h>
#include <Xm/PushBG.h>
#include <Xm/LabelG.h>
#include <Xm/PanedW.h>
/* The following help text information is a continuous stream of characters
* that will all be placed in a single ScrolledText object. If a specific
* newline is desired, you must do that yourself. See "index_help" below.
*/
String context_help[] = {
"This is context−sensitive help. Well, not really, but such",
"help text could easily be generated by a real help system.",
"All you really need to do is obtain information from the user",
"about the widget from which he needs help, or perhaps prompt",
"for other application−specific contexts.",
NULL
};
String window_help[] = {
"Each of the windows in your application should have an",
"XmNhelpCallback associated with it so you can monitor when",
"the user presses the Help key over any particular widget.",
"This is another way to provide context−sensitive help.",
"The MenuBar should always have a Help entry at the far right",
"that provides help for most aspects of the program, including",
"the user interface. By providing different levels of help",
"indexing, you can provide multiple stages of help, making the",
"entire help system easier to use.",
NULL
};
String index_help[] = {
"This is a small demonstration program, so there is very little",
8 Custom Dialogs 8.3 Building a Dialog
177
"material to provide an index. However, an index should contain",
"a summary of the type of help available. For example, we have:0,
" Help On Context0,
" Help On Windows0,
" This Index0,
"0,
"Higher−end applications might also provide a tutorial.",
NULL
};
String *help_texts[] = {
context_help,
window_help,
index_help
};
main(argc, argv)
int argc;
char *argv[];
{
XtAppContext app;
Widget toplevel, rc, main_w, menubar, w;
extern void help_cb(), file_cb();
XmString str1, str2, str3;
Widget *cascade_btns;
int num_btns;
XtSetLanguageProc (NULL, NULL, NULL);
toplevel = XtVaAppInitialize (&app, "Demos", NULL, 0,
&argc, argv, NULL, NULL);
/* the main window contains the work area and the menubar */
main_w = XtVaCreateWidget ("main_w",
xmMainWindowWidgetClass, toplevel, NULL);
/* Create a simple MenuBar that contains two cascade buttons */
str1 = XmStringCreateLocalized ("File");
str2 = XmStringCreateLocalized ("Help");
menubar = XmVaCreateSimpleMenuBar (main_w, "main_w",
XmVaCASCADEBUTTON, str1, 'F',
XmVaCASCADEBUTTON, str2, 'H',
NULL);
XmStringFree (str1);
XmStringFree (str2);
/* create the "File" pulldown menu −− callback is file_cb() */
str1 = XmStringCreateLocalized ("New");
str2 = XmStringCreateLocalized ("Open");
str3 = XmStringCreateLocalized ("Quit");
XmVaCreateSimplePulldownMenu (menubar, "file_menu", 0, file_cb,
XmVaPUSHBUTTON, str1, 'N', NULL, NULL,
XmVaPUSHBUTTON, str2, 'O', NULL, NULL,
XmVaSEPARATOR,
XmVaPUSHBUTTON, str3, 'Q', NULL, NULL,
NULL);
XmStringFree (str1);
XmStringFree (str2);
XmStringFree (str3);
/* create the "Help" menu −− callback is help_cb() */
8 Custom Dialogs 8.3 Building a Dialog
178
str1 = XmStringCreateLocalized ("On Context");
str2 = XmStringCreateLocalized ("On Window");
str3 = XmStringCreateLocalized ("Index");
w = XmVaCreateSimplePulldownMenu (menubar, "help_menu", 1, help_cb,
XmVaPUSHBUTTON, str1, 'C', NULL, NULL,
XmVaPUSHBUTTON, str2, 'W', NULL, NULL,
XmVaPUSHBUTTON, str3, 'I', NULL, NULL,
NULL);
XmStringFree (str1);
XmStringFree (str2);
XmStringFree (str3);
/* Identify the Help Menu for the MenuBar */
XtVaGetValues (menubar,
XmNchildren, &cascade_btns,
XmNnumChildren, &num_btns,
NULL);
XtVaSetValues (menubar,
XmNmenuHelpWidget, cascade_btns[num_btns−1],
NULL);
XtManageChild (menubar);
/* the work area for the main window −− just create dummy stuff */
rc = XtVaCreateWidget ("rc", xmRowColumnWidgetClass, main_w, NULL);
str1 = XmStringCreateLtoR ("0 This is an Empty0ample Control Area0 ",
XmFONTLIST_DEFAULT_TAG);
XtVaCreateManagedWidget ("label", xmLabelGadgetClass, rc,
XmNlabelString, str1,
NULL);
XmStringFree (str1);
XtManageChild (rc);
XtManageChild (main_w);
XtRealizeWidget (toplevel);
XtAppMainLoop (app);
}
/* callback for all the entries in the File pulldown menu. */
void
file_cb(w, client_data, call_data)
Widget w;
XtPointer client_data;
XtPointer call_data;
{
int item_no = (int) client_data;
if (item_no == 2) /* the Quit menu button */
exit (0);
printf ("Item %d (%s) selected0, item_no + 1, XtName (w));
}
/* climb widget tree until we get to the top. Return the Shell */
Widget
GetTopShell(w)
Widget w;
{
while (w && !XtIsWMShell (w))
w = XtParent (w);
return w;
}
8 Custom Dialogs 8.3 Building a Dialog
179
#include "info.xbm" /* bitmap data used by our dialog */
/* callback for all the entries in the Help pulldown menu.
* Create a dialog box that contains control and action areas.
*/
void
help_cb(w, client_data, call_data)
Widget w;
XtPointer client_data;
XtPointer call_data;
{
Widget help_dialog, pane, text_w, form, sep, widget, label;
extern void DestroyShell();
Pixmap pixmap;
Pixel fg, bg;
Arg args[10];
int n = 0;
int i;
char *p, buf[BUFSIZ];
int item_no = (int) client_data;
Dimension h;
/* Set up a DialogShell as a popup window. Set the delete
* window protocol response to XmDESTROY to make sure that
* the window goes away appropriately. Otherwise, it's XmUNMAP
* which means it'd be lost forever, since we're not storing
* the widget globally or statically to this function.
*/
help_dialog = XtVaCreatePopupShell ("Help",
xmDialogShellWidgetClass, GetTopShell (w),
XmNdeleteResponse, XmDESTROY,
NULL);
/* Create a PanedWindow to manage the stuff in this dialog. */
pane = XtVaCreateWidget ("pane", xmPanedWindowWidgetClass, help_dialog,
XmNsashWidth, 1, /* PanedWindow won't let us set these to 0! */
XmNsashHeight, 1, /* Make small so user doesn't try to resize */
NULL);
/* Create a RowColumn in the form for Label and Text widgets.
* This is the control area.
*/
form = XtVaCreateWidget ("form1", xmFormWidgetClass, pane, NULL);
XtVaGetValues (form, /* once created, we can get its colors */
XmNforeground, &fg,
XmNbackground, &bg,
NULL);
/* create the pixmap of the appropriate depth using the colors
* that will be used by the parent (form).
*/
pixmap = XCreatePixmapFromBitmapData (XtDisplay (form),
RootWindowOfScreen (XtScreen (form)),
info_bits, info_width, info_height,
fg, bg, DefaultDepthOfScreen (XtScreen (form)));
/* Create a label gadget using this pixmap */
label = XtVaCreateManagedWidget ("label", xmLabelGadgetClass, form,
XmNlabelType, XmPIXMAP,
XmNlabelPixmap, pixmap,
XmNleftAttachment, XmATTACH_FORM,
8 Custom Dialogs 8.3 Building a Dialog
180
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.