/*
 *      Plot.c
 *
 *      Plotter demo program using motif
 *      klin, Sat Aug 15 16:08:51 1992
 */

#include <stdio.h>
#include <math.h>
#include <Xm/Xm.h>

#include <X11/At/Plotter.h>
#include <X11/At/XYAxis.h>
#include <X11/At/XYLinePlot.h>

#include "mplot.xbm"

Widget plotter;                         /* The plotter widget */
Widget xaxis, yaxis;                    /* The axis widgets */
Widget line1 = NULL;                    /* The 3 demo lines */
Widget line2 = NULL;
Widget line3 = NULL;
Widget line4 = NULL;                    /* The 3 user lines */
Widget line5 = NULL;
Widget line6 = NULL;

Widget zplotter = NULL;                 /* The zoom plotter */
Widget zxaxis, zyaxis;                  /* The zoom axes */
Widget zline1 = NULL;                   /* The 3 zoom demo lines */
Widget zline2 = NULL;
Widget zline3 = NULL;
Widget zline4 = NULL;                   /* The 3 zoom user lines */
Widget zline5 = NULL;
Widget zline6 = NULL;

double zoomxmin, zoomxmax;              /* X values for zooming */
double zoomymin, zoomymax;              /* Y values for zooming */

static double minxlen, minylen;

#define TITLE  "Plotter Widget Demo"    /* Plotter title */
#define WIDTH  640                      /* Plotter width */
#define HEIGHT 480                      /* Plotter height */
#define MARGIN 6                        /* Plotter margin */
#define ZOOM   100.0                    /* Max zoom in % */

#define VERSION "\
\n\
The Athena Tools Plotter Widget Set\n\
Version 6.0\n\
August 1992\
\n";

#define COPYRIGHT "\
\n\
(c) 1990 by the Massachusetts Institute of Technology\n\
(c) 1991 by Burdett, Buckeridge & Young Ltd.\n\
(c) 1992 by University of Paderborn\n";

#define AUTHOR "\
\n\
Motif Plotter Demo Program by Peter Klingebiel (klin@iat.uni-paderborn.de)\n\
with support by the User Interface Builder Motifation\n\
\n\
Have fun and enjoy\n"

char *version = VERSION;
char *copyright = COPYRIGHT;
char *author = AUTHOR;

/*
 *      External widgets used here
 */

extern Boolean display_demo_lines;
extern XtAppContext application_context;
extern Widget appshell;

extern Widget plotter_form, plotter_frame, position_frame, title_label;
extern Widget xpos_label, ypos_label, x_text, y_text;
extern Widget ask_label, zoom_label;
extern Widget linearx_button, lineary_button;
extern Widget logarithmicx_button, logarithmicy_button;
extern Widget subgrid_button;
extern Widget dialog;
extern Widget line_button;
extern Widget xscale, yscale;

Widget sline = NULL;
Widget zsline = NULL;
static void select_callback();

/*
 *      The plot data
 */

struct point {
  double xval;
  double yval1;
  double yval2;
};

#define CNUM 24
#define PNUM 6

static struct point curve[CNUM];

static AtDoublePoint polygon[PNUM];

/*
 *      Create plotter and axes
 */

static void MakePlotter(parent)
  Widget parent;
{
  Arg args[10];
  int n;

  /* Create the plotter */
  n = 0;
  XtSetArg(args[n], XtNwidth, WIDTH); n++;
  XtSetArg(args[n], XtNheight, HEIGHT); n++;
  XtSetArg(args[n], XtNborderWidth, 0); n++;
  XtSetArg(args[n], XtNmarginWidth, MARGIN); n++;
  XtSetArg(args[n], XtNmarginHeight, MARGIN); n++;
  XtSetArg(args[n], XtNtitle, TITLE); n++;
  XtSetArg(args[n], XtNshowTitle, False); n++;
  XtSetArg(args[n], XtNshowLegend, True); n++;
  XtSetArg(args[n], XtNusePixmap, True); n++;
  plotter = XtCreateManagedWidget("plotter", atPlotterWidgetClass, parent, args, n);
  XtAddCallback(plotter, XtNselectCallback, select_callback, NULL);

  /* Create the X axis */
  n = 0;
  XtSetArg(args[n], XtNlabel, "Time"); n++;
  XtSetArg(args[n], XtNaxisWidth, 1); n++;
  xaxis = XtCreateWidget("axis", atXYAxisWidgetClass, plotter, args, n);

  /* Create the Y axis */
  n = 0;
  XtSetArg(args[n], XtNlabel, "Amplitude"); n++;
  XtSetArg(args[n], XtNaxisWidth, 1); n++;
  XtSetArg(args[n], XtNvertical, True); n++;
  yaxis = XtCreateWidget("axis", atXYAxisWidgetClass, plotter, args, n);

  /* Attach X and Y axes to the plotter */
  n = 0;
  XtSetArg(args[n], XtNxAxis, xaxis); n++;
  XtSetArg(args[n], XtNyAxis, yaxis); n++;
  XtSetValues(plotter, args, n);

  /* Create the zoom dialog and plotter */
  MakeZoomDialogAndPlotter();
}

