/* $Header: /mit/atdev/src/plotter/RCS/Barchart.c,v 3.11 1996/09/11 18:32:15 dot Exp $ */

/*******************************************************************
  Copyright (C) 1990 by the Massachusetts Institute of Technology

   Export of this software from the United States of America is assumed
   to require a specific license from the United States Government.
   It is the responsibility of any person or organization contemplating
   export to obtain such a license before exporting.

WITHIN THAT CONSTRAINT, 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 M.I.T. not be used in advertising or publicity pertaining
to distribution of the software without specific, written prior
permission.  M.I.T. makes no representations about the suitability of
this software for any purpose.  It is provided "as is" without express
or implied warranty.

***************************************************************** */


#include <stdio.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>

#ifdef _AtDevelopment_
#include "Scale.h"
#include "AtConverters.h"
#include "AtBitmaps.h"
#include "BarchartP.h"
#else
#include <At/Scale.h>
#include <At/AtConverters.h>
#include <At/AtBitmaps.h>
#include <At/BarchartP.h>
#endif

#ifdef SYSV
#define bcopy(s1, s2, l) memcpy (s2, s1, l)
#endif /* SYSV */

typedef struct {
  char *data;
  unsigned int width, height;
} BitmapInfo;

static BitmapInfo bitmaps[] = {
  { gray0_bits, gray0_width, gray0_height },
  { gray1_bits, gray1_width, gray1_height },
  { gray2_bits, gray2_width, gray2_height },
  { gray3_bits, gray3_width, gray3_height },
  { gray4_bits, gray4_width, gray4_height },
  { gray5_bits, gray5_width, gray5_height },
};

extern Pixmap XmGetPixmap();

#define offset(field) XtOffset(AtBarchartWidget, field)

static XtResource resources[] = {
  {XtNxMin, XtCXMin, XtRDouble,
     sizeof(double), offset(barchart.xMin),
     XtRString, "0.0"},
  {XtNxMax, XtCXMax, XtRDouble,
     sizeof(double), offset(barchart.xMax),
     XtRString, "1.0"},
  {XtNyPoints, XtCYPoints, XtRDoubleArray,
     sizeof(double *), offset(barchart.yPoints),
     XtRImmediate, NULL},
  {XtNnumPoints, XtCNumPoints, XtRInt,
     sizeof(int), offset(barchart.numPoints),
     XtRImmediate, (caddr_t)0},
  {XtNdensity, XtCDensity, XtRDouble,
     sizeof(double), offset(barchart.density),
     XtRString, "1.0"},
  {XtNposition, XtCPosition, XtRInt,
     sizeof(int), offset(barchart.position),
     XtRImmediate, (caddr_t)0},
  {XtNshading, XtCShading, XtRBoolean,
     sizeof(Boolean), offset(barchart.shading),
     XtRImmediate, (caddr_t) False},
  {XtNpattern, XtCPattern, XtRPattern,
     sizeof(int), offset(barchart.pattern),
     XtRImmediate, (caddr_t) AtGRAY0}
};
#undef offset

static void ClassPartInitialize(WidgetClass);
static void Initialize(AtBarchartWidget, AtBarchartWidget);
static void Destroy(AtBarchartWidget);
static Boolean SetValues(AtBarchartWidget, AtBarchartWidget, 
			 AtBarchartWidget);
static void Draw(Display *, Window, AtPlotWidget, AtScale *, AtScale *,
		 Region);
static void Recompute(AtPlotWidget, AtScale *, AtScale *);
static void DrawIcon(Display *, Window, AtPlotWidget, int, int, int, int);
static void DrawPS(FILE *, AtPlotWidget, AtScale * , AtScale *);
static void DrawIconPS(FILE *, AtPlotWidget, int, int, int, int);
static void GetBoundingBox(AtBarchartWidget, BoundingBox *);

static void BuildRects(AtPlotWidget, AtScale *, AtScale *, Region,
		XRectangle **, int *);
static void Redraw(Display *, Window, AtPlotWidget, XRectangle *);
static void DrawInc(Display *, Window, AtPlotWidget, AtScale *, AtScale *, Region);

