/* Written by Dan Heller and Paula Ferguson. * Copyright 1994, O'Reilly & Associates, Inc. * Permission to use, copy, and modify this program without * restriction is hereby granted, as long as this copyright * notice appears in each copy of the program source code. * This program is freely distributable without licensing fees and * is provided without guarantee or warrantee expressed or implied. * This program is -not- in the public domain. */ /* action_area.c -- demonstrate how CreateActionArea() can be used * in a real application. Create what would otherwise be identified * as a PromptDialog, only this is of our own creation. As such, * we provide a TextField widget for input. When the user presses * Return, the OK button is activated. */ #include <Xm/DialogS.h> #include <Xm/PushBG.h> #include <Xm/PushB.h> #include <Xm/LabelG.h> #include <Xm/PanedW.h> #include <Xm/Form.h> #include <Xm/RowColumn.h> #include <Xm/TextF.h> typedef struct { char *label; void (*callback)(); XtPointer data; } ActionAreaItem; static void do_dialog(), close_dialog(), activate_cb(), ok_pushed(), clear_pushed(), help(); main(argc, argv) int argc; char *argv[]; { Widget toplevel, button; XtAppContext app; XtSetLanguageProc (NULL, NULL, NULL); toplevel = XtVaAppInitialize (&app, "Demos", NULL, 0, &argc, argv, NULL, NULL); button = XtVaCreateManagedWidget ("Push Me", xmPushButtonWidgetClass, toplevel, NULL); XtAddCallback (button, XmNactivateCallback, do_dialog, NULL); XtRealizeWidget (toplevel); XtAppMainLoop (app); } /* callback routine for "Push Me" button. Actually, this represents * a function that could be invoked by any arbitrary callback. Here, * we demonstrate how one can build a standard customized dialog box. * The control area is created here and the action area is created in * a separate, generic routine: CreateActionArea(). */ static void do_dialog(w, client_data, call_data) Widget w; /* will act as dialog's parent */ XtPointer client_data; XtPointer call_data; { Widget dialog, pane, rc, text_w, action_a; XmString string; extern Widget CreateActionArea(); static ActionAreaItem action_items[] = { { "OK", ok_pushed, NULL }, { "Clear", clear_pushed, NULL }, { "Cancel", close_dialog, NULL }, { "Help", help, "Help Button" }, }; /* The DialogShell is the Shell for this dialog. Set it up so * that the "Close" button in the window manager's system menu * destroys the shell (it only unmaps it by default). */ dialog = XtVaCreatePopupShell ("dialog", xmDialogShellWidgetClass, XtParent (w), XmNtitle, "Dialog Shell", /* give arbitrary title in wm */ XmNdeleteResponse, XmDESTROY, /* system menu "Close" action */ NULL); /* now that the dialog is created, set the Cancel button's * client data, so close_dialog() will know what to destroy. */ action_items[2].data = (XtPointer) dialog; /* Create the paned window as a child of the dialog. This will * contain the control area and the action area * (created by CreateActionArea() using the action_items above). */ pane = XtVaCreateWidget ("pane", xmPanedWindowWidgetClass, dialog, XmNsashWidth, 1, XmNsashHeight, 1, NULL); /* create the control area which contains a * Label gadget and a TextField widget. */ rc = XtVaCreateWidget ("control_area", xmRowColumnWidgetClass, pane, NULL); string = XmStringCreateLocalized ("Type Something:"); XtVaCreateManagedWidget ("label", xmLabelGadgetClass, rc, XmNlabelString, string, NULL); XmStringFree (string); text_w = XtVaCreateManagedWidget ("text-field", xmTextFieldWidgetClass, rc, NULL); /* RowColumn is full -- now manage */ XtManageChild (rc); /* Set the client data for the "OK" and "Cancel" buttons */ action_items[0].data = (XtPointer) text_w; action_items[1].data = (XtPointer) text_w; /* Create the action area. */ action_a = CreateActionArea (pane, action_items, XtNumber (action_items)); /* callback for Return in TextField. Use action_a as client data */ XtAddCallback (text_w, XmNactivateCallback, activate_cb, action_a); XtManageChild (pane); XtPopup (dialog, XtGrabNone); } /* The next four functions are the callback routines for the buttons * in the action area for the dialog created above. Again, they are * simple examples, yet they demonstrate the fundamental design approach. */ static void close_dialog(w, client_data, call_data) Widget w; XtPointer client_data; XtPointer call_data; { Widget shell = (Widget) client_data; XtDestroyWidget (shell); } /* The "ok" button was pushed or the user pressed Return */ static void ok_pushed(w, client_data, call_data) Widget w; XtPointer client_data; XtPointer call_data; { Widget text_w = (Widget) client_data; XmAnyCallbackStruct *cbs = (XmAnyCallbackStruct *) call_data; char *text = XmTextFieldGetString (text_w); printf ("String = %s\n", text); XtFree (text); } static void clear_pushed(w, client_data, call_data) Widget w; XtPointer client_data; XtPointer call_data; { Widget text_w = (Widget) client_data; XmAnyCallbackStruct *cbs = (XmAnyCallbackStruct *) call_data; /* cancel the whole operation; reset to NULL. */ XmTextFieldSetString (text_w, ""); } static void help(w, client_data, call_data) Widget w; XtPointer client_data; XtPointer call_data; { String string = (String) client_data; puts(string); } /* When Return is pressed in TextField widget, respond by getting * the designated "default button" in the action area and activate * it as if the user had selected it. */ static void activate_cb(text_w, client_data, call_data) Widget text_w; /* user pressed Return in this widget */ XtPointer client_data; /* action_area passed as client data */ XtPointer call_data; { XmAnyCallbackStruct *cbs = (XmAnyCallbackStruct *) call_data; Widget dflt, action_area = (Widget) client_data; /* get the "default button" from the action area... */ XtVaGetValues (action_area, XmNdefaultButton, &dflt, NULL); if (dflt) /* sanity check -- this better work */ /* make the default button think it got pushed using * XtCallActionProc(). This function causes the button * to appear to be activated as if the user pressed it. */ XtCallActionProc (dflt, "ArmAndActivate", cbs->event, NULL, 0); } #define TIGHTNESS 20 Widget CreateActionArea(parent, actions, num_actions) Widget parent; ActionAreaItem *actions; int num_actions; { Widget action_area, widget; int i; action_area = XtVaCreateWidget ("action_area", xmFormWidgetClass, parent, XmNfractionBase, TIGHTNESS*num_actions - 1, XmNleftOffset, 10, XmNrightOffset, 10, NULL); for (i = 0; i < num_actions; i++) { widget = XtVaCreateManagedWidget (actions[i].label, xmPushButtonWidgetClass, action_area, XmNleftAttachment, i? XmATTACH_POSITION : XmATTACH_FORM, XmNleftPosition, TIGHTNESS*i, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNrightAttachment, i != num_actions - 1 ? XmATTACH_POSITION : XmATTACH_FORM, XmNrightPosition, TIGHTNESS * i + (TIGHTNESS - 1), XmNshowAsDefault, i == 0, XmNdefaultButtonShadowThickness, 1, NULL); if (actions[i].callback) XtAddCallback (widget, XmNactivateCallback, actions[i].callback, actions[i].data); if (i == 0) { /* Set the action_area's default button to the first widget * created (or, make the index a parameter to the function * or have it be part of the data structure). Also, set the * pane window constraint for max and min heights so this * particular pane in the PanedWindow is not resizable. */ Dimension height, h; XtVaGetValues (action_area, XmNmarginHeight, &h, NULL); XtVaGetValues (widget, XmNheight, &height, NULL); height += 2 * h; XtVaSetValues (action_area, XmNdefaultButton, widget, XmNpaneMaximum, height, XmNpaneMinimum, height, NULL); } } XtManageChild (action_area); return action_area; }