/* Written by 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_area2.c -- a variation of action_area.c that uses the Motif 1.2
 * TemplateDialog to create a customized dialog.
 */
#include <Xm/PushB.h>
#include <Xm/LabelG.h>
#include <Xm/RowColumn.h>
#include <Xm/TextF.h>
#include <Xm/MessageB.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, rc, text_w;
    XmString string;
    Arg args[5];
    int n = 0;
    extern void CreateActionArea();
    static ActionAreaItem action_items[] = {
        { "OK",     ok_pushed,     NULL          },
        { "Clear",  clear_pushed,  NULL          },
        { "Cancel", close_dialog,  NULL          },
        { "Help",   help,          "Help Button" },
    };

    /* Create a TemplateDialog that will contain the control area
     * and the action area buttons for the dialog
     */
    string = XmStringCreateLocalized ("Dialog Shell");
    XtSetArg (args[n], XmNdialogTitle, string); n++;
    XtSetArg (args[n], XmNautoUnmanage, False); n++;
    dialog = XmCreateTemplateDialog (XtParent (w), "dialog", args, n);
    XmStringFree (string);

    /* 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 control area which contains a
     * Label gadget and a TextField widget.
     */
    rc = XtVaCreateWidget ("control_area", 
        xmRowColumnWidgetClass, dialog, 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 "Clear" buttons */
    action_items[0].data = (XtPointer) text_w;
    action_items[1].data = (XtPointer) text_w;

    /* Create the action area. */
    CreateActionArea (dialog, action_items, XtNumber (action_items));

    /* callback for Return in TextField.  Use dialog as client data */
    XtAddCallback (text_w, XmNactivateCallback, activate_cb, dialog);

    XtManageChild (dialog);
    XtPopup (XtParent (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;        /* dialog passed as client data */
XtPointer call_data;
{
    XmAnyCallbackStruct *cbs = (XmAnyCallbackStruct *) call_data;
    Widget dflt, dialog = (Widget) client_data;

    /* get the "default button" from the action area... */
    XtVaGetValues (dialog, 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);
}

void
CreateActionArea(dialog, actions, num_actions)
Widget dialog;
ActionAreaItem *actions;
int num_actions;
{
    Widget widget;
    int i;

    for (i = 0; i < num_actions; i++) {
        widget = XtVaCreateManagedWidget (actions[i].label,
            xmPushButtonWidgetClass, dialog,
	    XmNshowAsDefault, i == 0,
	    XmNdefaultButtonShadowThickness, 1,
            NULL);
	if (actions[i].callback)
            XtAddCallback (widget, XmNactivateCallback,
                actions[i].callback, actions[i].data);
        if (i == 0) 
            XtVaSetValues (dialog, XmNdefaultButton, widget, NULL);
    }
}