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

#include <X11/Xaw/XawInit.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Toggle.h>
#include <X11/Xaw/Viewport.h>
#include <X11/Xaw/ViewportP.h>

#include <X11/Xtw/RoloP.h>

static XtResource roloResources[] = 
{
  {XtNplace, XtCPlace, XtRPlaceType, sizeof(XtwPlaceType),
     XtOffset(RoloWidget, rolo.place), XtRString, "Left"},  
};

static XtResource roloConstraintResources[] = 
{
  {XtNlabel, XtCLabel, XtRString, sizeof(String),
     XtOffset(RoloConstraints, rolo.label), XtRString, NULL},  
};


static void ClassInitialize();
static void Initialize();
static void InsertChild();
static void Realize();
static void Flip();
static Widget cousin = (Widget) NULL;


RoloClassRec roloClassRec = {
  { /* core_class fields */
    /* superclass         */    (WidgetClass) &formClassRec,
    /* class_name         */    "Rolo",
    /* widget_size        */    sizeof(RoloRec),
    /* class_initialize   */    ClassInitialize,
    /* class_part init    */    NULL,
    /* class_inited       */    FALSE,
    /* initialize         */    Initialize,
    /* initialize_hook    */    NULL,
    /* realize            */    Realize,
    /* actions            */    NULL,
    /* num_actions        */    0,
    /* resources          */    roloResources,
    /* num_resources      */    XtNumber(roloResources),
    /* xrm_class          */    NULLQUARK,
    /* compress_motion    */    TRUE,
    /* 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           */    NULL,
    /* query_geometry     */	XtInheritQueryGeometry,
    /* display_accelerator*/	XtInheritDisplayAccelerator,
    /* extension          */	NULL
  },
  { /* composite_class fields */
    /* geometry_manager   */   XtInheritGeometryManager,
    /* change_managed     */   XtInheritChangeManaged,
    /* insert_child       */   InsertChild,
    /* delete_child       */   XtInheritDeleteChild,
    /* extension          */   NULL
  },
  { /* constraint_class fields */
    /* subresourses       */   roloConstraintResources,
    /* subresource_count  */   XtNumber(roloConstraintResources),
    /* constraint_size    */   sizeof(RoloConstraintsRec),
    /* initialize         */   NULL,
    /* destroy            */   NULL,
    /* set_values         */   NULL,
    /* extension          */   NULL
  },
  { /* form_class fields */
    /* layout             */   XtInheritLayout
  },
  { /* rolo_class fields */
    /* empty              */   0
  }
};

WidgetClass roloWidgetClass = (WidgetClass) &roloClassRec;


static void 
ClassInitialize()
{
  XawInitializeWidgetSet();
  XtwInitializePlaceCvt();
  XtAddConverter(XtRString, XtRPlaceType, XtwCvtStringToPlaceType, NULL, 0);
}


