#ifndef lint
static char *rcs="$Header: /mit/hst/src/plot/RCS/Plot.c,v 3.1 90/08/28 17:31:31 tldavis Exp $";
#endif

/*****************************************************************************
 * 
 * Plot widget for X11 Cardiovascular Simulator
 * Copyright 1988 by Timothy L. Davis
 *
 * $Source: /mit/hst/src/plot/RCS/Plot.c,v $
 * $Log:	Plot.c,v $
 * Revision 3.1  90/08/28  17:31:31  tldavis
 * Removed a bug that cropped up with an absent X resource file.
 * 
 * Revision 3.0  90/08/28  14:41:51  tldavis
 * Added support for the XtNtiming set of flags (at least 16 bit int).
 * XtNtiming has flags which determine the current portion of cardiac cycle,
 * the portion to plot, and whether to average data before plotting.
 * 
 * Revision 1.1  90/08/19  18:42:25  tldavis
 * Initial revision
 * 
 * Revision 2.2  90/08/18  18:36:40  tldavis
 * Many changes:  reworked all the display code for speed and bugfixes.
 * Now fully supports color resources.
 * 
 * Revision 2.1  90/08/10  10:57:23  dot
 * moved Xaw header files to X11/Xaw for R4
 * 
 * Revision 2.0  90/08/06  17:59:46  tldavis
 * Final X11R3 version.
 * 
 * Revision 1.24  90/08/06  17:05:47  tldavis
 * Fixed problems with color on Suns.
 * 
 * Revision 1.23  90/05/31  16:29:06  tldavis
 * Pre-ACIS checkin.
 * 
 * Revision 1.22  90/02/09  15:28:45  tldavis
 * Avoids redisplaying at almost all costs.
 * Tweaked to keep plotting in same place after exposures.
 * 
 * Revision 1.21  89/10/12  22:15:29  tldavis
 * Added possibility for bitmap saving, if you #define PIXDRAW.
 * 
 * Revision 1.20  89/10/10  23:13:12  tldavis
 * mwm support, works well but no saving of background pixmap.
 * Works with either stripchart or scope or xy mode.
 * R3 fonts fixed.
 * Revision 1.13  89/02/22  12:27:07  tldavis
 * X11R3 version (no saves of old data).
 * Revision 1.10  88/10/10  21:45:34  hst
 * Fixed several bugs to do with labels, removed ball for speed reasons,
 * Revision 1.2  88/08/03  18:21:34  tldavis
 * First successful compile of X11 version.
 * Revision 1.1  88/08/03  14:53:09  tldavis
 * Initial revision
 *
 * PLOT: Everything needed for the plot windows, both striphart and X v. Y
 * style plots.  Accepts up to 3 separate variables on the Y axis, plotted
 * against a common X axis.  Each variable may be "auto-rescaling", meaning
 * that the plot axes for that variable are recalculated if the values go
 * out of bounds.
 *
 * WidgetClass is plotWidgetClass
 *
 * void PlotData(Window w, double *pressures) is the main routine to 
 *    provide the plot widget with a new set of data values to be plotted.
 *    pressures should point to a 9-element array containing the 6 pressures,
 *    time, Cl(t) and Cr(t) for that time, as produced inside simulate.c
 *    Generally, this routine should only be called by the control loop which
 *    polls the simulation data pipe and broadcasts new data to all active
 *    plots.
 *
 * void PlotModifySimulation(Window w, int place, int type, double value)
 *    allows for changes to the widget's view of the simulation, so that
 *    variables for plotting may be calculated appropriately from the given
 *    pressures.
 *
 * define PIXDRAW to draw all data to the background pixmap.  It won't be lost
 *   when the window is obscured, but this is MUCH slower than the other way.
 *
 * define MOVINGBALL to put a pen-ball head at the right of the stripchart.
 *   This also slows down the animation.
 *  
 * define SAVEDATA to save a list of previously-plotted data.
 *
 ****************************************************************************/
#ifdef NOTDEF
#define PIXDRAW /* Save plot data in background pixmaps SURE IS SLOW! */
#endif
#include <stdio.h>
#ifdef SVR4
#include <string.h>
#else
#include <strings.h>
#endif
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <X11/Xaw/Command.h>
#include <X11/cursorfont.h>
#include "PlotP.h"
#include "../form/PlotForm.h" /* For Modify Axes menu. */
#include "../sim/CVDefs.h"
#include <math.h>
extern double getval(); /* from ../sim/eqns.c */
extern unsigned int UpdatePeriod(); /* from ../sim/eqns.c */
extern double drawAxis();
static int drawOldData();

extern Display *dpy;
extern Window root;
extern int screen;

#define PAD 40 /* pad around outside of graph (to include labels/nums) */
#define AXISPAD 12 /* pad for axis dimensions */
#define SAMPLEPAD 32 /* pad for sample line dashes */
/* screen resolution in pixels per cm */
#define RESOLUTION (10.*XDisplayWidth(dpy,XDefaultScreen(dpy))/ \
                        XDisplayWidthMM(dpy,XDefaultScreen(dpy)))

