/********************************************************************
This file is part of the abs 0.907 distribution.  abs is a spreadsheet
with graphical user interface.

Copyright (C) 1998-2001  André Bertin (Andre.Bertin@ping.be) 

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version if in the same spirit as version 2.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

Concact: abs@pi.be
         http://home.pi.be/bertin/abs.shtml

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


































#include <X11/Xos.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/Xresource.h>
#include <X11/Intrinsic.h>
#include "plot.h"

#include <math.h>
#include <stdio.h>
#include "plot.h"
#include "graphic_gvar.h"
#include "graph.h"

#include "gr_interf.h"

#ifndef PI
#define PI 3.14
#endif

#ifdef mips
#define irint(x) rint(x)
#endif

#ifndef irint
#define irint(x) floor((x)+0.5)
#endif

extern char *textparsing (char *buf);

int D;

int curfontwidth, curfontheight;

#define Nwidths 10
unsigned int widths[Nwidths] =
{2, 0, 0, 0, 0, 0, 0, 0, 0, 0};
#define Ndashes 10
char dashes[Ndashes][5];

int plotcol[10] =
{20 + 5, 2 + 5, 17 + 5, 25 + 4, 27 + 4, 29 + 4, 31 + 4, 1 + 4, 24 + 4, 20 + 4};

enum JUSTIFY
  {
    LEFT, CENTRE, RIGHT
  }
jmode;

extern int getpixmap ();
extern double get_value ();
extern char *get_text ();

static Pixmap gpixmap;
static Display *gdpy;
static Graph *ggr;
static int X0, Y0;

static double grvalue[10][100];
static char grtext[100][32];
static int imax, jmax;

int
newplot (Widget drawa, Graph * gr)
{

  int gX, gY, W, H;


  ggr = gr;
  if (ggr == NULL)
    return -1;
  if (ggr->pixmap == 0)
    return -2;

  getpixmap (gr, &gX, &gY, &W, &H);	
  gpixmap = gr->pixmap;
  X0 = gX;
  Y0 = gY;
  

  WIN_W = W;
  WIN_H = H;
  RECT_X = 40;
  RECT_Y = 40;
  RECT_W = W - 80;
  RECT_H = H - 80;

  

  D = 8;
  gdpy = XtDisplay (drawa);

  setfont2 (0, 1, 0, 2);
  curfontheight = gettexth ("W", 1, 1, 0, 2);
  curfontwidth = gettextw ("W", 1, 1, 0, 2);

  

  fillrectangle (gdpy, gpixmap, 0, 0, 0, W, H, X0, Y0, -1);
  setbackground (0, 0);
  setforeground (0, 1);

  drawrectangle (gdpy, gpixmap, 0, 0, 0, W, H, X0, Y0);
  



  set_grvalue ();


  switch (gr->type)
    {
    case 0:
      plot_XY ();
      break;
    case 1:
      plot_pie ();
      break;
    case 2:
      plot_bar ();
      break;
    default:
      plot_XY ();
      break;
    }
  return 0;
}


int
set_grvalue ()
{
  int ii, jj, i, j;
  char *buf;
  jmax = 0;



  if (ggr->numrange == 1)
    {
      jj = 0;
      for (i = (ggr->range[0]).i1; i <= (ggr->range[0]).i2; i++)
	{
	  for (j = (ggr->range[0]).j1; j <= (ggr->range[0]).j2; j++)
	    {
	      if (jj < 100)
		{
		  grvalue[1][jj] = get_value (i, j);
		  grvalue[0][jj] = jj + 1;
		  buf = get_text (i, j);
		  if (buf != NULL)
		    if (strlen (buf) > 0)
		      strncpy (grtext[jj], buf, 30);
		  j++;
		}
	      if (jj > jmax)
		jmax = jj;
	      
	    }
	}
      imax = 2;
    }
  else if (ggr->numrange > 1)
    {
      for (ii = 0; ii < ggr->numrange && ii < 10; ii++)
	{

	  jj = 0;

	  for (i = (ggr->range[ii]).i1; i <= (ggr->range[ii]).i2; i++)
	    {
	      for (j = (ggr->range[ii]).j1; j <= (ggr->range[ii]).j2; j++)
		{
		  if (jj < 100 && ii < 11)
		    {
		      grvalue[ii][jj] = get_value (i, j);
		      if (ii == 0)
			{
			  buf = get_text (i, j);
			  if (buf != NULL)
			    if (strlen (buf) > 0)
			      strncpy (grtext[jj], buf, 30);
			}
		      jj++;
		    }
		  if (jj > jmax)
		    jmax = jj;
		  

		  
		}
	    }
	}
      imax = ii;

    }
  return 0;
}

int
plot_XY ()
{
  double x_max, x_min, y_max, y_min, x_unit, y_unit;
  double x_range, y_range;
  double y_power, x_power;
  double xx, yy, x0, y0;
  char label[256];

  int i, j, k, len;
  int grid_l_x, grid_l_y, grid_w, grid_h;
  int text_w;
  int legend_n;
  int x, y, x1 = 0, y1 = 0;
  int first_point;		
				
  double pv;
  double xentv, yentv;		
  int cells = 0;

  int cheight;

  char str[100];

  
  
  
  

  x_max = x_min = grvalue[0][0];
  for (j = 1; j < jmax; j++)
    {
      pv = grvalue[0][j];
      cells++;
      x_max = Max (x_max, pv);
      x_min = Min (x_min, pv);
    }				

  if (cells < 2)
    {
      
      return -1;
    }
  
  
  

  y_max = y_min = grvalue[1][0];
  for (i = 1; i < imax; i++)
    {
      for (j = 0; j <= jmax; j++)
	{
	  pv = grvalue[i][j];
	  y_max = Max (y_max, pv);
	  y_min = Min (y_min, pv);
	}
    }
  x_power = -floor (log10 ((x_max - x_min)));	
  y_power = -floor (log10 ((y_max - y_min)));
  x_power = pow10 (x_power);
  y_power = pow10 (y_power);
  x_min = floor (x_min * x_power) / x_power;
  x_max = ceil (x_max * x_power) / x_power;
  y_min = floor (y_min * y_power) / y_power;
  y_max = ceil (y_max * y_power) / y_power;

  x_unit = (x_max - x_min) / (jmax - 1);
  y_unit = (y_max - y_min) / 10;

  
  
  
  

  if (!ggr->Axes[xlCategory].MinimumScaleIsAuto)
    x_min = ggr->Axes[xlCategory].MinimumScale;
  else
    ggr->Axes[xlCategory].MinimumScale = x_min;

  if (!ggr->Axes[xlCategory].MaximumScaleIsAuto)
    x_max = ggr->Axes[xlCategory].MaximumScale;
  else
    ggr->Axes[xlCategory].MaximumScale = x_max;

  if (!ggr->Axes[xlCategory].MajorUnitIsAuto)
    x_unit = ggr->Axes[xlCategory].MajorUnit;
  else
    ggr->Axes[xlCategory].MajorUnit = x_unit;

  if (!ggr->Axes[xlValue].MinimumScaleIsAuto)
    y_min = ggr->Axes[xlValue].MinimumScale;
  else
    ggr->Axes[xlValue].MinimumScale = y_min;

  if (!ggr->Axes[xlValue].MaximumScaleIsAuto)
    y_max = ggr->Axes[xlValue].MaximumScale;
  else
    ggr->Axes[xlValue].MaximumScale = y_max;

  if (!ggr->Axes[xlValue].MajorUnitIsAuto)
    y_unit = ggr->Axes[xlValue].MajorUnit;
  else
    ggr->Axes[xlValue].MajorUnit = y_unit;

  x_range = x_max - x_min;
  y_range = y_max - y_min;

  pad = PLBORDER;
  bw = 1;

  
  
  

  drawrectangle (gdpy, gpixmap, 1, RECT_X, RECT_Y, RECT_W, RECT_H, X0, Y0);

  
  
  
  
  
  
  

  grid_l_x = 5;			
  grid_l_y = 5;

  if (ggr->Axes[xlValue].HasMajorGridLines)
    {				
      grid_l_x = RECT_W;
    }
  if (ggr->Axes[xlCategory].HasMajorGridLines)
    {				
      grid_l_y = RECT_H;
    }


  grid_w = RECT_W;		
  grid_h = RECT_H;

  xx = x_min;
  while (xx <= x_max && x_min != x_max)
    {
      x0 = (xx - x_min) / x_range * grid_w;
      x = (int) x0;

      if (xx > x_min && xx < x_max)
	{
	  drawline (gdpy, gpixmap, 2,
		    RECT_X + x, RECT_Y + 1,
		    RECT_X + x, RECT_Y + grid_l_y,
		    X0, Y0);
	  drawline (gdpy, gpixmap, 2, RECT_X + x, RECT_Y + RECT_H - 1,
		    RECT_X + x, RECT_Y + RECT_H - grid_l_y,
		    X0, Y0);
	}
      sprintf (str, "%g", xx);
      len = strlen (str);

      cheight = gettexth (str, len, 1, 0, 2);
      text_w = gettextw (str, len, 1, 0, 2);

      drawimagestring (gdpy, gpixmap, 1, RECT_X + x - text_w / 2,
		       RECT_H + RECT_Y * 8 / 6, str, len, X0, Y0);

      xx += x_unit;

    }

  yy = y_min;
  while (yy <= y_max && y_min != y_max)
    {
      y0 = (yy - y_min) / y_range * grid_h;
      y = (int) y0;
      if (yy > y_min && yy < y_max)
	{
	  drawline (gdpy, gpixmap, 2,
		    RECT_X, RECT_Y + RECT_H - y,
		    RECT_X + grid_l_x, RECT_Y + RECT_H - y,
		    X0, Y0);
	  drawline (gdpy, gpixmap, 2,
		    RECT_X + RECT_W, RECT_Y + RECT_H - y,
		    RECT_X + RECT_W - grid_l_x, RECT_Y + RECT_H - y,
		    X0, Y0);
	}
      sprintf (str, "%g", yy);
      len = strlen (str);

      cheight = gettexth (str, len, 1, 0, 2);
      text_w = gettextw (str, len, 1, 0, 2);

      drawimagestring (gdpy, gpixmap, 1,
		       RECT_X - text_w * 8 / 6,
		       RECT_Y + RECT_H - y + curfontheight / 3,
		       str, len,
		       X0, Y0);
      yy += y_unit;
    }

  
  
  
  
  if (ggr->HasTitle)
    {
      if (strlen (ggr->ChartTitle.Text) > 1)
	strcpy (label, (char *) textparsing (ggr->ChartTitle.Text));
      else
	strcpy (label, ggr->ChartTitle.Text);
      len = strlen (label);
      text_w = gettextw (label, len, 1, 0, 2);

      drawimagestring (gdpy, gpixmap, 1, (WIN_W - text_w) / 2, RECT_Y / 3,
		       label, len,
		       X0, Y0);
    }

  
  if (ggr->Axes[xlCategory].HasTitle)
    {
      if (strlen (ggr->Axes[xlCategory].AxisTitle.Text) > 1)
	strcpy (label, (char *) textparsing (ggr->Axes[xlCategory].AxisTitle.Text));
      else
	strcpy (label, ggr->Axes[xlCategory].AxisTitle.Text);

      len = strlen (label);
      text_w = gettextw (label, len, 1, 0, 2);
      drawimagestring (gdpy, gpixmap, 1,
	      (WIN_W - text_w) / 2, RECT_H + RECT_Y * 9 / 6 + curfontheight,
		       label, len,
		       X0, Y0);
    }

  
  if (ggr->Axes[xlValue].HasTitle)
    {
      if (strlen (ggr->Axes[xlValue].AxisTitle.Text) > 1)
	strcpy (label, (char *) textparsing (ggr->Axes[xlValue].AxisTitle.Text));
      else
	strcpy (label, ggr->Axes[xlValue].AxisTitle.Text);

      len = strlen (label);
      text_w = gettextw (label, len, 1, 0, 2);
      if ((RECT_X - text_w) < 0)
	x = curfontwidth;
      else
	x = RECT_X - text_w;
      drawimagestring (gdpy, gpixmap, 1,
		       x, RECT_Y - 2 * curfontheight,
		       label, len,
		       X0, Y0);
    }


  
  
  

  legend_n = 0;
  curves_n = imax;
  for (i = 1; i < imax; i++)

    {
      if (strlen ((ggr->range[i]).name) > 1)
	strcpy (label, (char *) textparsing ((ggr->range[i]).name));
      else
	strcpy (label, (ggr->range[i]).name);

      len = strlen (label);
      text_w = gettextw (label, len, 1, 0, 2);
      if (imax == 2)
	{
	  

	  
	  
	  
	  
	  
	  
	  
	  
	  
	  
	  x = RECT_X + (RECT_W - text_w) / 2 - 25;
	  y = RECT_Y * 2 + RECT_H - curfontheight / 2;
	  switch (i - 1)
	    {
	    case 0:
	      DrawOpenSquare (x + 10, y, plotcol[i - 1]);
	      break;
	    case 1:
	      DrawOpenTriangle (x + 10, y, plotcol[i - 1]);
	      break;
	    case 2:
	      DrawOpenDiamon (x + 10, y, plotcol[i - 1]);
	      break;
	    case 3:
	      DrawCross (x + 10, y, plotcol[i - 1]);
	      break;
	    case 4:
	      DrawCloseSquare (x + 10, y, plotcol[i - 1]);
	      break;
	    case 5:
	      DrawCloseDiamon (x + 10, y, plotcol[i - 1]);
	      break;
	    }
	  
	  drawline (gdpy, gpixmap, plotcol[i - 1],
		    x, y,
		    x + 20, y,
		    X0, Y0);
	  
	  

	  drawimagestring (gdpy, gpixmap, plotcol[i - 1],
			RECT_X + (RECT_W - text_w) / 2, RECT_Y * 2 + RECT_H,
			   label, len,
			   X0, Y0);

	  break;
	}
      else
	{
	  y = RECT_Y * 2 + RECT_H - curfontheight / 2;
	  

	  
	  
	  
	  
	  
	  
	  
	  
	  
	  
	  
	  switch (i - 1)
	    {
	    case 0:
	      DrawOpenSquare (RECT_X / 2 + legend_n * (WIN_W / curves_n - 10),
			      y, plotcol[i - 1]);
	      break;
	    case 1:
	      DrawOpenTriangle (RECT_X / 2 + legend_n * (WIN_W / curves_n - 10),
				y, plotcol[i - 1]);
	      break;
	    case 2:
	      DrawOpenDiamon (RECT_X / 2 + legend_n * (WIN_W / curves_n - 10),
			      y, plotcol[i - 1]);
	      break;
	    case 3:
	      DrawCross (RECT_X / 2 + legend_n * (WIN_W / curves_n - 10),
			 y, plotcol[i - 1]);
	      break;
	    case 4:
	      DrawCloseSquare (RECT_X / 2 + legend_n * (WIN_W / curves_n - 10),
			       y, plotcol[i - 1]);
	      break;
	    case 5:
	      DrawCloseDiamon (RECT_X / 2 + legend_n * (WIN_W / curves_n - 10),
			       y, plotcol[i - 1]);
	      break;
	    }
	  
	  drawline (gdpy, gpixmap, plotcol[i - 1],
		    RECT_X / 2 + legend_n * (WIN_W / curves_n - 10) - 10,
		    y,
		    RECT_X / 2 + legend_n * (WIN_W / curves_n - 10) + 10,
		    y,
		    X0, Y0);

	  
	  
	  drawimagestring (gdpy, gpixmap, plotcol[i - 1],
		       RECT_X / 2 + legend_n * (WIN_W / curves_n - 10) + 25,
			   y,
			   label, len,
			   X0, Y0);
	  legend_n++;
	}
    }


  
  
  

  for (i = 1; i < imax; i++)
    {
      first_point = 1;


      for (j = 0, k = 0; j < jmax && k < jmax; j++, k++)
	{

	  xentv = grvalue[0][j];
	  if ((xentv < x_min) || (xentv > x_max))
	    continue;
	  yentv = grvalue[i][j];
	  if ((yentv < y_min) || (yentv > y_max))
	    continue;

	  if (first_point)
	    {
	      x1 = RECT_X + RECT_W * (xentv - x_min) / x_range;
	      y1 = RECT_Y + RECT_H - RECT_H * (yentv - y_min) / y_range;
	      if ((ggr->graphic_format[i] == grsymb) || (ggr->graphic_format[i] == grboth))
		switch (i - 1)
		  {
		  case 0:
		    DrawOpenSquare (x1, y1, plotcol[i - 1]);
		    break;
		  case 1:
		    DrawOpenTriangle (x1, y1, plotcol[i - 1]);
		    break;
		  case 2:
		    DrawOpenDiamon (x1, y1, plotcol[i - 1]);
		    break;
		  case 3:
		    DrawCross (x1, y1, plotcol[i - 1]);
		    break;
		  case 4:
		    DrawCloseSquare (x1, y1, plotcol[i - 1]);
		    break;
		  case 5:
		    DrawCloseDiamon (x1, y1, plotcol[i - 1]);
		    break;
		  }
	      first_point = 0;
	      continue;
	    }
	  x = RECT_X + RECT_W * (xentv - x_min) / x_range;
	  y = RECT_Y + RECT_H - RECT_H * (yentv - y_min) / y_range;

	  if ((ggr->graphic_format[i] == grline) || (ggr->graphic_format[i] == grboth))
	    drawline (gdpy, gpixmap, plotcol[i - 1], x1, y1, x, y,
		      X0, Y0);
	  if ((ggr->graphic_format[i] == grsymb) || (ggr->graphic_format[i] == grboth))
	    switch (i - 1)
	      {
	      case 0:
		DrawOpenSquare (x, y, plotcol[i - 1]);
		break;
	      case 1:
		DrawOpenTriangle (x, y, plotcol[i - 1]);
		break;
	      case 2:
		DrawOpenDiamon (x, y, plotcol[i - 1]);
		break;
	      case 3:
		DrawCross (x, y, plotcol[i - 1]);
		break;
	      case 4:
		DrawCloseSquare (x, y, plotcol[i - 1]);
		break;
	      case 5:
		DrawCloseDiamon (x, y, plotcol[i - 1]);
		break;
	      }
	  x1 = x;
	  y1 = y;
	}
    }
  
  return 0;
}				

int
plot_pie ()
{
  int i, j, len;
  int text_w;
  int X, Y, X1, Y1, Temp_X, Temp_Y;
  double pv;
  int cells = 0;
  int slice;			
  double Range_Total = 0;	
  double Percentage = 0;	
  double Angle_Size = 0;	
  double Starting_Angle = 0;	
  double Rad_Angle = 0;		
  double Bisector_Angle = 0;	
  double Label_R = 0;		
  char label[256];
  char str[100];
  char per_str[10];
  int PIE_D;			
  int PIE_R;			
  int col;
  int a1, a2;


  
  
  
  

  if (ggr->numrange > 1)
    col = 1;
  else
    col = 0;

  Range_Total = 0;
  for (j = 0; j <= jmax; j++)
    {
      pv = grvalue[col][j];
      cells++;
      Range_Total = Range_Total + pv;
    }				


  if (cells < 1)
    {

      return -1;
    }

  
  
  
  

  pad = PLBORDER;
  bw = 1;
  if (WIN_H > WIN_W)
    PIE_D = WIN_W - 20;
  else
    PIE_D = WIN_H - 50;
  if (WIN_H < 5)
    return -1;

  PIE_R = PIE_D / 2;

  
  
  

  
  if (ggr->HasTitle)
    {
      if (strlen (ggr->ChartTitle.Text) > 1)
	strcpy (label, (char *) textparsing (ggr->ChartTitle.Text));
      else
	strcpy (label, ggr->ChartTitle.Text);


      len = strlen (label);
      text_w = gettextw (label, len, 1, 0, 2);

      drawimagestring (gdpy, gpixmap, 1, (WIN_W - text_w) / 2, RECT_Y / 3,
		       label, len,
		       X0, Y0);
    }


  Starting_Angle = 0;
  slice = 1;
  for (j = 0; j < jmax; j++)
    {

      pv = grvalue[col][j];

      
      Percentage = (pv / Range_Total);


      
      
      
      

      Angle_Size = Percentage * 360;
      i = slice;
      while (i > 9)
	i -= 10;
      setforeground (0, plotcol[i]);
      





















































































      



      
      i = slice;
      while (i > 9)
	i -= 10;
      setforeground (0, plotcol[i]);
      a1 = Starting_Angle * 64;
      a2 = Angle_Size * 64;
      fillarc (gdpy, gpixmap, plotcol[slice - 1],
	    (WIN_W / 2) - (PIE_R), (WIN_H / 2) - (PIE_R) + 10, PIE_D, PIE_D,
	       a1, a2, X0, Y0);
      setforeground (0, 1);





      
      setfillstyle (gdpy, 1, FillSolid);

      
      
      
      
      

      Rad_Angle = (Starting_Angle) * PI / 180;
      Temp_X = (PIE_R) * cos (Rad_Angle);
      Temp_Y = -((PIE_R) * sin (Rad_Angle));
      X = Temp_X + (WIN_W / 2);
      Y = Temp_Y + (WIN_H / 2) + 10;
      drawline (gdpy, gpixmap, 1, WIN_W / 2, (WIN_H / 2 + 10), X, Y,
		X0, Y0);

      
      setfillstyle (gdpy, 0, FillSolid);
      drawarc (gdpy, gpixmap, 1, (WIN_W / 2) - (PIE_R), (WIN_H / 2) - (PIE_R) + 10,
	       PIE_D, PIE_D, 0, 360 * 64, X0, Y0);
      
      
      
      
      

      Label_R = PIE_R - (PIE_R / 4);
      Bisector_Angle = (Starting_Angle) + (Angle_Size / 2);
      Rad_Angle = Bisector_Angle * PI / 180;
      Temp_X = (Label_R) * cos (Rad_Angle);
      Temp_Y = -((Label_R) * sin (Rad_Angle));
      X1 = Temp_X + (WIN_W / 2);
      Y1 = Temp_Y + (WIN_H / 2) + 10;

      if (col > 0)
	sprintf (str, "%s", grtext[j]);
      else
	str[0] = '\0';

      sprintf (per_str, "%.0f", (Percentage * 100));
      strcat (str, " (");
      strcat (str, per_str);
      strcat (str, "%)");
      len = strlen (str);
      text_w = gettextw (str, len, 1, 0, 2);

      
      if ((Bisector_Angle > 90) && (Bisector_Angle <= 270))
	X = X1 - text_w;
      else
	X = X1;
      Y = Y1 + curfontheight / 2;
      drawimagestring (gdpy, gpixmap, 1, X, Y, str, len,
		       X0, Y0);

      Starting_Angle = (Starting_Angle) + (Angle_Size);
      slice++;
    }


  return 0;
}






void
DrawOpenDiamon (x, y, col)
     short x, y, col;
{
  XPoint points[5];

  points[0].x = x;
  points[0].y = y - 3;
  points[1].x = 3;
  points[1].y = 3;
  points[2].x = -3;
  points[2].y = 3;
  points[3].x = -3;
  points[3].y = -3;
  points[4].x = 3;
  points[4].y = -3;
  drawlines (gdpy, gpixmap, col, points, 5, CoordModePrevious, X0, Y0);
}

void
DrawCloseDiamon (x, y, col)
     short x, y, col;
{
  XPoint points[12];

  points[0].x = x;
  points[0].y = y;
  points[1].x = -2;
  points[1].y = 0;
  points[2].x = 4;
  points[2].y = 0;
  points[3].x = -2;
  points[3].y = 0;
  points[4].x = 0;
  points[4].y = -2;
  points[5].x = 0;
  points[5].y = 4;
  points[6].x = 0;
  points[6].y = -2;
  points[7].x = 1;
  points[7].y = 1;
  points[8].x = -2;
  points[8].y = -2;
  points[9].x = 1;
  points[9].y = 1;
  points[10].x = -1;
  points[10].y = 1;
  points[11].x = 2;
  points[11].y = -2;
  drawlines (gdpy, gpixmap, col, points, 12, CoordModePrevious, X0, Y0);
}

void
DrawOpenSquare (x, y, col)
     short x, y, col;
{
  XPoint points[5];
  points[0].x = x - 2;
  points[0].y = y - 2;
  points[1].x = 4;
  points[1].y = 0;
  points[2].x = 0;
  points[2].y = 4;
  points[3].x = -4;
  points[3].y = 0;
  points[4].x = 0;
  points[4].y = -4;
  drawlines (gdpy, gpixmap, col, points, 5, CoordModePrevious, X0, Y0);
}

void
DrawCloseSquare (x, y, col)
     short x, y, col;
{
  XPoint points[9];

  points[0].x = x - 2;
  points[0].y = y - 2;
  points[1].x = 4;
  points[1].y = 0;
  points[2].x = 0;
  points[2].y = 4;
  points[3].x = -4;
  points[3].y = 0;
  points[4].x = 0;
  points[4].y = -4;
  points[5].x = 4;
  points[5].y = 4;
  points[6].x = -2;
  points[6].y = -2;
  points[7].x = -2;
  points[7].y = 2;
  points[8].x = 4;
  points[8].y = -4;
  drawlines (gdpy, gpixmap, col, points, 9, CoordModePrevious, X0, Y0);
}

void
DrawOpenTriangle (x, y, col)
     short x, y, col;
{
  XPoint points[4];

  points[0].x = x;
  points[0].y = y - 3;
  points[1].x = 2;
  points[1].y = 5;
  points[2].x = -4;
  points[2].y = 0;
  points[3].x = 2;
  points[3].y = -5;
  drawlines (gdpy, gpixmap, col, points, 4, CoordModePrevious, X0, Y0);
}


void
DrawCross (x, y, col)
     short x, y, col;
{
  XPoint points[6];

  points[0].x = x;
  points[0].y = y;
  points[1].x = -2;
  points[1].y = 0;
  points[2].x = 4;
  points[2].y = 0;
  points[3].x = -2;
  points[3].y = 0;
  points[4].x = 0;
  points[4].y = -2;
  points[5].x = 0;
  points[5].y = 4;
  drawlines (gdpy, gpixmap, col, points, 6, CoordModePrevious, X0, Y0);
}





double
pow10 (p)
     double p;
{
  double q;

  if (p > 1e99 || p < -1e99)
    return 0;

  p = floor (p);
  if (p >= 0)
    {
      for (q = 1; p > 0; --p)
	q = q * 10;
    }
  else
    {
      p = -p;
      for (q = 1; p > 0; --p)
	q = q / 10;
    }
  return q;
}








char *
rm_tail_zero (s)
     char *s;
{
  char *t;
  
  return s;
  for (t = s; *t == ' ' || *t == '\t'; t++);
  strcpy (s, t);

  
  t = s;
  while ((*t) && (*t != '\n'))	
    t++;
  t--;
  while ((t != s) && ((*t == ' ') || (*t == '0')))
    t--;
  if (*t != '.')		
    t++;
  *t = '\0';
  return s;
}


#define PIX_SEP 6		
int
plot_bar ()
{
  double max_y = 0;		
  double min_y = 0;		
  double y_power;
  double Y_Range;		
  double pv;
  char label[256];

  int i, j, k;			
  int len;			
  int grid_l_x;			
  int grid_l_y;
  int grid_h;
  char str[100];		
  int height, width;		
  int text_w;			
  int x, y;			
  int first_bar = 1;		
  int num_rows = 0;		
  int num_cols = 0;		
  int row;			
  int bars;			
  int labelsize;		

  
  
  


  bars = 0;
  for (j = 0; j < jmax; j++)
    {
      pv = grvalue[0][j];

      bars++;
    }

  if (bars < 1)
    {
      fprintf (stderr, "\007");
      fprintf (stderr, "Not enough valid X labels");
      return -1;
    }

  for (i = 1; i < imax; i++)
    {
      num_cols++;
      row = 0;
      for (j = 0; j < jmax; j++)
	{
	  pv = grvalue[i][j];

	  row++;

	  if (first_bar)
	    {
	      max_y = pv;	
	      min_y = pv;	
	      first_bar = 0;
	    }
	  else
	    {
	      max_y = Max (max_y, pv);
	      min_y = Min (min_y, pv);
	    }
	  num_rows = Max (row, num_rows);
	}
    }

  min_y -= 0.1 * (fabs (min_y));	



  y_power = -floor (log10 ((max_y - min_y)));
  y_power = pow10 (y_power);
  min_y = floor (min_y * y_power) / y_power;
  max_y = ceil (max_y * y_power) / y_power;

  if (!ggr->Axes[xlValue].MinimumScaleIsAuto)
    min_y = ggr->Axes[xlValue].MinimumScale;
  else
    ggr->Axes[xlValue].MinimumScale = min_y;

  if (!ggr->Axes[xlValue].MaximumScaleIsAuto)
    max_y = ggr->Axes[xlValue].MaximumScale;
  else
    ggr->Axes[xlValue].MaximumScale = max_y;


  
  
  
  


  bw = 1;


  drawrectangle (gdpy, gpixmap, 1,
		 RECT_X, RECT_Y, RECT_W, RECT_H, X0, Y0);

  
  
  
  
  
  
  
  
  
  
  
  
  grid_l_x = 0;			
  grid_l_y = 0;

  if (ggr->Axes[xlValue].HasMajorGridLines)
    {				
      grid_l_x = RECT_W;
    }
  if (ggr->Axes[xlCategory].HasMajorGridLines)
    {				
      grid_l_y = RECT_H;
    }

  grid_h = RECT_H;		

  Y_Range = max_y - min_y;

  
  width = (RECT_W - (PIX_SEP * num_rows)) / (num_cols * num_rows);

  

  for (i = 0; i < 11; i++)
    {
      if (i > 0 && i < 10)
	drawline (gdpy, gpixmap, 2,
		  RECT_X - 4, RECT_Y + i * grid_h / 10,
		  RECT_X, RECT_Y + i * grid_h / 10, X0, Y0);
      drawline (gdpy, gpixmap, 2,
		RECT_X, RECT_Y + i * grid_h / 10,
		RECT_X + grid_l_x, RECT_Y + i * grid_h / 10, X0, Y0);
      drawline (gdpy, gpixmap, 2,
		RECT_X + RECT_W, RECT_Y + i * grid_h / 10,
	      RECT_X + RECT_W - grid_l_x, RECT_Y + i * grid_h / 10, X0, Y0);

      sprintf (str, "%.1f", (max_y - Y_Range * i / 10));
      len = strlen (str);
      text_w = gettextw (str, len + 2, 1, 0, 2);
      drawimagestring (gdpy, gpixmap, 1,
		       RECT_X - text_w,
		       RECT_Y + i * grid_h / 10 + curfontheight / 3,
		       str, len, X0, Y0);

    }				

  for (i = 1; i < num_rows; i++)
    {
      x = RECT_X + PIX_SEP * i + i * width * (num_cols);
      drawline (gdpy, gpixmap, 1,
		x, RECT_Y, x, RECT_Y + grid_l_y, X0, Y0);
      drawline (gdpy, gpixmap, 1,
		x, RECT_Y + RECT_H, x, RECT_Y + RECT_H - grid_l_y, X0, Y0);
    }				

  
  
  
  
  
  if (ggr->HasTitle)
    {
      if (strlen (ggr->ChartTitle.Text) > 1)
	strcpy (label, (char *) textparsing (ggr->ChartTitle.Text));
      else
	strcpy (label, ggr->ChartTitle.Text);


      len = strlen (label);
      text_w = gettextw (label, len, 1, 0, 2);

      drawimagestring (gdpy, gpixmap, 1, (WIN_W - text_w) / 2, RECT_Y / 3,
		       label, len,
		       X0, Y0);
    }

  
  if (ggr->Axes[xlCategory].HasTitle)
    {
      if (strlen (ggr->Axes[xlCategory].AxisTitle.Text) > 1)
	strcpy (label, (char *) textparsing (ggr->Axes[xlCategory].AxisTitle.Text));
      else
	strcpy (label, ggr->Axes[xlCategory].AxisTitle.Text);



      len = strlen (label);
      text_w = gettextw (label, len, 1, 0, 2);
      drawimagestring (gdpy, gpixmap, 1,
	      (WIN_W - text_w) / 2, RECT_H + RECT_Y * 9 / 6 + curfontheight,
		       label, len,
		       X0, Y0);
    }

  
  if (ggr->Axes[xlValue].HasTitle)
    {
      if (strlen (ggr->Axes[xlValue].AxisTitle.Text) > 1)
	strcpy (label, (char *) textparsing (ggr->Axes[xlValue].AxisTitle.Text));
      else
	strcpy (label, ggr->Axes[xlValue].AxisTitle.Text);



      len = strlen (label);
      text_w = gettextw (label, len, 1, 0, 2);
      if ((RECT_X - text_w) < 0)
	x = curfontwidth;
      else
	x = RECT_X - text_w;
      drawimagestring (gdpy, gpixmap, 1,
		       x, RECT_Y - 2 * curfontheight,
		       label, len,
		       X0, Y0);
    }

  
  
  
  
  
  
  





  
  
  
  labelsize = irint (floor ((width * num_cols) / (double) curfontwidth) - 1);
  y = RECT_Y * 2 + RECT_H - curfontheight / 2;
  bars = 0;
  x = RECT_X + (PIX_SEP) * (bars - 1) + width * (bars - 1) * num_cols;
  for (i = 1; i < imax; i++)
    {
      if (strlen ((ggr->range[i]).name) > 1)
	strcpy (label, (char *) textparsing ((ggr->range[i]).name));
      else
	strcpy (label, (ggr->range[i]).name);



      len = strlen (label);
      text_w = gettextw (label, len, 1, 0, 2);
      x = x + (width * num_cols / 2) + text_w + 25;
      drawimagestring (gdpy, gpixmap, plotcol[i - 1],
		       x + 25, y,
		       label, len, X0, Y0);
      fillrectangle (gdpy, gpixmap, plotcol[i - 1], x, y - curfontheight, 20, curfontheight, X0, Y0, 1);
    }
  
  
  
  
  

  for (i = 1; i < imax; i++)
    {

      row = 0;
      for (j = 0, k = 0; j < jmax && k < jmax; j++, k++)
	{
	  row++;


	  x = RECT_X + (row - 1) * (PIX_SEP) + (row - 1) * (num_cols) * width + width * (i - 1);

	  pv = grvalue[i][j];

	  height = (pv * RECT_H) / (max_y);	
	  y = RECT_Y + RECT_H - height;


	  

	  














	  

	  
	  

	  setforeground (0, plotcol[i - 1]);
	  fillrectangle (gdpy, gpixmap, plotcol[i - 1], x, y, width, height, X0, Y0, 1);
	  setforeground (0, 1);

	  


	  
	  drawrectangle (gdpy, gpixmap, plotcol[i - 1], x, y, width, height, X0, Y0);

	}
    }
  return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1