
#include <X11/Xlib.h>
#include <X11/Xos.h>
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <X11/Xmu/Misc.h>

#include <X11/Shell.h>
#include <X11/Xaw/XawInit.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/CommandP.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/List.h>
#include <X11/Xaw/Viewport.h>

#include <X11/Xtw/Frame.h>
#include <X11/Xtw/ChooserP.h>

static void ClassInitialize();
static void Initialize();
static void Popup();
static void Close();
static void Apply();
static void MakeList();
static void Unselect();
static void Unselect2();

static XtResource chooserResources[] = 
{
  {XtNselection, XtCSelection, XtRString, sizeof(String),
     XtOffset(ChooserWidget, chooser.selection), XtRString, NULL},
  {XtNnoSelection, XtCNoSelection, XtRString, sizeof(String),
     XtOffset(ChooserWidget, chooser.noselection), XtRString, "*none*"},
  {XtNselectionIndex, XtCSelectionIndex, XtRInt, sizeof(int),
     XtOffset(ChooserWidget, chooser.sindex), XtRImmediate, 0},
  {XtNchoices, XtCChoices, XtRPointer, sizeof(char **),
     XtOffset(ChooserWidget, chooser.choices), XtRString, NULL},
  {XtNindices, XtCIndices, XtRPointer, sizeof(char **),
     XtOffset(ChooserWidget, chooser.indices), XtRString, NULL},
  {XtNnumberStrings, XtCNumberStrings, XtRInt, sizeof(int),
     XtOffset(ChooserWidget, chooser.nchoices), XtRImmediate, 0},
  {XtNallowUnselect, XtCAllowUnselect, XtRBoolean, sizeof(Boolean),
     XtOffset(ChooserWidget, chooser.allowUnselect), XtRImmediate, True},
};

static char defaultTranslations[] = 
  "<EnterWindow>:         highlight(Always)    \n\
   <LeaveWindow>:         unhighlight()        \n\
   <Btn1Down>:            set()                \n\
   <Btn1Up>:              popup() unset()      \n\
   <Btn3Up>:              unselect()"; 


static XtActionsRec actionsList[] = 
{
  {"popup",    Popup},
  {"unselect", Unselect2},
};


ChooserClassRec chooserClassRec = {
  { /* core_class fields */
    /* superclass         */    (WidgetClass) &commandClassRec,
    /* class_name         */    "Chooser",
    /* widget_size        */    sizeof(ChooserRec),
    /* class_initialize   */    ClassInitialize,
    /* class_part init    */    NULL,
    /* class_inited       */    FALSE,
    /* initialize         */    Initialize,
    /* initialize_hook    */    NULL,
    /* realize            */    XtInheritRealize,
    /* actions            */    actionsList,
    /* num_actions        */    XtNumber(actionsList),
    /* resources          */    chooserResources,
    /* num_resources      */    XtNumber(chooserResources),
    /* xrm_class          */    NULLQUARK,
    /* compress_motion    */    FALSE,
    /* compress_exposure  */    TRUE,
    /* compress_enterleave*/    TRUE,
    /* visible_interest   */    FALSE,
    /* destroy            */    NULL,
    /* resize             */    XtInheritResize,
    /* expose             */    XtInheritExpose,
    /* set_values         */    NULL,
    /* set_values_hook    */    NULL,
    /* set_values_almost  */    XtInheritSetValuesAlmost,
    /* get_values_hook    */    NULL,
    /* accept_focus       */    NULL,
    /* version            */    XtVersion,
    /* callback_private   */    NULL,
    /* tm_table           */    defaultTranslations,
    /* query_geometry     */	XtInheritQueryGeometry,
    /* display_accelerator*/	XtInheritDisplayAccelerator,
    /* extension          */	NULL
  },
  { /* simple_class fields */
    /* change_sensitive   */    XtInheritChangeSensitive
  },
  { /* label_class fields */
    /* empty              */    0
  },
  { /* comamnd_class fields */
    /* empty              */    0
  },
  { /* chooser_class fields */
    /* empty              */    0
  }
};

WidgetClass chooserWidgetClass = (WidgetClass) &chooserClassRec;


static void 
ClassInitialize()
{
  XawInitializeWidgetSet();
}


