/*
 * Plot Form composite widget for X11R4 Cardiovascular Simulator
 * Copyright 1988 by Timothy L. Davis
 *
 * PlotForm is the form which is used to choose variables to be plotted and
 * their axes/labels and other plotting parameters.
 * There are four variable "frames" in which information can be entered.
 * The bottom of the menu provides an overall parameter, the length of time
 * before a plot begins to be erased, and completion buttons.
 * Note: This is NOT a widget definition, but an instance of widget usage.
 *
 * #defines:  SAVEDATA to add a "persist" label and value to the menu
 *            XAW_BC for (probable) backward compatibility to X11R3
 *            DO_GRABS if you wish to grab the server during menu popup.
 *            TIMINGCHOICE if you want control over the portion(s) of the
 *                         cardiac cycle to plot and/or average.
 *            
 * $Source: /mit/hst/src/form/RCS/PlotForm.c,v $ 
 * $Log:	PlotForm.c,v $
 * Revision 3.1  90/08/28  17:33:50  tldavis
 * small fix.
 * 
 * Revision 3.0  90/08/28  14:38:43  tldavis
 * Added buttons for setting averaging and partial cardiac cycle plotting.
 * 
 * Revision 2.4  90/08/18  18:33:02  tldavis
 * General cleanup.  Also added formatting, removed specific formatting
 * to use resource file instead.  Fixed a few fixUnders bugs.
 * 
 * Revision 2.2  90/08/10  17:31:46  tldavis
 * Fixing problems with interacting with the text in text widgets.
 * 1) Text widgets get "useInPlace" to allow for reading of text values
 * 2) Use XtSetValues instead of XawReplaceText to put text in widget.
 * 
 * Revision 2.1  90/08/10  10:53:31  dot
 * upgrade to R4; mostly changes to the ascii text widgets
 * new code ifdef'd under !XAW_BC
 * 
 * Revision 2.0  90/08/06  17:53:25  tldavis
 * Final X11R3 version.
 * 
 * Revision 1.16  90/08/06  17:07:50  tldavis
 * Fixed a problem with color.
 * Revision 1.14  90/05/31  16:54:09  tldavis
 * Pre-ACIS checkin.
 * Revision 1.13  89/10/12  22:13:16  tldavis
 * Fixed for Motif window manager plus indep. var. plottability.
 * Revision 1.11  89/06/28  11:48:46  tldavis:removed persist, added stripMode.
 * Revision 1.10  89/06/13  21:24:47  tldavis : R3 fonts fixed.
 * Revision 1.9  89/02/22  12:23:22  tldavis : X11R3 version.
 * Revision 1.8  88/10/10  21:36:48  hst
 * Fixed several bugs, notably resize subwidgets.
 */
#include <stdio.h>
#include <math.h>
#ifdef XAW_BC
#include <X11/IntrinsicP.h>
#include <X11/Xaw/TextP.h> /* necessary to get XtTextBlock definition! */
#endif
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Box.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Toggle.h>
#include <X11/Xaw/Paned.h>
#include <X11/Xaw/AsciiText.h>
#include <X11/cursorfont.h>
#include "../plot/Plot.h"
#include "../sim/CVDefs.h"
#include "../data/Parameter.h"
#include "PlotForm.h"
#include "../event/Event.h" /* for extern int Stopped */

extern Display *dpy;
extern Window  root;
extern int screen;
extern int patientActive; /* from Interface.c */
extern Widget BUTTON_BOX; /* from ../main/Interface.c */

/***************************************************************
 *
 * PRIVATE DATA
 *
 ***************************************************************/

typedef struct {
  Widget form;
  Widget axisLabel, varLabel, nameLabel, minLabel, maxLabel, speedLabel, 
         scaleLabel, titleLabel, unitLabel, modeLabel;
  Widget minText, maxText, titleText, scaleButton, unitText, circuitButton,
         speedText, hideButton, modeButton;
  char *minString, *maxString, *speedString, *titleString, *unitsString;
  Boolean scaleValue, modeValue;
  int place, type;
} *PFData, PFDataRec;

static Boolean FormActive = False;

  /* The first 10 elements represent number key presses; the intent of this
   * translation table is to allow only numeric entry on only 1 line of text.
   */
static String numericTextEventTable = 
    "<Key>0x030:  kill-to-end-of-line() beginning-of-file() end-of-line() \
              insert-char() \n\
     <Key>0x031:  kill-to-end-of-line() beginning-of-file() end-of-line() \
              insert-char() \n\
     <Key>0x032:  kill-to-end-of-line() beginning-of-file() end-of-line() \
              insert-char() \n\
     <Key>0x033:  kill-to-end-of-line() beginning-of-file() end-of-line() \
              insert-char() \n\
     <Key>0x034:  kill-to-end-of-line() beginning-of-file() end-of-line() \
              insert-char() \n\
     <Key>0x035:  kill-to-end-of-line() beginning-of-file() end-of-line() \
              insert-char() \n\
     <Key>0x036:  kill-to-end-of-line() beginning-of-file() end-of-line() \
              insert-char() \n\
     <Key>0x037:  kill-to-end-of-line() beginning-of-file() end-of-line() \
              insert-char() \n\
     <Key>0x038:  kill-to-end-of-line() beginning-of-file() end-of-line() \
              insert-char() \n\
     <Key>0x039:  kill-to-end-of-line() beginning-of-file() end-of-line() \
              insert-char() \n\
     <Key>.: kill-to-end-of-line() beginning-of-file() end-of-line() \
              insert-char() \n\
     <Key>-: kill-to-end-of-line() beginning-of-file() end-of-line() \
              insert-char() \n\
     Ctrl<Key>F:	forward-character() \n\
     <Key>0xff53:	forward-character() \n\
     Ctrl<Key>B:	backward-character() \n\
     <Key>0xff51:	backward-character() \n\
     Ctrl<Key>A:	beginning-of-line() \n\
     Ctrl<Key>E:	end-of-line() \n\
     Ctrl<Key>P:	previous-line() \n\
     <Key>0xff52:	previous-line() \n\
     Meta<Key>\\<:	beginning-of-file() \n\
     Ctrl<Key>Z:	scroll-one-line-up() \n\
     Ctrl<Key>D:	delete-next-character() \n\
     Ctrl<Key>H:	delete-previous-character() \n\
     <Key>0xff7f:	delete-previous-character() \n\
     <Key>0xffff:	delete-previous-character() \n\
     <Key>0xff08:	delete-previous-character() \n\
     Meta<Key>D:	delete-next-word() \n\
     Meta<Key>H:	delete-previous-word() \n\
     Shift Meta<Key>D:	kill-word() \n\
     Shift Meta<Key>H:	backward-kill-word() \n\
     Ctrl<Key>W:	kill-selection() \n\
     Ctrl<Key>K:	kill-to-end-of-line() \n\
     Meta<Key>K:	kill-to-end-of-paragraph()";

static  XtTranslations parsedNumeric;

/****************************************************************
 *
 * Private Procedures
 *
 ****************************************************************/
/*FORWARD*/  static void UpdateAxisForm();