AtBarchartClassRec atBarchartClassRec = {
{ /* core part */
    /* superclass         */    (WidgetClass)&atPlotClassRec,
    /* class_name         */    "AtBarchart",
    /* widget_size        */    sizeof(AtBarchartRec),
    /* class_initialize   */    NULL,
    /* class_part_initialize*/  ClassPartInitialize,
    /* class_inited       */    FALSE,
    /* initialize         */    (XtInitProc) Initialize,
    /* initialize_hook    */    NULL,
    /* pad                */    NULL,
    /* pad                */    NULL,
    /* pad                */    0,
    /* resources          */    resources,
    /* num_resources      */    XtNumber(resources),
    /* xrm_class          */    NULLQUARK,
    /* pad                */    FALSE,
    /* pad                */    FALSE,
    /* pad                */    FALSE,
    /* pad                */    FALSE,
    /* destroy            */    (XtWidgetProc)Destroy,
    /* pad                */    NULL,
    /* pad                */    NULL,
    /* set_values         */    (XtSetValuesFunc) SetValues,
    /* set_values_hook    */    NULL,
    /* pad                */    NULL,
    /* get_values_hook    */    NULL,
    /* pad                */    NULL,
    /* version            */    XtVersion,
    /* callback_offsets   */    NULL,
    /* pad                */    NULL,
    /* pad                */    NULL,
    /* pad                */    NULL,
    /* extension            */  NULL
},
  /* AtPlotClassPart initialization */
{
  /* draw()       */   Draw,
  /* drawIcon()   */   DrawIcon,
  /* resize()     */   Recompute,
  /* rescale()    */   Recompute,
  /* drawPS()     */   DrawPS,
  /* drawIconPS() */   DrawIconPS,
  /* checkhit()   */   NULL,
},
{
  /* AtBarchartClassPart initialization */
  /* getrects()   */   BuildRects,
  /* redraw()     */   Redraw,
  /* drawinc()    */   DrawInc,
},
};

WidgetClass atBarchartWidgetClass = (WidgetClass) &atBarchartClassRec;

#define AtWarning(w,msg) XtWarning(msg)

/**********************************************************************/
/* get a gc for drawing and filling the bars. */

static void get_fillGc (AtBarchartWidget bcw, int pattern) 
{     
  Display *dpy;
  Widget pw;
  XGCValues values;
  XtGCMask valuemask;
  Pixmap tile;

  pw = XtParent((Widget) bcw);
  dpy = XtDisplay(pw);
  if (bcw->barchart.shading) {
    tile = XCreatePixmapFromBitmapData(dpy, DefaultRootWindow(dpy),
				       bitmaps[pattern].data, 
				       bitmaps[pattern].width,
				       bitmaps[pattern].height,
				       bcw->plot.foreground,
				       bcw->plot.background, 
				       DefaultDepthOfScreen(XtScreen(pw)));
    values.tile = tile;
    values.fill_style = FillTiled;
    valuemask = GCFillStyle | GCTile ;
  }
  else {
    values.foreground = bcw->plot.foreground;
    values.fill_style = FillSolid;
    valuemask = GCFillStyle | GCForeground;
  }

  bcw->barchart.fillGc = XtGetGC(XtParent((Widget)bcw), valuemask, &values);
}


/**********************************************************************/

static void ClassPartInitialize(WidgetClass class)
{
  AtBarchartWidgetClass bc, super;

  bc = (AtBarchartWidgetClass) class;
  super = (AtBarchartWidgetClass) bc->object_class.superclass;
  AtRegisterPatternConverter();

#define CheckInherit(proc) \
  if ((XtProc)bc->barchart_class.proc == _XtInherit)\
    bc->barchart_class.proc = super->barchart_class.proc

  CheckInherit(getrects);
  CheckInherit(redraw);
  CheckInherit(drawinc);

#undef CheckInherit
}

/**********************************************************************/

#define NEW new->barchart