#define offset(field) XtOffset(PlotWidget,plot.field)
static XtResource resources[] =
  {
    {XtNcolor1, XtCForeground, XtRPixel, sizeof(Pixel),
       offset(color1), XtRString, "XtDefaultForeground"},
    {XtNcolor2, XtCForeground, XtRPixel, sizeof(Pixel),
       offset(color2), XtRString, "XtDefaultForeground"},
    {XtNcolor3, XtCForeground, XtRPixel, sizeof(Pixel),
       offset(color3), XtRString, "XtDefaultForeground"},
    {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
       offset(foreground), XtRString, "XtDefaultForeground"},
    {XtNbackground, XtCBackground, XtRPixel, sizeof(Pixel),
       offset(background), XtRString, "XtDefaultBackground"},
    {XtNplotback, XtCBackground, XtRPixel, sizeof(Pixel),
       offset(plotback), XtRString, "XtDefaultBackground"},
    {XtNlabel, XtCLabel, XtRString, sizeof(String), 
       offset(title), XtRString, NULL},
    {XtNpaperSpeed, XtCValue, XtRDouble, sizeof(double),
        offset(paperSpeed), XtRString, "5.0"},
    {XtNdecayTime, XtCValue, XtRDouble, sizeof(double),
       offset(decayTime),  XtRString, "1.0"},
    {XtNplaceX, XtCValue, XtRInt, sizeof(int),
        offset(placeX), XtRString, "0"},
    {XtNplace1, XtCValue, XtRInt, sizeof(int),
        offset(place1), XtRString, "-1"},
    {XtNplace2, XtCValue, XtRInt, sizeof(int),
        offset(place2), XtRString, "-1"},
    {XtNplace3, XtCValue, XtRInt, sizeof(int),
        offset(place3), XtRString, "-1"},
    {XtNtypeX, XtCValue, XtRInt, sizeof(int),
        offset(typeX), XtRString, "0"},
    {XtNtype1, XtCValue, XtRInt, sizeof(int),
        offset(type1), XtRString, "-1"},
    {XtNtype2, XtCValue, XtRInt, sizeof(int),
        offset(type2), XtRString, "-1"},
    {XtNtype3, XtCValue, XtRInt, sizeof(int),
        offset(type3), XtRString, "-1"},
    {XtNlabelX, XtCValue, XtRString, sizeof(String),
        offset(labelX), XtRString, "Time"},
    {XtNlabel1, XtCValue, XtRString, sizeof(String),
        offset(label1), XtRString, NULL},
    {XtNlabel2, XtCValue, XtRString, sizeof(String),
        offset(label2), XtRString, NULL},
    {XtNlabel3, XtCValue, XtRString, sizeof(String),
        offset(label3), XtRString, NULL},
    {XtNminX, XtCValue, XtRDouble, sizeof(double),
        offset(minX), XtRString, "0."},
    {XtNmin1, XtCValue, XtRDouble, sizeof(double),
        offset(min1), XtRString, "0."},
    {XtNmin2, XtCValue, XtRDouble, sizeof(double),
        offset(min2), XtRString, "0."},
    {XtNmin3, XtCValue, XtRDouble, sizeof(double),
        offset(min3), XtRString, "0."},
    {XtNmaxX, XtCValue, XtRDouble, sizeof(double),
        offset(maxX), XtRString, "100."},
    {XtNmax1, XtCValue, XtRDouble, sizeof(double),
        offset(max1), XtRString, "100."},
    {XtNmax2, XtCValue, XtRDouble, sizeof(double),
        offset(max2), XtRString, "100."},
    {XtNmax3, XtCValue, XtRDouble, sizeof(double),
        offset(max3), XtRString, "100."},
    {XtNunitX, XtCValue, XtRString, sizeof(String),
        offset(unitX), XtRString, NULL},
    {XtNunit1, XtCValue, XtRString, sizeof(String),
        offset(unit1), XtRString, NULL},
    {XtNunit2, XtCValue, XtRString, sizeof(String),
        offset(unit2), XtRString, NULL},
    {XtNunit3, XtCValue, XtRString, sizeof(String),
        offset(unit3), XtRString, NULL},
    {XtNautoScaleX, XtCValue, XtRBoolean, sizeof(Boolean),
       offset(autoX), XtRBoolean, False},
    {XtNautoScale1, XtCValue, XtRBoolean, sizeof(Boolean),
       offset(auto1), XtRBoolean, False},
    {XtNautoScale2, XtCValue, XtRBoolean, sizeof(Boolean),
       offset(auto2), XtRBoolean, False},
    {XtNautoScale3, XtCValue, XtRBoolean, sizeof(Boolean),
       offset(auto3), XtRBoolean, False},
    {XtNstripMode,  XtCValue, XtRBoolean, sizeof(Boolean),
       offset(stripMode), XtRBoolean, False},
    {XtNcallback, XtCCallback, XtRCallback, sizeof(caddr_t),
       offset(callbacks), XtRCallback, NULL},
    {XtNtiming, XtCValue, XtRInt, sizeof(int),
       offset(timing), XtRString, "0"},
};
#undef offset


/*
 * FORWARD defines for the widget activity routines to be put in core struct
 * These routines follow widget interaction rules.
 */
static void ClassInitialize();
static void Initialize();
static void Realize();
static void Destroy(); 
static void Redisplay();
static void UpdateCaliper(), WriteCaliper(), EraseCaliper();
static Boolean SetValues();
static XtGeometryResult GeometryManager();

PlotClassRec plotClassRec = {
  { /* core_class fields */
#define superclass ((WidgetClass) &compositeClassRec)
    /* superclass		*/	superclass,
    /* class_name		*/	"Plot",
    /* widget_size		*/	sizeof(PlotRec),
    /* class_initialize		*/	ClassInitialize,
    /* class_part_initialize	*/	NULL,
    /* class_inited		*/	False,
    /* initialize		*/	Initialize,
    /* initialize_hook		*/	NULL,
    /* realize			*/	Realize,
    /* actions			*/	NULL, /* TOO SLOW */
    /* num_actions		*/	0,
    /* resources		*/	resources,
    /* num_resources		*/	XtNumber(resources),
    /* xrm_class		*/	NULLQUARK,
    /* compress_motion		*/	True,
    /* compress_exposure	*/	True,
    /* compress_enterleave	*/	True,
    /* visible_interest		*/	False,
    /* destroy			*/	Destroy,
    /* resize			*/	XtInheritResize,
    /* expose			*/	Redisplay,
    /* set_values		*/	SetValues,
    /* set_values_hook		*/	NULL,
    /* set_values_almost	*/	XtInheritSetValuesAlmost,
    /* get_values_hook		*/	NULL,
    /* accept_focus		*/	NULL,
    /* version			*/	XtVersion,
    /* callback_private		*/	NULL,
    /* tm_table			*/	NULL, /* TOO SLOW */
    /* query_geometry		*/	XtInheritQueryGeometry,
    /* ***NEWR3*** display_accel*/      XtInheritDisplayAccelerator,
    /* ***NEWR3*** extension    */	NULL
  },
  { /* composite_class fields */
    /* geometry_manager */   GeometryManager,
    /* change_managed */     XtInheritChangeManaged,
    /* insert_child */       XtInheritInsertChild,
    /* delete_child */       XtInheritDeleteChild,
    /* ***NEWR3*** extension */ NULL
  },
  { /* Plot fields */
    /* gc's */                          (GC)NULL, (GC)NULL, (GC)NULL, (GC)NULL,
    /* small_font */                    (XFontStruct *)NULL,
    /* pointer_cursor */                (Cursor)NULL, (Cursor)NULL,
  }
};
WidgetClass plotWidgetClass = (WidgetClass) &plotClassRec;

/****************************************************************
 *
 * Private Procedures
 *
 ****************************************************************/
/*FORWARD*/ static void ModCallback(), RefreshCallback();

/*ARGSUSED*/
static void CvtStringToDouble(args, num_args, fromVal, toVal)
XrmValue *args;
Cardinal *num_args;
XrmValue *fromVal, *toVal;
{
  static double i;
  if (*num_args != 0)
    XtWarning("String to Double conversion needs no extra arguments");
  if (sscanf ((char *)fromVal->addr,"%lf",&i) == 1) {
    toVal->size = sizeof(double);
    toVal->addr = (caddr_t) &i;
  }
}