/* callback routine for toggling scale button label*/
/*ARGSUSED*/
static void ScaleButtonCallback(w, closure, call)
Widget w;
caddr_t closure, call;
{
  PFData data = (PFData) closure;
  Arg args[2];
  data->scaleValue = !data->scaleValue;
  XtSetArg(args[0], XtNlabel, data->scaleValue ? "Yes" : "No");
  XtSetValues(data->scaleButton, args, 1);
}

/* callback routine for toggling mode button label*/
/*ARGSUSED*/
static void ModeButtonCallback(w, closure, call)
Widget w;
caddr_t closure, call;
{
  PFData data = (PFData) closure;
  Arg args[2];
  data->modeValue = !data->modeValue;
  XtSetArg(args[0], XtNlabel, data->modeValue ? "StripChart" : "Scope");
  XtSetValues(data->modeButton, args, 1);
}

/* change to NO PARAMETER for this axis */
/*ARGSUSED*/
static void hideButtonCallback(w, closure, call)
Widget w;
caddr_t closure, call;
{
  PFData data = (PFData) closure;
  data->place = -1;
  data->type =  -1;
  UpdateAxisForm(data, (char *)NULL, (AxisData)NULL);
}

/* this replaces the text in a Text widget kludgily */
/*PUBLIC*/ void replaceText(widget, text)
Widget widget;
char *text;
{
#ifdef XAW_BC
  XtTextBlock block;
  XtTextPosition top;

  XtTextSetLastPos(widget,top=XtTextTopPosition(widget)); 

  block.firstPos = 0;
  block.length = strlen(text);
  block.ptr = text;
  block.format = FMT8BIT;

  if (block.length) XtTextReplace(widget, top, top, &block);
  XtTextSetInsertionPoint(widget, top);
#else /* ! XAW_BC */
  Arg args[5];
  int i=0;

  char *tmp = XtMalloc(strlen(text)>40 ? strlen(text)+10 : 40);
  static char *oldstr=0;
  strcpy(tmp, text);

  XtSetArg(args[i], XtNstring, &oldstr); i++;
  XtGetValues(widget, args, i);
#ifdef NOTDEF
/* The following causes problems with the time axis! */
  if (oldstr) XtFree(oldstr);
#endif
  i=0;
  XtSetArg(args[i], XtNstring, tmp); i++;
  XtSetValues(widget, args, i);
  XawTextSetInsertionPoint(widget, XawTextTopPosition(widget));
#endif
}

/* runs the circuit diagram & fills in data slots; run on button press */
/*ARGSUSED*/
static void CircuitButtonCallback(widget, closure, call)
     Widget widget;
     caddr_t closure, call;
{
  PFData data = (PFData)closure;
  int place, type;
  Arg args[1];
  VarData *vd;

  modify_parameters(patientActive ? 1 : 2, &place, &type); 
             /* 1: p,v,f only, 2: p,v,f + indep. parameters */
  if (place < 0 || type < 0) return; /* No update: no choice made */
  data->place = place; data->type = type;
  vd = get_vardata(data->place, data->type);
  
  strcpy(data->titleString, vd->name);
  replaceText(data->titleText, data->titleString);
  (void) sprintf(data->minString,"%lg", vd->gmin);
  replaceText(data->minText, data->minString);
  (void) sprintf(data->maxString,"%lg", vd->gmax);
  replaceText(data->maxText, data->maxString);
  (void) sprintf(data->speedString,"%lg", 5.0);
  replaceText(data->speedText, data->speedString);

  data->unitsString = vd->units;
  XtSetArg(args[0], XtNlabel, vd->units);
  XtSetValues(data->unitText, args, 1);
  UpdateAxisForm(data, (char *)NULL, (AxisData)NULL);
}

/*ARGSUSED*/
static void DoFocusKeyboard(w, client, event)
     Widget w;
     caddr_t client;
     XEvent *event;
{
  if (XtWindow(w)/*||| && w->core.visible */) {
    XWindowAttributes att;
    XGetWindowAttributes(dpy, XtWindow(w), &att);
    if (att.map_state == IsViewable)
      XSetInputFocus(dpy, XtWindow(w), RevertToParent, CurrentTime);
  }
}

/*
 * routines for single-axis form creation, display, and data cleanup
 * These are usually called by the menu manager later this file.
 */