/* ARGSUSED */
static void 
Initialize(request, new)
     Widget request;
     Widget new;
{
  RoloWidget rw = (RoloWidget) new;
  Arg arglist[12];
  Cardinal num_args = 0;
  Widget w;

  rw->rolo.current = (Widget) NULL;
  cousin = (Widget) NULL;
  
  if((rw->rolo.place == XtwLeft) || (rw->rolo.place == XtwTop))
    {
      num_args = 0;
      XtSetArg(arglist[num_args], XtNborderWidth, 0);            num_args++;
      rw->rolo.index = XtCreateManagedWidget("roloIndex", viewportWidgetClass,
					     new, arglist, num_args);
      rw->rolo.index_box = XtCreateManagedWidget("roloBox", formWidgetClass,
						 rw->rolo.index, 
						 arglist, num_args);
    }

  num_args = 0;
  XtSetArg(arglist[num_args], XtNleft, XtChainLeft);             num_args++;
  XtSetArg(arglist[num_args], XtNright, XtChainRight);           num_args++;
  XtSetArg(arglist[num_args], XtNtop, XtChainTop);               num_args++;
  XtSetArg(arglist[num_args], XtNbottom, XtChainBottom);         num_args++;
  XtSetArg(arglist[num_args], XtNborderWidth, 1);                num_args++;
  XtSetArg(arglist[num_args], XtNallowVert, True);               num_args++;
  XtSetArg(arglist[num_args], XtNallowHoriz, True);              num_args++;
  XtSetArg(arglist[num_args], XtNuseBottom, True);               num_args++;
  XtSetArg(arglist[num_args], XtNuseRight, True);                num_args++;

  w = XtCreateManagedWidget("roloViewport", viewportWidgetClass,
			    new, arglist, num_args); 
 
  num_args = 0;
  XtSetArg(arglist[num_args], XtNleft, XtChainLeft);             num_args++;
  XtSetArg(arglist[num_args], XtNright, XtChainLeft);            num_args++;
  XtSetArg(arglist[num_args], XtNtop, XtChainTop);               num_args++;
  XtSetArg(arglist[num_args], XtNbottom, XtChainTop);            num_args++;
  XtSetArg(arglist[num_args], XtNborderWidth, 0);                num_args++;
  rw->rolo.view = XtCreateManagedWidget("roloView", formWidgetClass,
					w, arglist, num_args); 

  /*
   * This is unfortunate but I don't want to deal with
   * reordering later.
   */

  if((rw->rolo.place == XtwRight) || (rw->rolo.place == XtwBottom))
    {
      num_args = 0;
      XtSetArg(arglist[num_args], XtNborderWidth, 0);            num_args++;
      rw->rolo.index = XtCreateManagedWidget("roloIndex", viewportWidgetClass,
					     new, arglist, num_args);
      rw->rolo.index_box = XtCreateManagedWidget("roloBox", formWidgetClass,
						 rw->rolo.index, 
						 arglist, num_args);
    }

  num_args = 0;
  switch(rw->rolo.place)
    {
    case XtwBottom:
      XtSetArg(arglist[num_args], XtNfromVert, w);               num_args++;
      XtSetArg(arglist[num_args], XtNtop, XtChainBottom);        num_args++;
      XtSetArg(arglist[num_args], XtNbottom, XtChainBottom);     num_args++;
      XtSetArg(arglist[num_args], XtNleft, XtChainLeft);         num_args++;
      XtSetArg(arglist[num_args], XtNright, XtChainRight);       num_args++;
      XtSetArg(arglist[num_args], XtNallowHoriz, True);          num_args++;
      XtSetArg(arglist[num_args], XtNuseBottom, True);           num_args++;
      XtSetValues(rw->rolo.index, arglist, num_args);
      break;

    case XtwRight:
      XtSetArg(arglist[num_args], XtNfromHoriz, w);              num_args++;
      XtSetArg(arglist[num_args], XtNtop, XtChainTop);           num_args++;
      XtSetArg(arglist[num_args], XtNbottom, XtChainBottom);     num_args++;
      XtSetArg(arglist[num_args], XtNleft, XtChainRight);        num_args++;
      XtSetArg(arglist[num_args], XtNright, XtChainRight);       num_args++;
      XtSetArg(arglist[num_args], XtNallowVert, True);           num_args++;
      XtSetArg(arglist[num_args], XtNuseRight, False);           num_args++;
      XtSetValues(rw->rolo.index, arglist, num_args);
      break;

    case XtwTop:
      XtSetArg(arglist[num_args], XtNfromVert, rw->rolo.index);  num_args++;
      XtSetValues(w, arglist, num_args);
      num_args = 0;
      XtSetArg(arglist[num_args], XtNtop, XtChainTop);           num_args++;
      XtSetArg(arglist[num_args], XtNbottom, XtChainTop);        num_args++;
      XtSetArg(arglist[num_args], XtNleft, XtChainLeft);         num_args++;
      XtSetArg(arglist[num_args], XtNright, XtChainRight);       num_args++;
      XtSetArg(arglist[num_args], XtNallowHoriz, True);          num_args++;
      XtSetArg(arglist[num_args], XtNuseBottom, True);           num_args++;
      XtSetValues(rw->rolo.index, arglist, num_args);
      break;

    case XtwLeft:
      XtSetArg(arglist[num_args], XtNfromHoriz, rw->rolo.index); num_args++;
      XtSetValues(w, arglist, num_args);
      num_args = 0;
      XtSetArg(arglist[num_args], XtNtop, XtChainTop);           num_args++;
      XtSetArg(arglist[num_args], XtNbottom, XtChainBottom);     num_args++;
      XtSetArg(arglist[num_args], XtNleft, XtChainLeft);         num_args++;
      XtSetArg(arglist[num_args], XtNright, XtChainLeft);        num_args++;
      XtSetArg(arglist[num_args], XtNallowVert, True);           num_args++;
      XtSetArg(arglist[num_args], XtNuseRight, True);            num_args++;
      XtSetValues(rw->rolo.index, arglist, num_args);
      break;
    }
}