/*
 *      Create the 3 lines
 */
void MakeDemoLines()
{
  Arg args[4];
  int n;

  /* Create line 1 */
  n = 0;
  XtSetArg(args[n], XtNlegendName, "sinus-points"); n++;
  XtSetArg(args[n], XtNplotLineStyle, AtLineDOTTED); n++;
  XtSetArg(args[n], XtNplotMarkType,  AtMarkRECTANGLE); n++;
  line1 = XtCreateWidget("line1",  atXYLinePlotWidgetClass, plotter, args, n);
  zline1 = XtCreateWidget("line1", atXYLinePlotWidgetClass, zplotter, args, n);

  /* Create line 2 */
  n = 0;
  XtSetArg(args[n], XtNlegendName, "cosinus-points"); n++;
  XtSetArg(args[n], XtNplotLineStyle, AtLineDOTDASHED); n++;
  XtSetArg(args[n], XtNplotMarkType,  AtMarkXMARK); n++;
  line2 = XtCreateWidget("line2", atXYLinePlotWidgetClass, plotter, args, n);
  zline2 = XtCreateWidget("line2", atXYLinePlotWidgetClass, zplotter, args, n);

  /* Create line 3 */
  n = 0;
  XtSetArg(args[n], XtNlegendName, "polygon"); n++;
  XtSetArg(args[n], XtNplotMarkType,  AtMarkSTAR); n++;
  line3 = XtCreateWidget("line3", atXYLinePlotWidgetClass, plotter, args, n);
  zline3 = XtCreateWidget("line3", atXYLinePlotWidgetClass, zplotter, args, n);
}

/*
 *      Create the plot data and attach them to the demo lines
 */

static void MakeData()
{
  double sin(), cos();
  double x;
  int i;

  /* Create two curves from own data type struct point */
  for(i = 0, x = 0.125; i < CNUM; i++, x += 0.275) {
    curve[i].xval  = x;
    curve[i].yval1 = 3.50 * sin(x);
    curve[i].yval2 = 2.67 * cos(x);
  }

  /* Create a polygon from type AtDoublePoint */
  polygon[0].x = 1.0; polygon[0].y =  1.0;
  polygon[1].x = 5.0; polygon[1].y =  4.0;
  polygon[2].x = 8.0; polygon[2].y =  3.0;
  polygon[3].x = 6.0; polygon[3].y = -2.0;
  polygon[4].x = 3.0; polygon[4].y = -3.0;
  polygon[5].x = 1.0; polygon[5].y =  1.0;
}

static void AttachData()
{
  /* Attach curve from own defined type point to line1 and line 2*/
  AtXYLinePlotAttachData(line1,
    (XtPointer) &curve[0].xval,  AtDouble, sizeof(struct point),
    (XtPointer) &curve[0].yval1, AtDouble, sizeof(struct point),
    1, CNUM);
  AtXYLinePlotAttachData(line2,
    (XtPointer) &curve[0].xval,  AtDouble, sizeof(struct point),
    (XtPointer) &curve[0].yval2, AtDouble, sizeof(struct point),
    1, CNUM);

  /* Attach polygon from predefined type AtDoublePoint to line3 */
  AtXYLinePlotAttachDoublePoints(line3, &polygon[0], 1, PNUM);

  /* Attach curve from own defined type point to zline1 and zline 2*/
  AtXYLinePlotAttachData(zline1,
    (XtPointer) &curve[0].xval,  AtDouble, sizeof(struct point),
    (XtPointer) &curve[0].yval1, AtDouble, sizeof(struct point),
    1, CNUM);
  AtXYLinePlotAttachData(zline2,
    (XtPointer) &curve[0].xval,  AtDouble, sizeof(struct point),
    (XtPointer) &curve[0].yval2, AtDouble, sizeof(struct point),
    1, CNUM);

  /* Attach polygon from predefined type AtDoublePoint to zline3 */
  AtXYLinePlotAttachDoublePoints(zline3, &polygon[0], 1, PNUM);
}