static PFData CreateAxisForm(parent, passed_args, passed_i)
Widget parent; 
Arg *passed_args;
int passed_i;
{
  Arg args[20];
  int i, j;
  PFData data = (PFData) XtMalloc(sizeof(PFDataRec));

  data->form = XtCreateManagedWidget("Axis", formWidgetClass, parent, 
				     passed_args, passed_i);

  parsedNumeric = XtParseTranslationTable(numericTextEventTable);
  /*
   * Create a bunch of widget instances to go in the form, and 
   * Organize these labels & widgets into a pretty form layout.
   */

  i=0;
  XtSetArg(args[i], XtNtop, XtChainTop);i++;
  XtSetArg(args[i], XtNbottom, XtChainTop);i++;
  XtSetArg(args[i], XtNleft, XtChainLeft);i++;
  XtSetArg(args[i], XtNright, XtChainLeft);i++;
  XtSetArg(args[i], XtNvertDistance, 8);i++;
  XtSetArg(args[i], XtNresizable, True);i++;
  j = i;
  /* Row 1 */
  XtSetArg(args[i], XtNborderWidth, 0);i++;
  XtSetArg(args[i], XtNwidth, 75);i++;
  data->axisLabel = XtCreateManagedWidget("AxisLabel", labelWidgetClass, 
					  data->form, args, i);
  i=j;
  XtSetArg(args[i], XtNfromHoriz, data->axisLabel);i++;
  XtSetArg(args[i], XtNborderWidth, 3);i++;
  data->circuitButton = XtCreateManagedWidget("Choose Variable",
				     commandWidgetClass, data->form, args, i);
  XtAddCallback(data->circuitButton, XtNcallback, CircuitButtonCallback, 
		(caddr_t)data);
  i=j;
  XtSetArg(args[i], XtNfromHoriz, data->circuitButton);i++;
  XtSetArg(args[i], XtNhorizDistance, 10); 
  XtSetArg(args[i], XtNborderWidth, 3);i++;
  data->hideButton = XtCreateManagedWidget("Delete", commandWidgetClass, 
					   data->form, args, i);
  XtAddCallback(data->hideButton, XtNcallback, hideButtonCallback, 
		(caddr_t)data);
  /* Row 2 */
  i=j;
  XtSetArg(args[i], XtNfromVert, data->circuitButton);i++;
  XtSetArg(args[i], XtNborderWidth, 0);i++;
  data->varLabel = XtCreateManagedWidget("Variable", labelWidgetClass, 
					 data->form, args, i);
  i=j;
  XtSetArg(args[i], XtNfromVert, data->circuitButton);i++;
  XtSetArg(args[i], XtNfromHoriz, data->varLabel);i++;
  XtSetArg(args[i], XtNwidth, 200);i++;
  XtSetArg(args[i], XtNborderWidth, 0);i++;
  data->nameLabel = XtCreateManagedWidget("nameLabel", labelWidgetClass,
					  data->form, args, i);
  /* Row 3 */
  i=j;
  XtSetArg(args[i], XtNborderWidth, 0);i++;
  XtSetArg(args[i], XtNfromVert, data->nameLabel);i++;
  data->titleLabel = XtCreateManagedWidget("Title:", labelWidgetClass,
					   data->form, args, i);
  i=j;
  XtSetArg(args[i], XtNfromVert, data->nameLabel);i++;
  XtSetArg(args[i], XtNfromHoriz, data->titleLabel);i++;
  data->titleString = (char *) XtMalloc(40*sizeof(char));
  *data->titleString = 0;
  XtSetArg(args[i], XtNwidth, 200);i++;
#ifdef XAW_BC
  XtSetArg(args[i], XtNstring, data->titleString);i++;
  XtSetArg(args[i], XtNeditType, XttextEdit);i++;
  XtSetArg(args[i], XtNtextOptions, editable);i++;
#else /* ! XAW_BC */
  XtSetArg(args[i], XtNeditType, XawtextEdit);i++;
#endif
  XtSetArg(args[i], XtNlength, 40);i++;
#ifdef XAW_BC
  data->titleText = XtCreateManagedWidget("titleText", asciiStringWidgetClass,
					  data->form, args, i);
#else /* ! XAW_BC */
  data->titleText = XtCreateManagedWidget("titleText", asciiTextWidgetClass,
					  data->form, args, i);
#endif
  XtAddEventHandler(data->titleText, EnterWindowMask, False, DoFocusKeyboard, (caddr_t)0);
  /* Row 4 */
  i=j;
  XtSetArg(args[i], XtNfromVert, data->titleText);i++;
  XtSetArg(args[i], XtNborderWidth, 0);i++;
  data->minLabel = XtCreateManagedWidget("Min:", labelWidgetClass,
					 data->form, args, i);
  i=j;
  XtSetArg(args[i], XtNfromVert, data->titleText);i++;
  XtSetArg(args[i], XtNfromHoriz, data->minLabel);i++;
  data->minString = (char *) XtMalloc(40*sizeof(char));
  *data->minString = 0;
  XtSetArg(args[i], XtNwidth, 75);i++;
#ifdef XAW_BC
  XtSetArg(args[i], XtNstring, data->minString);i++;
  XtSetArg(args[i], XtNeditType, XttextEdit);i++;
  XtSetArg(args[i], XtNtextOptions, editable);i++;
#else /* ! XAW_BC */
  XtSetArg(args[i], XtNeditType, XawtextEdit);i++;
#endif
  XtSetArg(args[i], XtNlength, 40);i++;
  XtSetArg(args[i], XtNtranslations, parsedNumeric);i++;
#ifdef XAW_BC
  data->minText = XtCreateManagedWidget("minText", asciiStringWidgetClass,
					data->form, args, i);
#else /* ! XAW_BC */
  data->minText = XtCreateManagedWidget("minText", asciiTextWidgetClass,
					data->form, args, i);
#endif
  XtAddEventHandler(data->minText, EnterWindowMask, False, DoFocusKeyboard, (caddr_t)0);
  i=j;
  XtSetArg(args[i], XtNfromVert, data->titleText);i++;
  XtSetArg(args[i], XtNfromHoriz, data->minText);i++;
  XtSetArg(args[i], XtNborderWidth, 0);i++;
  data->maxLabel = XtCreateManagedWidget("Max:", labelWidgetClass,
					 data->form, args, i);
  i=j;
  XtSetArg(args[i], XtNfromVert, data->titleText);i++;
  XtSetArg(args[i], XtNfromHoriz, data->maxLabel);i++;
  data->maxString = (char *) XtMalloc(40*sizeof(char));
  *data->maxString = 0;
  XtSetArg(args[i], XtNwidth, 75);i++;
#ifdef XAW_BC
  XtSetArg(args[i], XtNstring, data->maxString);i++;
  XtSetArg(args[i], XtNeditType, XttextEdit);i++;
  XtSetArg(args[i], XtNtextOptions, editable);i++;
#else /* ! XAW_BC */
  XtSetArg(args[i], XtNeditType, XawtextEdit);i++;
#endif
  XtSetArg(args[i], XtNlength, 40);i++;
  XtSetArg(args[i], XtNtranslations, parsedNumeric);i++;
#ifdef XAW_BC
  data->maxText = XtCreateManagedWidget("maxText", asciiStringWidgetClass,
					data->form, args, i);
#else /* ! XAW_BC */
  data->maxText = XtCreateManagedWidget("maxText", asciiTextWidgetClass,
					data->form, args, i);
#endif
  XtAddEventHandler(data->maxText, EnterWindowMask, False, DoFocusKeyboard, (caddr_t)0);

  /* Row 4 for TIME */
  i=j;
  XtSetArg(args[i], XtNfromVert, data->titleText);i++;
  XtSetArg(args[i], XtNborderWidth, 0);i++;
  data->speedLabel = XtCreateManagedWidget("Paper Speed", labelWidgetClass,
					   data->form, args, i);
  i=j;
  XtSetArg(args[i], XtNfromVert, data->titleText);i++;
  XtSetArg(args[i], XtNfromHoriz, data->speedLabel);i++;
  data->speedString = (char *) XtMalloc(40*sizeof(char));
  *data->speedString= 0;
  XtSetArg(args[i], XtNwidth, 75);i++;
#ifdef XAW_BC
  XtSetArg(args[i], XtNstring, data->speedString);i++;
  XtSetArg(args[i], XtNeditType, XttextEdit);i++;
  XtSetArg(args[i], XtNtextOptions, editable);i++;
#else /* ! XAW_BC */
  XtSetArg(args[i], XtNeditType, XawtextEdit);i++;
#endif
  XtSetArg(args[i], XtNlength, 40);i++;
  XtSetArg(args[i], XtNtranslations, parsedNumeric);i++;
#ifdef XAW_BC
  data->speedText = XtCreateManagedWidget("speedText", asciiStringWidgetClass,
					  data->form, args, i);
#else /* ! XAW_BC */
  data->speedText = XtCreateManagedWidget("speedText", asciiTextWidgetClass,
					  data->form, args, i);
#endif
  XtAddEventHandler(data->speedText, EnterWindowMask, False, DoFocusKeyboard, (caddr_t)0);
  /* Row 5 */ 
  i=j;
  XtSetArg(args[i], XtNfromVert, data->maxText);i++;
  XtSetArg(args[i], XtNborderWidth, 0);i++;
  data->unitLabel = XtCreateManagedWidget("Units:", labelWidgetClass,
					  data->form, args, i);
  i=j;
  XtSetArg(args[i], XtNfromVert, data->maxText);i++;
  XtSetArg(args[i], XtNfromHoriz, data->unitLabel);i++;
  XtSetArg(args[i], XtNlength, 40);i++;
  XtSetArg(args[i], XtNwidth, 75);i++;
  data->unitText = XtCreateManagedWidget("unitText", labelWidgetClass,
					 data->form, args, i);
  i=j;
  XtSetArg(args[i], XtNfromVert, data->maxText);i++;
  XtSetArg(args[i], XtNfromHoriz, data->unitText);i++;
  XtSetArg(args[i], XtNborderWidth, 0);i++;
  data->scaleLabel = XtCreateManagedWidget("Auto Rescale", labelWidgetClass,
					   data->form, args, i);
  i=j;
  XtSetArg(args[i], XtNfromVert, data->maxText);i++;
  XtSetArg(args[i], XtNfromHoriz, data->unitText);i++;
  XtSetArg(args[i], XtNborderWidth, 0);i++;
  data->modeLabel = XtCreateManagedWidget("Disp. Mode:", labelWidgetClass,
					   data->form, args, i);
  i=j;
  XtSetArg(args[i], XtNfromVert, data->maxText);i++;
  XtSetArg(args[i], XtNfromHoriz, data->scaleLabel);i++;
  data->scaleValue = 0;
  XtSetArg(args[i], XtNlabel, data->scaleValue ? "Yes" : "No" );i++;
  data->scaleButton = XtCreateManagedWidget("scaleButton", commandWidgetClass,
					    data->form, args, i);
  XtAddCallback(data->scaleButton, XtNcallback, ScaleButtonCallback, 
		(caddr_t)data);
  i=j;
  XtSetArg(args[i], XtNfromVert, data->maxText);i++;
  XtSetArg(args[i], XtNfromHoriz, data->modeLabel);i++;
  data->modeValue = 0;
  XtSetArg(args[i], XtNlabel, data->modeValue ? "Strip Chart" : "Scope" );i++;
  XtSetArg(args[i], XtNwidth, 75);i++;
  data->modeButton = XtCreateManagedWidget("modeButton", commandWidgetClass,
					    data->form, args, i);
  XtAddCallback(data->modeButton, XtNcallback, ModeButtonCallback, 
		(caddr_t)data);
  return(data);
}

