/*
 * Copyright 1989 Massachusetts Institute of Technology
 *
 * 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 M.I.T. not be used in advertising
 * or publicity pertaining to distribution of the software without specific,
 * written prior permission.  M.I.T. makes no representations about the
 * suitability of this software for any purpose.  It is provided "as is"
 * without express or implied warranty.
 *
 * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
 * 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.
 *
 * Author: Carlo Lisa
 *	   MIT Project Athena
 *	   carlo@athena.mit.edu
 *
 * Modified by Lachlan Wetherall (lachlan@compsys.com.au) for use in the 
 * xregal program. December 1995.
 *
 */

#include <stdio.h>
#include <X11/Intrinsic.h>	/* Intrinsics Definitions */
#include <X11/StringDefs.h>	/* Standard Name-String definitions */
#include <X11/Shell.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Form.h>	
#include <X11/Xaw/AsciiText.h>
#include "Mlabel.h"

#include "xregal.h"
#include "popup.h"

/* stole this chunk from xdm/dm.c */
#if defined(USE_PROTOTYPES) || defined(__STDC__)
#include <stdarg.h>
#define Va_start(a,b)	va_start(a,b)
#else
#include <varargs.h>
#define Va_start(a,b)	va_start(a)
#endif



void popdownBox(Widget widget, XtPointer closure, XtPointer callData) {
	XtPopdown((Widget)closure);
	XtDestroyWidget((Widget) closure);
	}


/*
 *	Function Name: DialogBox
 *	Description:   This function creates a single dialog box.
 *	Arguments:  top		parent widget;
 *		    conf_func	confirm function (callback);
 *		    c_data	callback data (for conf_func);
 *		    label	label for the dialog box;
 *		    selection 	user's input (back).
 *	Returns:    popup	the dialogbox widget id.
 */

Widget DialogBox(Widget top, 
	XtCallbackProc confirm_func, 
	XtCallbackProc cancel_func, 
	XtPointer c_data, 
	const char *dialogname,
	const char *label, 
	const char *conflab, 
	char *selection) {

  static XtActionsRec dbactions[2];
  static String myreturn = "#override <Key>Return:   set() notify() unset()\n";
  static String myesc = "#override <Key>Escape: set() notify() unset()\n";
  XtAccelerators accel, escaccel;
  static int init = 0;
  Widget popup, form, lbl, input, confirm, cancel;
  Arg args[15];
  Cardinal i;
  XtCallbackRec callback[2];

  dbactions[0].string = "Nothing";
  dbactions[0].proc = (XtActionProc)NULL;

  if (!init) {
    XtAddActions(dbactions, XtNumber(dbactions));
    init = 1;
  }

  accel = XtParseAcceleratorTable(myreturn);
  escaccel = XtParseAcceleratorTable(myesc);

  callback[1].callback = NULL;
  callback[1].closure = (XtPointer)NULL;

  i = 0;
  XtSetArg(args[0], XtNallowShellResize, True); i++;
  popup = XtCreatePopupShell(dialogname, transientShellWidgetClass, top, args, i);

  i = 0;
  form = XtCreateManagedWidget("form", formWidgetClass, popup, args, i);

  i = 0;
  XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
  XtSetArg(args[i], XtNborderWidth, 0); i++;
  if (label!=NULL) {
	  XtSetArg(args[i], XtNlabel, label); i++;
		}
  XtSetArg(args[i], XtNright, XtChainLeft); i++;
  XtSetArg(args[i], XtNleft, XtChainLeft); i++;
  lbl = XtCreateManagedWidget("prompt", labelWidgetClass, form, args, i);

  i = 0;
  XtSetArg(args[i], XtNeditType, XawtextEdit); i++;
  XtSetArg(args[i], XtNstring, selection); i++;
  XtSetArg(args[i], XtNlength, 256); i++;
  XtSetArg(args[i], XtNwidth, 200); i++;
  XtSetArg(args[i], XtNresizable, True); i++;
#ifdef X11R4
  XtSetArg(args[i], XtNtextOptions, resizeWidth); i++;
#endif
  XtSetArg(args[i], XtNvertDistance, 0); i++;
  XtSetArg(args[i], XtNfromVert, lbl); i++;
  XtSetArg(args[i], XtNfromHoriz, NULL); i++;
  XtSetArg(args[i], XtNright, XtChainLeft); i++;
  XtSetArg(args[i], XtNleft, XtChainLeft); i++;
  XtSetArg(args[i], XtNuseStringInPlace, True); i++;
  input = XtCreateManagedWidget("input", asciiTextWidgetClass, form, args, i);
  XtSetKeyboardFocus(form, input);

  i = 0;
  XtSetArg(args[i], XtNvertDistance, 5); i++;
  XtSetArg(args[i], XtNfromVert, input); i++;
  XtSetArg(args[i], XtNfromHoriz, NULL); i++;
  XtSetArg(args[i], XtNright, XtChainLeft); i++;
  XtSetArg(args[i], XtNleft, XtChainLeft); i++;
  callback[0].callback = confirm_func;
  callback[0].closure = c_data;
  XtSetArg(args[i], XtNcallback, callback); i++;
  XtSetArg(args[i], XtNaccelerators, accel); i++;
  confirm = XtCreateManagedWidget(conflab, commandWidgetClass, form, args, i);

  i = 0;
  XtSetArg(args[i], XtNvertDistance, 5); i++;
  XtSetArg(args[i], XtNhorizDistance, 2); i++;
  XtSetArg(args[i], XtNfromVert, input); i++;
  XtSetArg(args[i], XtNfromHoriz, confirm); i++;
  XtSetArg(args[i], XtNright, XtChainLeft); i++;
  XtSetArg(args[i], XtNleft, XtChainLeft); i++;
  callback[0].callback = cancel_func;
  callback[0].closure = (XtPointer)popup;
  XtSetArg(args[i], XtNcallback, callback); i++;
  XtSetArg(args[i], XtNaccelerators, escaccel); i++;
  cancel = XtCreateManagedWidget("Cancel", commandWidgetClass, form,
				 args, i);

  XtInstallAccelerators(input, confirm);
  XtInstallAccelerators(input, cancel);

  return(popup);
}