/*
 * registered private widget initialization and event handling routines:
 *
 */
#ifdef PIXDRAW
static GC whiteGC = (GC)0;
#endif
static char Dash2[] = {1, 3, 0};
static char Dash3[] = {3, 5, 0};
static char *trans = "<BtnUp>: notify() unset() unhighlight() \n";
static XtTranslations parsed_translations;

static void ClassInitialize() 
{
  XGCValues gcvalues;
  unsigned long fontmask = 0;

  if (plotClassRec.plot_class.small_font =     
      XLoadQueryFont(dpy,"*-courier-medium-r-*-*-*-80-*"))
    fontmask = GCFont; /* successful font acquisition, else default. */
  plotClassRec.plot_class.pointer_cursor = XCreateFontCursor(dpy, XC_arrow);
  if (plotClassRec.plot_class.small_font)
    gcvalues.font = plotClassRec.plot_class.small_font->fid;
  plotClassRec.plot_class.plotwin_cursor = 
    XCreateFontCursor(dpy, XC_crosshair);
 
  gcvalues.graphics_exposures = False;
  plotClassRec.plot_class.gc1 = XCreateGC(dpy, root, GCGraphicsExposures |
					  fontmask, &gcvalues);
  gcvalues.line_style = LineOnOffDash;
  plotClassRec.plot_class.gc2 = XCreateGC(dpy, root, GCGraphicsExposures |
					  fontmask | GCLineStyle,
					  &gcvalues);
  XSetDashes(dpy, plotClassRec.plot_class.gc2, 0, Dash2, strlen(Dash2));
  gcvalues.line_style = LineOnOffDash;
  plotClassRec.plot_class.gc3 = XCreateGC(dpy, root, GCGraphicsExposures |
					  fontmask | GCLineStyle,
					  &gcvalues);
  XSetDashes(dpy, plotClassRec.plot_class.gc3, 0, Dash3, strlen(Dash3));
  XtAddConverter(XtRString, XtRDouble, CvtStringToDouble, (XtConvertArgList)0, 0);

#ifdef PIXDRAW
  gcvalues.foreground = BlackPixel(dpy,screen);
  gcvalues.background = WhitePixel(dpy,screen);
  whiteGC = XCreateGC(dpy, root, GCForeground | GCBackground, &gcvalues);
#endif
  
  gcvalues.function = GXcopy;
  plotClassRec.plot_class.pointerGC = 
    XCreateGC(dpy, root, GCFunction | fontmask, &gcvalues);

  parsed_translations = XtParseTranslationTable(trans);
} /* ClassInitialize() */


static void Initialize(request, new)
     Widget request, new;
{
  PlotWidget pw = (PlotWidget) new;
  PlotPart *plot = & pw->plot;
  static PlotRec blank = {{0,}, {0,}, 
			  {0, 0, 0, 0, 0, 0,
			   0, 0.0, 0.0, -1, -1, -1, -1, -1, -1, -1, -1, 0, }};
  int i;
  Arg arg[10];

  XSetForeground(dpy, plotClassRec.plot_class.gc1, plot->color1);
  XSetBackground(dpy, plotClassRec.plot_class.gc1, plot->plotback);
  XSetForeground(dpy, plotClassRec.plot_class.gc2, plot->color2);
  XSetBackground(dpy, plotClassRec.plot_class.gc2, plot->plotback);
  XSetForeground(dpy, plotClassRec.plot_class.gc3, plot->color3);
  XSetBackground(dpy, plotClassRec.plot_class.gc3, plot->plotback);
  XSetForeground(dpy, plotClassRec.plot_class.pointerGC, plot->foreground);
  XSetBackground(dpy, plotClassRec.plot_class.pointerGC, plot->background);

  plot->titlePad = 5; 
  plot->labelPad = 5;
  plot->slideDots = 1; 
  plot->outX = plot->out1 = plot->out2 = plot->out3 = 0;
  plot->phase2 = plot->phase3 = 0;
  plot->lastX = plot->last1 = plot->last2 = plot->last3 = 0.;
  plot->sfX = 0.0;
  if (pw->core.width == 0) pw->core.width = 400;
  if (pw->core.height == 0) pw->core.height = 200;
  plot->plotwin = 0;

  i=0;
  XtSetArg(arg[i], XtNlabel, "Modify Axes");i++;
  plot->modButton = 
    XtCreateManagedWidget("Modify Axes", commandWidgetClass, (Widget)pw, arg, i);
  XtAddCallback(plot->modButton, XtNcallback, ModCallback, (caddr_t)pw);
  XtOverrideTranslations(plot->modButton, parsed_translations);

  i=0;
  XtSetArg(arg[i], XtNlabel, "Refresh");i++;
  plot->refreshButton = 
    XtCreateManagedWidget("Refresh", commandWidgetClass, (Widget)pw, arg, i);
  XtAddCallback(plot->refreshButton, XtNcallback, RefreshCallback,(caddr_t)pw);

  /* Leave them unmanaged for now... manage them selectively in SetValues */
  i=0;
  XtSetArg(arg[i], XtNforeground, plot->color1);i++;
  XtSetArg(arg[i], XtNbackground, plot->background);i++;
  plot->label1w = XtCreateWidget("label1", labelWidgetClass, (Widget)pw, arg, i);
  i=0;
  XtSetArg(arg[i], XtNforeground, plot->color2);i++;
  XtSetArg(arg[i], XtNbackground, plot->background);i++;
  plot->label2w = XtCreateWidget("label2", labelWidgetClass, (Widget)pw, arg, i);
  i=0;
  XtSetArg(arg[i], XtNforeground, plot->color3);i++;
  XtSetArg(arg[i], XtNbackground, plot->background);i++;
  plot->label3w = XtCreateWidget("label3", labelWidgetClass, (Widget)pw, arg, i);
 
  XtAddEventHandler(new, PointerMotionMask, False,UpdateCaliper, (caddr_t)0);
  XtAddEventHandler(new, LeaveWindowMask, False, EraseCaliper, (caddr_t)0);
  XtAddEventHandler(new, ButtonPressMask, False, WriteCaliper, (caddr_t)0);
  SetValues((Widget) &blank, request, new);
} /* Initialize() */


static void Realize(widget, mask, attributes)
     Widget widget;
     Mask *mask;
     XSetWindowAttributes *attributes;
{
  PlotPart *plot = &((PlotWidget)widget)->plot;

  *mask = *mask | CWBackingStore | CWSaveUnder;
  attributes->backing_store = Always;
  attributes->save_under = True;
  (*superclass->core_class.realize)(widget, mask, attributes);
  XDefineCursor(dpy, XtWindow(widget), plotClassRec.plot_class.pointer_cursor);
  plot->plotwin = XCreateSimpleWindow(dpy, XtWindow(widget), 1, 1, 1, 1, 0, 
				     (unsigned long)plot->foreground,
				     (unsigned long)plot->plotback);
  XDefineCursor(dpy, plot->plotwin, plotClassRec.plot_class.plotwin_cursor);
  plot->plotpix = (Drawable)0;
  XMapWindow(dpy, plot->plotwin);
} /* Realize() */

