/*
 *      bplot.c
 *      Test 2: plotter using the athena widget set
 *
 *      Test plotting 3 lines using 2 y axes within 1 plotter
 *
 *      klin, Wed Jul  1 11:52:06 1992
 *      klin, Sat Aug 15 13:39:50 1992, <At/..> changed to <X11/At/...>
 */

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

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

/*
 *      The plotter Widgets
 */
static Widget plotter, xaxis, yaxis, y2axis;
static Widget line1, line2, line3;

/*
 *      Create the plotter, the axes and the lines
 */

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

  /* Create the plotter */
  n = 0;
  XtSetArg(args[n], XtNtitle, "Plotter Demo B"); n++;
  XtSetArg(args[n], XtNshowLegend, True); n++;
  XtSetArg(args[n], XtNwidth,  640); n++;
  XtSetArg(args[n], XtNheight, 480); n++;
  XtSetArg(args[n], XtNborderWidth, 0); n++;
  plotter = XtCreateManagedWidget("plotter", atPlotterWidgetClass,
				  parent, args, n);

  /* Create the x and y axes */
  n = 0;
  XtSetArg(args[n], XtNlabel, "Time"); n++;
  XtSetArg(args[n], XtNdrawGrid, False); n++;
  XtSetArg(args[n], XtNdrawOrigin, False); n++;
  XtSetArg(args[n], XtNaxisWidth, 1); n++;
  XtSetArg(args[n], XtNlinTicFormat, "%g"); n++;
  xaxis = XtCreateWidget("xaxis", atXYAxisWidgetClass, plotter, args, n);
  n = 0;
  XtSetArg(args[n], XtNvertical, True); n++;
  XtSetArg(args[n], XtNlabel, "Amplitude"); n++;
  XtSetArg(args[n], XtNdrawGrid, False); n++;
  XtSetArg(args[n], XtNdrawOrigin, False); n++;
  XtSetArg(args[n], XtNaxisWidth, 1); n++;
  XtSetArg(args[n], XtNlinTicFormat, "%g"); n++;
  yaxis = XtCreateWidget("yaxis", atXYAxisWidgetClass, plotter, args, n);
  n = 0;
  XtSetArg(args[n], XtNvertical, True); n++;
  XtSetArg(args[n], XtNmirror, True); n++;
  XtSetArg(args[n], XtNlabel, "Phase"); n++;
  XtSetArg(args[n], XtNdrawGrid, False); n++;
  XtSetArg(args[n], XtNdrawOrigin, False); n++;
  XtSetArg(args[n], XtNaxisWidth, 1); n++;
  XtSetArg(args[n], XtNlinTicFormat, "%g"); n++;
  y2axis = XtCreateWidget("y2axis", atXYAxisWidgetClass, plotter, args, n);

  /* Attach the axes */
  n = 0;
  XtSetArg(args[n], XtNxAxis,  xaxis); n++;
  XtSetArg(args[n], XtNyAxis,  yaxis); n++;
  XtSetArg(args[n], XtNy2Axis, y2axis); n++;
  XtSetValues(plotter, args, n);

  /* Create the lines */
  line1 = XtVaCreateWidget("line1", atXYLinePlotWidgetClass, plotter,
			   XtNlegendName, "sinus (at y1)",
			   XtNplotLineType, AtPlotPOINTS,
			   XtNplotMarkType, AtMarkPLUS,
			   NULL);
  line2 = XtVaCreateWidget("line2", atXYLinePlotWidgetClass, plotter,
			   XtNlegendName, "cosinus (at y2)",
			   XtNplotLineType,  AtPlotLINEIMPULSES,
			   XtNplotLineStyle, AtLineDASHED,
			   XtNuseY2Axis, True,
			   NULL);
  line3 = XtVaCreateWidget("line3", atXYLinePlotWidgetClass, plotter,
			   XtNlegendName, "polygon (at y1)",
			   XtNplotLineType, AtPlotLINEPOINTS,
			   XtNplotLineStyle, AtLineDOTTED,
			   XtNplotMarkType,  AtMarkSTAR,
			   NULL);
}

/*
 *      The data
 */

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

#define PNUM 6
#define NNUM 18

static AtDoublePoint poly[PNUM];
static struct point curve[NNUM];

