/****************************************************************************
**
*A  popdial.c			XGAP source	                 Frank Celler
**
*H  @(#)$Id: popdial.c,v 1.2 1993/12/23 08:45:54 fceller Exp $
**
*Y  Copyright 1992-1994,  Lehrstuhl D fuer Mathematik,  RWTH Aachen,  Germany
**
**  This file contains functions for popping up dialogs.
**
*H  $Log: popdial.c,v $
*H  Revision 1.2  1993/12/23  08:45:54  fceller
*H  used unsigned bitmaps to avoid compiler warnings
*H
*H  Revision 1.1  1993/08/12  13:50:35  fceller
*H  fixed keyboard grab on dec station
*H
*H  Revision 1.1  1993/08/12  13:50:35  fceller
*H  fixed keyboard grab on dec station
*H
*H  Revision 1.0  1993/04/05  11:42:18  fceller
*H  Initial revision
*/
#include    <X11/X.h>
#include    <X11/Intrinsic.h>
#include    <X11/StringDefs.h>
#include    <X11/Shell.h>

#include    <X11/Xaw/Dialog.h>
#include    <X11/Xaw/Command.h>
#include    <X11/Xaw/SmeBSB.h>

#include    "utils.h"
#include    "popdial.h"


/****************************************************************************
**
*F  ButtonSelected( <w>, <cld>, <cd> )	. . . . . . callback for button click
*/
static struct { char * name;  int flag; } buttons[] =
{
    { "yes",	    YES       },
    { "no",         NO        },
    { "OK",         OK        },
    { "cancel",     CANCEL    },
    { "abort",      ABORT     },
    { "retry",      RETRY     },
    { "append",     APPEND    },
    { "overwrite",  OVERWRITE }
};

static void ButtonSelected ( w, cld, cd )
    Widget	    w;
    XtPointer       cld;
    XtPointer       cd;
{
    int           * res = (int*) cld;
    String          name;
    int             i;

    /* find name in <buttons> and set result */
    XtVaGetValues( w, XtNlabel, &name, 0, 0 );
    for ( i = 0;  i < XtNumber(buttons);  i++ )
	if ( ! strcmp( buttons[i].name, name ) )
	    (*res) |= buttons[i].flag;
}


