
#if !defined(lint) &&!defined(SABER)
static char XRNrcsid[] = "$Header: /wrld/mnt11/ricks/src/X/xrn/RCS/dialogs.c,v 1.20 91/08/01 13:19:57 ricks Exp $";
#endif

/*
 * xrn - an X-based NNTP news reader
 *
 * Copyright (c) 1988, 1989, 1990, 1991, Ellen M. Sentovich and Rick L. Spickelmier.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted, provided
 * that the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of the University of California not
 * be used in advertising or publicity pertaining to distribution of 
 * the software without specific, written prior permission.  The University
 * of California makes no representations about the suitability of this
 * software for any purpose.  It is provided "as is" without express or
 * implied warranty.
 *
 * THE UNIVERSITY OF CALIFORNIA DISCLAIMS ALL WARRANTIES WITH REGARD TO 
 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 
 * FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE FOR
 * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * dialogs.c: create simple moded dialog boxes
 */

#include "copyright.h"
#include <X11/Xos.h>
#include "config.h"
#include "utils.h"
#include <X11/StringDefs.h>
#include <X11/Intrinsic.h>
#include <X11/Shell.h>

#ifndef MOTIF
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Dialog.h>
#else
#include <Xm/PushB.h>
#include <Xm/RowColumn.h>
#include <Xm/Form.h>
#include <Xm/Label.h>
#include <Xm/Text.h>
#endif

#include <stdio.h>

#include "xthelper.h"
#include "xmisc.h"
#include "xrn.h"
#include "dialogs.h"

#ifdef VMS
Widget MyNameToWidget();
#define XtNameToWidget MyNameToWidget
#endif /* VMS */

#ifdef MOTIF
/**********************************************************************
Called when return is pressed in the text field.  When this happens,
simulate pressing of the default button and call the default button's
callback.
**********************************************************************/

void returnHandler(w, data, call_data)
Widget w;
Widget data;
caddr_t call_data;
{
  Pixel topShadow, bottomShadow, bg, armColor;
  Boolean fillArm;
  Arg args[5];
  int ct;

/* This is bad -- we assume that the top and bottom shadows are colors */
  ct = 0;
  XtSetArg(args[ct], XmNtopShadowColor, &topShadow);  ct++;
  XtSetArg(args[ct], XmNbottomShadowColor, &bottomShadow);  ct++;
  XtSetArg(args[ct], XmNbackground, &bg);  ct++;
  XtSetArg(args[ct], XmNarmColor, &armColor);  ct++;
  XtSetArg(args[ct], XmNfillOnArm, &fillArm);  ct++;
  XtGetValues(data, args, ct);

  ct = 0;
  XtSetArg(args[ct], XmNtopShadowColor, bottomShadow);  ct++;
  XtSetArg(args[ct], XmNbottomShadowColor, topShadow);  ct++;
  if (fillArm) {
    XtSetArg(args[ct], XmNbackground, armColor);  ct++;
  }
  XtSetValues(data, args, ct);
  XmUpdateDisplay(data);

  XtCallCallbacks(data, XmNactivateCallback, NULL);

  ct = 0;
  XtSetArg(args[ct], XmNtopShadowColor, topShadow);  ct++;
  XtSetArg(args[ct], XmNbottomShadowColor, bottomShadow);  ct++;
  if (fillArm) {
    XtSetArg(args[ct], XmNbackground, bg);  ct++;
  }
  XtSetValues(data, args, ct);
  XmUpdateDisplay(data);
}
#endif

static Widget
GetAncestorShell(w)
Widget w;
/*
 * find the closest ancestor of w which is a shell
 */
{
    while (w && (! XtIsShell(w)))
	w = XtParent(w);

    return (w);
}