/*
 * Update a previously-created form, optionally updating from axisName
 * or axisData.  if axisName or AxisData are NULL, the previous values
 * for this widget are used.
 */
static void UpdateAxisForm(data , axisName, axisData)
PFData data;
char *axisName;
AxisData axisData;
{
  VarData *vd;
  Arg args[1];

  if (axisName) {
    XtSetArg(args[0], XtNlabel, axisName);
    XtSetValues(data->axisLabel, args, 1);
  }
  if (axisData) {
    data->place = axisData->place;
    data->type = axisData->type;
    replaceText(data->titleText, axisData->title);
    (void) sprintf(data->minString,"%lg", axisData->min);
    replaceText(data->minText, data->minString);
    (void) sprintf(data->maxString,"%lg", axisData->max);
    replaceText(data->maxText, data->maxString);
    (void) sprintf(data->speedString,"%lg", axisData->paperSpeed);
    replaceText(data->speedText, data->speedString);
    XtSetArg(args[0], XtNlabel, axisData->units);
    XtSetValues(data->unitText, args, 1);
    if (data->scaleValue != axisData->autoScale) 
       ScaleButtonCallback(data->form, (caddr_t)data, (caddr_t)NULL);
    if (data->modeValue != axisData->stripMode) 
       ModeButtonCallback(data->form, (caddr_t)data, (caddr_t)NULL);
  }
  if ((vd = get_vardata(data->place, data->type)) == NULL) {
    XtSetMappedWhenManaged(data->nameLabel, False);
    XtSetMappedWhenManaged(data->varLabel, False);
    XtSetMappedWhenManaged(data->titleLabel, False);
    XtSetMappedWhenManaged(data->titleText, False);
    XtSetMappedWhenManaged(data->scaleLabel, False);
    XtSetMappedWhenManaged(data->scaleButton, False);
    XtSetMappedWhenManaged(data->modeLabel, False);
    XtSetMappedWhenManaged(data->modeButton, False);
    XtSetMappedWhenManaged(data->unitLabel, False);
    XtSetMappedWhenManaged(data->unitText, False);
    XtSetMappedWhenManaged(data->hideButton, False);
    XtSetMappedWhenManaged(data->minLabel, False);
    XtSetMappedWhenManaged(data->minText, False);
    XtSetMappedWhenManaged(data->maxLabel, False);
    XtSetMappedWhenManaged(data->maxText, False);
    XtSetMappedWhenManaged(data->speedLabel, False);
    XtSetMappedWhenManaged(data->speedText, False);
    {
      Dimension w, h, w_r, h_r;
      Arg args[2];
      int i = 0;
      XtSetArg(args[i], XtNwidth, &w);i++;
      XtSetArg(args[i], XtNheight, &h);i++;
      XtGetValues(data->form, args, i);
      XtMakeResizeRequest(data->form, w, h /*+20*/, &w_r, &h_r);
    }
    return;
  } else {
    XtSetMappedWhenManaged(data->nameLabel, True);
    XtSetMappedWhenManaged(data->varLabel, True);
    XtSetMappedWhenManaged(data->titleLabel, True);
    XtSetMappedWhenManaged(data->titleText, True);
    XtSetMappedWhenManaged(data->unitLabel, True);
    XtSetMappedWhenManaged(data->unitText, True);
    XtSetMappedWhenManaged(data->hideButton, True);
    if (data->type == TIME) {
      XtSetMappedWhenManaged(data->minLabel, False);
      XtSetMappedWhenManaged(data->minText, False);
      XtSetMappedWhenManaged(data->maxLabel, False);
      XtSetMappedWhenManaged(data->maxText, False);
      XtSetMappedWhenManaged(data->scaleLabel, False);
      XtSetMappedWhenManaged(data->scaleButton, False);
      XtSetMappedWhenManaged(data->modeLabel, True);
      XtSetMappedWhenManaged(data->modeButton, True);
      XtSetMappedWhenManaged(data->speedLabel, True);
      XtSetMappedWhenManaged(data->speedText,  True);
    } else {
      XtSetMappedWhenManaged(data->minLabel, True);
      XtSetMappedWhenManaged(data->minText, True);
      XtSetMappedWhenManaged(data->maxLabel, True);
      XtSetMappedWhenManaged(data->maxText, True);
      XtSetMappedWhenManaged(data->scaleLabel, True);
      XtSetMappedWhenManaged(data->scaleButton, True);
      XtSetMappedWhenManaged(data->modeLabel, False);
      XtSetMappedWhenManaged(data->modeButton, False);
      XtSetMappedWhenManaged(data->speedLabel, False);
      XtSetMappedWhenManaged(data->speedText,  False);
    }
  }
  XtSetArg(args[0], XtNlabel, vd->name);
  XtSetValues(data->nameLabel, args, 1);
  data->unitsString = vd->units;
  XtSetArg(args[0], XtNlabel, data->unitsString);
  XtSetValues(data->unitText, args, 1);
}

/*
 * Dump the current data from this widget into the record specified by axisData
 * and then make the window invisible.  The widget is reused instead of being
 * destroyed and re-created for subsequent calls.  This is a little fishy,
 * but no problem since there are never 2 PlotForm menues at once.
 *
 */
static void FinishAxisFormData(data, axisData)
     PFData data;
     AxisData axisData;
{
  Arg args[5];
  int i=0;
  char *str;

  XtSetArg(args[i], XtNstring, &str);i++;
  
  XtGetValues(data->minText, args, i);
  (void) sscanf(str, "%lf", &axisData->min);

  XtGetValues(data->maxText, args, i);
  (void) sscanf(str, "%lf", &axisData->max);

  XtGetValues(data->speedText, args, i);
  (void) sscanf(str, "%lf", &axisData->paperSpeed);

  XtGetValues(data->titleText, args, i);
  axisData->title     = XtMalloc(strlen(str)+1);
  strcpy(axisData->title, str);

  axisData->units     = data->unitsString;
  axisData->autoScale = data->scaleValue;
  axisData->stripMode = data->modeValue;
  axisData->place     = data->place;
  axisData->type      = data->type;
}

