static char RCSid[] = "$Id: LinePlot.c,v 1.0 91/08/22 15:33:40 gnb Exp $"; 
/*
 * $Source: /export/data/sources/x/At/Plotter/RCS/LinePlot.c,v $
 * 
 * $Log:	LinePlot.c,v $
 * Revision 1.0  91/08/22  15:33:40  gnb
 * Initial revision
 * 
 * 
 */

/*

Copyright 1991 by Burdett, Buckeridge & Young Ltd.

All rights reserved.

Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Burdett, Buckeridge &
Young Ltd. (BBY) not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.

BBY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
BBY BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.

*/
/*
 * The line plot widget.  Sort of like the xy plot, but has implicit x
 * axis running from start -> (start + num_points - 1).
 */

#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>

#include <math.h>

#ifdef _AtDevelopment_
#include "LinePlotP.h"
#else
#include <At/LinePlotP.h>
#endif

/*
 * Forward declare all the private widgetclass routines
 */
static void LinePlotDraw P((AtPlotWidget, Display *, Window, Region, int));
static void LinePlotDrawIcon P((AtPlotWidget, Display *, Window, 
				int, int, int, int, Region));
static void LinePlotDrawPS P((AtPlotWidget, FILE *, AtScale *, AtScale *));
static void LinePlotDrawIconPS P((AtPlotWidget, FILE *, int, int, int, int));
static void LinePlotRecalc P((AtPlotWidget, AtScale *, AtScale *, 
			      int from, int to));

static void  LinePlotAttach P((AtSPlotWidget, BoundingBox *, int));


AtLinePlotClassRec atLinePlotClassRec = {
  { /* core fields */
    /* superclass		*/	(WidgetClass) &atSPlotClassRec,
    /* class_name		*/	"AtLinePlot",
    /* widget_size		*/	sizeof(AtLinePlotRec),
    /* class_initialize		*/	NULL,
    /* class_part_initialize	*/	NULL,
    /* class_inited		*/	FALSE,
    /* initialize		*/	NULL,
    /* initialize_hook		*/	NULL,
    /* pad			*/	NULL,
    /* pad			*/	NULL,
    /* pad			*/	0,
    /* resources		*/	NULL,
    /* num_resources		*/	0,
    /* xrm_class		*/	NULLQUARK,
    /* pad			*/	FALSE,
    /* pad			*/	FALSE,
    /* pad			*/	FALSE,
    /* pad			*/	FALSE,
    /* destroy			*/	NULL,
    /* pad			*/	NULL,
    /* pad			*/	NULL,
    /* set_values		*/	NULL,
    /* set_values_hook		*/	NULL,
    /* pad			*/	NULL,
    /* get_values_hook		*/	NULL,
    /* pad			*/	NULL,
    /* version			*/	XtVersion,
    /* callback_private		*/	NULL,
    /* pad			*/	NULL,
    /* pad			*/	NULL,
    /* pad			*/	NULL,
    /* pad			*/	NULL
  },
  { /* atPlot fields */
    /* draw			*/	LinePlotDraw,
    /* draw_icon		*/	LinePlotDrawIcon,
    /* drawPS			*/	LinePlotDrawPS,
    /* draw_iconPS		*/	LinePlotDrawIconPS,
    /* recalc			*/	LinePlotRecalc
  },
  { /* atSPlot fields */
    /* attach_data		*/	LinePlotAttach,
  },
  { /* atLinePlot fields */
    /* empty			*/	0
  }
};

WidgetClass atLinePlotWidgetClass = (WidgetClass)&atLinePlotClassRec;

/*****************************************************************
 *
 * These routines are the ones called by the parent plot widget
 */
#define lp ((AtLinePlotWidget)self)
#define PIX ((XPoint *)lp->splot.pix)
/* NB: PIX is NOT an lvalue (on some very picky compilers!!!) */

/*
 * Don't need to adjust the bbox, only to allocate the memory.
 */
static void LinePlotAttach(self, bbp, extending)
AtSPlotWidget self;
BoundingBox *bbp;
int extending;
{
     if (extending)
	  lp->splot.pix = XtRealloc((char *)PIX, 
				    lp->splot.num_points * sizeof (XPoint));  
     else
	  lp->splot.pix = XtMalloc(lp->splot.num_points * sizeof (XPoint)); 
}