static void Initialize(AtBarchartWidget request, AtBarchartWidget new)
{
  double tempx;
  int i;
  Arg a[2];
  Cardinal count;
  BoundingBox b;
  
  if (NEW.numPoints < 0) {
    AtWarning(new, "AtBarchart: numPoints cannot be < 0.");
    NEW.numPoints = 0;
  }

  if ((NEW.numPoints == 0) && (NEW.yPoints != NULL)) {
    AtWarning(new, "AtBarchart: numPoints is zero, but some points were specified.");
  }

  /*
    if ((NEW.numPoints != 0 ) && (NEW.yPoints == NULL)) {
      AtWarning(new, "AtBarchart: numPoints non-zero, but no points specified.");
      NEW.numPoints = 0;
      NEW.yPoints = NULL;
    }
  */

  if (NEW.density < 0.0) {
    AtWarning(new, "AtBarchart: density can not be less than zero.");
    NEW.density = 0.0;
  }
  if (NEW.density > 1.0) {
    AtWarning(new, "AtBarchart: density can not be greater than one.");
    NEW.density = 1.0;
  }
    
  NEW.halfdensity = NEW.density / 2;

  if (NEW.shading) {
    if(NEW.pattern < 0 || NEW.pattern > XtNumber(bitmaps)) {
      AtWarning(new, "AtBarchart: Wrong pattern specified. No shading will be done");
      NEW.shading = False;
    }
  }

  get_fillGc (new, NEW.pattern);

  /* make a private copy of the data points
   * this works even if numPoints == 0.
   * we want an allocated piece of memory even if numPoints == 0
   * so that realloc is guaranteed to work on it.
   */

  NEW.pixpts = (XPoint *) XtCalloc(NEW.numPoints, sizeof(XPoint));
  NEW.oldpixpts = (XPoint *) XtCalloc(NEW.numPoints, sizeof(XPoint));

  NEW.xpts = (double *)XtMalloc(sizeof(double) * NEW.numPoints);

  /* the following if statement is necessary, because FBarcharts initialy
     have numPoints of zero. They have their numPoints set in set values
     and have their xIncrement calculated there.
     */

  if (NEW.numPoints > 0) 
    NEW.xIncrement = ((NEW.xMax - NEW.xMin)) / (NEW.numPoints - 1);

  for (i=0, tempx=NEW.xMin - NEW.halfdensity * NEW.xIncrement; 
       i < NEW.numPoints;
       i++, tempx += NEW.xIncrement)
    NEW.xpts[i] = tempx;

  NEW.ypts = (double *) XtMalloc(sizeof(double) * NEW.numPoints);
  
  bcopy((char *)NEW.yPoints, (char *)NEW.ypts, 
	sizeof(double) * NEW.numPoints);
  NEW.valid = False;
  NEW.refreshBars = False;
  NEW.yPoints = NULL;
  /* yPoints is used ONLY for getting new coordinates from the outside
   * world (as in now) at all other times it should be NULL */
  /* figure out our bounding box */
 
  GetBoundingBox(new, &b);
  count = 0;
  XtSetArg(a[count], XtNboundingBox, &b); count++;
  XtSetValues(new, a, count);        /* set a constraint resource */
}

/**********************************************************************/