/*
 *      Read data from file
 */
static char *ReadPlotData(filename)
  char *filename;
{
  static char msg[256];
  Arg args[8];
  char buf[256];
  AtDoublePoint *data, *p;
  FILE *fp;
  double x, y;
  char *errmsg;
  int nd, n;

  if(fp = fopen(filename, "r")) {
    fgets(buf, sizeof(buf), fp);
    nd = atoi(buf);
    data = (AtDoublePoint *) calloc(nd, sizeof(AtDoublePoint));
    for(p = data, n = 0; n < nd && fgets(buf, sizeof(buf), fp); p++, n++) {
      sscanf(buf, "%lf %lf", &x, &y);
      p->x = x;
      p->y = y;
    }
    fclose(fp);
    if(nd == n) {
      if(line4 == NULL) {
	n = 0;
	XtSetArg(args[n], XtNlegendName,    "test-data1"); n++;
	XtSetArg(args[n], XtNplotLineType,  AtPlotLINEPOINTS); n++;
	XtSetArg(args[n], XtNplotMarkType,  AtMarkDIAMOND); n++;
	XtSetArg(args[n], XtNplotLineStyle, AtLineSOLID), n++;
	line4 = XtCreateWidget("line4", atXYLinePlotWidgetClass, plotter, args, n);
	AtXYLinePlotAttachDoublePoints(line4, data, 1, nd);
	zline4 = XtCreateWidget("line4", atXYLinePlotWidgetClass, zplotter, args, n);
	AtXYLinePlotAttachDoublePoints(zline4, data, 1, nd);
      }
      else if(line5 == NULL) {
	n = 0;
	XtSetArg(args[n], XtNlegendName,    "test-data2"); n++;
	XtSetArg(args[n], XtNplotLineType,  AtPlotLINEPOINTS); n++;
	XtSetArg(args[n], XtNplotMarkType,  AtMarkTRIANGLE1); n++;
	XtSetArg(args[n], XtNplotLineStyle, AtLineDASHED), n++;
	line5 = XtCreateWidget("line5", atXYLinePlotWidgetClass, plotter, args, n);
	AtXYLinePlotAttachDoublePoints(line5, data, 1, nd);
	zline5 = XtCreateWidget("line5", atXYLinePlotWidgetClass, zplotter, args, n);
	AtXYLinePlotAttachDoublePoints(zline5, data, 1, nd);
      }
      else if(line6 == NULL) {
	n = 0;
	XtSetArg(args[n], XtNlegendName,    "test-data3"); n++;
	XtSetArg(args[n], XtNplotLineType,  AtPlotLINEIMPULSES); n++;
	XtSetArg(args[n], XtNplotMarkType,  AtMarkDIAMOND); n++;
	XtSetArg(args[n], XtNplotLineStyle, AtLineSOLID), n++;
	line6 = XtCreateWidget("line6", atXYLinePlotWidgetClass, plotter, args, n);
	AtXYLinePlotAttachDoublePoints(line6, data, 1, nd);
	zline6 = XtCreateWidget("line6", atXYLinePlotWidgetClass, zplotter, args, n);
	AtXYLinePlotAttachDoublePoints(zline6, data, 1, nd);
      }
      errmsg = NULL;
    }
    else {
      free(data);
      sprintf(msg, "Warning: Cannot not read %d items from data file %s", nd, filename);
      errmsg = msg;
    }
  }
  else {
    sprintf(msg, "Warning: Cannot open data file %s", filename);
    errmsg = msg;
  }
  return(errmsg);
}

/*
 *      The line plot select callback
 */

static void select_callback(widget, client_data, call_data)
  Widget widget;
  XtPointer client_data;
  AtSelectCallbackData *call_data;
{
  Widget w;

  sline = zsline = NULL;
  if(call_data->reason == AtSelectSELECTED) {
    w = call_data->widget;
    if(w == (Widget) line1) {
      sline  = line1;
      zsline = zline1;
    }
    else if(w == (Widget) line2) {
      sline  = line2;
      zsline = zline2;
    }
    else if(w == (Widget) line3) {
      sline  = line3;
      zsline = zline3;
    }
    else if(w == (Widget) line4) {
      sline  = line4;
      zsline = zline4;
    }
    else if(w == (Widget) line5) {
      sline  = line5;
      zsline = zline5;
    }
    else if(w == (Widget) line6) {
      sline  = line6;
      zsline = zline6;
    }
  }
  XtSetSensitive(line_button, sline ? True : False);
}