/*
 *      Create the plot data
 */

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

  poly[0].x = 1.0; poly[0].y =  1.0;
  poly[1].x = 5.0; poly[1].y =  4.0;
  poly[2].x = 8.0; poly[2].y =  3.0;
  poly[3].x = 6.0; poly[3].y = -2.0;
  poly[4].x = 3.0; poly[4].y = -3.0;
  poly[5].x = 1.0; poly[5].y =  1.0;
  for(i = 0, x = 0.125; i < NNUM; i++, x += 0.275) {
    curve[i].xval  = x;
    curve[i].yval1 = 3.5 * sin(x);
    curve[i].yval2 = 2.35 + 2.67 * cos(x);
  }
}

/*
 *      Attach the data to the lines
 */

void AttachData()
{
  /* Attach data from own defined data type struct point */
  AtXYLinePlotAttachData(line1,
    (XtPointer) &curve[0].xval,  AtDouble, sizeof(struct point),
    (XtPointer) &curve[0].yval1, AtDouble, sizeof(struct point),
    1, NNUM);
  AtXYLinePlotAttachData(line2,
    (XtPointer) &curve[0].xval,  AtDouble, sizeof(struct point),
    (XtPointer) &curve[0].yval2, AtDouble, sizeof(struct point),
    1, NNUM);
  /* Attach data from predefined data type AtDoublePoint */
  AtXYLinePlotAttachDoublePoints(line3, &poly[0], 1, PNUM);
}

/*
 *      Other widgets
 */

static Widget form;
static Widget quitbutton, printbutton, legendbutton;
static Widget gridbutton, grid2button;
static Widget framebutton;
static Widget motionbutton, dragbutton;

/*
 *      The button callbacks
 */

#ifndef __STDC__
extern int exit();
#endif

void quit_callback()
{
  exit(0);
}

void print_callback()
{
  AtPlotterGeneratePostscript("bplot.ps", (AtPlotterWidget) plotter,
			      "bplot.ps", 50, 50, 520, 400, False);
  printf("Print callback: Plot dumped to bplot.ps\n");
}

void legend_callback()
{
  Arg args[2];
  Boolean f;

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

void grid_callback()
{
  Arg args[2];

  XtSetArg(args[0], XtNdrawGrid, False);
  XtSetValues(y2axis, args, 1);
  XtSetArg(args[0], XtNdrawGrid, True);
  XtSetValues(xaxis, args, 1);
  XtSetValues(yaxis, args, 1);
}


void grid2_callback()
{
  Arg args[2];

  XtSetArg(args[0], XtNdrawGrid, False);
  XtSetValues(yaxis, args, 1);
  XtSetArg(args[0], XtNdrawGrid, True);
  XtSetValues(xaxis, args, 1);
  XtSetValues(y2axis, args, 1);
}

void frame_callback()
{
  Arg args[2];
  Boolean f;

  XtVaGetValues(xaxis, XtNdrawFrame, &f, NULL);
  f = f ? False : True;
  XtSetArg(args[0], XtNdrawFrame, f);
  XtSetValues(xaxis, args, 1);
  XtSetValues(yaxis, args, 1);
}

void get_motion_callback(widget, client_data, call_data)
  Widget widget;
  XtPointer client_data;
  AtPointCallbackData *call_data;
{
  double x, y1, y2;

  x  = call_data->x1;
  y1 = call_data->y1;
  y2 = call_data->y2;
  printf("Get motion callback: x=%lf y1=%lf y2=%lf\n", x, y1, y2);
}

void motion_callback()
{
  Arg args[2];
  static int t = 0;

  if(t) {
    XtRemoveAllCallbacks(plotter, XtNmotionCallback);
    printf("Motion callback: get motion 1 -> 0\n");
    t = 0;
  }
  else {
    XtAddCallback(plotter, XtNmotionCallback, get_motion_callback, NULL);
    printf("Motion callback: get motion 0 -> 1\n");
    t = 1;
  }
}

static double oldxmin, oldxmax, oldymin, oldymax, oldy2min, oldy2max;

void get_drag_callback(widget, client_data, call_data)
  Widget widget;
  XtPointer client_data;
  AtRectangleCallbackData *call_data;
{
  Arg args[4];
  static double x1, y1, x2, y2, y21, y22;
  double pow();

  x1  = call_data->x11;
  x2  = call_data->x12;
  y1  = call_data->y11;
  y2  = call_data->y12;
  y21 = call_data->y21;
  y22 = call_data->y22;
  XtSetArg(args[0], XtNmin, &x1);
  XtSetArg(args[1], XtNmax, &x2);
  XtSetArg(args[2], XtNautoScale, False);
  XtSetValues(xaxis, args, 3);
  XtSetArg(args[0], XtNmin, &y1);
  XtSetArg(args[1], XtNmax, &y2);
  XtSetArg(args[2], XtNautoScale, False);
  XtSetValues(yaxis, args, 3);
  XtSetArg(args[0], XtNmin, &y21);
  XtSetArg(args[1], XtNmax, &y22);
  XtSetArg(args[2], XtNautoScale, False);
  XtSetValues(y2axis, args, 3);
  printf("Get drag callback: x1=%lf x2=%lf y1=%lf y2=%lf y21=%lf y22=%lf\n",
	  x1, x2, y1, y2, y21, y22);
}

void drag_callback()
{
  Arg args[4];
  int n;
  static int t = 0;

  if(t) {
    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], XtNmin, &oldy2min);
    XtSetArg(args[1], XtNmax, &oldy2max);
    XtSetArg(args[2], XtNautoScale, True);
    XtSetValues(y2axis, args, 3);
    XtRemoveAllCallbacks(plotter, XtNdragCallback);
    printf("Drag callback: get drag 1 -> 0\n");
    t = 0;
  }
  else {
    XtVaGetValues(xaxis, XtNmin, &oldxmin, XtNmax, &oldxmax, NULL);
    XtVaGetValues(yaxis, XtNmin, &oldymin, XtNmax, &oldymax, NULL);
    XtVaGetValues(y2axis, XtNmin, &oldy2min, XtNmax, &oldy2max, NULL);
    XtAddCallback(plotter, XtNdragCallback, get_drag_callback, NULL);
    printf("Drag callback: get drag 0 -> 1\n");
    t = 1;
  }
}