static Boolean SetValues(AtBarchartWidget current,
                         AtBarchartWidget request,
                         AtBarchartWidget new)
{
  int i;
  double tempx;
  Arg a[2];
  Cardinal count;
  Boolean autoS;
  BoundingBox b;

#define Changed(field) (new->barchart.field != current->barchart.field)

  count = 0;
  XtSetArg(a[count], XtNboundingBox, &b); count++;
  XtGetValues((Widget) new, a, count);

  count = 0;
  XtSetArg(a[count], XtNautoScale, &autoS); count++;
  XtGetValues(XtParent((Widget) new), a, count);

  if (Changed(density)) {
    if (NEW.density < 0.0) {
      AtWarning(new, "AtBarchart: density can not be less than zero.");
      NEW.density = 0.0;
    }
    if (NEW.density > 1.0) {
      AtWarning(new, "AtBarchart: density can not be greater than one.");
      NEW.density = 1.0;
    }
    NEW.halfdensity = NEW.density / 2;
  }

  if (Changed(numPoints)) {
    XtFree(NEW.xpts);
    XtFree(NEW.ypts);
    XtFree(NEW.pixpts);
    XtFree(NEW.oldpixpts);
    NEW.pixpts = (XPoint *) XtCalloc(NEW.numPoints, sizeof(XPoint));
    NEW.oldpixpts = (XPoint *) XtCalloc(NEW.numPoints, sizeof(XPoint));
    NEW.xpts = (double *)XtMalloc(sizeof(double) * NEW.numPoints);
    NEW.ypts = (double *)XtMalloc(sizeof(double) * NEW.numPoints);

    if (NEW.numPoints > 0) 
      NEW.xIncrement = ((NEW.xMax - NEW.xMin) + 1) / (NEW.numPoints - 1);
    else
      AtWarning(new, "AtBarchart: numPoints must be greater than zero");

    bcopy((char *)NEW.yPoints, (char *)NEW.ypts,
          sizeof(double) * NEW.numPoints);
  }


  if (Changed(numPoints) || Changed(density) ||	Changed(xMin) ||
      Changed(xMax)) {
    if (NEW.numPoints > 0) 
      NEW.xIncrement = (NEW.xMax - NEW.xMin) / (NEW.numPoints - 1);
    for (i=0, tempx=NEW.xMin - NEW.halfdensity * NEW.xIncrement; 
         i < NEW.numPoints;
         i++, tempx += NEW.xIncrement)
      NEW.xpts[i] = tempx;
    NEW.valid = False;
    GetBoundingBox(new, &b);
    new->plot.redisplay = True; /* refresh all plots. NOTE, we may
				   want to change this later to 
				   refresh only this plot if no autoS.
				   should be done for XYPlot. DrawInc
				   should be changed for the barchart */
  }
  
  /*  check if yPoints changed  */
  /* yPoints is used ONLY for getting new coordinates from the outside
   * world (as in now) at all other times it should be NULL */


  if (NEW.yPoints) {
    bcopy(NEW.yPoints, NEW.ypts,
	  sizeof(double) * NEW.numPoints);

    NEW.valid = False;
    if (autoS) {       /* refresh everything */
      GetBoundingBox(new, &b);
      new->plot.redisplay = True;
    }
    else
      NEW.refreshBars = True; /* refresh only this plot */
    NEW.yPoints = NULL;
  }
  
  if (Changed(shading) || Changed(pattern) ||
      (current->plot.foreground != new->plot.foreground) ||
      (current->plot.background != new->plot.background)) {
    /*  XmDestroyPixmap (XtScreen(XtParent((Widget)new)), NEW.tile); */
    XtReleaseGC (XtParent((Widget)new), new->barchart.fillGc);
    get_fillGc (new, NEW.pattern);
    new->plot.redisplay = True; /* refresh all plots.
				   WILL change it later to refresh
				   only this plot */
  }

    /*
     * if the plot needs a redisplay, and if the plot is not a subclass
     * of Barchart, ask to be redisplayed.  If the plot is a subclass,
     * then the subclass will handle redisplay.
     */

  if ((new->plot.redisplay) && /* redisplay all plots */ 
      (new->object.widget_class == atBarchartWidgetClass)) {

    new->plot.redisplay = False;
    count = 0;
    XtSetArg(a[count], XtNneedsRedraw, True); count++;
    XtSetArg(a[count], XtNboundingBox, &b); count++;
    XtSetValues(new, a, count);
  }
  else if ((NEW.refreshBars) && 
	   (new->object.widget_class == atBarchartWidgetClass)) {
    NEW.refreshBars = False;
    count = 0;
    XtSetArg(a[count], XtNneedsRefresh, True); count++;
    XtSetArg(a[count], XtNboundingBox, &b); count++;
    XtSetValues(new, a, count);
  }

  return False;
#undef Changed
#undef NEW
}

/**********************************************************************/

#define W w->barchart

static void GetBoundingBox(AtBarchartWidget w, BoundingBox *b) {
    double xmin, ymin, xmax, ymax;
    int i;
    if (W.numPoints == 0) {
        xmin = ymin = xmax = ymax = 0.0;
    }
    else {
        xmin = W.xpts[0];
	xmax = W.xpts[W.numPoints - 1] + W.density * W.xIncrement;

        ymin = ymax = W.ypts[0];
        for(i=1; i < W.numPoints; i++) {
            if (W.ypts[i] < ymin)
                ymin = W.ypts[i];
            if (W.ypts[i] > ymax)
                ymax = W.ypts[i];
        }
    }

    b->xmin = xmin;
    b->ymin = ymin;
    b->xmax = xmax;
    b->ymax = ymax;
}