/* ARGSUSED */
static void 
Initialize(request, new)
     Widget request;
     Widget new;
{
  ChooserWidget cw = (ChooserWidget) new;
  Arg arglist[10];
  Cardinal num_args = 0;
  Widget form;
  Widget w;
  
  if(cw->chooser.selection)
    {
      XtSetArg(arglist[num_args], XtNlabel, cw->chooser.selection); ++num_args;
    }
  else
    {
      XtSetArg(arglist[num_args], XtNlabel, 
	       cw->chooser.noselection);                            ++num_args;
    }
  XtSetArg(arglist[num_args], XtNresize, True);                     ++num_args;
  XtSetArg(arglist[num_args], XtNhighlightThickness, 1);            ++num_args;
  XtSetValues(cw, arglist, num_args);
  
  XtAddCallback(cw, XtNcallback, Popup, NULL);

  /*
   * popup shell
   */

  cw->chooser.popup = XtCreatePopupShell("chooser", topLevelShellWidgetClass,
					 cw, NULL, 0);
  num_args = 0;
  form = XtCreateManagedWidget("frame", frameWidgetClass, cw->chooser.popup, 
			       arglist, num_args);

  num_args = 0;
  XtSetArg(arglist[num_args], XtNdefaultColumns, 1);                ++num_args;
  XtSetArg(arglist[num_args], XtNforceColumns, True);               ++num_args;
  cw->chooser.list = XtCreateManagedWidget("list", listWidgetClass, 
					   form, arglist, num_args);

  XtSetArg(arglist[0], XtNlabel, "ok");
  w    = XtwAddFrameCommand("commandOK", commandWidgetClass, form, 
			    arglist, 1);
  XtAddCallback(w, XtNcallback, Apply, cw);

  XtSetArg(arglist[0], XtNlabel, "cancel");
  w    = XtwAddFrameCommand("commandCancel", commandWidgetClass, form, 
			    arglist, 1);
  XtAddCallback(w, XtNcallback, Close, cw->chooser.popup);
  if(cw->chooser.allowUnselect)
    {
      XtSetArg(arglist[0], XtNlabel, "unselect");
      w    = XtwAddFrameCommand("commandUnselect", commandWidgetClass, form, 
				arglist, 1);
      XtAddCallback(w, XtNcallback, Unselect, cw);
    }
  MakeList(cw, 0, 1);
}




static void
Popup(cw, closure, call_data)
     ChooserWidget cw;
     XtPointer closure;
     XtPointer call_data;
{
  if(cw->chooser.popped)
    {
      XtMapWidget(cw->chooser.popup);
      XRaiseWindow(XtDisplay(cw->chooser.popup), XtWindow(cw->chooser.popup));
    }
  else
    {
      XtPopup(cw->chooser.popup, XtGrabNone);
      cw->chooser.popped = 1;
    }
}

static void
Apply(w, cw, call_data)
     Widget w;
     ChooserWidget cw;
     XtPointer call_data;
{
  XawListReturnStruct *l;
  Arg args[1];

  l = XawListShowCurrent(cw->chooser.list);
  if(l)
    {
      XtSetArg(args[0], XtNlabel, cw->chooser.choices[l->list_index]);
      XtSetValues(cw, args, 1);
      cw->chooser.selection = cw->chooser.choices[l->list_index];
      cw->chooser.sindex = l->list_index;
    }
  Close(w, cw->chooser.popup, NULL);
}


static void
Unselect(w, cw, call_data)
     Widget w;
     ChooserWidget cw;
     XtPointer call_data;
{
  Arg args[1];
  if(!cw)                    /* if we're coming via callback on cw */
    cw = (ChooserWidget) w;
  XawListUnhighlight(cw->chooser.list);
  cw->chooser.selection = NULL;
  cw->chooser.sindex = 0;
  XtSetArg(args[0], XtNlabel, cw->chooser.noselection);
  XtSetValues(cw, args, 1);
  if(cw != (ChooserWidget) w)
    Close(cw, cw->chooser.popup, NULL);
}


static void
Unselect2(w, closure, call_data)
     Widget w;
     XtPointer closure;
     XtPointer call_data;
{
  Unselect(w, NULL, NULL);
}


static void
Close(w, popup, call_data)
     Widget w;
     Widget popup;
     XtPointer call_data;
{
  XtUnmapWidget(popup);
}


static void
MakeList(cw, length, resize)
     ChooserWidget cw;
     Cardinal length;
     Boolean resize;
{
  register int i = 0;
  register char *c;
  int len;
  int maxlen = 0;

  if(!cw->chooser.choices)
    return;

  /*
   * count number of choices anf find longest index
   */

  i = 0;
  while(cw->chooser.choices[i])
    {
      if(cw->chooser.indices)
	{
	  len = strlen(cw->chooser.indices[i]);
	  if(len > maxlen)
	    maxlen = len;
	}
     ++i; 
    }

  if(!(cw->chooser.text = (String *) XtMalloc((i+1) * sizeof(String))))
    return;

  i = 0;
  while(cw->chooser.choices[i])
    {
      if(cw->chooser.indices)
	{
	  if(!(c = (String) XtMalloc((strlen(cw->chooser.choices[i]) +
				      maxlen + 5) *  sizeof(char))))
	    return;
	  else
	    sprintf(c, "%*.*s   %s", maxlen, maxlen, cw->chooser.indices[i], 
		    cw->chooser.choices[i]);
	  cw->chooser.text[i] = c;
	}
      else
	cw->chooser.text[i] = cw->chooser.choices[i];

      ++i;
      if(cw->chooser.nchoices && (i > cw->chooser.nchoices))
	break;
    }

  cw->chooser.text[i] = (String) NULL;
  cw->chooser.nchoices = i;

  XawListChange(cw->chooser.list, cw->chooser.text, i, length, 1);
}


void
XtwChooserChange(cw, choices, indices, number, pixels, resize)
     ChooserWidget cw;
     String *choices;
     String *indices;
     Cardinal number;
     Cardinal pixels;
     Boolean resize;
{
  cw->chooser.choices  = choices;
  cw->chooser.indices  = indices;
  cw->chooser.nchoices = number;
  MakeList(cw, pixels, resize);
  return;
}
