.CT "Sample Program Listings
.sh 2 "The Motif Test Program mplot"
.pp
The OSF/Motif demo program \f5mplot\f1,
as shown on the title page,
should be included in the directory \f5motif\f1.
Most of the Motif stuff was generated with
the User Interface Builder \f2Motifation\f1.
All the interesting stuff on
how to use and program the plotter widgets
can bei found in the source file \f5Plot.c\f1:
.sp
.nf
.ft 5
.vs -3
.ps -2
/*
 *      Plot.c
 *
 *      Plotter demo program using motif
 *      klin, Mon Aug  3 16:24:02 1992
 */

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

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

#include "mplot.xbm"

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

#define TITLE  "Plotter Widget Demo"    /* Plotter title */
#define WIDTH  600                      /* Plotter width */
#define HEIGHT 400                      /* 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-beta\n\
Patchlevel 3, Aug  4 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\
OSF/Motif Demo Program by Peter Klingebiel (klin@iat.uni-paderborn.de)\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;

/*
 *      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++;
  plotter = XtCreateManagedWidget("plotter", atPlotterWidgetClass, parent, args, n);

  /* Create the X axis */
  n = 0;
  XtSetArg(args[n], XtNlabel, "Time"); n++;
  XtSetArg(args[n], XtNaxisWidth, 1); n++;
  xaxis = XtCreateWidget("xaxis", 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("yaxis", 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 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);

  /* 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);

  /* Create line 3 */
  n = 0;
  XtSetArg(args[n], XtNlegendName, "polygon"); n++;
  XtSetArg(args[n], XtNplotMarkType,  AtMarkSTAR); n++;
  line3 = XtCreateWidget("line3", atXYLinePlotWidgetClass, plotter, 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);
}

/*
 *      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);
      }
      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);
      }
      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);
      }
      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 mainmenu callbacks
 */

extern int exit();

/* 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);
    XtSetArg(args[0], XmNsensitive, False);
    XtSetValues(ask_label, args, 1);
    is_asking = False;
  }
  else {
    XtAddCallback(plotter, XtNclickCallback, get_click_callback, NULL);
    XtSetArg(args[0], XmNsensitive, True);
    XtSetValues(ask_label, args, 1);
    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);
    XtSetArg(args[0], XmNsensitive, False);
    XtSetValues(xpos_label, args, 1);
    XtSetValues(ypos_label, args, 1);
    XtSetArg(args[0], XmNvalue, "");
    XtSetValues(x_text, args, 1);
    XtSetValues(y_text, args, 1);
    is_positioning = False;
  }
  else {
    XtSetArg(args[0], XmNsensitive, True);
    XtSetValues(xpos_label, args, 1);
    XtSetValues(ypos_label, args, 1);
    XtAddCallback(plotter, XtNmotionCallback, get_motion_callback, NULL);
    is_positioning = True;
  }
}

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

  if(enter) {
    XtSetArg(args[0], XmNshadowType, XmSHADOW_IN);
  }
  else {
    if(is_positioning && !is_asking) {
      XtSetArg(args[0], XmNvalue, "");
      XtSetValues(x_text, args, 1);
      XtSetValues(y_text, args, 1);
    }
    XtSetArg(args[0], XmNshadowType, XmSHADOW_OUT);
  }
  XtSetValues(plotter_frame, args, 1);
}

/* plot_pulldown: zoom_button */

static double oldxmin, oldxmax, minxlen;
static double oldymin, oldymax, minylen;

void get_drag_callback(widget, client_data, call_data)
  Widget widget;
  XtPointer client_data;
  AtRectangleCallbackData *call_data;
{
  Arg args[4];
  char msg[256];
  static 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(xaxis, 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(yaxis, args, 3);
  }
}

void zoom_callback()
{
  Arg args[6];
  int n;
  static Boolean is_zooming = False;

  if(is_zooming) {
    XtRemoveAllCallbacks(plotter, XtNdragCallback);
    XtSetArg(args[0], XtNmin, &oldxmin);
    XtSetArg(args[1], XtNmax, &oldxmax);
    XtSetArg(args[2], XtNautoScale, True);
    XtSetValues(xaxis, args, 3);
    XtSetArg(args[0], XtNmin, &oldymin);
    XtSetArg(args[1], XtNmax, &oldymax);
    XtSetArg(args[2], XtNautoScale, True);
    XtSetValues(yaxis, args, 3);
    XtSetArg(args[0], XmNsensitive, False);
    XtSetValues(zoom_label, args, 1);
    is_zooming = False;
  }
  else {
    XtVaGetValues(xaxis, XtNmin, &oldxmin, XtNmax, &oldxmax, NULL);
    XtVaGetValues(yaxis, XtNmin, &oldymin, XtNmax, &oldymax, NULL);
    minxlen = (oldxmax - oldxmin) / ZOOM;
    minylen = (oldymax - oldymin) / ZOOM;
    XtAddCallback(plotter, XtNdragCallback, get_drag_callback, NULL);
    XtSetArg(args[0], XmNsensitive, True);
    XtSetValues(zoom_label, args, 1);
    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);
}

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

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

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

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

  XtSetArg(args[0], XtNaxisTransform, AtTransformLOGARITHMIC);
  XtSetValues(yaxis, 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(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);
}