/*
 *      The mainmenu callbacks
 */

#ifndef __STDC__
extern int exit();
#endif

/* callback from dialog */
static char *plotfilename = NULL;

/* file_pulldown: quit_button */
void quit_callback()
{
     exit(0);
}

/* file_pulldown: read_button */
void cancelread_callback();

void readdata_callback(widget, client_data, call_data)
  Widget widget;
  XtPointer client_data;
  XmSelectionBoxCallbackStruct *call_data;
{
  char *msg;

  XtRemoveCallback(dialog, XmNokCallback, readdata_callback, NULL);
  XtRemoveCallback(dialog, XmNcancelCallback, cancelread_callback, NULL);
  XmStringGetLtoR(call_data->value, XmSTRING_DEFAULT_CHARSET, &plotfilename);
  if(plotfilename) {
    if(msg = ReadPlotData(plotfilename))
      Popup_warning(msg);
    XtFree(plotfilename);
    plotfilename = NULL;
  }
}

void cancelread_callback()
{
  XtRemoveCallback(dialog, XmNokCallback, readdata_callback, NULL);
  XtRemoveCallback(dialog, XmNcancelCallback, cancelread_callback, NULL);
}

void read_callback()
{
  if(line4 && line5 && line6) {
    Popup_warning("Warning: Cannot create more than 3 lines");
  }
  else
    Popup_dialog(readdata_callback, cancelread_callback,
		 "Plotter Demo Datafile Selection", "*.data");
}

/* file_pulldown: print_button */
static char *printfilename = NULL;

void cancelprint_callback();

void psprint_callback(widget, client_data, call_data)
  Widget widget;
  XtPointer client_data;
  XmSelectionBoxCallbackStruct *call_data;
{
  char msg[256];

  XtRemoveCallback(dialog, XmNokCallback, psprint_callback, NULL);
  XtRemoveCallback(dialog, XmNcancelCallback, cancelprint_callback, NULL);
  XmStringGetLtoR(call_data->value, XmSTRING_DEFAULT_CHARSET, &printfilename);
  if(printfilename) {
    AtPlotterGeneratePostscript(printfilename, (AtPlotterWidget) plotter,
				"Sample Plot", 50, 50, 480, 320, False);
    XtFree(printfilename);
    printfilename = NULL;
  }
}

void cancelprint_callback()
{
  XtRemoveCallback(dialog, XmNokCallback, psprint_callback, NULL);
  XtRemoveCallback(dialog, XmNcancelCallback, cancelprint_callback, NULL);
}

void print_callback()
{
  Popup_dialog(psprint_callback, cancelprint_callback,
	       "Plot Demo PS Print", "*.ps");
}

/* plot_pulldown: askposition_button */
static Boolean is_asking = False;

void get_click_callback(widget, client_data, call_data)
  Widget widget;
  XtPointer client_data;
  AtPointCallbackData *call_data;
{
  static char xstr[64], ystr[64];
  Arg args[2];

  sprintf(xstr, "%.4lf", call_data->x1);
  XtSetArg(args[0], XmNvalue, xstr);
  XtSetValues(x_text, args, 1);
  sprintf(ystr, "%.4lf", call_data->y1);
  XtSetArg(args[0], XmNvalue, ystr);
  XtSetValues(y_text, args, 1);
}

void askposition_callback()
{
  Arg args[4];

  if(is_asking) {
    XtRemoveAllCallbacks(plotter, XtNclickCallback);
    XtSetArg(args[0], XmNvalue, "");
    XtSetValues(x_text, args, 1);
    XtSetValues(y_text, args, 1);
    XtSetSensitive(ask_label, False);
    is_asking = False;
  }
  else {
    XtAddCallback(plotter, XtNclickCallback, get_click_callback, NULL);
    XtSetSensitive(ask_label, True);
    is_asking = True;
  }
}

/* plot_pulldown: getposition_button */
static Boolean is_positioning = False;