static void 
InsertChild(w)
     register Widget w;
{
  RoloWidget rw = (RoloWidget) XtParent(w);
  RoloConstraints rc = (RoloConstraints) w->core.constraints;
  Arg arglist[5];
  Cardinal num_args = 0;
  XtTranslations translations;
  char *transtr =
    "<EnterWindow>:        highlight(Always)     \n\
     <LeaveWindow>:        unhighlight()         \n\
     <Btn1Up>, <Btn1Down>: notify()";

  if(!strncmp(w->core.name, "rolo", 4))
    {
      (*((FormWidgetClass) &formClassRec)->composite_class.insert_child)(w);
      return;
    }

  /*
   * set the viewport to be the parent
   */

  w->core.parent = rw->rolo.view;
  (*((FormWidgetClass) &formClassRec)->composite_class.insert_child)(w);

  if(!rw->rolo.current)
    {
      rw->rolo.current = w;
      XtSetArg(arglist[num_args], XtNstate, True);               num_args++;
    } 

  if(cousin)
    {
      XtSetArg(arglist[num_args], XtNradioGroup, cousin);        num_args++;
      switch(rw->rolo.place)
	{
	case XtwLeft:
	case XtwRight:
	  XtSetArg(arglist[num_args], XtNfromVert, cousin);      num_args++;
	  break;
	case XtwTop:
	case XtwBottom:
	  XtSetArg(arglist[num_args], XtNfromHoriz, cousin);     num_args++;
	  break;
	}
    }

  XtSetArg(arglist[num_args], XtNborderWidth, 0);                num_args++;
  if(rc->rolo.label)
    {
      XtSetArg(arglist[num_args], XtNlabel, rc->rolo.label);     num_args++;
    }

  cousin = XtCreateManagedWidget(w->core.name, toggleWidgetClass, 
				 rw->rolo.index_box, arglist, num_args);
  XtAddCallback(cousin, XtNcallback, Flip, w);
  translations = XtParseTranslationTable(transtr);
  XtOverrideTranslations(cousin, translations);

  return;
}
 

static void
Realize(w, valueMask, attributes)
     Widget w;
     Mask *valueMask;
     XSetWindowAttributes *attributes;
{
  RoloWidget rw = (RoloWidget) w;
  Widget *childP;
  Arg arg;

  (*((FormWidgetClass) &formClassRec)->core_class.realize) (w, valueMask, attributes);
  
  for ((childP) = ((ViewportWidget) (rw->rolo.view))->composite.children ; 
        (childP) < ((ViewportWidget) (rw->rolo.view))->composite.children + 
       ((ViewportWidget) (rw->rolo.view))->composite.num_children ; 
        (childP)++)
    if(XtIsManaged(*childP))
      XtUnmanageChild(*childP);

  if(rw->rolo.current)
    XtManageChild(rw->rolo.current);

  XtSetArg(arg, XtNheight, rw->rolo.view->core.height);
  XtSetValues(rw->rolo.index, &arg, 1);

  return;
}


static void
Flip(w, card, closure)
     Widget w;
     Widget card;
     XtPointer closure;
{
  RoloWidget rw = (RoloWidget) XtParent(XtParent(XtParent(w)));
  Arg arg;
  int state;

  if(rw->rolo.current == card)
    return;

  XtSetArg(arg, XtNstate, &state);
  XtGetValues(w, &arg, 1);
  
  if(state)
    {
      XtUnmanageChild(rw->rolo.current);
      rw->rolo.current = card;
      XtManageChild(rw->rolo.current);
    }
  return;
}