/**********************************************************************/

static void Destroy(AtBarchartWidget w)
{
    XtFree(W.xpts);
    XtFree(W.ypts);
    XtFree(W.pixpts);
    XtFree(W.oldpixpts);
    XtReleaseGC(XtParent((Widget)w), W.fillGc);
}

#undef W

/**********************************************************************/

static void Recompute(AtPlotWidget plot, AtScale *xscale, AtScale *yscale)
{
  AtBarchartWidget p = (AtBarchartWidget) plot;
  int i;
  double xmin, ymin;

  
  for(i=0; i < p->barchart.numPoints; i++){
    p->barchart.oldpixpts[i].x = p->barchart.pixpts[i].x;
    p->barchart.pixpts[i].x = AtScaleUserToPixel(xscale, p->barchart.xpts[i]);
    p->barchart.oldpixpts[i].y = p->barchart.pixpts[i].y;
    p->barchart.pixpts[i].y = AtScaleUserToPixel(yscale, p->barchart.ypts[i]);
  }
  
  xmin = AtScaleGetLow(xscale);
  ymin = AtScaleGetLow(yscale);
  p->barchart.zeroxpt = AtScaleUserToPixel(xscale, xmin);
  p->barchart.zeroypt = AtScaleUserToPixel(yscale, ymin);
  
  p->barchart.valid = True;
}

/**********************************************************************/

#define BCW p->barchart

static void Draw(Display *dpy, Window win, AtPlotWidget plot,
                 AtScale *xscale, AtScale *yscale, Region region)
{
  AtBarchartWidget p = (AtBarchartWidget) plot;
  int i;
  GC local_gc1, local_gc2;
  XRectangle clip_rect;
  int barwidth;
  unsigned long valueMask;

  if (BCW.valid == False) Recompute(plot, xscale, yscale);

  /* set the clipping region */
  local_gc1 = XCreateGC (dpy, win, 0, NULL);
  local_gc2 = XCreateGC (dpy, win, 0, NULL);
  
  valueMask = GCClipXOrigin | GCClipYOrigin | GCClipMask |
    GCFunction | GCForeground | GCBackground, GCTile | GCPlaneMask |
      GCFillStyle | GCSubwindowMode | GCStipple | GCTileStipXOrigin |
	GCTileStipYOrigin;
  XCopyGC (dpy, p->plot.gc, valueMask, local_gc1);
  XCopyGC (dpy, BCW.fillGc, valueMask, local_gc2);

  if (region == NULL)  {
    clip_rect.x = AtScaleGetLowPix(xscale);
    clip_rect.y = AtScaleGetHighPix(yscale);
    clip_rect.width = AtScaleGetHighPix(xscale) - clip_rect.x;
    clip_rect.height = AtScaleGetLowPix(yscale) - clip_rect.y;

    XSetClipRectangles(dpy, local_gc1, 0,0,&clip_rect, 1, Unsorted);
    XSetClipRectangles(dpy, local_gc2,0,0,&clip_rect, 1, Unsorted);
  }
  else  {
    XSetRegion(dpy, local_gc1, region);
    XSetRegion(dpy, local_gc2, region);
  }

  barwidth = (BCW.pixpts[1].x - BCW.pixpts[0].x) * BCW.density;

  for (i=0; i<BCW.numPoints; i++) {
    XFillRectangle(dpy, win, local_gc2, BCW.pixpts[i].x, BCW.pixpts[i].y,
		   barwidth, BCW.zeroypt-BCW.pixpts[i].y);
  }
  XFreeGC (dpy, local_gc1);
  XFreeGC (dpy, local_gc2);

}

/**********************************************************************/

static void DrawPS(FILE *f, AtPlotWidget plot, AtScale *xs, AtScale *ys)