void get_motion_callback(widget, client_data, call_data)
  Widget widget;
  XtPointer client_data;
  AtPointCallbackData *call_data;
{
  static char xstr[64], ystr[64];
  Arg args[2];

  sprintf(xstr, "%.4lf", call_data->x1);
  XtSetArg(args[0], XmNvalue, xstr);
  XtSetValues(x_text, args, 1);
  sprintf(ystr, "%.4lf", call_data->y1);
  XtSetArg(args[0], XmNvalue, ystr);
  XtSetValues(y_text, args, 1);
}

void getposition_callback()
{
  Arg args[4];

  if(is_positioning) {
    XtRemoveAllCallbacks(plotter, XtNmotionCallback);
    XtSetSensitive(xpos_label, False);
    XtSetSensitive(ypos_label, False);
    XtSetArg(args[0], XmNvalue, "");
    XtSetValues(x_text, args, 1);
    XtSetValues(y_text, args, 1);
    is_positioning = False;
  }
  else {
    XtAddCallback(plotter, XtNmotionCallback, get_motion_callback, NULL);
    XtSetSensitive(xpos_label, True);
    XtSetSensitive(ypos_label, True);
    is_positioning = True;
  }
}

void plotterform_callback(widget, client_data, event, cont)
  Widget widget;
  XtPointer client_data;
  XEvent *event;
  Boolean cont;
{
  Arg args[2];

  if(is_positioning && !is_asking) {
    XtSetArg(args[0], XmNvalue, "");
    XtSetValues(x_text, args, 1);
    XtSetValues(y_text, args, 1);
  }
}

/* plot_pulldown: zoom_button */

void get_drag_callback(widget, client_data, call_data)
  Widget widget;
  XtPointer client_data;
  AtRectangleCallbackData *call_data;
{
  Arg args[4];
  char msg[256];
  double x1, y1, x2, y2;
  double xl, yl;

  x1 = call_data->x11;
  x2 = call_data->x12;
  xl = fabs(x2 - x1);
  y1 = call_data->y11;
  y2 = call_data->y12;
  yl = fabs(y2 - y1);
  if(xl < minxlen) {
    sprintf(msg, "Warning: Zooming not possible for X axis (>%.0lf%%)", ZOOM);
    Popup_warning(msg);
  }
  else {
    XtSetArg(args[0], XtNmin, &x1);
    XtSetArg(args[1], XtNmax, &x2);
    XtSetArg(args[2], XtNautoScale, False);
    XtSetValues(zxaxis, args, 3);
  }
  if(yl < minylen) {
    sprintf(msg, "Warning: Zooming not possible for Y axis (>%.0lf%%)", ZOOM);
    Popup_warning(msg);
  }
  else {
    XtSetArg(args[0], XtNmin, &y1);
    XtSetArg(args[1], XtNmax, &y2);
    XtSetArg(args[2], XtNautoScale, False);
    XtSetValues(zyaxis, args, 3);
  }
  Popup_zoom(x1, x2, y1, y2);
}

void zoom_callback()
{
  static Boolean is_zooming = False;

  if(is_zooming) {
    XtRemoveAllCallbacks(plotter, XtNdragCallback);
    XtSetSensitive(zoom_label, False);
    Popdown_zoom();
    is_zooming = False;
  }
  else {
    XtVaGetValues(xaxis, XtNmin, &zoomxmin, XtNmax, &zoomxmax, NULL);
    XtVaGetValues(yaxis, XtNmin, &zoomymin, XtNmax, &zoomymax, NULL);
    minxlen = (zoomxmax - zoomxmin) / ZOOM;
    minylen = (zoomymax - zoomymin) / ZOOM;
    XtAddCallback(plotter, XtNdragCallback, get_drag_callback, NULL);
    XtSetSensitive(zoom_label, True);
    is_zooming = True;
  }
}


/* plot_pulldown: legend_button */
void legend_callback()
{
  Arg args[2];
  Boolean l;

  XtVaGetValues(plotter, XtNshowLegend, &l, NULL);
  l = l ? False : True;
  XtSetArg(args[0], XtNshowLegend, l);
  XtSetValues(plotter, args, 1);
}

/* plot_pulldown: position_button */
void position_callback()
{
  Arg args[4];
  Boolean l;

  XtVaGetValues(plotter, XtNlegendLeft, &l, NULL);
  l = l ? False : True;
  XtSetArg(args[0], XtNshowLegend, True);
  XtSetArg(args[1], XtNlegendLeft, l);
  XtSetValues(plotter, args, 2);
}