/***************************************************
 *
 *  The following data and code define the menu for choosing
 *  all axes of a plot, and then for creating that plot.
 *  These routines are presently used in ../cv/Interface.c
 *
 ***************************************************/

/*
 *
 * Private data and functions for Menu
 *
 */

/*
 * struct for the menu
 */
typedef struct {
 Widget popup;
 Widget menu,  lastForm, Cancel, Create, timingGroup, timingEndGroup;
 PFData pfDataX, pfData1, pfData2, pfData3;
 AxisDataRec adx, ad1, ad2, ad3;
#ifdef SAVEDATA
 char DispTime[80];
 Widget DispTimeText, DispTimeLabel;
#endif
 Widget widget;
 void (* Callback)();
 Boolean averaging;
} *MenuData, MenuDataRec;


/* callback for cancel button, makes the menu dissappear. */
/*ARGSUSED*/
static void CancelCallback(widget, closure, call)
     Widget widget;
     caddr_t closure, call;
{
  MenuData data = (MenuData) closure;

  XtPopdown(data->popup);
  FinishAxisFormData(data->pfDataX, &data->adx);
  FinishAxisFormData(data->pfData1, &data->ad1);
  FinishAxisFormData(data->pfData2, &data->ad2);
  FinishAxisFormData(data->pfData3, &data->ad3);
  FormActive = False;
}

/* callback for creating a plot from the present state of the menu */
/*ARGSUSED*/
static void CreateCallback(widget, closure, call)
     Widget widget;
     caddr_t closure, call;
{
  MenuData data = (MenuData) closure;
  Arg args[40];
  int i;
#ifdef SAVEDATA
  double DispTimeDouble;
#endif

  XtPopdown(data->popup);
  if (data->pfDataX) FinishAxisFormData(data->pfDataX, &data->adx);
  if (data->pfData1) FinishAxisFormData(data->pfData1, &data->ad1);
  if (data->pfData2) FinishAxisFormData(data->pfData2, &data->ad2);
  if (data->pfData3) FinishAxisFormData(data->pfData3, &data->ad3);
  FormActive = False;

  /* Set up the arguments based on form data */
  i = 0;
  XtSetArg(args[i],XtNplaceX , data->adx.place);i++;
  XtSetArg(args[i],XtNtypeX  , data->adx.type);i++;
  XtSetArg(args[i],XtNlabelX , data->adx.title);i++;
  XtSetArg(args[i],XtNunitX  , data->adx.units);i++;
  XtSetArg(args[i],XtNminX   , &data->adx.min);i++;
  XtSetArg(args[i],XtNmaxX   , &data->adx.max);i++;
  XtSetArg(args[i],XtNautoScaleX, data->adx.autoScale);i++;
  XtSetArg(args[i],XtNstripMode, data->adx.stripMode);i++;
  XtSetArg(args[i],XtNpaperSpeed, &data->adx.paperSpeed);i++;
  XtSetArg(args[i],XtNplace1 , data->ad1.place);i++;
  XtSetArg(args[i],XtNtype1  , data->ad1.type);i++;
  XtSetArg(args[i],XtNlabel1 , data->ad1.title);i++;
  XtSetArg(args[i],XtNunit1  , data->ad1.units);i++;
  XtSetArg(args[i],XtNmin1   , &data->ad1.min);i++;
  XtSetArg(args[i],XtNmax1   , &data->ad1.max);i++;
  XtSetArg(args[i],XtNautoScale1, data->ad1.autoScale);i++;
  XtSetArg(args[i],XtNplace2 , data->ad2.place);i++;
  XtSetArg(args[i],XtNtype2  , data->ad2.type);i++;
  XtSetArg(args[i],XtNlabel2 , data->ad2.title);i++;
  XtSetArg(args[i],XtNunit2  , data->ad2.units);i++;
  XtSetArg(args[i],XtNmin2   , &data->ad2.min);i++;
  XtSetArg(args[i],XtNmax2   , &data->ad2.max);i++;
  XtSetArg(args[i],XtNautoScale2, data->ad2.autoScale);i++;
  XtSetArg(args[i],XtNplace3 , data->ad3.place);i++;
  XtSetArg(args[i],XtNtype3  , data->ad3.type);i++;
  XtSetArg(args[i],XtNlabel3 , data->ad3.title);i++;
  XtSetArg(args[i],XtNunit3  , data->ad3.units);i++;
  XtSetArg(args[i],XtNmin3   , &data->ad3.min);i++;
  XtSetArg(args[i],XtNmax3   , &data->ad3.max);i++;
  XtSetArg(args[i],XtNautoScale3, data->ad3.autoScale);i++;
#ifdef SAVEDATA
 (void) sscanf(data->DispTime, "%lf", &DispTimeDouble);
  XtSetArg(args[i],XtNdecayTime, &DispTimeDouble);i++;
#endif
#ifdef TIMINGCHOICE
  { unsigned int timing2, timing  = 
      (unsigned int) XawToggleGetCurrent(data->timingGroup);
    if (timing == 15) timing = 0;
    timing2 = (unsigned int) XawToggleGetCurrent(data->timingEndGroup);
    if (timing2 == 15<<4) timing2 = 0;
    timing |= timing2;
    timing &= 0x00FF;
    if (data->averaging) timing |= 0x0800;

    XtSetArg(args[i], XtNtiming, timing);i++;
  }
#endif
  if (data->Callback) (*data->Callback)(data->widget, args, i);
}

static Pixmap savedUnder = (Pixmap) 0;
static GC imageGC = (GC) 0;
static Boolean simulating = False;

/*ARGSUSED*/
static void doSaveUnder(w, client, call)
Widget w;
caddr_t client, call;
{
  if (!imageGC) {
      XGCValues xgcv;
      xgcv.subwindow_mode = IncludeInferiors;
      imageGC = XCreateGC(dpy, root, GCSubwindowMode, &xgcv);
    }
  if (savedUnder) XFreePixmap(dpy, savedUnder);
  
  /* POP-UP! This does a manual save-under, since I can't get the 
   * automatic one to work.
   */
  
#ifdef DO_GRABS
  XGrabServer(dpy); /* Don't let reality change while we've got it saved */
  if (XtWindow(w))
    XGrabKeyboard(dpy, XtWindow(w), True, GrabModeAsync, GrabModeAsync, CurrentTime);
#endif
  simulating = !Stopped;
  StopSimulator();
  SimFlush();
  /* Calculate the footprint of this window. */
  { 
    Dimension width=0, height=0, bdr=0;
    int x=0, y=0;
    Arg args[6];
    int i = 0;
    XtSetArg(args[i], XtNx, &x);i++;
    XtSetArg(args[i], XtNy, &y);i++;
    XtSetArg(args[i], XtNwidth, &width);i++;
    XtSetArg(args[i], XtNheight, &height);i++;
    XtSetArg(args[i], XtNborderWidth, &bdr);i++;
    XtGetValues(w, args, i);

    if (width > 100 || height > 100) {
      XSync(dpy, False); /* Save the most up-to-date picture possible. */
      savedUnder = XCreatePixmap(dpy, root, width+2*bdr, height + 2*bdr,
				 DefaultDepth(dpy,screen));
      XCopyArea(dpy, root, savedUnder, imageGC, x, y, 
		width + 2*bdr, height+ 2*bdr, 0, 0);
    } else savedUnder = 0;
  }
}