{
  AtBarchartWidget p = (AtBarchartWidget) plot;
  double *xpts = (double *) XtMalloc(p->barchart.numPoints * sizeof(double));
  double *ypts = (double *) XtMalloc(p->barchart.numPoints * sizeof(double));
  double baseline, pattern;
  double barwidth, ymin;
  int i;

  /* adjust scales so I get greater accuracy */
  AtScaleResize(xs, AtScaleGetLowPix(xs)*100, AtScaleGetHighPix(xs)*100);
  AtScaleResize(ys, AtScaleGetLowPix(ys)*100, AtScaleGetHighPix(ys)*100);

  /* compute points */
  for(i=0; i < p->barchart.numPoints; i++) {
    xpts[i] = AtScaleUserToPixel(xs, p->barchart.xpts[i])/100.0;
    ypts[i] = AtScaleUserToPixel(ys, p->barchart.ypts[i])/100.0;
  }
  barwidth = (xpts[1] - xpts[0]) * BCW.density;

  if (BCW.shading)
    pattern = 1.0 - ((p->barchart.pattern + 1.0) / 
		     ((double) XtNumber(bitmaps) + 1));
  else
    pattern = 0.0;

  fprintf(f, "%%%% BeginObject: AtBarchart\ngsave\n");

  fprintf(f, "%d setlinewidth\n",
          (p->plot.lineWidth==0)?1:p->plot.lineWidth);
  ymin = AtScaleGetLow(ys);
  baseline = AtScaleUserToPixel(ys, ymin) / 100.0;

  for (i=0; i<BCW.numPoints; i++) {
    fprintf(f, "%g %g M\n", xpts[i], ypts[i]);
    fprintf(f, "%g %g RL\n", barwidth, 0.0);
    fprintf(f, "%g %g RL\n", 0.0, baseline - ypts[i]);
    fprintf(f, "%g %g RL\n", -barwidth, 0.0);
    fprintf(f, "closepath\n");
    fprintf(f, "%g setgray\n", pattern);
    fprintf(f, "fill\n");
  }
  fprintf(f, "grestore\n%%%% EndObject\n");
  XtFree(xpts);
  XtFree(ypts);

  /* adjust scales back to original value */
  AtScaleResize(xs, AtScaleGetLowPix(xs)/100, AtScaleGetHighPix(xs)/100);
  AtScaleResize(ys, AtScaleGetLowPix(ys)/100, AtScaleGetHighPix(ys)/100);
}

/**********************************************************************/

static void DrawIcon(Display *dpy, Window win, AtPlotWidget pw, int x,
                     int y, int width, int height)

{
  AtBarchartWidget p = (AtBarchartWidget) pw;

  XFillRectangle(dpy, win, p->barchart.fillGc, x, y, width, height);
}

/**********************************************************************/

static void DrawIconPS(FILE *f, AtPlotWidget pw, int x, int y,
		       int width, int height)

{
  AtBarchartWidget p = (AtBarchartWidget) pw;
  double  pattern;

  if (BCW.shading)
    pattern = 1.0 - ((p->barchart.pattern + 1.0) / 
		     ((double) XtNumber(bitmaps) + 1));
  else
    pattern = 0.0;

  fprintf(f, "%%%% BeginObject: AtBarchart\ngsave\n");

  fprintf(f, "%g %g M\n", (double)x, (double)y);
  fprintf(f, "%g %g RL\n", (double)width, 0.0);
  fprintf(f, "%g %g RL\n", 0.0, (double)-height);
  fprintf(f, "%g %g RL\n", (double)-width, 0.0);
  fprintf(f, "closepath\n");
  fprintf(f, "%g setgray\n", pattern);
  fprintf(f, "fill\n");

  fprintf(f, "grestore\n%%%% EndObject\n");
}

/**********************************************************************/
/**********************************************************************/

#define BCW p->barchart

/**********************************************************************/