/*
 *	Function Name:	MessageBox
 *	Description:	This function creates the message dialog box.
 *	Arguments:  top		widget to use as message box parent
 *		    msg		message to display
 *		    btnlabel	label on next button
 *		    btnproc	callback executed when next button is pressed
 *	Returns:    widget	id of the message box.
 */

Widget MessageBox(Widget top, const char *msgname, const char *msg, ...) {
	Widget msg_pop, form, msg_label, button, firstbutton;
	XtCallbackRec callback[2];
	static String myreturn = "#override <Key>Return: set() notify() unset()\n";
	XtAccelerators accel;
	const char *btntext;
	XtCallbackProc btnproc;
	va_list vap;
	Dimension wd;
	int x, numbuttons;

	/* can't popup a messagebox if widgets haven't been realized yet... */
	if (!XtIsRealized(top)) 
		return 0;

	accel = XtParseAcceleratorTable(myreturn);

	callback[1].callback = (XtCallbackProc) NULL;
	callback[1].closure = (XtPointer) NULL;

	msg_pop = XtVaCreatePopupShell(msgname, transientShellWidgetClass, top,
				XtNallowShellResize, True, NULL);

	form = XtVaCreateManagedWidget("form", formWidgetClass, msg_pop, 
				XtNallowShellResize, True, NULL);

	msg_label = XtVaCreateManagedWidget("message", mlabelWidgetClass, form,
				XtNshrinkToFit, True,
				XtNborderWidth, 0,
				XtNlabel, msg,
				NULL);

	Va_start(vap, msg);
	btntext = (const char *)va_arg(vap, const char *);

	button = NULL;
	numbuttons=0;
	while (btntext) {
		btnproc = (XtCallbackProc )va_arg(vap, XtCallbackProc);

		if (btnproc)
			callback[0].callback = btnproc;
		else
			callback[0].callback = popdownBox;
	    callback[0].closure = (XtPointer)msg_pop;
		numbuttons++;
    	button = XtVaCreateManagedWidget(btntext, commandWidgetClass, form, 
				XtNwidth, 100,
				XtNvertDistance, 1,
				XtNfromVert, msg_label,
				XtNfromHoriz, button,
				XtNright, XtChainRight,
				XtNleft, XtChainRight,
				XtNcallback, callback,
				XtNaccelerators, accel,
				NULL);
		if (numbuttons==1)
			firstbutton=button; 
	    XtInstallAccelerators(form, button);

	    btntext = (const char *)va_arg(vap, const char *);
		}
	
	/* try to center the button(s) */
	if (numbuttons>0) {
		XtRealizeWidget(msg_pop);
		XtVaGetValues(msg_pop, XtNwidth, &wd, NULL);
		x=(wd - (100*numbuttons))/2;
		if (x>0)
			XtVaSetValues(firstbutton, XtNhorizDistance, x, NULL);
		}

	return(msg_pop);
	}