static void Destroy(w)
     Widget w;
{
  PlotPart *plot = &((PlotWidget)w)->plot;
#ifdef PIXDRAW
/*|||###  XFreePixmap(dpy, (Pixmap)plot->plotpix); */
#endif
  XDestroyWindow(dpy, plot->plotwin);
}

/*
 *
 * Repaint the widget window
 *
 */
/*ARGSUSED*/
static void Redisplay(w, event, region)
     Widget w;
     XEvent *event;
     Region region; /*unused*/
{
  Window window = XtWindow(w);
  PlotWidget pw = (PlotWidget) w;
  PlotPart *plot = &pw->plot;
  CorePart *core = &pw->core;

  GC gc1 = plotClassRec.plot_class.gc1, 
     gc2 = plotClassRec.plot_class.gc2,
     gc3 = plotClassRec.plot_class.gc3,
     gc  = plotClassRec.plot_class.pointerGC;

  XFontStruct *smallFont = plotClassRec.plot_class.small_font;
  register int startX, startY, endX, endY; /* start,end of plotwin widget */
#ifdef SAVEDATA
  double oldestVisibleTime;
#endif
  int label1pos = 0, label2pos = 0, label3pos = 0;

  if ((event && (event->type != Expose
		 || (event->type == Expose && event->xexpose.count)))
      || !w || !XtIsRealized(w))
    return; /*Skip all region events but last expose (count == 0)*/

  /* draw the widget */

  XSetBackground(dpy, gc1, plot->background);
  XSetBackground(dpy, gc2, plot->background);
  XSetBackground(dpy, gc3, plot->background);

  XClearWindow(dpy, window); 

#ifdef PIXDRAW
  XClearWindow(dpy, plot->plotwin);
#endif

  /* Establish coordinates for graphing and conversion constants */
  /* X-axis related stuff */
  startX = PAD;
  if (plot->place1 > -1) startX += AXISPAD;
  if (plot->place2 > -1) startX += PAD+AXISPAD;
  endX = core->width - AXISPAD;
  if (plot->place3 > -1) endX -= PAD;
  if (plot->typeX == TIME) {
    if (plot->stripMode) plot->maxX = plot->currentTime;
    plot->sfX = plot->paperSpeed * RESOLUTION;
    plot->minX = plot->maxX - (endX - startX) / plot->sfX;
    /* fix the end of the graph again to fix the roundoff error */
    endX = startX + plot->sfX*(plot->maxX - plot->minX);
  } 
  /* Y-axis oriented stuff */
  {
    int top = plot->titlePad;
    int bot = core->height - plot->labelPad;

    /* add the modify axes button and the refresh button to the top */
    plot->xoff = PAD;
    XtMoveWidget(plot->modButton, plot->xoff, top);
    plot->xoff += plot->modButton->core.width + 8;
    XtMoveWidget(plot->refreshButton,plot->xoff,top);
    plot->xoff += plot->refreshButton->core.width + 8;
    top += (plot->modButton->core.height > plot->refreshButton->core.height) ?
             plot->modButton->core.height : plot->refreshButton->core.height;
    if (XtIsManaged(plot->label3w)) {
      bot -= plot->label3w->core.height;
      label3pos = bot + (plot->label3w->core.height + 0.5)/2;
      XtConfigureWidget(plot->label3w, plot->labelPad + SAMPLEPAD, bot, 
	  core->width - 2*plot->labelPad - SAMPLEPAD, plot->label3w->core.height,0);
      bot -= plot->labelPad;
    }
    if (XtIsManaged(plot->label2w)) {
      bot -= plot->label2w->core.height;
      label2pos = bot + (plot->label2w->core.height + 0.5)/2;
      XtConfigureWidget(plot->label2w, plot->labelPad + SAMPLEPAD, bot, 
			core->width- 2*plot->labelPad - SAMPLEPAD, plot->label2w->core.height,0);
      bot -= plot->labelPad;
    }
    if (XtIsManaged(plot->label1w)) {
      bot -= plot->label1w->core.height;
      label1pos = bot + (plot->label1w->core.height + 0.5)/2;
      XtConfigureWidget(plot->label1w, plot->labelPad + SAMPLEPAD, bot, 
	     core->width-2*plot->labelPad - SAMPLEPAD, plot->label1w->core.height,0);
      bot -= plot->labelPad;
    }
    bot -= AXISPAD*2;
    startY = bot-AXISPAD;
    endY   = top+AXISPAD;
  }

  {
    int oldw = plot->plotWidth;  
    int oldh = plot->plotHeight;

    plot->plotWidth = endX-startX;
    plot->plotHeight = startY-endY;
    plot->slideDots = (endX-startX)*abs(endY-startY)/10000. + 1;
    plot->nextHash = ceil(plot->minX);
    if (plot->plotWidth < 2 || plot->plotHeight < 2) { /***abort display***/
      return;
    }
    XMoveResizeWindow(dpy, plot->plotwin, startX, endY,
		      plot->plotWidth, plot->plotHeight);
#ifdef SAVEDATA
    oldestVisibleTime = plot->currentTime - plot->decayTime;
    if (plot->decayTime == 0.0)
      oldestVisibleTime = 0.0; /* visible forever */
    if (plot->typeX == TIME) oldestVisibleTime = plot->minX;
#endif
    if (plot->typeX != TIME) {
      plot->sfX = drawAxis(dpy, window, gc, smallFont,
			   startX, startY+AXISPAD, endX, startY+AXISPAD,
			   plot->minX, plot->maxX, 1);
    }
    if (!plot->plotpix || plot->plotWidth != oldw || plot->plotHeight != oldh){
#ifdef PIXDRAW
      Pixmap newpix = XCreatePixmap(dpy, plot->plotwin, plot->plotWidth,
				    plot->plotHeight, 
				    XDisplayPlanes(dpy, XDefaultScreen(dpy)));
      XFillRectangle(dpy, newpix, whiteGC, 0, 0, plot->plotWidth, plot->plotHeight);
      if (plot->plotpix) XFreePixmap(dpy, plot->plotpix);
      XSetWindowBackgroundPixmap(dpy, plot->plotwin, newpix);
#else
      Window newpix = plot->plotwin;
#endif
      /****||||||?????? copy old pixmap to new */
      XClearWindow(dpy, plot->plotwin);
      plot->plotpix = (Drawable) newpix;
    }
  }
  if (plot->place1 > -1) {
    plot->sf1 = drawAxis(dpy, window, gc1, smallFont, startX - AXISPAD, startY,
			 startX - AXISPAD, endY, plot->min1, plot->max1, 1);
    XDrawImageString(dpy, window, gc,startX-AXISPAD, startY+AXISPAD, "#1", 2);
    XDrawLine(dpy, window, gc1, plot->labelPad, label1pos, 
	      plot->labelPad + SAMPLEPAD, label1pos);
    plot->lastPt1 = drawOldData(pw, gc1,smallFont, plot->max1, plot->sf1);
  }
  if (plot->place2 > -1) {
    XSetLineAttributes(dpy, gc2, 0, LineSolid, CapButt, JoinMiter);
    plot->sf2 = drawAxis(dpy,window,gc2,smallFont, startX-2*AXISPAD-PAD,startY,
			 startX-2*AXISPAD-PAD,endY, plot->min2, plot->max2, 1);
    XDrawImageString(dpy, window, gc, startX-2*AXISPAD-PAD, startY+AXISPAD, 
		     "#2", 2);
    XSetLineAttributes(dpy, gc2, 0, LineOnOffDash, CapButt, JoinMiter);
    XDrawLine(dpy, window, gc2, plot->labelPad, label2pos, 
	      plot->labelPad + SAMPLEPAD, label2pos);
    plot->lastPt2 = drawOldData(pw, gc2,smallFont, plot->max2, plot->sf2);
  }
  if (plot->place3 > -1) {
    XSetLineAttributes(dpy, gc3, 0, LineSolid, CapButt, JoinMiter);
    plot->sf3 = drawAxis(dpy, window, gc3, smallFont, endX+AXISPAD, startY, 
			 endX+AXISPAD, endY, plot->min3, plot->max3, -1);
    XDrawImageString(dpy, window, gc, endX+AXISPAD-5, startY+AXISPAD, 
		     "#3", 2);
    XSetLineAttributes(dpy, gc3, 0, LineOnOffDash, CapButt, JoinMiter);
    XDrawLine(dpy, window, gc3, plot->labelPad, label3pos, 
	      plot->labelPad + SAMPLEPAD, label3pos);
    plot->lastPt3 = drawOldData(pw, gc3,smallFont, plot->max3, plot->sf3);
  }
  XSetBackground(dpy, gc1, plot->plotback);
  XSetBackground(dpy, gc2, plot->plotback);
  XSetBackground(dpy, gc3, plot->plotback);

 /* (superclass->core_class.expose)(w, event, region);*/
} /* END Redisplay() */