/* 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];

  XtSetArg(args[0], XtNlineWidth, client_data);
  if(line1)
    XtSetValues(line1, args, 1);
  if(line2)
    XtSetValues(line2, args, 1);
  if(line3)
    XtSetValues(line3, args, 1);
  if(line4)
    XtSetValues(line4, args, 1);
  if(line5)
    XtSetValues(line5, args, 1);
  if(line6)
    XtSetValues(line6, 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;

  switch((int) client_data) {
    case 0: type = AtPlotLINES;        break;
    case 1: type = AtPlotPOINTS;       break;
    case 2: type = AtPlotIMPULSES;     break;
    case 3: type = AtPlotSTEPS;        break;
    case 4: type = AtPlotLINEPOINTS;   break;
    case 5: type = AtPlotLINEIMPULSES; break;
    case 6: type = AtPlotBARS;         break;
    default: return;
  }
  XtSetArg(args[0], XtNplotLineType, type);
  if(line1)
    XtSetValues(line1, args, 1);
  if(line2)
    XtSetValues(line2, args, 1);
  if(line3)
    XtSetValues(line3, args, 1);
  if(line4)
    XtSetValues(line4, args, 1);
  if(line5)
    XtSetValues(line5, args, 1);
  if(line6)
    XtSetValues(line6, 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;

  switch((int) client_data) {
    case 0: style = AtLineSOLID;         break;
    case 1: style = AtLineDOTTED;        break;
    case 2: style = AtLineDASHED;        break;
    case 3: style = AtLineDOTDASHED;     break;
    case 4: style = AtLineDOTTED3;       break;
    case 5: style = AtLineDASHED4;       break;
    case 6: style = AtLineDOTDASHED2;    break;
    default: return;
  }
  XtSetArg(args[0], XtNplotLineStyle, style);
  if(line1)
    XtSetValues(line1, args, 1);
  if(line2)
    XtSetValues(line2, args, 1);
  if(line3)
    XtSetValues(line3, args, 1);
  if(line4)
    XtSetValues(line4, args, 1);
  if(line5)
    XtSetValues(line5, args, 1);
  if(line6)
    XtSetValues(line6, args, 1);
}

/* 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);
}
.ps +2
.vs +3
.ft 1
.fi
.bp
.sh 2 "The Test Program sample_prog"
.pp
Gregory Bond's test program \f5sample_prog.c\f1
from version 5 of the plotter widget set should
be included in the directory \f5athena\f1.
.sp
.nf
.ft 5
.vs -3
.ps -2
/*
 * A simple sample test program
 *
 * Copyright 1991 by Burdett, Buckeridge & Young Ltd.
 */

/* First, the various headers required */

#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Form.h>

#ifdef _AtDevelopment_
#include "Plotter.h"
#include "LinePlot.h"
#include "BarPlot.h"
#include "Axis.h"
#else
#include <At/Plotter.h>
#include <At/LinePlot.h>
#include <At/BarPlot.h>
#include <At/Axis.h>
#endif

/*
 * The application data - weekly sales data for Widgets.
 */
struct profits {
     /* From database */
     long volume;
     float buy_price;
     float sell_price;
     /* calculated values */
     double sales;
     double cost;
     double profit;
};

#define NUM_WEEKS 52

struct profits profits[NUM_WEEKS];

/*
 * Read from the database - a dummy routine, we'll use random numbers
 */
void ReadFromDatabase()
{
     int i;
     extern int rand();

     for (i = 0; i < NUM_WEEKS; i++) {
	  /* Volume between 1000 and 5095 */
	  profits[i].volume = (rand() & 0xfff) + 1000;
	  /* Sell price between $15 and $25 */
	  profits[i].sell_price = (double)(rand() & 0xffffff) /
	       0xffffff * 10.0 + 15.0;
	  /* Buy price between $5 and $15 */
	  profits[i].buy_price = (double)(rand() & 0xffffff) /
	       0xffffff * 10.0 + 5.0;
     }
}

/*
 * Calculate the profit from the above data
 */

void CalculateProfit()
{
     int i;

     for (i = 0; i < NUM_WEEKS; i++) {
	  profits[i].sales = profits[i].volume *
	       profits[i].sell_price;
	  profits[i].cost = profits[i].volume * profits[i].buy_price;
	  profits[i].profit = profits[i].sales - profits[i].cost;
     }
}


