/* 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.
 */

/* ask_user.c -- the user is presented with two pushbuttons.  
 * The first creates a file (/tmp/foo) and the second removes it.  
 * In each case, a dialog pops up asking for verification of the action.
 *
 * This program is intended to demonstrate an advanced implementation
 * of the AskUser() function.  This time, the function is passed the
 * strings to use for the OK button and the Cancel button as well as
 * the button to use as the default value.
 */
#include <Xm/DialogS.h>
#include <Xm/SelectioB.h>
#include <Xm/RowColumn.h>
#include <Xm/MessageB.h>
#include <Xm/PushB.h>

#define YES 1
#define NO  2

/* Generalize the question/answer process by creating a data structure
 * that has the necessary labels, questions and everything needed to
 * execute a command.
 */
typedef struct {
    char *label;    /* label for pushbutton used to invoke cmd */
    char *question; /* question for dialog box to confirm cmd */
    char *yes;      /* what the "OK" button says */
    char *no;       /* what the "Cancel" button says */
    int   dflt;     /* which should be the default answer */
    char *cmd;      /* actual command to execute (using system()) */
} QandA;

QandA touch_foo = {
    "Create", "Create /tmp/foo?", "Yes", "No", YES, "touch /tmp/foo"
};
QandA rm_foo = {
    "Remove", "Remove /tmp/foo?", "Yes", "No", NO, "rm /tmp/foo"
};

XtAppContext app;

main(argc, argv)
int argc;
char *argv[];
{
    Widget toplevel, button, rowcolumn;
    XmString label;
    void pushed();

    XtSetLanguageProc (NULL, NULL, NULL);

    toplevel = XtVaAppInitialize (&app, "Demos",
        NULL, 0, &argc, argv, NULL, NULL);

    rowcolumn = XtVaCreateManagedWidget ("rowcolumn",
        xmRowColumnWidgetClass, toplevel, NULL);

    label = XmStringCreateLocalized (touch_foo.label);
    button = XtVaCreateManagedWidget ("button",
        xmPushButtonWidgetClass, rowcolumn,
        XmNlabelString,          label,
        NULL);
    XtAddCallback (button, XmNactivateCallback, pushed, &touch_foo);
    XmStringFree (label);

    label = XmStringCreateLocalized (rm_foo.label);
    button = XtVaCreateManagedWidget ("button",
        xmPushButtonWidgetClass, rowcolumn,
        XmNlabelString,          label,
        NULL);
    XtAddCallback (button, XmNactivateCallback, pushed, &rm_foo);
    XmStringFree (label);

    XtManageChild (rowcolumn);
    XtRealizeWidget (toplevel);
    XtAppMainLoop (app);
}

/* pushed() --when a button is pressed, ask the question described
 * by the QandA parameter (client_data).  Execute the cmd if YES.
 */
void
pushed(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
    QandA *quest = (QandA *) client_data;

    if (AskUser (widget, quest->question, quest->yes, quest->no,
            quest->dflt) == YES) {
        printf ("Executing: %s\n", quest->cmd);
        system (quest->cmd);
    } else
        printf ("Not executing: %s\n", quest->cmd);
}

/*
 * AskUser() -- a generalized routine that asks the user a question
 * and returns a response.  Parameters are: the question, the labels
 * for the "Yes" and "No" buttons, and the default selection to use.
 */
int AskUser(parent, question, ans1, ans2, default_ans)
Widget parent;
char *question, *ans1, *ans2;
int default_ans;
{
    static Widget dialog; /* static to avoid multiple creation */
    XmString text, yes, no;
    static int answer;
    extern void response();

    if (!dialog) {
        dialog = XmCreateQuestionDialog (parent, "dialog", NULL, 0);
        XtVaSetValues (dialog,
            XmNdialogStyle,        XmDIALOG_FULL_APPLICATION_MODAL,
            NULL);
        XtSetSensitive (
            XmMessageBoxGetChild (dialog, XmDIALOG_HELP_BUTTON),
            False);
        XtAddCallback (dialog, XmNokCallback, response, &answer);
        XtAddCallback (dialog, XmNcancelCallback, response, &answer);
    }
    answer = 0;
    text = XmStringCreateLocalized (question);
    yes = XmStringCreateLocalized (ans1);
    no = XmStringCreateLocalized (ans2);
    XtVaSetValues (dialog,
        XmNmessageString,      text,
        XmNokLabelString,      yes,
        XmNcancelLabelString,  no,
        XmNdefaultButtonType,  default_ans == YES ?
            XmDIALOG_OK_BUTTON : XmDIALOG_CANCEL_BUTTON,
        NULL);
    XmStringFree (text);
    XmStringFree (yes);
    XmStringFree (no);
    XtManageChild (dialog);
    XtPopup (XtParent (dialog), XtGrabNone);

    while (answer == 0)
        XtAppProcessEvent (app, XtIMAll);

    XtPopdown (XtParent (dialog));
    /* make sure the dialog goes away before returning. Sync with server
     * and update the display.
     */
    XSync (XtDisplay (dialog), 0);
    XmUpdateDisplay (parent);

    return answer;
}

/* response() --The user made some sort of response to the
 * question posed in AskUser().  Set the answer (client_data)
 * accordingly.
 */
void
response(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
    int *answer = (int *) client_data;
    XmAnyCallbackStruct *cbs = (XmAnyCallbackStruct *) call_data;

    if (cbs->reason == XmCR_OK)
        *answer = YES;
    else if (cbs->reason == XmCR_CANCEL)
        *answer = NO;
}