/*
 *      Function name:  SetPopup
 *      Description:    This function pops up the specified dialog box.
 *      Arguments:      top - where to pop up this dialog box
 *                      wdg - the widget to be popped up.
 *      Returns:        None.
 */

void SetPopup(Widget top, Widget wdg) {
  Position x=0, y=0;
  Arg args[5];
  Window rwin;
  Window chwin;
  int rx, ry, wx, wy;
  Dimension wd = 0;
  Dimension he = 0;
  unsigned int mask;

  /* Make the popup shell "wdg" come up at the current pointer position */
  XQueryPointer(XtDisplay(top), XtWindow(top), &rwin, &chwin, &rx, &ry,
                &wx, &wy, &mask);

  XtRealizeWidget(wdg);
  XtSetArg(args[0], XtNwidth, &wd);
  XtSetArg(args[1], XtNheight, &he);
  XtGetValues(wdg, args, (Cardinal)2);
  if (wd == 0) wd = 350;
  if (he == 0) he = 150;

  x = rx - wd/2;
  y = ry - he/2;

  if (x<0) x=0;
  if (y<0) y=0;
  XtSetArg(args[0], XtNx, x);
  XtSetArg(args[1], XtNy, y);
  XtSetValues(wdg, args, (Cardinal)2);

  /* Popup the widget */
  XtPopup(wdg, XtGrabNone);
}


void PopDownAlert(Widget w, XtPointer closure, XtPointer call_data) {
        XtPopdown((Widget) closure);
        XtDestroyWidget((Widget) closure);
        }

void Alert(char *msg) {
	Widget alert;

    alert=MessageBox(topLevel, "Alert", msg, "OK", PopDownAlert, NULL);
    SetPopup(topLevel, alert);
    XStoreName(XtDisplay(alert), XtWindow(alert), "Alert");
    }


void SetPopupPosition(Widget w, Widget shell) {
    int dh, dw;
    Window rwin, chwin;
    int rx, ry, wx, wy;
    short int height, width;
    short int sx, sy;
    unsigned int mask;

	if (app_data.popupPosition != NULL) {
		if (sscanf(app_data.popupPosition, "%d,%d", &rx, &ry) != 2) {
			Alert("Invalid value for 'popupPosition' resource.");
			rx=ry=0;
			}
	    XtVaGetValues(shell, XtNx, &sx, XtNy, &sy, NULL);
	    XtVaSetValues(w, XtNx, sx+rx, XtNy, sy+ry, NULL);
		return;
		}

	/* adjust the position of the popup so that it is under the pointer cursor
        but at least 50 pixels from the screen edge */

	dw=DisplayWidth(XtDisplay(topLevel), 0);
    dh=DisplayHeight(XtDisplay(topLevel), 0);
    XQueryPointer(XtDisplay(topLevel), XtWindow(topLevel), &rwin, &chwin, 
                &rx, &ry, &wx, &wy, &mask);
	rx -= 50;
	ry -= 50;

    XtVaGetValues(w, XtNwidth, &width, XtNheight, &height, NULL);
    if (ry+height+50 >dh) ry= dh-height-50;
    if (rx+width+50>dw) rx=dw-width-50;
    XtVaSetValues(w, XtNx, rx, XtNy, ry, NULL);
	}