/*ARGSUSED*/
static void UpdateCaliper(w, client, event)
     Widget w;
     caddr_t client;/*unused*/
     XEvent *event;
{
  Window window = XtWindow(w);
  PlotWidget pw = (PlotWidget) w;
  PlotPart *plot = &pw->plot;
  GC gc = plotClassRec.plot_class.pointerGC;
  XMotionEvent *mev = (XMotionEvent *) event;
  char buf[132], bufX[40], buf1[40], buf2[40], buf3[40];
  int xPt, yPt;
  Window root_ret, child;
  int rootx, rooty;
  unsigned int mask;
		    
  if (XQueryPointer(dpy, plot->plotwin, &root_ret, &child, &rootx, &rooty,
		    &xPt, &yPt, &mask) == False) return; /* wrong screen */
  if (mev->subwindow == plot->plotwin) {
    if (plot->sfX)
      sprintf(bufX,"X:%-7.3f", xPt/plot->sfX + plot->minX);
    if (plot->place1 > -1  && plot->sf1)
      sprintf(buf1,", Y1:%-7.3f", yPt/plot->sf1 + plot->max1);
    else buf1[0] = (char)0;
    if (plot->place2 > -1 && plot->sf2)
      sprintf(buf2,", Y2:%-7.3f", yPt/plot->sf2 + plot->max2);
    else buf2[0] = (char)0;
    if (plot->place3 > -1 && plot->sf3)
      sprintf(buf3,", Y3:%-7.3f", yPt/plot->sf3 + plot->max3);
    else buf3[0] = (char)0;
    sprintf(buf,"%s%s%s%s", bufX, buf1, buf2, buf3);
    XDrawImageString(dpy, window, gc, plot->xoff, plot->titlePad + 20, 
		     buf, strlen(buf));
  } else
    EraseCaliper(w, client, event);
}

/*ARGSUSED*/
static void WriteCaliper(w, client, event)
     Widget w;
     caddr_t client; /*unused*/
     XEvent *event;
{
  Window window = XtWindow(w);
  PlotWidget pw = (PlotWidget) w;
  PlotPart *plot = &pw->plot;
  GC gc = plotClassRec.plot_class.pointerGC;
  XButtonEvent *bev = (XButtonEvent *) event;
  char buf[132], bufX[40], buf1[40], buf2[40], buf3[40];
  int xPt, yPt;
  Window child;

  if (bev->subwindow == plot->plotwin && 
      XTranslateCoordinates(dpy, window, plot->plotwin, bev->x, bev->y,
			    &xPt, &yPt, &child)) {
    XSetBackground(dpy, plotClassRec.plot_class.pointerGC, plot->plotback);
    if (plot->sfX) 
      sprintf(bufX,"X:%-.3f", xPt/plot->sfX + plot->minX);
    if (plot->place1 > -1 && plot->sf1)
      sprintf(buf1," Y1:%-.3f", yPt/plot->sf1 + plot->max1);
    else buf1[0] = (char)0;
    if (plot->place2 > -1 && plot->sf2)
      sprintf(buf2," Y2:%-.3f", yPt/plot->sf2 + plot->max2);
    else buf2[0] = (char)0;
    if (plot->place3 > -1 && plot->sf3)
      sprintf(buf3," Y3:%-.3f", yPt/plot->sf3 + plot->max3);
    else buf3[0] = (char)0;
    sprintf(buf,"%s%s%s%s", bufX, buf1, buf2, buf3);
    XDrawLine(dpy, plot->plotpix, gc, xPt-10, yPt, xPt+10, yPt);
    XDrawLine(dpy, plot->plotpix, gc, xPt, yPt-10, xPt, yPt+10);
    xPt += 10;
    if (yPt < 15) yPt += 18;
    else yPt -= 10;
    XDrawImageString(dpy, plot->plotpix, gc, xPt, yPt, buf, strlen(buf));
    XSetBackground(dpy, plotClassRec.plot_class.pointerGC, plot->background);
  }
}