/*
 * Draw the line clipped by the given region.
 */
static void LinePlotDraw(self, dpy, win, region, refresh)
AtPlotWidget self;
Display *dpy;
Window win;
Region region;
int refresh; 
{
#ifdef TRACE
     fprintf(stderr, "LinePlotDraw %d segments\n",
	     lp->splot.num_points);
#endif 
     if (lp->splot.old_pix) {
	  if (lp->plot.fast_update && refresh) {
	       /* 
		* We are in fast update mode, doing a refresh and have old
		* pixpoints, so draw them to "erase" the old s first
		*/
	       XDrawLines(dpy, win, lp->plot.gc, (XPoint *)lp->splot.old_pix,
			  lp->splot.old_num_points, CoordModeOrigin);
	  }
	  XtFree((char *)lp->splot.old_pix);
	  lp->splot.old_pix = NULL;
	  lp->splot.old_num_points = 0;
     }
     
     if (region) XSetRegion(dpy, lp->plot.gc, region);
     XDrawLines(dpy, win, lp->plot.gc, PIX,
		lp->splot.num_points, CoordModeOrigin);
     if (region) XSetClipMask(dpy, lp->plot.gc, None);
}

/*
 * draw the "icon" in the given place.
 */
static void LinePlotDrawIcon(self, dpy, win, x1, y1, width, height, region)
AtPlotWidget self;
Display *dpy;
Window win;
int x1, y1, width, height;
Region region;
{
     y1 += height >> 1;
     XDrawLine(dpy, win, lp->plot.gc, x1, y1, x1 + width, y1);
}

/*
 * postscript stuff
 */
static void LinePlotDrawPS(self, fp, xs, ys)
AtPlotWidget self;
FILE *fp;
AtScale *xs, *ys; 
{
     int i = 0, count = 0;
     
     fprintf(fp, "%%BeginObject: AtLinePlot\nGS\n");
     AtPlotPSLineStyle(fp, self);
     
     for (i = 1; i < lp->splot.num_points; i++) {
	  if (!count) {
	       fprintf(fp, "%d %d M ", 
		       AtScaleUserToPixel(xs, (double)(i+lp->splot.start-1)), 
		       AtScaleUserToPixel(ys, AtSPlotGetValue((AtSPlotWidget)lp, 
							      i - 1)));
	  }
	  fprintf(fp, "%d %d L\n", 
		  AtScaleUserToPixel(xs, (double)(i + lp->splot.start)),
		  AtScaleUserToPixel(ys, AtSPlotGetValue((AtSPlotWidget)lp, i)));
	  if (++count > 50) {
	       fprintf(fp, "ST\n");
	       count = 0;
	  }
     }
     fprintf(fp, "%sGR\n%% EndObject\n", count ? "ST\n" : "");
     fp = (FILE *)RCSid;	/* Keep gcc quiet */
}


static void LinePlotDrawIconPS(self, fp, x1, y1, width, height)
AtPlotWidget self;
FILE *fp;
int x1, y1, width, height;
{
     fprintf(fp, "GS "); 
     AtPlotPSLineStyle(fp, self);
     fprintf(fp, "%d %d M %d 0 rlineto ST GR\n", x1,
	     y1 - (height >> 1), width);
}


/*
 * Recalc the data according to the passed x and y scales
 */
static void LinePlotRecalc(self, xs, ys, from, to)
AtPlotWidget self;
AtScale *xs, *ys; 
int from, to;
{
     int i;

#ifdef TRACE
     fprintf(stderr, " -- LinePlotRecalc from %d to %d\n", from, to);
#endif 
     if (from > to) {
	  from = 0;
	  to = lp->splot.num_points - 1;
     }
     for (i = from; i <= to; i++) {
	  PIX[i].x = AtScaleUserToPixel(xs, (double)(i + lp->splot.start));
	  PIX[i].y = 
	       AtScaleUserToPixel(ys, AtSPlotGetValue((AtSPlotWidget)lp, i));
     }
}
#undef lp