Widget
CreateDialog(parent, title, textField, args, count)
Widget parent;           /* parent window                         */
char *title;             /* title of the dialog box               */
char *textField;	 /* default text field                    */
struct DialogArg *args;  /* description of the buttons            */
unsigned int count;      /* number of buttons                     */
/*
 * create a simple moded dialog box
 */
{
    Widget popup, dialog;
    Arg dargs[4];
    int cnt = 0;
    int i;
    Widget typein;
    Widget bb;
    Arg bbArgs[3];
    static Arg shellArgs[] = {
	{XtNallowShellResize, (XtArgVal) True},
	{XtNinput, (XtArgVal) True},
        {XtNtransientFor, (XtArgVal) NULL},
    };
#ifdef MOTIF
    Widget form, textf, lastButton;
    XmString xs;
    int defaultThickness = 2;
#endif

    XtSetArg(shellArgs[2], XtNtransientFor, GetAncestorShell(parent));
    /* override does not get titlebar, transient does */
    popup = XtCreatePopupShell("popup", transientShellWidgetClass, parent,
			       shellArgs, XtNumber(shellArgs));
    
    /* create the dialog box */
#ifndef MOTIF
    XtSetArg(dargs[cnt], XtNvalue, textField); cnt++;
    XtSetArg(dargs[cnt], XtNlabel, title); cnt++;
    XtSetArg(dargs[cnt], XtNinput, True); cnt++;
    dialog = XtCreateManagedWidget("dialog", dialogWidgetClass, popup, dargs, cnt);
#else
    xs = XmStringCreate(title, XmSTRING_DEFAULT_CHARSET);
    dialog = XmCreateRowColumn(popup, "dialog", dargs, cnt);
    
    cnt = 0;
    XtSetArg(dargs[cnt], XmNlabelString, xs); cnt++;
    XtSetArg(dargs[cnt], XmNalignment, XmALIGNMENT_BEGINNING); cnt++;
    XtManageChild(XmCreateLabel(dialog, "label", dargs, cnt));
    XmStringFree(xs);
    
    if (textField != DIALOG_NOTEXT) {
      cnt = 0;
      XtSetArg(dargs[cnt], XmNvalue, textField); cnt++;
      textf = XmCreateText(dialog, "textField", dargs, cnt);
      XtManageChild(textf);
      XtSetKeyboardFocus(dialog, textf);
    }

    cnt = 0;
    XtSetArg(dargs[cnt], XmNorientation, XmHORIZONTAL); cnt++;
    form = XmCreateForm(dialog, "buttons", dargs, cnt);
#endif

    /* add the buttons */
    for (i = 0; i < count; i++) {
	Arg bargs[2];
	Widget button;
	static XtCallbackRec callbacks[] = {
	    {CBbusyCursor, NULL},
	    {NULL, NULL},
	    {CBunbusyCursor, NULL},
	    {NULL, NULL},
	};

	callbacks[1].callback = args[i].handler;
	callbacks[1].closure = args[i].data;

#ifndef MOTIF
	XtSetArg(bargs[0], XtNlabel, args[i].buttonName);
	XtSetArg(bargs[1], XtNcallback, callbacks);
	if (i == count - 1) {
	    bb = button = XtCreateManagedWidget("default", commandWidgetClass,
					dialog, bargs, XtNumber(bargs));
	} else {
	    button = XtCreateManagedWidget("command", commandWidgetClass,
					dialog, bargs, XtNumber(bargs));
	}
#else
	{
	    static XtCallbackRec callback1[] = {
	       {NULL, NULL},
	       {NULL, NULL},
	    };
	    static XtCallbackRec callback2[] = {
	       {NULL, NULL},
	       {NULL, NULL},
	    };
	    static XtCallbackRec callback3[] = {
	       {NULL, NULL},
	       {NULL, NULL},
	    };
	    Arg margs[10];
	    int ct = 0;

	    xs = XmStringCreate(args[i].buttonName, XmSTRING_DEFAULT_CHARSET);
	    XtSetArg(margs[ct], XmNlabelString, xs);  ct++;
	    callback1[0] = callbacks[0];
	    XtSetArg(margs[ct], XmNarmCallback, callback1);  ct++;
	    callback2[0] = callbacks[1];
	    XtSetArg(margs[ct], XmNactivateCallback, callback2); ct++;
	    callback3[0] = callbacks[2];
	    XtSetArg(margs[ct], XmNdisarmCallback, callback3);  ct++;
	    callback3[0] = callbacks[2];
	    XtSetArg(margs[ct], XmNdisarmCallback, callback3);  ct++;
	    XtSetArg(margs[ct], XmNtopAttachment, XmATTACH_FORM);  ct++;
	    if (!i) {
	        XtSetArg(margs[ct], XmNtopOffset, 3*defaultThickness);  ct++;
	        XtSetArg(margs[ct], XmNleftAttachment, XmATTACH_FORM);  ct++;
	    } else {
	        XtSetArg(margs[ct], XmNtopOffset, 3*defaultThickness);  ct++;
	        XtSetArg(margs[ct], XmNleftAttachment, XmATTACH_WIDGET);  ct++;
	        XtSetArg(margs[ct], XmNleftWidget, lastButton);  ct++;
	    }

	    if (i == count - 1) {
	        bb = button = XmCreatePushButton(form, "default", margs, ct);
	    } else {
	        button = XmCreatePushButton(form, "command", margs, ct);
	    }

	    XtManageChild(button);
	    lastButton = button;
	    XmStringFree(xs);
	}
#endif
    }

#ifndef MOTIF
    if ((typein = XtNameToWidget(dialog, "value")) != 0) {
	XtSetKeyboardFocus(dialog, typein);
	/* XtSetKeyboardFocus(TopLevel, typein); XXX causes occasional core dumps */
    }

    XtSetArg(bbArgs[0], XtNborderWidth, 0);
    XtSetArg(bbArgs[1], XtNhighlightThickness, 0);
    XtGetValues(bb, bbArgs, 2);

    XtSetArg(bbArgs[0], XtNborderWidth, bbArgs[0].value + 1);
    XtSetArg(bbArgs[1], XtNhighlightThickness, bbArgs[0].value + 1);
    XtSetValues(bb, bbArgs, 2);
#else
    XtSetArg(bbArgs[0], XmNshowAsDefault, defaultThickness);
    XtSetArg(bbArgs[1], XmNtopOffset, 0);
    XtSetValues(bb, bbArgs, 2);

    XtManageChild(form);
    XtManageChild(dialog);

    if (textField != DIALOG_NOTEXT) {
      static XtCallbackRec callback[] = {
	{returnHandler, NULL},
	{NULL, NULL},
      };

      callback[0].closure = (caddr_t) bb;
      XtSetArg(bbArgs[0], XmNactivateCallback, callback);
      XtSetValues(textf, bbArgs, 1);
    }
#endif
	
    XtRealizeWidget(popup);

#ifndef ACCELERATORBUG
    XtInstallAccelerators(dialog, bb);
    XtInstallAccelerators(popup, bb);
#endif
#ifndef MOTIF
    if (typein != 0) {
	XtInstallAccelerators(typein, bb);
	if (textField) {
	    XEvent ev;
	    /* force the text field to be 'big enough' */
	    XtCallActionProc(typein, "beginning-of-line", &ev, 0, 0);
	}
    }
#endif
    return(popup);
}