/*ARGSUSED*/
static void EraseCaliper(w, client, event)
     Widget w;
     caddr_t client; /*unused*/
     XEvent *event;
{
  Window window = XtWindow(w);
  PlotWidget pw = (PlotWidget) w;
  PlotPart *plot = &pw->plot;
  CorePart *core = &pw->core;

  /* Clear text including descenders, but don't bite into axes. */
  XClearArea(dpy, window, 0, 0, (int)core->width, plot->titlePad+20+5, False);
}

/*ARGSUSED*/
static int drawOldData(pw, gc, font, maxY, sfY)
PlotWidget pw;
GC gc;
XFontStruct *font;
double maxY, sfY;
{
  return(-1);
}

#ifdef MOVINGBALL
/*ARGSUSED*/
static void moveBall(w, x1, y1, x2, y2)
Drawable w;
int x1, y1, x2, y2;
{
  GC invert_gc = plotClassRec.plot_class.pointerGC;
/*||| A travesty! This will slow it down miserably!!!!!!!! ||||||*/
  XFillRectangle(dpy, w, invert_gc, x2-1, y2-1, 3, 3);
  XFlush(dpy);
  XFillRectangle(dpy, w, invert_gc, x2-1, y2-1, 3, 3);
}
#endif
 
/*
 * ModCallback() is the action for the modify axes button.
 */
/*ARGSUSED*/
static void ModCallback(widget, closure, call_data)
Widget widget;
caddr_t closure, call_data;
{
  PlotWidget pw = (PlotWidget) closure;
  PlotPart *plot = &pw->plot;
  Widget menu;
  AxisDataRec adX, ad1, ad2, ad3;

  adX.paperSpeed = plot->paperSpeed;
  adX.place = plot->placeX;
  adX.type = plot->typeX;
  adX.title = plot->labelX;
  adX.min = plot->minX;
  adX.max = plot->maxX;
  adX.units = plot->unitX;
  adX.autoScale = plot->autoX;
  adX.stripMode = plot->stripMode;
  ad1.place = plot->place1;
  ad1.type = plot->type1;
  ad1.title = plot->label1;
  ad1.min = plot->min1;
  ad1.max = plot->max1;
  ad1.units = plot->unit1;
  ad1.autoScale = plot->auto1;
  ad2.place = plot->place2;
  ad2.type = plot->type2;
  ad2.title = plot->label2;
  ad2.min = plot->min2;
  ad2.max = plot->max2;
  ad2.units = plot->unit2;
  ad2.autoScale = plot->auto2;
  ad3.place = plot->place3;
  ad3.type = plot->type3;
  ad3.title = plot->label3;
  ad3.min = plot->min3;
  ad3.max = plot->max3;
  ad3.units = plot->unit3;
  ad3.autoScale = plot->auto3;

  menu = MakePlotMenu((Widget)pw, XtSetValues, 500, 5, 
		      &adX, &ad1, &ad2, &ad3);
#ifdef DEBUG
  printf("Pushed Modify Button ...\n");
#endif
  XtPopup(menu, XtGrabExclusive);
}

/*ARGSUSED*/
static void RefreshCallback(widget, closure, call_data)
Widget widget;
caddr_t closure, call_data;
{
  PlotPart *plot = &((PlotWidget)closure)->plot;
  /* ||| XPixFill plot->plotWin to BlackPixel would give a nice effect */
  XClearWindow(dpy, plot->plotwin); 
      /* Clear here, since we won't do it on Redisplay any more */
  plot->lastPtX = plot->lastPt1 = plot->lastPt2 = plot->lastPt3 = -1;
  Redisplay((Widget)closure, (XEvent *)NULL, (Region)NULL);
}

/*ARGSUSED*/
static Boolean SetValues(prev, request, new_widget)
     Widget prev, request, new_widget;
{
  PlotPart *old = & ((PlotWidget)prev)->plot;
  PlotPart *new  = & ((PlotWidget)new_widget)->plot;
  Arg arg[10];
  int i;

  if (old->place3 != new->place3 || old->type3 != new->type3 ||
      old->place2 != new->place2 || old->type2 != new->type2 ||
      old->place1 != new->place1 || old->type1 != new->type1 ||
      old->placeX != new->placeX || old->typeX != new->typeX) {
    }

  if (new->place1 > -1) {
    char buf[1024];
    if (new->typeX == TIME) 
      sprintf(buf, "#1: %s (%s) v. %s (%g %s)",
	      new->label1, new->unit1, new->labelX, (double)new->paperSpeed, 
	      new->unitX);
    else
      sprintf(buf, "#1: %s (%s) v. %s (%s)",
	      new->label1, new->unit1, new->labelX, new->unitX);
    i=0;
    XtSetArg(arg[i], XtNlabel, buf);i++;
    XtSetValues(new->label1w, arg, i);
    XtManageChild(new->label1w);
  } else {
    new->label1 = NULL;
    XtUnmanageChild(new->label1w);
  }
  
  if (new->place2 > -1) {
    char buf[1024];
    if (new->typeX == TIME) 
      sprintf(buf, "#2: %s (%s) v. %s (%g %s)",
	      new->label2, new->unit2, new->labelX, (double)new->paperSpeed, 
	      new->unitX);
    else
      sprintf(buf, "#2: %s (%s) v. %s (%s)",
	      new->label2, new->unit2, new->labelX, new->unitX);
    i=0;
    XtSetArg(arg[i], XtNlabel, buf);i++;
    XtSetValues(new->label2w, arg, i);
    XtManageChild(new->label2w);
  } else {
    new->label2 =  NULL;
    XtUnmanageChild(new->label2w);
  }

  if (new->place3 > -1) {
    char buf[1024];
    if (new->typeX == TIME) 
      sprintf(buf, "#3: %s (%s) v. %s (%g %s)",
	      new->label3, new->unit3, new->labelX, (double)new->paperSpeed, 
	      new->unitX);
    else
      sprintf(buf, "#3: %s (%s) v. %s (%s)", 
	      new->label3, new->unit3, new->labelX, new->unitX);
    i=0;
    XtSetArg(arg[i], XtNlabel, buf);i++;
    XtSetValues(new->label3w, arg, i);
    XtManageChild(new->label3w);
  } else {
    new->label3 = NULL;
    XtUnmanageChild(new->label3w);
  }
  new->lastPtX = new->lastPt1 = new->lastPt2 = new->lastPt3 = -1;
  new->nextHash = 0;
  if (new->stripMode != old->stripMode) {
    new->slideDots = 1; 
    new->outX = new->out1 = new->out2 = new->out3 = 0;
    new->lastX = new->last1 = new->last2 = new->last3 = 0.;
  }
  return(True); /* always redisplay */
}