/* plot_pulldown: pixmap_button */
void pixmap_callback()
{
  Arg args[2];
  Boolean l;

  XtVaGetValues(plotter, XtNusePixmap, &l, NULL);
  l = l ? False : True;
  XtSetArg(args[0], XtNusePixmap, l);
  XtSetValues(plotter, args, 1);
}

/* axis_pulldown: transform_button */
void transform_callback(widget, client_data, call_data)
  Widget widget;
  XtPointer client_data;
  XmAnyCallbackStruct call_data;

{
  Arg args[2];

  if(AtAxisGetTransform(xaxis) == AtTransformLOGARITHMIC) {
    XtSetArg(args[0], XmNsensitive, True);
    XtSetValues(linearx_button, args, 1);
    XtSetArg(args[0], XmNsensitive, False);
    XtSetValues(logarithmicx_button, args, 1);
  }
  else {        /* LINEAR */
    XtSetArg(args[0], XmNsensitive, False);
    XtSetValues(linearx_button, args, 1);
    XtSetArg(args[0], XmNsensitive, True);
    XtSetValues(logarithmicx_button, args, 1);
  }
  if(AtAxisGetTransform(yaxis) == AtTransformLOGARITHMIC) {
    XtSetArg(args[0], XmNsensitive, True);
    XtSetValues(lineary_button, args, 1);
    XtSetArg(args[0], XmNsensitive, False);
    XtSetValues(logarithmicy_button, args, 1);
  }
  else {        /* LINEAR */
    XtSetArg(args[0], XmNsensitive, False);
    XtSetValues(lineary_button, args, 1);
    XtSetArg(args[0], XmNsensitive, True);
    XtSetValues(logarithmicy_button, args, 1);
  }
}

/* axis_pulldown/transform_pulldown: linearx_button */
void linearx_callback()
{
  Arg args[2];

  XtSetArg(args[0], XtNaxisTransform, AtTransformLINEAR);
  XtSetValues(xaxis, args, 1);
  XtSetValues(zxaxis, args, 1);
}

/* axis_pulldown/transform_pulldown: logarithmicx_button */
void logarithmicx_callback()
{
  Arg args[2];

  XtSetArg(args[0], XtNaxisTransform, AtTransformLOGARITHMIC);
  XtSetValues(xaxis, args, 1);
  XtSetValues(zxaxis, args, 1);
}
/* axis_pulldown/transform_pulldown: lineary_button */
void lineary_callback()
{
  Arg args[2];

  XtSetArg(args[0], XtNaxisTransform, AtTransformLINEAR);
  XtSetValues(yaxis, args, 1);
  XtSetValues(zyaxis, args, 1);
}

/* axis_pulldown/transform_pulldown: logarithmicy_button */
void logarithmicy_callback()
{
  Arg args[2];

  XtSetArg(args[0], XtNaxisTransform, AtTransformLOGARITHMIC);
  XtSetValues(yaxis, args, 1);
  XtSetValues(zyaxis, args, 1);
}

/* axis_pulldown/round button: roundx_button */
void roundx_callback()
{
  Arg args[2];
  Boolean r;

  XtVaGetValues(xaxis, XtNroundEndpoints, &r, NULL);
  XtSetArg(args[0], XtNroundEndpoints, r ? False : True);
  XtSetValues(xaxis, args, 1);
}

/* axis_pulldown/round button: roundy_button */
void roundy_callback()
{
  Arg args[2];
  Boolean r;

  XtVaGetValues(yaxis, XtNroundEndpoints, &r, NULL);
  XtSetArg(args[0], XtNroundEndpoints, r ? False : True);
  XtSetValues(yaxis, args, 1);
}

/* axis_pulldown: grid_button */
void grid_callback()
{
  Arg aargs[2];
  Arg gargs[2];
  Boolean gx, gy;

  XtVaGetValues(xaxis, XtNdrawGrid, &gx, NULL);
  XtVaGetValues(yaxis, XtNdrawGrid, &gy, NULL);
  if(gx || gy) {
    XtSetArg(aargs[0], XtNdrawGrid, False);
    XtSetArg(gargs[0], XmNsensitive, False);
  }
  else {
    XtSetArg(aargs[0], XtNdrawGrid, True);
    XtSetArg(gargs[0], XmNsensitive, True);
  }
  XtSetValues(xaxis, aargs, 1);
  XtSetValues(yaxis, aargs, 1);
  XtSetValues(zxaxis, aargs, 1);
  XtSetValues(zyaxis, aargs, 1);
  XtSetValues(subgrid_button, gargs, 1);
}