/*ARGSUSED*/
static void doFixUnder(w, client, call)
Widget w;
caddr_t client, call;
{
  if (savedUnder) {
    Dimension width=0, height=0, bdr=0;
    int x=0, y=0;
    Arg args[6];
    int i = 0;
    XtSetArg(args[i], XtNx, &x);i++;
    XtSetArg(args[i], XtNy, &y);i++;
    XtSetArg(args[i], XtNwidth, &width);i++;
    XtSetArg(args[i], XtNheight, &height);i++;
    XtSetArg(args[i], XtNborderWidth, &bdr);i++;
    XtGetValues(w, args, i);
    /* POP DOWN! */
    /* Try to avoid redisplays, since we have saved all the bits. */
    XCopyArea(dpy, savedUnder, root, imageGC, 0, 0,
	      width + 2*bdr, height +2*bdr, x, y);
    XFreePixmap(dpy, savedUnder); savedUnder = (Pixmap) 0;
    {/* Discard all accumulated exposure events. */
      XEvent ev;
      XSync(dpy, False); 
      while (XCheckTypedEvent(dpy, Expose, &ev) == True)
	; /* discard them since we repainted the screen instead. */
    }
#ifdef DO_GRABS
    XUngrabServer(dpy);
    XUngrabKeyboard(dpy, CurrentTime);
#endif
  }
  if (simulating) ResumeSimulator();
}

/*ARGSUSED*/
static void fixButtons(w, client, call)
     Widget w;
     caddr_t client, call;
{
  Widget box = (Widget) client;
  if (/*|||| box->core.visible && */ XtWindow(box)) {
    XtUnmapWidget(box);
    XtMapWidget(box);
  }
}

#ifdef TIMINGCHOICE
static Widget averageLabel, averageButton;
static Widget cycleLabel, continuous, iso_contr, fill, iso_relax, eject;
static Widget cycleToLabel, none, to_iso_c, to_fill, to_iso_r, to_eject;

/*ARGSUSED*/
static void averageCallback(w, client, call)
     Widget w;
     caddr_t client, call;
{
  MenuData data = (MenuData) client;
  Arg args[2];

  if (w) data->averaging = !data->averaging;
  XtSetArg(args[0], XtNlabel, data->averaging ? "Yes" : "No");
  XtSetValues(averageButton, args, 1);
}

static void ToButtonsSetSens(n, c, ej, r, f)
     Boolean n, c, ej, r, f;
{
    XtSetSensitive(none, n);
    XtSetSensitive(to_iso_c, c);
    XtSetSensitive(to_eject, ej);
    XtSetSensitive(to_iso_r, r);
    XtSetSensitive(to_fill, f);
}

static void FromButtonsSetSens(n, c, ej, r, f)
     Boolean n, c, ej, r, f;
{
    XtSetSensitive(continuous, n);
    XtSetSensitive(iso_contr, c);
    XtSetSensitive(eject, ej);
    XtSetSensitive(iso_relax, r);
    XtSetSensitive(fill, f);
}
  
/*
 * Keeps the radio buttons associated with toggle choice
 * in the right state.  Always makes the current button insensitive
 * so that it can't be inactivated by pressing again. |||| 
 * There should be a better way to do that.
 */
/*ARGSUSED*/
static void toggleCallback(w, client, call)
Widget w;
caddr_t client, call;
{
  unsigned int flags = (unsigned int) client;
  Arg args[5];
  int i=0;
  XtSetArg(args[i], XtNstate, True);i++;
  if (call) switch (flags) {
  case /* continuous: */ 15:
    XawToggleUnsetCurrent(none);
    ToButtonsSetSens(False, False, False, False, False);
    FromButtonsSetSens(False, True, True, True, True);
    XtSetValues(continuous, args, i);
    break;
  case /* iso_contr: */ 4:
    XawToggleSetCurrent(none, 15<<4);
    ToButtonsSetSens(False, False, True, True, True);
    FromButtonsSetSens(True, False, True, True, True);
    XtSetValues(iso_contr, args, i);
    break;
  case /* eject: */ 2:
    XawToggleSetCurrent(none, 15<<4);
    ToButtonsSetSens(False, True, False, True, True);
    FromButtonsSetSens(True, True, False, True, True);
    XtSetValues(eject, args, i);
    break;
  case /* iso_relax: */ 8:
    XawToggleSetCurrent(none, 15<<4);
    ToButtonsSetSens(False, True, True, False, True);
    FromButtonsSetSens(True, True, True, False, True);
    XtSetValues(iso_relax, args, i);
    break;
  case /* fill: */ 1:
    XawToggleSetCurrent(none, 15<<4);
    ToButtonsSetSens(False, True, True, True, False);
    FromButtonsSetSens(True, True, True, True, False);
    XtSetValues(fill, args, i);
    break;

  case /* none: */ 15<<4:
    ToButtonsSetSens(False, True, True, True, True);
    XtSetValues(none, args, i);
    break;
  case /* to_iso_c: */ 4<<4:
    ToButtonsSetSens(True, False, True, True, True);
    XtSetValues(to_iso_c, args, i);
    break;
  case /* to_eject: */ 2<<4:
    ToButtonsSetSens(True, True, False, True, True);
    XtSetValues(to_eject, args, i);
    break;
  case /* to_iso_r: */ 8<<4:
    ToButtonsSetSens(True, True, True, False, True);
    XtSetValues(to_iso_r, args, i);
    break;
  case /* to_fill: */ 1<<4:
    ToButtonsSetSens(True, True, True, True, False);
    XtSetValues(to_fill, args, i);
    break;
  }
}
#endif