#ifdef DECFOCUSPATCH
void
FocusPopUp(popup, data, event)
Widget popup;
caddr_t data;
XEvent *event;
{
    if (event->type == MapNotify) {
	XSetInputFocus(XtDisplay(popup), XtWindow(popup),
		     RevertToPointerRoot,  CurrentTime);
	XtRemoveEventHandler(popup, XtAllEvents, True, FocusPopUp, 0);
    }
    return;
}
#endif


void
PopUpDialog(popup)
Widget popup;
{
    xthCenterWidgetOverCursor(popup);
    XtPopup(popup, XtGrabExclusive);
#ifdef DECFOCUSPATCH
    XtAddEventHandler(popup, StructureNotifyMask, False, FocusPopUp, 0);
#endif
    return;
}


void
PopDownDialog(dialog)
Widget dialog;
/*
 * pop down the dialog (do not destroy, it will be used again)
 */
{
    XtPopdown(dialog);
    XtDestroyWidget(dialog);
    return;
}


char *
GetDialogValue(popup)
Widget popup;
{
  
#ifndef MOTIF
    return XawDialogGetValueString(XtNameToWidget(popup, "dialog"));
#else
    char *result;

    result = XmTextGetString(XtNameToWidget(XtNameToWidget(popup, "dialog"),
					    "textField"));
    if (result) {
      return result;
    } else {
      return "";
    }
#endif
}


/*
 * simple confirmation box
 */

static int retVal;

/* ARGSUSED */
static void
cbHandler(widget, client_data, call_data)
Widget widget;
caddr_t client_data;
caddr_t call_data;
{
    retVal = (int) client_data;
    return;
}


int
ConfirmationBox(parent, message)
Widget parent;
char *message;
/*
 * pop up a confirmation box and return either 'XRN_CB_ABORT' or 'XRN_CB_CONTINUE'
 */
{
    static struct DialogArg args[] = {
	{"no", cbHandler, (caddr_t) XRN_CB_ABORT},
	{"yes", cbHandler, (caddr_t) XRN_CB_CONTINUE},
    };
    XEvent ev;
    Widget widget;

    retVal = -1;

    widget = CreateDialog(parent, message, DIALOG_NOTEXT, args, XtNumber(args));
    PopUpDialog(widget);

    for(;;) {
	XtNextEvent(&ev);
	(void) XtDispatchEvent(&ev);
	if (retVal != -1) {
	    PopDownDialog(widget);
	    return(retVal);
	}
    }
}