/* axis_pulldown: subgrid_button */
void subgrid_callback()
{
  Arg args[2];
  Boolean gx, gy, gn;

  XtVaGetValues(xaxis, XtNdrawSubgrid, &gx, NULL);
  XtVaGetValues(yaxis, XtNdrawSubgrid, &gy, NULL);
  gn = gx || gy ? False : True;
  XtSetArg(args[0], XtNdrawSubgrid, gn);
  XtSetValues(xaxis, args, 1);
  XtSetValues(yaxis, args, 1);
  XtSetValues(zxaxis, args, 1);
  XtSetValues(zyaxis, args, 1);
}

/* line_pulldown: linewidth_buttons 0..3 contained in client_data */
void width_callback(widget, client_data, call_data)
  Widget widget;
  XtPointer client_data;
  XmAnyCallbackStruct call_data;
{
  Arg args[2];
  int width = (int) client_data;

  XtSetArg(args[0], XtNlineWidth, width);
  XtSetValues(sline,  args, 1);
  XtSetValues(zsline, args, 1);
}

/* line_pulldown: linetype_buttons. Type is contained in client_data */
void type_callback(widget, client_data, call_data)
  Widget widget;
  XtPointer client_data;
  XmAnyCallbackStruct call_data;
{
  Arg args[2];
  AtPlotLineType type = (AtPlotLineType) client_data;

  XtSetArg(args[0], XtNplotLineType, type);
  XtSetValues(sline,  args, 1);
  XtSetValues(zsline, args, 1);
}

/* line_pulldown: linestyle_buttons. Style is contained in client_data */
void style_callback(widget, client_data, call_data)
  Widget widget;
  XtPointer client_data;
  XmAnyCallbackStruct call_data;
{
  Arg args[2];
  AtPlotLineStyle style = (AtPlotLineStyle) client_data;

  XtSetArg(args[0], XtNplotLineStyle, style);
  XtSetValues(sline,  args, 1);
  XtSetValues(zsline, args, 1);
}

/* line_pulldown: mark_buttons. Marker type is contained in client_data */
void mark_callback(widget, client_data, call_data)
  Widget widget;
  XtPointer client_data;
  XmAnyCallbackStruct call_data;
{
  Arg args[2];
  AtPlotMarkType type = (AtPlotMarkType) client_data;

  XtSetArg(args[0], XtNplotMarkType, type);
  XtSetValues(sline,  args, 1);
  XtSetValues(zsline, args, 1);
}

/* line_pulldown: offset_button */
void offset_callback()
{
  Popup_offset(-1000, 1000);
}

/* help_pulldown: version_button */
void version_callback()
{
  Popup_help(version);
}

/* help_pulldown: copyright_button */
void copyright_callback()
{
  Popup_help(copyright);
}

/* help_pulldown: author_button */
void author_callback()
{
  Popup_help(author);
}

/*
 *      Handler for Xt warnings
 */

static void warning_handler(msg)
  char *msg;
{
  char buf[256];

  sprintf(buf, "Warning: %s", msg);
  Popup_warning(buf);
}

/*
 *      Build plotter and create/attach data
 */

void BuildPlotter()
{
  Arg args[2];
  XmString xms[1];
  Display *dpy;
  Window win;
  Pixmap ipm;

  /* Set the icon bitmap */
  dpy = XtDisplay(appshell);
  win = DefaultRootWindow(dpy);
  ipm = XCreateBitmapFromData(dpy, win, mplot_bits, mplot_width, mplot_height);
  XtSetArg(args[0], XmNiconPixmap, ipm);
  XtSetValues(appshell, args, 1);

  /* Set the title */
  xms[0] = (XmString) XmStringCreateLtoR(TITLE, XmSTRING_DEFAULT_CHARSET);
  XtSetArg(args[0], XmNlabelString, xms[0]);
  XtSetValues(title_label, args, 1);
  XmStringFree(xms[0]);

  /* Make plotter/axes/lines and data */
  MakePlotter(plotter_frame);

  /* Create the demo lines and attach data */
  if(display_demo_lines == True) {
    MakeDemoLines();
    MakeData();
    AttachData();
  }

  /* Set a warning message handler */
  XtAppSetWarningHandler(application_context, warning_handler);
}