/*PUBLIC*/
Widget MakePlotMenu(widget, Callback, x, y, adX, ad1, ad2,ad3)
     Widget widget; /* widget to be passed to Callback (usu. parent of plot)*/
     void (*  Callback)();
     int x, y; /* location for menu */
     AxisData adX, ad1, ad2, ad3;
{
  static AxisDataRec adProto = {-1, -1, "",0.,0., 5, "",FALSE}, 
                     adTime = {0, TIME, "Time",0., 999., 5, "cm/sec",FALSE};
  static XFontStruct *cor = NULL; 
  static MenuData data = NULL;
  int i, j;
  Arg args[15];

  if (FormActive) return(NULL); /* Allow only one at a time */
  FormActive = True;
  if (!cor) cor = XLoadQueryFont(dpy, "*-new cent*-bold-r-*-*-*-180-*");
  if (!data) { /* only create this stuff once for speed */
    data = (MenuData) XtMalloc(sizeof(MenuDataRec));
    data->popup = XtCreatePopupShell("cvsbin",overrideShellWidgetClass,
#ifdef NOTDEF /* (error on sparcstation)||| why??? */
			    XtIsComposite(widget) ? widget : XtParent(widget), 
#endif
				     widget,
				     (ArgList)NULL, 0);
    data->menu = XtCreateManagedWidget("plotForm",panedWidgetClass,data->popup,
				       (ArgList)NULL, 0);
    i=0;
    XtSetArg(args[i], XtNborderWidth, 2);i++;
    XtSetArg(args[i], XtNallowResize, True);i++;
    XtSetArg(args[i], XtNresizeToPreferred, True);i++;
    data->pfDataX = CreateAxisForm(data->menu, args, i); 
    i=0;
    XtSetArg(args[i], XtNborderWidth, 2);i++;
    XtSetArg(args[i], XtNallowResize, True);i++;
    XtSetArg(args[i], XtNresizeToPreferred, True);i++;
    data->pfData1 = CreateAxisForm(data->menu, args, i);
    i=0;
    XtSetArg(args[i], XtNborderWidth, 2);i++;
    XtSetArg(args[i], XtNallowResize, True);i++;
    XtSetArg(args[i], XtNresizeToPreferred, True);i++;
    data->pfData2 = CreateAxisForm(data->menu,args, i);
    i=0;
    XtSetArg(args[i], XtNborderWidth, 2);i++;
    XtSetArg(args[i], XtNallowResize, True);i++;
    XtSetArg(args[i], XtNresizeToPreferred, True);i++;
    data->pfData3 = CreateAxisForm(data->menu, args, i);
    i=0;
    XtSetArg(args[i], XtNborderWidth, 0);i++;
    XtSetArg(args[i], XtNallowResize, False);i++;
    XtSetArg(args[i], XtNresizeToPreferred, True);i++;
    data->lastForm = XtCreateManagedWidget("lastForm", formWidgetClass,
					   data->menu, args, i);
    XtAddCallback(data->popup, XtNpopupCallback, 
		  doSaveUnder, (caddr_t) data->menu);
    XtAddCallback(data->popup, XtNpopdownCallback, 
		  doFixUnder,(caddr_t) data->menu);
    XtAddCallback(data->popup, XtNpopdownCallback,
		  fixButtons, (caddr_t) widget);
#ifdef SAVEDATA
    i=0;
    XtSetArg(args[i], XtNlabel, "Persist (sec):");i++;
    XtSetArg(args[i], XtNborderWidth, 0);i++;
    data->DispTimeLabel = XtCreateManagedWidget("Persist", labelWidgetClass,
						data->lastForm, args, i);
#endif

    j=0;
#ifdef TIMINGCHOICE
/*
 *  DEFINE TIMINGCHOICE to add a bunch of buttons for choosing
 *  the time in the cardiac cycle that you wish to have plotted.
 */

    /* Radio group for plotting only at specific times. */
    XtSetArg(args[j], XtNtop, XtChainTop);j++;
    XtSetArg(args[j], XtNbottom, XtChainTop);j++;
    XtSetArg(args[j], XtNleft, XtChainLeft);j++;
    XtSetArg(args[j], XtNright, XtChainLeft);j++;

    i=j;
    XtSetArg(args[i], XtNlabel, "Average:");i++;
    XtSetArg(args[i], XtNborderWidth, 0);i++;
    averageLabel = XtCreateManagedWidget("AverageLabel", labelWidgetClass, 
				       data->lastForm, args, i);
    i=j;
    XtSetArg(args[i], XtNlabel, "No");i++;
    XtSetArg(args[i], XtNfromHoriz, averageLabel);i++;
    averageButton =  XtCreateManagedWidget("AverageButton", commandWidgetClass,
					   data->lastForm, args, i);
    XtAddCallback(averageButton, XtNcallback, averageCallback,
		  (caddr_t)data);
    
    i=j;
    XtSetArg(args[i], XtNlabel, "Portion of cardiac cycle:");i++;
    XtSetArg(args[i], XtNborderWidth, 0);i++;
    XtSetArg(args[i], XtNfromVert, averageButton);i++;
    cycleLabel = XtCreateManagedWidget("CycleLabel", labelWidgetClass, 
				       data->lastForm, args, i);
    i=j;
    XtSetArg(args[i], XtNlabel, "Continuous");i++;
    XtSetArg(args[i], XtNradioData, 15);i++;
    XtSetArg(args[i], XtNfromVert, cycleLabel);i++;
    data->timingGroup = 
      continuous =  XtCreateManagedWidget("Continuous", toggleWidgetClass,
					  data->lastForm, args, i);
    
    i=j;
    XtSetArg(args[i], XtNlabel, "Isovolumic Contraction");i++;
    XtSetArg(args[i], XtNradioGroup, continuous);i++;
    XtSetArg(args[i], XtNfromVert, continuous);i++;
    XtSetArg(args[i], XtNradioData, 4);i++;
    iso_contr =  XtCreateManagedWidget("IsoC", toggleWidgetClass,
				       data->lastForm, args, i);
    i=j;
    XtSetArg(args[i], XtNlabel, "Ejection");i++;
    XtSetArg(args[i], XtNradioGroup, continuous);i++;
    XtSetArg(args[i], XtNfromVert, iso_contr);i++;
    XtSetArg(args[i], XtNradioData, 2);i++;
    eject =  XtCreateManagedWidget("Ej", toggleWidgetClass,
				   data->lastForm, args, i);
    i=j;
    XtSetArg(args[i], XtNlabel, "Isovolumic Relaxation");i++;
    XtSetArg(args[i], XtNradioGroup, continuous);i++;
    XtSetArg(args[i], XtNfromVert, eject); i++;
    XtSetArg(args[i], XtNradioData, 8);i++;
    iso_relax =  XtCreateManagedWidget("IsoR", toggleWidgetClass,
				       data->lastForm, args, i);
    i=j;
    XtSetArg(args[i], XtNlabel, "Filling");i++;
    XtSetArg(args[i], XtNradioGroup, continuous);i++;
    XtSetArg(args[i], XtNfromVert, iso_relax); i++;
    XtSetArg(args[i], XtNradioData, 1);i++;
    fill =  XtCreateManagedWidget("Fill", toggleWidgetClass,
				  data->lastForm, args, i);
    
    XawToggleUnsetCurrent(continuous);
    XawToggleSetCurrent(continuous, (caddr_t)15);
    
    
    i=j;
    XtSetArg(args[i], XtNlabel, "To beginning of:");i++;
    XtSetArg(args[i], XtNborderWidth, 0);i++;
    XtSetArg(args[i], XtNfromHoriz, iso_contr);i++;
    XtSetArg(args[i], XtNfromVert, averageButton);i++;
    cycleToLabel = XtCreateManagedWidget("CycleToLabel", labelWidgetClass, 
					 data->lastForm, args, i);
    
    i=j;
    XtSetArg(args[i], XtNlabel, "1 pt. per cycle");i++;
    XtSetArg(args[i], XtNfromVert, cycleToLabel);i++;
    XtSetArg(args[i], XtNfromHoriz, iso_contr);i++;
    XtSetArg(args[i], XtNradioData, 15<<4);i++;
    none =  XtCreateManagedWidget("OnePt", toggleWidgetClass,
				  data->lastForm, args, i);
    i=j;
    XtSetArg(args[i], XtNlabel, "Stop at Contraction");i++;
    XtSetArg(args[i], XtNfromVert, none);i++;
    XtSetArg(args[i], XtNradioGroup, none);i++;
    XtSetArg(args[i], XtNfromHoriz, iso_contr);i++;
    XtSetArg(args[i], XtNradioData, 4<<4);i++;
    data->timingEndGroup = 
      to_iso_c =  XtCreateManagedWidget("ToIsoC", toggleWidgetClass,
					data->lastForm, args, i);
    i=j;
    XtSetArg(args[i], XtNlabel, "Stop at Ejection");i++;
    XtSetArg(args[i], XtNradioGroup, to_iso_c);i++;
    XtSetArg(args[i], XtNfromVert, to_iso_c);i++;
    XtSetArg(args[i], XtNfromHoriz, iso_contr);i++;
    XtSetArg(args[i], XtNradioData, 2<<4);i++;
    to_eject =  XtCreateManagedWidget("ToEj", toggleWidgetClass,
				      data->lastForm, args, i);
    i=j;
    XtSetArg(args[i], XtNlabel, "Stop at Relaxation");i++;
    XtSetArg(args[i], XtNradioGroup, to_iso_c);i++;
    XtSetArg(args[i], XtNfromVert, to_eject); i++;
    XtSetArg(args[i], XtNfromHoriz, iso_contr);i++;
    XtSetArg(args[i], XtNradioData, 8<<4);i++;
    to_iso_r =  XtCreateManagedWidget("ToIsoR", toggleWidgetClass,
				      data->lastForm, args, i);
    i=j;
    XtSetArg(args[i], XtNlabel, "Stop at Filling");i++;
    XtSetArg(args[i], XtNradioGroup, to_iso_c);i++;
    XtSetArg(args[i], XtNfromVert, to_iso_r); i++;
    XtSetArg(args[i], XtNfromHoriz, iso_contr);i++;
    XtSetArg(args[i], XtNradioData, 1<<4);i++;
    to_fill =  XtCreateManagedWidget("ToFill", toggleWidgetClass,
				     data->lastForm, args, i);
    
    XawToggleUnsetCurrent(to_iso_c);

    XtAddCallback(to_fill, XtNcallback, toggleCallback, (caddr_t)(1<<4));
    XtAddCallback(to_iso_r, XtNcallback, toggleCallback, (caddr_t)(8<<4));
    XtAddCallback(to_eject, XtNcallback, toggleCallback, (caddr_t)(2<<4));
    XtAddCallback(to_iso_c, XtNcallback, toggleCallback, (caddr_t) (4<<4));
    XtAddCallback(none, XtNcallback, toggleCallback, (caddr_t) (15<<4));
    XtAddCallback(iso_relax, XtNcallback, toggleCallback, (caddr_t) 8);
    XtAddCallback(eject, XtNcallback, toggleCallback, (caddr_t) 2);
    XtAddCallback(iso_contr, XtNcallback, toggleCallback, (caddr_t) 4);
    XtAddCallback(continuous, XtNcallback, toggleCallback, (caddr_t) 15);
    XtAddCallback(fill, XtNcallback, toggleCallback, (caddr_t) 1);
#endif
    
    i=j;
    XtSetArg(args[i], XtNlabel, "Do Plot");i++;
    if (cor) { XtSetArg(args[i], XtNfont, cor);i++; }
#ifdef TIMINGCHOICE
    XtSetArg(args[i], XtNfromVert, fill); i++;
#endif
    XtSetArg(args[i], XtNborderWidth, 3);i++;
    data->Create = XtCreateManagedWidget("DoPlot", commandWidgetClass,
					 data->lastForm, args, i);
    XtAddCallback(data->Create, XtNcallback, CreateCallback, (caddr_t)data);
    i=j;
    XtSetArg(args[i], XtNlabel, "Cancel");i++;
    if (cor) {XtSetArg(args[i], XtNfont, cor);i++; }
    XtSetArg(args[i], XtNborderWidth, 3);i++;
#ifdef TIMINGCHOICE
    XtSetArg(args[i], XtNfromVert, fill); i++;
#endif
    XtSetArg(args[i], XtNfromHoriz, data->Create);i++;
    data->Cancel = XtCreateManagedWidget("Cancel", commandWidgetClass,
					 data->lastForm, args, i);
    XtAddCallback(data->Cancel, XtNcallback, CancelCallback, (caddr_t)data);
#ifdef SAVEDATA
    (void) strcpy(data->DispTime, "99999.9");
    i=j;
    XtSetArg(args[i], XtNwidth, 75);i++;
#ifdef XAW_BC
    XtSetArg(args[i], XtNstring, data->DispTime);i++;
    XtSetArg(args[i], XtNeditType, XttextEdit);i++;
    XtSetArg(args[i], XtNtextOptions, editable);i++;
#else /* ! XAW_BC */
    XtSetArg(args[i], XtNeditType, XawtextEdit);i++;
#endif
    XtSetArg(args[i], XtNlength, 40);i++;
    XtSetArg(args[i], XtNfromHoriz, data->DispTimeLabel);i++;
    XtSetArg(args[i], XtNtranslations, parsedNumeric);i++;
#ifdef XAW_BC
    data->DispTimeText = XtCreateManagedWidget("DispTimeText", 
			      asciiStringWidgetClass, data->lastForm, args, i);
#else /* ! XAW_BC */
    data->DispTimeText = XtCreateManagedWidget("DispTimeText", 
			      asciiTextWidgetClass, data->lastForm, args, i);
#endif
    XtAddEventHandler(data->DispTimeText, EnterWindowMask, False, DoFocusKeyboard, (caddr_t)0);
#endif
  }
  XtMoveWidget(data->popup, x, y);
  data->widget = widget;
  data->Callback = Callback;
  if (adX && adX->place > -1 && adX->type > -1) data->adx = *adX; 
  else data->adx = adTime;
  UpdateAxisForm(data->pfDataX, "X Axis:  ", &data->adx);
  if (ad1 && ad1->place > -1 && ad1->type > -1) data->ad1 = *ad1; 
  else data->ad1 = adProto;
  UpdateAxisForm(data->pfData1, "Y Axis 1:", &data->ad1);
  if (ad2 && ad2->place > -1 && ad2->type > -1) data->ad2 = *ad2; 
  else data->ad2 = adProto;
  UpdateAxisForm(data->pfData2, "Y Axis 2:", &data->ad2);
  if (ad3 && ad3->place > -1 && ad3->type > -1) data->ad3 = *ad3; 
  else data->ad3 = adProto;
  UpdateAxisForm(data->pfData3, "Y Axis 3:", &data->ad3);
  { 
#ifdef TIMINGCHOICE
    unsigned int timing = 0;
    i=0;
    XtSetArg(args[i], XtNtiming, &timing);i++;
    XtGetValues(data->widget, args, i);
    if (!(timing & 0x0F)) {                                                 
      timing &= 0xFF00;
      XawToggleUnsetCurrent(data->timingEndGroup);
    } else 
      XawToggleSetCurrent(data->timingEndGroup, (caddr_t) (timing & 0xF0));
    XawToggleSetCurrent(data->timingGroup, (caddr_t) (timing & 0x0F));
    toggleCallback((Widget)0, (caddr_t)timing, (caddr_t)1);
    data->averaging = timing&0x0800 ? True : False;
    averageCallback((Widget)0, (caddr_t)data, (caddr_t)0);
#endif
    XtSetArg(args[0], XtNresizeToPreferred, False);
    XtSetValues(data->lastForm, args, 1);
  }
  return(data->popup);
}