/*****************************************************************
 *
 * This is the interesting bit.  Make a simple graph, profits on left,
 * volume on right, weeknumber on bottom, profit a line graph, volume
 * a bar graph.
 */

Widget plotter, xaxis, yaxis, y2axis, line, bar;

void MakePlotter(parent)
Widget parent;
{
     double thousandth = 1.0e-3;
     plotter = XtVaCreateManagedWidget("plotter", atPlotterWidgetClass, parent,
				       XtNtitle, "Widget Sales & Profits",
				       XtNwidth, 600, XtNheight, 450,
				       NULL);
     /* Note axis objects are unmanaged */
     xaxis = XtVaCreateWidget("xaxis", atAxisWidgetClass, plotter,
			      XtNlabel, "Week Number",
			      XtNticFormat, "%.0f",
			      NULL);
     /* Note Y axis is vertical */
     yaxis = XtVaCreateWidget("yaxis", atAxisWidgetClass, plotter,
			      XtNvertical, True,
			      XtNlabel, "Profit ($1,000's)",
			      XtNticMultiplier, &thousandth,
			      NULL);
     /* Note Y2 axis is vertical and mirrored */
     y2axis = XtVaCreateWidget("y2axis", atAxisWidgetClass, plotter,
			       XtNvertical, True,
			       XtNmirror, True,
			       XtNlabel, "Volume Shipped (1,000s)",
			       XtNdrawGrid, False, /* Two grids is confusing */
			       XtNticMultiplier, &thousandth,
			       XtNticFormat, "%4.1f",
			       NULL);
     /* Now attach axes to the parent */
     XtVaSetValues(plotter, XtNxAxis, xaxis,
		   XtNyAxis, yaxis,
		   XtNy2Axis, y2axis,
		   NULL);

     /* Now create the plots */
     /* The volume is scaled against y2 axis */
     bar = XtVaCreateWidget("vol", atBarPlotWidgetClass, plotter,
			    XtNlegendName, "Volume",
			    XtNuseY2Axis, True,
			    XtNshading, AtGRAY3, /* For better PS */
			    NULL);
     /* But profit against Y axis */
     line = XtVaCreateWidget("profit", atLinePlotWidgetClass, plotter,
			     XtNlegendName, "Profit",
			     XtNlineWidth, 2,
			     NULL);
}

/*****************************************************************
 *
 * Attach the application data to the plot children
 */

void AttachData()
{
     AtLinePlotAttachData(line, (XtPointer)&profits[0].profit,
			  AtDouble, sizeof (struct profits),
			  1, NUM_WEEKS);
     AtBarPlotAttachData(bar, (XtPointer)&profits[0].volume,
			 AtInt, sizeof (struct profits),
			 1, NUM_WEEKS);
}

/*****************************************************************
 *
 * This is the boring bit: a form with two buttons and the plotter as
 * children
 */

Widget form, quitbutton, printbutton;

extern int exit();

void quit_callback()
{
     exit(0);
}

void print_callback()
{
     AtPlotterGeneratePostscript("ps.out", (AtPlotterWidget)plotter,
				 "Widget Profits", 0, 0, 400, 250, False);
     fprintf(stderr, "Plot dumped in ps.out\n");
}

void MakeForm(parent)
Widget parent;
{
     form = XtVaCreateManagedWidget("form", formWidgetClass, parent, NULL);
     quitbutton = XtVaCreateManagedWidget("quit", commandWidgetClass, form,
					  XtNlabel, "Quit",
					  XtNleft, XtChainLeft,
					  NULL);
     XtAddCallback(quitbutton, XtNcallback, quit_callback, NULL);
     printbutton = XtVaCreateManagedWidget("print", commandWidgetClass, form,
					   XtNlabel, "Print",
					   XtNfromHoriz, quitbutton,
					   NULL);
     XtAddCallback(printbutton, XtNcallback, print_callback, NULL);
}


int main(ac, av)
Cardinal ac;
char **av;
{
     Widget appShell;
     XtAppContext app;

     appShell = XtAppInitialize(&app, "Test", NULL, 0, &ac, av,
				NULL, NULL, 0);

     MakeForm(appShell);
     MakePlotter(form);
     /* Make the plotter below the buttons! */
     XtVaSetValues(plotter, XtNleft, XtChainLeft,
		   XtNfromVert, quitbutton,
		   NULL);

     /* Now read the data and calculate it */
     ReadFromDatabase();
     CalculateProfit();

     /* Now attach the data to the plot widget */
     AttachData();

     XtRealizeWidget(appShell);

     XtAppMainLoop(app);
     /*NOTREACHED*/
     return 0;
}
.ps +2
.vs +3
.ft 1
.fi
.\"
.\"     End Listings
.\"