/*ARGSUSED*/
static XtGeometryResult GeometryManager(w, request, geometry_return)
     Widget w;
     XtWidgetGeometry *request;
     XtWidgetGeometry *geometry_return;
{
  return(XtGeometryYes); /* always allow subwidgets to resize themselves */
}

/****************************************************************
 *
 * Public Procedures
 *
 ****************************************************************/

/*ARGSUSED*/
void PlotModifySimulation(w, place, type, value)
     Widget w;
     int place, type;
     double value;
{
/* No longer used. */
#ifdef DEBUG
  printf("Setting p:%d, t:%d, v:%lf\n",place,type,value);
#endif
}

/*
 *
 * Plot New Data event handler
 * Could stand to be cleaned up for execution speed!
 */
/*PUBLIC*/ 
void PlotData(w, pressures)
     Widget w;
     double *pressures;
{
  register PlotPart *plot = &((PlotWidget)w)->plot;
  double x, y1 = 0.0, y2 = 0.0, y3 = 0.0;
  register int xPt, yPt;
  double slideInc; /* in seconds */
#ifdef SAVEDATA
  double eraseTime;
#endif
  GC gc1 = plotClassRec.plot_class.gc1,
     gc2 = plotClassRec.plot_class.gc2,
     gc3 = plotClassRec.plot_class.gc3;
  
  if (!plot->plotpix) /* Not yet realized. */
    return;

  if (!UpdatePeriod(pressures, &plot->timing) 
      && ((plot->timing&0x1800) != 0x1800)) {
    if (plot->timing & 0xf0 && !(plot->timing&0x800))
      plot->lastPt1 = plot->lastPt2 = plot->lastPt3 = -1;
    return; /* Only plot interesting parts of the cycle */
  }

  if (plot->timing & 0x0800) {/* Plotting average instead of direct value */
    plot->cntX++; plot->cnt1++; plot->cnt2++; plot->cnt3++;
    if (plot->placeX > -1)
      plot->sumX += getval(pressures, plot->placeX, plot->typeX);
    if (plot->place1 > -1)
      plot->sum1 += getval(pressures, plot->place1, plot->type1);
    if (plot->place2 > -1)
      plot->sum2 += getval(pressures, plot->place2, plot->type2);
    if (plot->place3 > -1)
      plot->sum3 += getval(pressures, plot->place3, plot->type3);
    if (plot->timing & 0x1000) { /* Start of beat, so plot it */
      plot->sumX /= plot->cntX; plot->cntX = 0;
      plot->sum1 /= plot->cnt1; plot->cnt1 = 0;
      plot->sum2 /= plot->cnt2; plot->cnt2 = 0;
      plot->sum3 /= plot->cnt3; plot->cnt3 = 0;
    } else
      return; /* Wait until the start of the next beat. */
  }
  if (plot->typeX != TIME && (plot->timing & 0x0800))
    { x=plot->sumX; plot->sumX=0.0; }
  else
    x=getval(pressures, plot->placeX, plot->typeX);
  
  if (plot->typeX == TIME && plot->currentTime > x) 
    plot->nextHash = plot->currentTime;
  plot->currentTime = getval(pressures, SYSTEM, TIME);

  if (plot->typeX == TIME) {
    if (plot->lastPtX < 0) {
      /* Redefine the X axis */
      plot->maxX = x;
      plot->sfX = plot->paperSpeed * RESOLUTION;
      plot->minX = plot->maxX - plot->plotWidth / plot->sfX;
      Redisplay(w, (XEvent *)NULL, (Region)NULL);
    }
    if (x >= plot->maxX) { /* Off right edge of plot */
      if (plot->stripMode) {
	/* Strip Chart mode: slide image to left by slideDots dots */
	int diff;
	slideInc = plot->slideDots / plot->sfX;
	while ((diff= plot->sfX*(x - plot->minX)
		      - (plot->plotWidth+plot->slideDots)) > 0) {
	  /* make sure x will be visible */
	  plot->slideDots+= diff;
	  slideInc = plot->slideDots / plot->sfX;
	}
	plot->minX += slideInc;
	plot->maxX += slideInc;
	plot->lastPtX -= plot->slideDots;
	
	XCopyArea(dpy, plot->plotpix, plot->plotpix, gc1, plot->slideDots, 
		  0, plot->plotWidth - plot->slideDots, plot->plotHeight, 
		  0, 0);
#ifdef PIXDRAW
	XFillRectangle(dpy, plot->plotpix, whiteGC, 
		       plot->plotWidth - plot->slideDots,
		       0, plot->slideDots, plot->plotHeight /*full height*/);
#else
	XClearArea(dpy,(Window)plot->plotpix, 
		   plot->plotWidth-plot->slideDots, 
		   0, plot->slideDots, 0 /* full height */ , False);
#endif
#ifdef NOTDEF 
	/*|||??? do we need?  Some implementations write new before copying */
	XFlush(dpy);
#endif
      } else /* Not stripMode */ {
	/* Oscilloscope scan mode: restart at beginning of plot */
	slideInc = plot->maxX - plot->minX;
	plot->minX += slideInc;
	plot->maxX += slideInc;
	plot->lastPt1 = plot->lastPt2 = plot->lastPt3 = -1;
      }
    }
  }

#ifdef SAVEDATA
  eraseTime = plot->currentTime - plot->decayTime;
  if (plot->decayTime == 0.0) eraseTime = 0.0; /* never erase */
#endif
  xPt = plot->sfX * (x - plot->minX);

  if (plot->typeX == TIME  && !plot->stripMode) { 
    /* Erase a band of old data just in front of the current data */
    if (plot->lastPtX > xPt) {
#ifdef PIXDRAW
      XFillRectangle(dpy,plot->plotpix, whiteGC, 0, 0, xPt+6, plot->plotHeight);
#else
      XClearArea(dpy, (Window) plot->plotpix, 0, 0, xPt + 6, 0, False);
#endif
      if (plot->lastPtX > 0)
	plot->lastPtX = 0; /* start over from left side of screen */
      else
	plot->lastPtX = xPt; /* but not if we aren't going to be there */
    } else {
      if (xPt != plot->lastPtX) {
#ifdef PIXDRAW
	XFillRectangle(dpy, plot->plotpix, whiteGC, plot->lastPtX+6, 0,
		       plot->slideDots, plot->plotHeight);
#else
	XClearArea(dpy, (Window) plot->plotpix, plot->lastPtX+6, 0, 
		   xPt-plot->lastPtX, 0 /*entire height*/ ,False);
#endif
      }
    }
  }
  if (plot->lastPtX < 0) plot->lastPtX = xPt;

  if (plot->place1 > -1) {
    if (plot->timing&0x0800) 
      { y1 = plot->sum1; plot->sum1 = 0.0; }
    else
      y1 = getval(pressures, plot->place1, plot->type1);
    yPt = plot->sf1 * (y1 - plot->max1);
    if (plot->lastPtX != xPt || plot->lastPt1 != yPt) {
      if (plot->lastPt1 == -1) { plot->lastPt1 = yPt; plot->lastPtX = xPt; }
      XDrawLine(dpy, plot->plotpix, gc1, plot->lastPtX,plot->lastPt1,xPt, yPt);
      plot->lastPt1 = yPt;
#ifdef MOVINGBALL
      moveBall(plot->plotpix, plot->lastPtX, plot->lastPt1, xPt, yPt);
#endif
    }
  }
  if (plot->place2 > -1) {
    if (plot->timing&0x0800) 
      { y2 = plot->sum2; plot->sum2 = 0.0; }
    else
      y2 = getval(pressures, plot->place2, plot->type2);
    yPt = plot->sf2 * (y2 - plot->max2);
    if (plot->lastPtX != xPt || plot->lastPt2 != yPt) {
      if (plot->lastPt2 == -1) { plot->lastPt2 = yPt; plot->lastPtX = xPt; }
      if ( abs(xPt - plot->lastPtX) > abs(yPt - plot->lastPt2))
	plot->phase2 = (plot->phase2 + abs(xPt - plot->lastPtX)) % 4;
      else
	plot->phase2 = (plot->phase2 + abs(yPt - plot->lastPt2)) % 4;
      XSetDashes(dpy, gc2, plot->phase2, Dash2, strlen(Dash2));
      XDrawLine(dpy,plot->plotpix, gc2, plot->lastPtX,plot->lastPt2, xPt, yPt);
      plot->lastPt2 = yPt;
#ifdef MOVINGBALL
      moveBall(plot->plotpix, plot->lastPtX, plot->lastPt2, xPt, yPt);
#endif
    }
  }
  if (plot->place3 > -1) {
    if (plot->timing&0x0800) 
      { y3 = plot->sum3; plot->sum3 = 0.0; }
    else
      y3 = getval(pressures, plot->place3, plot->type3);
    yPt = plot->sf3 * (y3 - plot->max3);
    if (plot->lastPtX != xPt || plot->lastPt3 != yPt) {
      if (plot->lastPt3 == -1) { plot->lastPt3 = yPt; plot->lastPtX = xPt; }
      if ( abs(xPt - plot->lastPtX) > abs(yPt - plot->lastPt3))
	plot->phase3 = (plot->phase3 + abs(xPt - plot->lastPtX)) % 8;
      else
	plot->phase3 = (plot->phase3 + abs(yPt - plot->lastPt3)) % 8;
      XSetDashes(dpy, gc3, plot->phase3, Dash3, strlen(Dash3));
      XDrawLine(dpy,plot->plotpix, gc3, plot->lastPtX,plot->lastPt3, xPt, yPt);
      plot->lastPt3 = yPt;
#ifdef MOVINGBALL
      moveBall(plot->plotpix, plot->lastPtX, plot->lastPt3, xPt, yPt);
#endif
    }
  }
  plot->lastPtX = xPt;

  if (plot->typeX == TIME && plot->nextHash + 0.1 <= x) {
    xPt = plot->sfX*(plot->nextHash - plot->minX);
    yPt = plot->plotHeight;
    XDrawLine(dpy, plot->plotpix, plotClassRec.plot_class.pointerGC, 
	      xPt, yPt, xPt, yPt-3);
    plot->nextHash += 1;
  }

  if (plot->autoX) {
    switch (plot->outX) {
    case 0: 
      if (x > plot->maxX) plot->outX = 1;
      else if (x < plot->minX) plot->outX = -1;
      break;
    case -1: 
      if (plot->lastX < y1) {
	plot->minX = plot->lastX - (plot->maxX-plot->lastX) * .1; 
	plot->outX = 0;
	Redisplay(w, (XEvent *)NULL, (Region)NULL);
      }
      break;
    case 1:  
      if (plot->lastX > y1) {
	plot->maxX = plot->lastX + (plot->lastX-plot->minX) * .1; 
	plot->outX = 0;
	Redisplay(w, (XEvent *)NULL, (Region)NULL);
      }
      break;
    } 
    plot->lastX = x;
  }

  /*
   * Check for need to automatically rescale
   */
  if (plot->auto1) {
    switch (plot->out1) {
    case 0:
      if (y1 > plot->max1) plot->out1 = 1; 
      else if (y1 < plot->min1) plot->out1 = -1;
      break;
    case -1: 
      if (plot->last1 < y1) {
	plot->min1 = plot->last1 - (plot->max1-plot->last1) * .1; 
	plot->out1 = 0;
	Redisplay(w, (XEvent *)NULL, (Region)NULL);
      }
   break;
    case 1:  
      if (plot->last1 > y1) {
	plot->max1 = plot->last1 + (plot->last1-plot->min1) * .1; 
	plot->out1 = 0;
	Redisplay(w, (XEvent *)NULL, (Region)NULL);
      }
      break;
    } 
    plot->last1 = y1;
  }

  if (plot->auto2) {
    switch (plot->out2) {
    case 0:
      if (y2 > plot->max2) plot->out2 = 1;
      else if (y2 < plot->min2) plot->out2 = -1;
      break;
    case -1: 
      if (plot->last2 < y2) {
	plot->min2 = plot->last2 - (plot->max2-plot->last2) * .1; 
	plot->out2 = 0;
	Redisplay(w, (XEvent *)NULL, (Region)NULL);
      }
      break;
    case 1:  
      if (plot->last2 > y2) {
	plot->max2 = plot->last2 + (plot->last2-plot->min2) * .1; 
	plot->out2 = 0;
	Redisplay(w, (XEvent *)NULL, (Region)NULL);
      }
      break;
    }
    plot->last2 = y2;
  }

  if (plot->auto3) {
    switch (plot->out3) {
    case 0:
      if (y3 > plot->max3) plot->out3 = 1;
      else if (y3 < plot->min3) plot->out3 = -1;
      break;
    case -1: 
      if (plot->last3 < y3) {
	plot->min3 = plot->last3 - (plot->max3-plot->last3) * .1; 
	plot->out3 = 0;
	Redisplay(w, (XEvent *)NULL, (Region)NULL);
      }
      break;
    case 1:  
      if (plot->last3 > y3) {
	plot->max3 = plot->last3 + (plot->last3-plot->min3) * .1; 
	plot->out3 = 0;
	Redisplay(w, (XEvent *)NULL, (Region)NULL);
      }
      break;
    }
    plot->last3 = y3;
  }
#ifdef PIXDRAW
  XClearWindow(dpy, plot->plotwin); 
#endif
} /* END of PlotData() */