/*
 *      Create form and buttons
 */

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

  legendbutton = XtVaCreateManagedWidget("legend", commandWidgetClass, form,
					 XtNlabel, "Legend",
					 XtNfromHoriz, printbutton,
					 NULL);
  XtAddCallback(legendbutton, XtNcallback, legend_callback, NULL);

  gridbutton = XtVaCreateManagedWidget("grid1", commandWidgetClass, form,
				       XtNlabel, "Grid1",
				       XtNfromHoriz, legendbutton,
				       NULL);
  XtAddCallback(gridbutton, XtNcallback, grid_callback, NULL);

  grid2button = XtVaCreateManagedWidget("grid2", commandWidgetClass, form,
					XtNlabel, "Grid2",
					XtNfromHoriz, gridbutton,
					NULL);
  XtAddCallback(grid2button, XtNcallback, grid2_callback, NULL);

  framebutton = XtVaCreateManagedWidget("frame", commandWidgetClass, form,
					XtNlabel, "Frame",
					XtNfromHoriz, grid2button,
					NULL);
  XtAddCallback(framebutton, XtNcallback, frame_callback, NULL);

  motionbutton = XtVaCreateManagedWidget("motion", commandWidgetClass, form,
					 XtNlabel, "Motion",
					 XtNfromHoriz, framebutton,
					 NULL);
  XtAddCallback(motionbutton, XtNcallback, motion_callback, NULL);

  dragbutton = XtVaCreateManagedWidget("drag", commandWidgetClass, form,
				       XtNlabel, "Drag",
				       XtNfromHoriz, motionbutton,
				       NULL);
  XtAddCallback(dragbutton, XtNcallback, drag_callback, NULL);
}

/*
 *      Main
 */

main(argc, argv)
  int argc;
  char **argv;
{
  Widget appShell;
  XtAppContext app;

  appShell = XtAppInitialize(&app, "Plotter", NULL, 0, &argc, argv, NULL, NULL, 0);

  MakeForm(appShell);

  MakePlotter(form);
  XtVaSetValues(plotter, XtNleft, XtChainLeft, XtNfromVert, quitbutton, NULL);

  MakeData();
  AttachData();

  XtRealizeWidget(appShell);
  XtAppMainLoop(app);

  exit(0);
}
