/* Routines for making a pop-up menu */

#include <stdio.h>
#include <string.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include "Box.h"
#include "MenuBtn.h"


/* Global variables */
static Widget menu, box;
static void pop();

#define MAXITEMS 20
static char *mlabels[MAXITEMS];	        /* Menu button labels */
static XtCallbackProc cblist[MAXITEMS];	/* Call back routines */
static Widget button[MAXITEMS];		/* Menu button widgets */
static int mcount;		        /* Count of items in the above lists */


/* Initialization routine */
menu_init(parent)
     Widget parent;
{
  register int i;
  Arg arglist[10];
  static XtCallbackRec callbacks[] =
    { {(XtCallbackProc) pop, NULL}, {NULL, NULL} };

  static char
    menutr[] =   "<Btn1Up>:   MenuPopdown(menu)",
    boxtr[] =    "<Btn1Up>:   MenuPopdown(menu)",
    parenttr[] = "<Btn1Down>: MenuPopup(menu)";

  mcount = 0;

  /* Create a spring-loaded pop-up shell */
  i = 0;
  XtSetArg(arglist[i], XtNpopupCallback, callbacks); i++;
  /*** Using saveUnder seems to cause more overhead ***/
  XtSetArg(arglist[i], XtNsaveUnder, False); i++;
  XtSetArg(arglist[i], XtNtranslations, XtParseTranslationTable(menutr)); i++;
  menu = XtCreatePopupShell("menu", overrideShellWidgetClass, parent,
			    arglist, i);

  /* Create a Box widget to hold the menu bottons */
  XtSetArg(arglist[0], XtNtranslations, XtParseTranslationTable(boxtr));
  box = XtCreateManagedWidget("box", boxWidgetClass, menu, arglist, 1);

  /* Change parent's translation table to call us */
  XtOverrideTranslations(parent, XtParseTranslationTable(parenttr));
}


/* Routine to add a menu item.  Return item number.  */
int menu_add(label, cb)
     char *label;
     XtCallbackProc cb;
{
  if (mcount >= MAXITEMS) return mcount;
  mlabels[mcount] = strcpy(XtMalloc(strlen(label) + 1), label);
  cblist[mcount] = cb;
  return mcount++;
}


/* Call this routine after all items have been added */
menu_done()
{
  register int i;
  int j;
  Dimension internal_width, width, maxw;
  Widget dummy;
  XFontStruct* font;
  Arg arglist[10];
  XtTranslations trtable;
  static XtCallbackRec callbacks[] = { {NULL, NULL}, {NULL, NULL} };
  static char menutr[] =
    "<Btn1Down>:	set() \n\
     <Btn1Up>:		notify() unset() MenuPopdown(menu) \n\
     <EnterWindow>:	set() \n\
     <LeaveWindow>:	unset()";

  /* Create a dummy button so that we can get the font and width values */
  dummy = XtCreateWidget("x", menuBtnWidgetClass, box, NULL, 0);
  i = 0;
  XtSetArg(arglist[i], XtNfont, &font); i++;
  XtSetArg(arglist[i], XtNinternalWidth, &internal_width); i++;
  XtGetValues(dummy, arglist, i);
  XtDestroyWidget(dummy);

  /* Find the width of the widest menu button */
  maxw = 0;
  for (j = 0; j < mcount; j++)
    {
      width = XTextWidth(font, mlabels[j], strlen(mlabels[j]));
      if (width > maxw) maxw = width;
    }

  /* Compute width for all the buttons */
  width = maxw + 2 * internal_width;

  /* Create all the menu button widgets */
  trtable = XtParseTranslationTable(menutr);
  for (j = 0; j < mcount; j++) 
    {
      callbacks[0].callback = cblist[j];
      i = 0;
      XtSetArg(arglist[i], XtNlabel, mlabels[j]); i++;
      XtSetArg(arglist[i], XtNcallback, callbacks); i++;
      XtSetArg(arglist[i], XtNwidth, width); i++;
      XtSetArg(arglist[i], XtNjustify, XtJustifyLeft); i++;
      XtSetArg(arglist[i], XtNtranslations, trtable); i++;
      button[j] = XtCreateManagedWidget("menubutton", menuBtnWidgetClass,
					box, arglist, i);
      XtFree(mlabels[j]);
    }
}


/* Change a menu label */
menu_change(item_num, label)
     int item_num;
     char *label;
{
  Arg arglist[1];
  XtSetArg(arglist[0], XtNlabel, label);
  XtSetValues(button[item_num], arglist, 1);
}



/*** Private routines ***/


/* This routine gets called at pop-up time */
/*ARGSUSED*/ static void pop(w, client_data, call_data)
     Widget w;
     caddr_t client_data;
     caddr_t call_data;
{
  Window root, child;
  int x, y, winx, winy;
  Dimension width;
  unsigned int mask;
  static Arg getarg[] = { {XtNwidth, 0} };

  /* The MenuPop action routine does an automatic realize, but only
     after it does the callbacks.  Since we need a real window here,
     we call XtRealize in case it hasn't been done yet.  */
     
  XtRealizeWidget(w);

  /* Get current mouse position */
  XQueryPointer(XtDisplay(w), XtWindow(w), &root, &child, &x, &y,
		&winx, &winy, &mask);

  /* Get width of the menu window */
  XtSetArg(getarg[0], XtNwidth, &width);
  XtGetValues(w, getarg, XtNumber(getarg));

  /* Center the menu on current mouse position */
  x = x - width / 2;
  if (x < 0) x = 0;
  XtMoveWidget(w, (Position) x, (Position) y);
}