static void Redraw(Display *dpy, Window win, AtPlotWidget plot, 
		   XRectangle *cliprect)
{
  AtBarchartWidget p = (AtBarchartWidget) plot;
  int i;
  int barwidth;
  int clipx, clipy;
  Pixmap clip_mask;
  XGCValues values;
  unsigned long valueMask;

  valueMask = GCClipXOrigin | GCClipYOrigin | GCClipMask;
  XGetGCValues (dpy, BCW.fillGc, valueMask, &values);
  clipx = values.clip_x_origin;
  clipy = values.clip_y_origin;
  clip_mask = values.clip_mask;

  barwidth = (BCW.pixpts[1].x - BCW.pixpts[0].x) * BCW.density;
  
  XSetClipRectangles(dpy, BCW.fillGc, 0, 0, cliprect, 1, Unsorted);
  for (i = 0; i < BCW.numPoints; i++)
    XFillRectangle(dpy, win, BCW.fillGc, BCW.pixpts[i].x, BCW.pixpts[i].y,
		   barwidth, BCW.zeroypt-BCW.pixpts[i].y);

  XSetClipOrigin(dpy, BCW.fillGc, clipx, clipy);
  XSetClipMask(dpy, BCW.fillGc, clip_mask);
}

/**********************************************************************/

static void DrawInc(Display *dpy, Window win, AtPlotWidget plot,
		    AtScale *xscale, AtScale *yscale, Region region)
{
  AtBarchartWidget p = (AtBarchartWidget) plot;
  int i;
  int barwidth;
  int clipx, clipy;
  Pixmap clip_mask;
  XGCValues values;
  unsigned long valueMask;

  if (BCW.valid == False) Recompute(plot, xscale, yscale);

  valueMask = GCClipXOrigin | GCClipYOrigin | GCClipMask;
  XGetGCValues (dpy, BCW.fillGc, valueMask, &values);
  clipx = values.clip_x_origin;
  clipy = values.clip_y_origin;
  clip_mask = values.clip_mask;

  barwidth = (BCW.pixpts[1].x - BCW.pixpts[0].x) * BCW.density;
  XSetRegion (dpy, BCW.fillGc, region);

  for (i=0; i<BCW.numPoints; i++) 
    XFillRectangle(dpy, win, BCW.fillGc, BCW.pixpts[i].x, BCW.pixpts[i].y,
		   barwidth, BCW.zeroypt-BCW.pixpts[i].y);
  
  XSetClipOrigin(dpy,BCW.fillGc,clipx,clipy);
  XSetClipMask(dpy, BCW.fillGc, clip_mask);
}

/**********************************************************************/

static void BuildRects(AtPlotWidget plot, AtScale *xscale, AtScale *yscale, 
		       Region region, XRectangle **rlist_return,
		       int *num_return)
{
  AtBarchartWidget p = (AtBarchartWidget) plot;
  int i, barwidth, numshrinking = 0;
  XRectangle *rlist;

  if (BCW.valid == False) Recompute(plot, xscale, yscale);

  rlist = (XRectangle *) XtMalloc(BCW.numPoints * sizeof(XRectangle));
  barwidth = (BCW.pixpts[1].x - BCW.pixpts[0].x) * BCW.density;

  for (i = 0; i < BCW.numPoints; i++)  {
    if (BCW.pixpts[i].y < BCW.oldpixpts[i].y) { /* bar growing */
      rlist[numshrinking].x = (short) BCW.pixpts[i].x;
      rlist[numshrinking].y = (short) BCW.pixpts[i].y;
      rlist[numshrinking].width = (unsigned short) barwidth;
      rlist[numshrinking].height = (unsigned short) 
	(BCW.oldpixpts[i].y - BCW.pixpts[i].y);
      XUnionRectWithRegion(&rlist[numshrinking], region, region);
    }
    else if (BCW.pixpts[i].y > BCW.oldpixpts[i].y) { /* bar shrinking */
      rlist[numshrinking].x = (short) BCW.oldpixpts[i].x;
      rlist[numshrinking].y = (short) BCW.oldpixpts[i].y;
      rlist[numshrinking].width = (unsigned short) barwidth;
      rlist[numshrinking].height = (unsigned short)(BCW.pixpts[i].y - 
						    BCW.oldpixpts[i].y);
      XUnionRectWithRegion(&rlist[numshrinking], region, region);
      numshrinking++;
    }
  }
  *rlist_return = rlist;
  *num_return = numshrinking;
  return;
}

#undef BCW