/****************************************************************************
**
*F  CreatePopupDialog( <app>, <top>, <name>, <button>, <default> )  .  create
*/
#define ret_width 16
#define ret_height 16
static unsigned char ret_bits[] = {
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x60, 0x0c, 0x30, 0x0c,
   0x18, 0x0c, 0xfc, 0x07, 0xfc, 0x03, 0x18, 0x00, 0x30, 0x00, 0x60, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

TypePopupDialog CreatePopupDialog ( app, top, name, bt, def, pix )
    XtAppContext        app;
    Widget	        top;
    String              name;
    int                 bt;
    int                 def;
    Pixmap              pix;
{
    static Pixmap       symbol = 0;              
    TypePopupDialog     dialog;
    Display           * dp;
    Widget              entry;
    int                 i;

    
    /* create pixmap for default button */
    if ( symbol == 0 )
    {
	dp = XtDisplay(top);
	symbol = XCreateBitmapFromData( dp,
				        DefaultRootWindow(dp),
				        ret_bits,
				        ret_width,
				        ret_height );
    }

    /* create a new popup variable */
    dialog = (TypePopupDialog) XtMalloc( sizeof( struct _popup_dialog ) );
    dialog->topLevel   = top;
    dialog->popupShell = XtVaCreatePopupShell(
			     name, overrideShellWidgetClass, top,
			     XtNallowShellResize, True,
			     0, 0 );
    if ( pix == 0 )
        dialog->dialog = XtVaCreateManagedWidget(
                             "xgapDialog",  dialogWidgetClass,
                             dialog->popupShell,
                             XtNicon, pix,
                             0, 0 );
    else
        dialog->dialog = XtVaCreateManagedWidget(
                             "xgapDialog",  dialogWidgetClass,
                             dialog->popupShell,
                             XtNicon, pix,
                             0, 0 );
    dialog->button        = bt;
    dialog->context       = app;
    dialog->defaultButton = def;

    /* add buttons to the dialog */
    for ( i = 0;  i < XtNumber(buttons);  i++ )
	if ( bt & buttons[i].flag )
	{
	    if ( buttons[i].flag == def )
		entry = XtVaCreateManagedWidget(
			    buttons[i].name, commandWidgetClass,
			    dialog->dialog, 
			    XtNleftBitmap, symbol,
			    0, 0 );
	    else
		entry = XtVaCreateManagedWidget(
			    buttons[i].name, commandWidgetClass,
			    dialog->dialog, 
			    0, 0 );
	    XtAddCallback( entry,
			   XtNcallback,
			   ButtonSelected,
			   &(dialog->result) );
	}
    return dialog;
}


/****************************************************************************
**
*F  PopupDialog( <dialog>, <message>, <deflt>, <result> ) . . . . . . . do it
*/
int PopupDialog ( dialog, message, deflt, result )
    TypePopupDialog	dialog;
    String              message;
    String              deflt;
    String *            result;
{
    Display *           display;
    Position            x1,  y1,  tmp;
    Dimension           w1,  h1,  bw;
    Window              root;
    Window              child;
    int        	        x2,  y2,  x3,  y3;
    unsigned int        bt;

    /* set message and default answer in dialog */
    XtVaSetValues( dialog->dialog,
		   XtNlabel, 	message,
		   XtNvalue,    deflt,
		   0,           0 );
    XtRealizeWidget( dialog->popupShell );

    /* get size of popup dialog */
    XtVaGetValues( dialog->popupShell,
		   XtNwidth,       &w1,
		   XtNheight,      &h1,
		   XtNborderWidth, &bw,
		   0,              0 );

    /* get position of the mouse pointer */
    display = XtDisplay(dialog->popupShell);
    XQueryPointer( display, XtWindow(dialog->popupShell),
		   &root, &child, &x2, &y2, &x3, &y3, &bt );

    /* find a nice position for the dialog */
    tmp = DisplayWidth( XtDisplay(dialog->popupShell),
		        DefaultScreen(XtDisplay(dialog->popupShell)) );
    x1 = x2 - (bw+w1)/2;
    if ( tmp-w1-2*bw < x1 )  x1 = tmp-w1-2*bw;
    if ( x1 < 0 )  x1 = 0;
    tmp = DisplayHeight( XtDisplay(dialog->popupShell),
		         DefaultScreen(XtDisplay(dialog->popupShell)) );
    y1  = y2 - (bw+h1)/2;
    if ( tmp-h1-2*bw < y1 )  y1 = tmp-h1-2*bw;
    if ( y1 < 0 )  y1 = 0;

    /* move the popup dialog to this position */
    XtVaSetValues( dialog->popupShell,
		   XtNx, x1,
		   XtNy, y1,
		   0,    0 );

    /* pop up shell */
    XtPopup( dialog->popupShell, XtGrabExclusive );

    /* and grab keyboard */
    XGrabKeyboard( display, XtWindow(dialog->dialog), False,
		   GrabModeAsync, GrabModeAsync, CurrentTime );

    /* wait until at least one button is selected */
    dialog->result = 0;
    while ( ( dialog->result & dialog->button ) == 0 )
    {
	XEvent	event;
	char    str[128];
	KeySym  keysym;
	int     len;

	/* get next application event */
	XtAppNextEvent(dialog->context, &event);

	/* is the event a key event */
	if ( event.type == KeyPress )
	{
	    if ( dialog->defaultButton != 0 )
	    {

		/* convert key event into text string and check for return */
		len = XLookupString((XKeyEvent*)&event,str,128,&keysym,0);
		if ( len != 0 && ( str[0] == '\n' || str[0] == '\r' ) )
		{
		    dialog->result |= dialog->defaultButton;
		    continue;
		}
	    }
	}

	/* dipatch event normally */
	XtDispatchEvent(&event);
    }

    /* return answer string in <result> */
    if ( result )
        *result = XawDialogGetValueString(dialog->dialog);
    
    /* remove pop up menu from screen */
    XtPopdown(dialog->popupShell);
    return dialog->result & dialog->button;
}
