home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume19 / xephem / part15 / plotmenu.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-15  |  29.5 KB  |  1,037 lines

  1. /* code to manage the stuff on the "plot" menu.
  2.  */
  3.  
  4. #include <stdio.h>
  5. #include <ctype.h>
  6. #include <math.h>
  7. #if defined(__STDC__)
  8. #include <stdlib.h>
  9. #endif
  10. #include <X11/Xlib.h>
  11. #include <Xm/Xm.h>
  12. #include <Xm/Form.h>
  13. #include <Xm/Frame.h>
  14. #include <Xm/DrawingA.h>
  15. #include <Xm/Label.h>
  16. #include <Xm/PushB.h>
  17. #include <Xm/ToggleB.h>
  18. #include <Xm/RowColumn.h>
  19. #include <Xm/Separator.h>
  20. #include <Xm/Text.h>
  21.  
  22. #if defined(__STDC__) || defined(__cplusplus)
  23. #define P_(s) s
  24. #else
  25. #define P_(s) ()
  26. #endif
  27.  
  28. extern int plot_cartesian P_((FILE *pfp, Widget widget, unsigned int nx, unsigned int ny, int flipx, int flipy, int grid));
  29. extern void all_selection_mode P_((int whether));
  30. extern void f_string P_((Widget w, char *s));
  31. extern void get_something P_((Widget w, char *resource, char *value));
  32. extern void hlp_dialog P_((char *tag, char *deflt[], int ndeflt));
  33. extern void query P_((Widget tw, char *msg, char *label1, char *label2, char *label3, void (*func1)(), void (*func2)(), void (*func3)()));
  34. extern void set_something P_((Widget w, char *resource, char *value));
  35. extern void set_xmstring P_((Widget w, char *resource, char *txt));
  36. extern void xe_msg P_((char *msg, int app_modal));
  37.  
  38. void plot_manage P_((void));
  39. void plt_selection P_((char *name));
  40. void plt_log P_((char *name, double value));
  41. void plot P_((void));
  42. int plot_ison P_((void));
  43. void plt_cursor P_((Cursor c));
  44. static void plt_select P_((int whether));
  45. static void plot_create_form P_((void));
  46. static void plt_activate_cb P_((Widget w, XtPointer client, XtPointer call));
  47. static void plt_close_cb P_((Widget w, XtPointer client, XtPointer call));
  48. static void plt_help_cb P_((Widget w, XtPointer client, XtPointer call));
  49. static void plt_reset P_((void));
  50. static void plt_stop_selecting P_((void));
  51. static void plt_turn_off P_((void));
  52. static void init_next_tag P_((void));
  53. static void plt_try_append P_((void));
  54. static void plt_try_overwrite P_((void));
  55. static void plt_try_cancel P_((void));
  56. static void plt_try_turn_on P_((void));
  57. static void plt_turn_on P_((char *how));
  58. static void plt_da_manage P_((void));
  59. static void plt_da_destroy P_((Widget daform_w));
  60. static void plt_daform_map_cb P_((Widget w, XtPointer client, XtPointer call));
  61. static void plt_da_close_cb P_((Widget w, XtPointer client, XtPointer call));
  62. static void plt_da_flipx_cb P_((Widget w, XtPointer client, XtPointer call));
  63. static void plt_da_flipy_cb P_((Widget w, XtPointer client, XtPointer call));
  64. static void plt_da_grid_cb P_((Widget w, XtPointer client, XtPointer call));
  65. static void plt_da_exp_cb P_((Widget da_w, XtPointer client, XtPointer call));
  66.  
  67. #undef P_
  68.  
  69. extern int access();
  70. extern Widget toplevel_w;
  71. #define    XtD    XtDisplay(toplevel_w)
  72.  
  73. #ifdef VMS
  74. #include <perror.h>
  75. #include <errno.h>
  76. #else
  77. extern char *sys_errlist[];
  78. extern errno;
  79. #endif
  80.  
  81. #define    errsys    (sys_errlist[errno])
  82.  
  83. /* max number of things we can keep track of at once to plot */
  84. #define    MAXPLTLINES    10
  85. #define    MAXFLDNAM    32    /* longest allowed field name */
  86.  
  87. static Widget plotform_w;
  88. static Widget select_w, active_w, prompt_w;
  89. static Widget title_w, filename_w;
  90. static Widget table_w[MAXPLTLINES][3];    /* column indeces follow.. */
  91. static int selecting_xy;        /* also one of ... */
  92. #define    T    0
  93. #define    X    1
  94. #define    Y    2
  95.  
  96. #define    DEF_PLTFN    "ephem.plt"    /* default plot file name */
  97. static FILE *plt_fp;            /* the plot file; == 0 means don't plot */
  98.  
  99.  
  100. /* plt_activate_cb client values. */
  101. enum { SELECT, ACTIVE, SHOW};
  102.  
  103. /* store the name of each x and y line to track and their values.
  104.  * we get the label straight from the Text widget in the table as needed.
  105.  */
  106. typedef struct {
  107.     char pl_xn[MAXFLDNAM];    /* name of x field, or 0 if none */
  108.     double pl_xv;        /* last known value of x field */
  109.     char pl_yn[MAXFLDNAM];    /* name of y field, or 0 if none */
  110.     double pl_yv;        /* last known value of x field */
  111. } PltLine;
  112. static PltLine pltlines[MAXPLTLINES];
  113. static int npltlines;        /* number of pltlines[] in actual use */
  114.  
  115. /* one of these gets malloced and passed to the drawing area expose callback via
  116.  * its client parameter. be sure to free it when the parent FormDialog goes
  117.  * away too.
  118.  * by doing this, we can have lots of different plots up at once and yet we
  119.  * don't have to keep track of them - they track themselves.
  120.  */
  121. typedef struct {
  122.     char *filename;    /* name of file being plotted (also malloced) */
  123.     FILE *fp;        /* FILE pointer for the file */
  124.     int flipx, flipy;    /* flip state for this instance */
  125.     int grid;        /* whether to include a grid */
  126. } DrawInfo;
  127.  
  128. /* called when the plot menu is activated via the main menu pulldown.
  129.  * if never called before, create and manage all the widgets as a child of a
  130.  * form. otherwise, just toggle whether the form is managed.
  131.  */
  132. void
  133. plot_manage ()
  134. {
  135.     if (!plotform_w)
  136.         plot_create_form();
  137.     
  138.     if (XtIsManaged(plotform_w))
  139.         XtUnmanageChild (plotform_w);
  140.     else
  141.         XtManageChild (plotform_w);
  142. }
  143.  
  144. /* called by the other menus (data, etc) as their buttons are
  145.  * selected to inform us that that button is to be included in a plot.
  146.  */
  147. void
  148. plt_selection (name)
  149. char *name;
  150. {
  151.     Widget tw;
  152.  
  153.     if (!plotform_w
  154.         || !XtIsManaged(plotform_w)
  155.         || !XmToggleButtonGetState(select_w))
  156.         return;
  157.  
  158.     tw = table_w[npltlines][selecting_xy];
  159.     set_xmstring (tw, XmNlabelString, name);
  160.     XtManageChild (tw);
  161.  
  162.     if (selecting_xy == X) {
  163.         (void) strncpy (pltlines[npltlines].pl_xn, name, MAXFLDNAM-1);
  164.         selecting_xy = Y;
  165.         XtManageChild (prompt_w);
  166.         f_string (prompt_w, "Select quantity for Y..");
  167.     } else {
  168.         (void) strncpy (pltlines[npltlines].pl_yn, name, MAXFLDNAM-1);
  169.         if (++npltlines == MAXPLTLINES)
  170.         plt_stop_selecting();
  171.         else {
  172.         selecting_xy = X;
  173.         init_next_tag();
  174.         }
  175.     }
  176. }
  177.  
  178. /* called as each different field is written -- just save in pltlines[]
  179.  * if we are interested in it.
  180.  * might have the same field listed more than once so can't stop if find one.
  181.  */
  182. void
  183. plt_log (name, value)
  184. char *name;
  185. double value;
  186. {
  187.     if (plt_fp) {
  188.         PltLine *plp;
  189.         for (plp = pltlines; plp < &pltlines[npltlines]; plp++) {
  190.         if (strcmp (name, plp->pl_xn) == 0)
  191.             plp->pl_xv = value;
  192.         if (strcmp (name, plp->pl_yn) == 0)
  193.             plp->pl_yv = value;
  194.         }
  195.     }
  196. }
  197.  
  198. /* called when all fields have been updated and it's time to
  199.  * write the active plotfields to the current plot file, if one is open.
  200.  */
  201. void
  202. plot()
  203. {
  204.     if (plt_fp) {
  205.         /* plot in order of original selection */
  206.         PltLine *plp;
  207.         for (plp = pltlines; plp < &pltlines[npltlines]; plp++) {
  208.         char *lbl = XmTextGetString (table_w[plp-pltlines][T]);
  209.         (void) fprintf (plt_fp, "%c,%.12g,%.12g\n", lbl[0],
  210.                             plp->pl_xv, plp->pl_yv);
  211.         XtFree (lbl);
  212.         }
  213.     }
  214. }
  215.  
  216. plot_ison()
  217. {
  218.     return (plt_fp != 0);
  219. }
  220.  
  221. /* called to put up or remove the watch cursor.  */
  222. void
  223. plt_cursor (c)
  224. Cursor c;
  225. {
  226.     Window win;
  227.  
  228.     if (plotform_w && (win = XtWindow(plotform_w))) {
  229.         Display *dsp = XtDisplay(plotform_w);
  230.         if (c)
  231.         XDefineCursor (dsp, win, c);
  232.         else
  233.         XUndefineCursor (dsp, win);
  234.     }
  235. }
  236.  
  237. /* inform the other menues whether we are setting up for them to tell us
  238.  * what fields to plot.
  239.  */
  240. static void
  241. plt_select(whether)
  242. int whether;
  243. {
  244.     all_selection_mode(whether);
  245. }
  246.  
  247. static void
  248. plot_create_form()
  249. {
  250.     static struct {
  251.         char *title;
  252.         int cb_data;
  253.         Widget *wp;
  254.     } tbs[] = {
  255.         {"Select fields", SELECT, &select_w},
  256.         {"Plot to file", ACTIVE, &active_w},
  257.         {"Show plot file", SHOW, NULL},
  258.     };
  259.     XmString str;
  260.     Widget f_w, rc_w;
  261.     Widget w;
  262.     char *deffn;
  263.     Arg args[20];
  264.     int i, n;
  265.  
  266.     /* create the main dialog */
  267.  
  268.     n = 0;
  269.     XtSetArg (args[n], XmNautoUnmanage, False); n++;
  270.     XtSetArg (args[n], XmNdefaultPosition, False); n++;
  271.     plotform_w = XmCreateFormDialog (toplevel_w, "Plot", args, n);
  272.  
  273.     n = 0;
  274.     XtSetArg (args[n], XmNtitle, "xephem Plot Control"); n++;
  275.     XtSetValues (XtParent(plotform_w), args, n);
  276.  
  277.     /* make a RowColumn to hold everything */
  278.  
  279.     n = 0;
  280.     XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  281.     XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  282.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  283.     XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  284.     XtSetArg (args[n], XmNisAligned, False); n++;
  285.     XtSetArg (args[n], XmNadjustMargin, False); n++;
  286.     rc_w = XmCreateRowColumn(plotform_w, "PlotRC", args, n);
  287.     XtManageChild (rc_w);
  288.  
  289.     /* make the control toggle buttons */
  290.  
  291.     for (i = 0; i < XtNumber(tbs); i++) {
  292.         str = XmStringCreate(tbs[i].title, XmSTRING_DEFAULT_CHARSET);
  293.         n = 0;
  294.         XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
  295.         XtSetArg (args[n], XmNlabelString, str); n++;
  296.         w = XmCreateToggleButton(rc_w, "PlotTB", args, n);
  297.         XmStringFree (str);
  298.         XtManageChild (w);
  299.         XtAddCallback(w, XmNvalueChangedCallback, plt_activate_cb,
  300.                             (XtPointer)tbs[i].cb_data);
  301.         if (tbs[i].wp)
  302.         *tbs[i].wp = w;
  303.     }
  304.  
  305.     /* create filename text area and its label */
  306.  
  307.     n = 0;
  308.     str = XmStringCreate("File name:", XmSTRING_DEFAULT_CHARSET);
  309.     XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
  310.     XtSetArg (args[n], XmNlabelString, str); n++;
  311.     w = XmCreateLabel (rc_w, "PlotFnL", args, n);
  312.     XmStringFree (str);
  313.     XtManageChild (w);
  314.  
  315.     n = 0;
  316.     filename_w = XmCreateText (rc_w, "Filename", args, n);
  317.     deffn = XmTextGetString (filename_w);
  318.     if (strlen(deffn) == 0)
  319.         XmTextSetString (filename_w, DEF_PLTFN);
  320.     XtFree (deffn);
  321.     XtManageChild (filename_w);
  322.  
  323.     /* create title text area and its label */
  324.  
  325.     n = 0;
  326.     str = XmStringCreate("Title:", XmSTRING_DEFAULT_CHARSET);
  327.     XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
  328.     XtSetArg (args[n], XmNlabelString, str); n++;
  329.     w = XmCreateLabel (rc_w, "PlotTL", args, n);
  330.     XtManageChild (w);
  331.     XmStringFree (str);
  332.  
  333.     n = 0;
  334.     title_w = XmCreateText (rc_w, "PlotTitle", args, n);
  335.     XtManageChild (title_w);
  336.  
  337.     /* create prompt line -- it will be managed as necessary */
  338.  
  339.     n = 0;
  340.     XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
  341.     prompt_w = XmCreateLabel (rc_w, "PlotPrompt", args, n);
  342.  
  343.     /* create the table.
  344.      * each row is in a form to control its shape.
  345.      * loop index of -1 is used to make the column headings.
  346.      * the table entries are not managed at this time.
  347.      */
  348.  
  349.     for (i = -1; i < MAXPLTLINES; i++) {
  350.         n = 0;
  351.         XtSetArg (args[n], XmNfractionBase, 9); n++;
  352.         f_w = XmCreateForm (rc_w, "PlotTF", args, n);
  353.         XtManageChild (f_w);
  354.  
  355.         n = 0;
  356.         XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  357.         XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  358.         XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  359.         XtSetArg (args[n], XmNleftPosition, 0); n++;
  360.         XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
  361.         XtSetArg (args[n], XmNrightPosition, 1); n++;
  362.         if (i == -1) {
  363.         w = XmCreateLabel (f_w, "Tag", args, n);
  364.         XtManageChild (w);
  365.         } else {
  366.         XtSetArg (args[n], XmNmaxLength, 1); n++;
  367.         XtSetArg (args[n], XmNcolumns, 1); n++;
  368.         table_w[i][T] = XmCreateText (f_w, "PlotTag", args, n);
  369.         }
  370.  
  371.         n = 0;
  372.         XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  373.         XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  374.         XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  375.         XtSetArg (args[n], XmNleftPosition, 2); n++;
  376.         XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
  377.         XtSetArg (args[n], XmNrightPosition, 5); n++;
  378.         if (i == -1) {
  379.         w = XmCreateLabel (f_w, "X", args, n);
  380.         XtManageChild (w);
  381.         } else {
  382.         table_w[i][X] = XmCreateLabel (f_w, "PlotX", args, n);
  383.         }
  384.  
  385.         n = 0;
  386.         XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  387.         XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  388.         XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  389.         XtSetArg (args[n], XmNleftPosition, 6); n++;
  390.         XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
  391.         XtSetArg (args[n], XmNrightPosition, 9); n++;
  392.         if (i == -1) {
  393.         w = XmCreateLabel (f_w, "Y", args, n);
  394.         XtManageChild (w);
  395.         } else {
  396.         table_w[i][Y] = XmCreateLabel (f_w, "PlotY", args, n);
  397.         }
  398.     }
  399.  
  400.     /* create a separator */
  401.  
  402.     n = 0;
  403.     w = XmCreateSeparator (rc_w, "Sep", args, n);
  404.     XtManageChild (w);
  405.  
  406.     /* make a form to hold the close and help buttons evenly */
  407.  
  408.     n = 0;
  409.     XtSetArg (args[n], XmNfractionBase, 7); n++;
  410.     f_w = XmCreateForm (rc_w, "PlotCF", args, n);
  411.     XtManageChild(f_w);
  412.  
  413.         n = 0;
  414.         XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  415.         XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  416.         XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  417.         XtSetArg (args[n], XmNleftPosition, 1); n++;
  418.         XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
  419.         XtSetArg (args[n], XmNrightPosition, 3); n++;
  420.         w = XmCreatePushButton (f_w, "Close", args, n);
  421.         XtAddCallback (w, XmNactivateCallback, plt_close_cb, 0);
  422.         XtManageChild (w);
  423.  
  424.         n = 0;
  425.         XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  426.         XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  427.         XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  428.         XtSetArg (args[n], XmNleftPosition, 4); n++;
  429.         XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
  430.         XtSetArg (args[n], XmNrightPosition, 6); n++;
  431.         w = XmCreatePushButton (f_w, "Help", args, n);
  432.         XtAddCallback (w, XmNactivateCallback, plt_help_cb, 0);
  433.         XtManageChild (w);
  434. }
  435.  
  436. /* callback from any of the plot menu toggle buttons being activated.
  437.  */
  438. /* ARGSUSED */
  439. static void
  440. plt_activate_cb (w, client, call)
  441. Widget w;
  442. XtPointer client;
  443. XtPointer call;
  444. {
  445.     XmToggleButtonCallbackStruct *t = (XmToggleButtonCallbackStruct *) call;
  446.     int what = (int) client;
  447.  
  448.     switch (what) {
  449.     case SELECT:
  450.         if (t->set) {
  451.         /* first turn off plotting, if on, while we change things */
  452.         if (XmToggleButtonGetState(active_w))
  453.             XmToggleButtonSetState(active_w, False, True);
  454.         plt_reset();    /* reset pltlines array and unmanage the table*/
  455.         plt_select(1);    /* inform other menus to inform us of fields */
  456.         init_next_tag();/* set first tag to something and show it */
  457.         selecting_xy = X;
  458.         } else
  459.         plt_stop_selecting();
  460.         break;
  461.     case ACTIVE:
  462.         if (t->set) {
  463.         /* first turn off selecting, if on */
  464.         if (XmToggleButtonGetState(select_w))
  465.             XmToggleButtonSetState(select_w, False, True);
  466.         plt_try_turn_on();
  467.         } else
  468.         plt_turn_off();
  469.         break;
  470.     case SHOW:
  471.         /* turn off plotting, if on, to make sure file is complete. */
  472.         if (XmToggleButtonGetState(active_w))
  473.         XmToggleButtonSetState(active_w, False, True);
  474.         plt_da_manage();
  475.         /* we want this to work like it was a pushbutton, really */
  476.         XmToggleButtonSetState(w, False, False);
  477.         break;
  478.     }
  479. }
  480.  
  481. /* callback from the Close button.
  482.  */
  483. /* ARGSUSED */
  484. static void
  485. plt_close_cb (w, client, call)
  486. Widget w;
  487. XtPointer client;
  488. XtPointer call;
  489. {
  490.     XtUnmanageChild (plotform_w);
  491. }
  492.  
  493. /* callback from the Help button.
  494.  */
  495. /* ARGSUSED */
  496. static void
  497. plt_help_cb (w, client, call)
  498. Widget w;
  499. XtPointer client;
  500. XtPointer call;
  501. {
  502. static char *help_msg[] = {
  503. "This menu controls the plot generation and display functionality of xephem.",
  504. "Select fields to form x/y pairs, enable plotting to write them to a file on",
  505. "each xephem iteration step, then view. Each file may be titled, as desired."
  506. };
  507.     hlp_dialog ("Plot", help_msg, sizeof(help_msg)/sizeof(help_msg[0]));
  508. }
  509.  
  510. /* forget our list, and unmanage the table.
  511.  */
  512. static void
  513. plt_reset()
  514. {
  515.     int i;
  516.  
  517.     for (i = 0; i < npltlines; i++) {
  518.         XtUnmanageChild (table_w[i][T]);
  519.         XtUnmanageChild (table_w[i][X]);
  520.         XtUnmanageChild (table_w[i][Y]);
  521.     }
  522.  
  523.     npltlines = 0;
  524. }
  525.  
  526. /* stop selecting: unmanage a partitially filled in line specs; tell
  527.  * everybody else to drop their buttons, make sure toggle is off.
  528.  */
  529. static void
  530. plt_stop_selecting()
  531. {
  532.     /* harmless to unmanage something already unmanaged so do them all */
  533.     if (npltlines < MAXPLTLINES) {
  534.         XtUnmanageChild (table_w[npltlines][T]);
  535.         XtUnmanageChild (table_w[npltlines][X]);
  536.         XtUnmanageChild (table_w[npltlines][Y]);
  537.     }
  538.  
  539.     XmToggleButtonSetState (select_w, False, False);
  540.     plt_select(0);
  541.     XtUnmanageChild (prompt_w);
  542. }
  543.  
  544. static void
  545. plt_turn_off ()
  546. {
  547.     if (plt_fp) {
  548.         (void) fclose (plt_fp);
  549.         plt_fp = 0;
  550.     }
  551. }
  552.  
  553. static void
  554. init_next_tag()
  555. {
  556.     char buf[100];
  557.     Widget w = table_w[npltlines][T];
  558.  
  559.     XtManageChild (prompt_w);
  560.     f_string (prompt_w, "Select quantity for X..");
  561.     (void) sprintf (buf, "%c", 'A' + npltlines);
  562.     XmTextSetString (w, buf);
  563.     XtManageChild (w);
  564. }
  565.  
  566. /* called from the query routine when want to append to an existing plot file.*/
  567. static void
  568. plt_try_append()
  569. {
  570.     plt_turn_on("a");
  571. }
  572.  
  573. /* called from the query routine when want to overwrite to an existing plot
  574.  * file.
  575.  */
  576. static void
  577. plt_try_overwrite()
  578. {
  579.     plt_turn_on("w");
  580. }
  581.  
  582. /* called from the query routine when want decided not to make a plot file.  */
  583. static void
  584. plt_try_cancel()
  585. {
  586.     XmToggleButtonSetState (active_w, False, False);
  587. }
  588.  
  589. /* attempt to open file for use as a plot file.
  590.  * if it doesn't exist, then go ahead and make it.
  591.  * but if it does, first ask wheher to append or overwrite.
  592.  */
  593. static void
  594. plt_try_turn_on()
  595. {
  596.     char *txt = XmTextGetString (filename_w);
  597.     if (access (txt, 0) == 0) {
  598.         char *buf;
  599.         buf = XtMalloc (strlen(txt)+100);
  600.         (void) sprintf (buf, "%s exists: Append or Overwrite?", txt);
  601.         query (toplevel_w, buf, "Append", "Overwrite", "Cancel",
  602.                 plt_try_append, plt_try_overwrite, plt_try_cancel);
  603.         XtFree (buf);
  604.     } else
  605.         plt_turn_on("w");
  606.     XtFree (txt);
  607. }
  608.  
  609. /* turn on plotting.
  610.  * establish a file to use (and thereby set plt_fp, the plotting_is_on flag).
  611.  */
  612. static void
  613. plt_turn_on (how)
  614. char *how;    /* fopen how argument */
  615. {
  616.     char *txt;
  617.  
  618.     /* plotting is on if file opens ok */
  619.     txt = XmTextGetString (filename_w);
  620.     plt_fp = fopen (txt, how);
  621.     if (!plt_fp) {
  622.         char *buf;
  623.         XmToggleButtonSetState (active_w, False, False);
  624.         buf = XtMalloc (strlen(txt)+100);
  625.         (void) sprintf (buf, "Can not open %s: %s", txt, errsys);
  626.         xe_msg (buf, 1);
  627.         XtFree (buf);
  628.     }
  629.     XtFree (txt);
  630.     
  631.     if (plt_fp) {
  632.         /* add a title if it's not null */
  633.         txt = XmTextGetString (title_w);
  634.         if (txt[0] != '\0')
  635.         (void) fprintf (plt_fp, "* %s\n", txt);
  636.         XtFree (txt);
  637.     }
  638. }
  639.  
  640. /* make a new drawing area widget and manage it. it's unmanaged and destroyed
  641.  *   from the Close button or if something goes wrong during plotting.
  642.  * open the plot file and save it, the current state of the flipx/flipy/grid
  643.  *   buttons and the filename in a DrawInfo struct in the userData resource
  644.  *   for the FormDialog where the drawingarea callback can get at it each time.
  645.  * this way, we can have lots of different plots up at once yet we don't
  646.  *   have to keep track of them.
  647.  * by leaving the file open, we gain some protection against it being removed
  648.  *   or renamed.
  649.  */
  650. static void
  651. plt_da_manage()
  652. {
  653.     Widget daform_w;
  654.     Widget da_w, w;
  655.     Widget ctl_w;
  656.     Widget fr_w;
  657.     XmString str;
  658.     Arg args[20];
  659.     char titlebuf[64];
  660.     int n;
  661.     DrawInfo *di;
  662.     FILE *fp;
  663.     char *fn;
  664.  
  665.     /* first make sure we can open the plot file */
  666.     fn = XmTextGetString (filename_w);
  667.     fp = fopen (fn, "r");
  668.     if (!fp) {
  669.         char *buf;
  670.         buf = XtMalloc (strlen(fn)+100);
  671.         (void) sprintf (buf, "Can not open %s: %s", fn, errsys);
  672.         xe_msg (buf, 1);
  673.         XtFree (buf);
  674.         XtFree (fn);
  675.         return;
  676.     }
  677.  
  678.     /* create the form dialog parent.
  679.      * arrange for it to be square when it first comes up.
  680.      */
  681.     n = 0;
  682.     daform_w = XmCreateFormDialog (toplevel_w, "PlotD", args, n);
  683.     XtAddCallback (daform_w, XmNmapCallback, plt_daform_map_cb, NULL);
  684.  
  685.     /* set some stuff in the parent DialogShell.
  686.      * setting XmNdialogTitle in the Form didn't work..
  687.      */
  688.     (void) sprintf (titlebuf, "xephem Plot of `%.*s'", sizeof(titlebuf)-20,
  689.                                         fn);
  690.     n = 0;
  691.     XtSetArg (args[n], XmNtitle, titlebuf); n++;
  692.     XtSetValues (XtParent(daform_w), args, n);
  693.  
  694.     /* make the DrawInfo structure and save it in the userData of the Form.
  695.      * the memory gets freed when the the dialog is closed/unmanaged.
  696.      */
  697.     di = (DrawInfo *) XtMalloc (sizeof(DrawInfo));
  698.     di->filename = fn;
  699.     di->fp = fp;
  700.     di->flipx = 0;
  701.     di->flipy = 0;
  702.     di->grid = 0;
  703.     set_something (daform_w, XmNuserData, (char *)di);
  704.  
  705.     /* make a form for the bottom controls */
  706.  
  707.     n = 0;
  708.     XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  709.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  710.     XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  711.     XtSetArg (args[n], XmNverticalSpacing, 5); n++;
  712.     XtSetArg (args[n], XmNfractionBase, 17); n++;
  713.     ctl_w = XmCreateForm (daform_w, "CtlF", args, n);
  714.     XtManageChild (ctl_w);
  715.  
  716.     /* create the drawing area and connect plt_da_exp_cb().
  717.      * N.B. be sure this guys parent is the FormDialog so exp_cb can find
  718.      *   the DrawInfo by looking there at its userData.
  719.      * make this as high as it is wide when it is first mapped.
  720.      * N.B. if ever want this is a frame beware that other functions
  721.      *   assume that the daform_w is the parent of the DrawingArea.
  722.      */
  723.     n = 0;
  724.     XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  725.     XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
  726.     XtSetArg (args[n], XmNbottomWidget, ctl_w); n++;
  727.     XtSetArg (args[n], XmNbottomOffset, 2); n++;
  728.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  729.     XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  730.     XtSetArg (args[n], XmNmarginWidth, 0); n++;
  731.     XtSetArg (args[n], XmNmarginHeight, 0); n++;
  732.     da_w = XmCreateDrawingArea (daform_w, "PlotDA", args, n);
  733.     XtAddCallback (da_w, XmNexposeCallback, plt_da_exp_cb, NULL);
  734.     XtManageChild (da_w);
  735.  
  736.         /* make the flipx/y and grid toggle buttons (within frames) and the
  737.          * close button in the control form
  738.          */
  739.  
  740.         n = 0;
  741.         XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  742.         XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  743.         XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  744.         XtSetArg (args[n], XmNleftPosition, 1); n++;
  745.         XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
  746.         XtSetArg (args[n], XmNrightPosition, 4); n++;
  747.         fr_w = XmCreateFrame (ctl_w, "FlipXF", args, n);
  748.         XtManageChild (fr_w);
  749.         str = XmStringCreate("Flip X", XmSTRING_DEFAULT_CHARSET);
  750.         n = 0;
  751.         XtSetArg (args[n], XmNlabelString, str); n++;
  752.         XtSetArg (args[n], XmNset, di->flipx); n++;
  753.         w = XmCreateToggleButton(fr_w, "FlipX", args, n);
  754.         XmStringFree (str);
  755.         XtAddCallback (w, XmNvalueChangedCallback, plt_da_flipx_cb, da_w);
  756.         XtManageChild (w);
  757.  
  758.         n = 0;
  759.         XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  760.         XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  761.         XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  762.         XtSetArg (args[n], XmNleftPosition, 5); n++;
  763.         XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
  764.         XtSetArg (args[n], XmNrightPosition, 8); n++;
  765.         fr_w = XmCreateFrame (ctl_w, "FlipYF", args, n);
  766.         XtManageChild (fr_w);
  767.         str = XmStringCreate("Flip Y", XmSTRING_DEFAULT_CHARSET);
  768.         n = 0;
  769.         XtSetArg (args[n], XmNlabelString, str); n++;
  770.         XtSetArg (args[n], XmNset, di->flipy); n++;
  771.         w = XmCreateToggleButton(fr_w, "FlipY", args, n);
  772.         XmStringFree (str);
  773.         XtAddCallback (w, XmNvalueChangedCallback, plt_da_flipy_cb, da_w);
  774.         XtManageChild (w);
  775.  
  776.         n = 0;
  777.         XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  778.         XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  779.         XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  780.         XtSetArg (args[n], XmNleftPosition, 9); n++;
  781.         XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
  782.         XtSetArg (args[n], XmNrightPosition, 12); n++;
  783.         fr_w = XmCreateFrame (ctl_w, "GridF", args, n);
  784.         XtManageChild (fr_w);
  785.         n = 0;
  786.         XtSetArg (args[n], XmNset, di->grid); n++;
  787.         w = XmCreateToggleButton(fr_w, "Grid", args, n);
  788.         XtAddCallback (w, XmNvalueChangedCallback, plt_da_grid_cb, da_w);
  789.         XtManageChild (w);
  790.  
  791.         /* create a "Close" button.
  792.          * it destroys the dialog and frees the DrawInfo struct.
  793.          */
  794.         n = 0;
  795.         XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  796.         XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  797.         XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  798.         XtSetArg (args[n], XmNleftPosition, 13); n++;
  799.         XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
  800.         XtSetArg (args[n], XmNrightPosition, 16); n++;
  801.         w = XmCreatePushButton (ctl_w, "Close", args, n);
  802.         XtAddCallback (w, XmNactivateCallback, plt_da_close_cb, daform_w);
  803.         XtManageChild (w);
  804.     
  805.     /* go. the expose will do the actual plotting */
  806.     XtManageChild (daform_w);
  807. }
  808.  
  809. /* called when finished with a plot with its FormDialog widget.
  810.  * reclaim all memory in the userData DrawInfo and destroy it.
  811.  * N.B. caller's daform_w is useless when this returns.
  812.  */
  813. static void
  814. plt_da_destroy (daform_w)
  815. Widget daform_w;
  816. {
  817.     DrawInfo *di;
  818.  
  819.     get_something (daform_w, XmNuserData, (char *)&di);
  820.     (void) fclose (di->fp);
  821.     XtFree(di->filename);
  822.     XtFree((char *)di);
  823.     XtDestroyWidget(daform_w);
  824. }
  825.  
  826. /* called when a plot dialog is mapped.
  827.  * set the height equal to the width.
  828.  */
  829. /* ARGSUSED */
  830. static void
  831. plt_daform_map_cb (w, client, call)
  832. Widget w;
  833. XtPointer client;
  834. XtPointer call;
  835. {
  836.     Widget shell_w = XtParent(w);
  837.     Dimension width;
  838.     int iwidth;
  839.  
  840.     get_something (shell_w, XmNwidth, (char *)&width);
  841.     iwidth = width;
  842.     set_something (shell_w, XmNheight, (char *)iwidth);
  843. }
  844.  
  845.  
  846. /* called when the Close button is pushed on a plot.
  847.  * free the DrawInfo and destroy the dialog (passed as client).
  848.  */
  849. /* ARGSUSED */
  850. static void
  851. plt_da_close_cb (w, client, call)
  852. Widget w;
  853. XtPointer client;
  854. XtPointer call;
  855. {
  856.     plt_da_destroy ((Widget)client);
  857. }
  858.  
  859. /* callback from the Flip X toggle button within the drawing FormDiag itself.
  860.  * toggle the x bit in the parent's DrawInfo structure and fake an expose.
  861.  * client is the DrawingArea widget.
  862.  */
  863. /* ARGSUSED */
  864. static void
  865. plt_da_flipx_cb (w, client, call)
  866. Widget w;
  867. XtPointer client;
  868. XtPointer call;
  869. {
  870.     XmToggleButtonCallbackStruct *t = (XmToggleButtonCallbackStruct *) call;
  871.     Widget da_w = (Widget) client;
  872.     Widget daform_w = XtParent(da_w);
  873.     Display *dsp = XtDisplay(da_w);
  874.     Window win = XtWindow(da_w);
  875.     DrawInfo *di;
  876.     XExposeEvent ev;
  877.     Window root;
  878.     int x, y;
  879.     unsigned int nx, ny, bw, d;
  880.  
  881.     get_something (daform_w, XmNuserData, (char *)&di);
  882.     di->flipx = t->set;
  883.  
  884.     XGetGeometry(dsp, win, &root, &x, &y, &nx, &ny, &bw, &d);
  885.  
  886.     ev.type = Expose;
  887.     ev.send_event = 1;    /* gets set anyways */
  888.     ev.display = dsp;
  889.     ev.window = win;
  890.     ev.x = ev.y = 0;
  891.     ev.width = nx;
  892.     ev.height = ny;
  893.     ev.count = 0;
  894.  
  895.     XSendEvent (dsp, win, /*propagate*/False, ExposureMask, (XEvent *)&ev);
  896. }
  897.  
  898. /* callback from the Flip Y toggle button within the drawing FormDiag itself.
  899.  * toggle the y bit in the parent's DrawInfo structure and fake an expose.
  900.  * client is the DrawingArea widget.
  901.  */
  902. /* ARGSUSED */
  903. static void
  904. plt_da_flipy_cb (w, client, call)
  905. Widget w;
  906. XtPointer client;
  907. XtPointer call;
  908. {
  909.     XmToggleButtonCallbackStruct *t = (XmToggleButtonCallbackStruct *) call;
  910.     Widget da_w = (Widget) client;
  911.     Widget daform_w = XtParent(da_w);
  912.     Display *dsp = XtDisplay(da_w);
  913.     Window win = XtWindow(da_w);
  914.     DrawInfo *di;
  915.     XExposeEvent ev;
  916.     Window root;
  917.     int x, y;
  918.     unsigned int nx, ny, bw, d;
  919.  
  920.     get_something (daform_w, XmNuserData, (char *)&di);
  921.     di->flipy = t->set;
  922.  
  923.     XGetGeometry(dsp, win, &root, &x, &y, &nx, &ny, &bw, &d);
  924.  
  925.     ev.type = Expose;
  926.     ev.send_event = 1;    /* gets set anyways */
  927.     ev.display = dsp;
  928.     ev.window = win;
  929.     ev.x = ev.y = 0;
  930.     ev.width = nx;
  931.     ev.height = ny;
  932.     ev.count = 0;
  933.  
  934.     XSendEvent (dsp, win, /*propagate*/False, ExposureMask, (XEvent *)&ev);
  935. }
  936.  
  937. /* callback from the grid toggle button within the drawing FormDiag itself.
  938.  * toggle the grid flag in the parent's DrawInfo structure and fake an expose.
  939.  * client is the DrawingArea widget.
  940.  */
  941. /* ARGSUSED */
  942. static void
  943. plt_da_grid_cb (w, client, call)
  944. Widget w;
  945. XtPointer client;
  946. XtPointer call;
  947. {
  948.     XmToggleButtonCallbackStruct *t = (XmToggleButtonCallbackStruct *) call;
  949.     Widget da_w = (Widget) client;
  950.     Widget daform_w = XtParent(da_w);
  951.     Display *dsp = XtDisplay(da_w);
  952.     Window win = XtWindow(da_w);
  953.     DrawInfo *di;
  954.     XExposeEvent ev;
  955.     Window root;
  956.     int x, y;
  957.     unsigned int nx, ny, bw, d;
  958.  
  959.     get_something (daform_w, XmNuserData, (char *)&di);
  960.     di->grid = t->set;
  961.  
  962.     XGetGeometry(dsp, win, &root, &x, &y, &nx, &ny, &bw, &d);
  963.  
  964.     ev.type = Expose;
  965.     ev.send_event = 1;    /* gets set anyways */
  966.     ev.display = dsp;
  967.     ev.window = win;
  968.     ev.x = ev.y = 0;
  969.     ev.width = nx;
  970.     ev.height = ny;
  971.     ev.count = 0;
  972.  
  973.     XSendEvent (dsp, win, /*propagate*/False, ExposureMask, (XEvent *)&ev);
  974. }
  975.  
  976. /* plot drawing area's expose callback.
  977.  * redraw the graph to the (new?) size.
  978.  * get a DrawInfo from our parent's userData.
  979.  */
  980. /* ARGSUSED */
  981. static void
  982. plt_da_exp_cb (da_w, client, call)
  983. Widget da_w;
  984. XtPointer client;
  985. XtPointer call;
  986. {
  987.     XmDrawingAreaCallbackStruct *c = (XmDrawingAreaCallbackStruct *)call;
  988.     DrawInfo *di;
  989.     Widget daform_w;
  990.     XWindowAttributes xwa;
  991.  
  992.     switch (c->reason) {
  993.     case XmCR_EXPOSE: {
  994.         /* turn off gravity so we get expose events for either shrink or
  995.          * expand if we have never seen this window before.
  996.          */
  997.         XExposeEvent *e = &c->event->xexpose;
  998.  
  999.         /* wait for the last in the series */
  1000.         if (e->count != 0)
  1001.         return;
  1002.  
  1003.         XGetWindowAttributes (e->display, e->window, &xwa);
  1004.         if (xwa.bit_gravity != ForgetGravity) {
  1005.         /* first expose for this window -- set no gravity */
  1006.         XSetWindowAttributes swa;
  1007.         swa.bit_gravity = ForgetGravity;
  1008.         XChangeWindowAttributes (e->display, e->window,
  1009.                                 CWBitGravity, &swa);
  1010.         }
  1011.         break;
  1012.         }
  1013.     default:
  1014.         printf ("Unexpected da_w event. type=%d\n", c->reason);
  1015.         exit(1);
  1016.     }
  1017.  
  1018.     /* use xwa for the drawing area window size.
  1019.      * get di from the FormDiaglog parent and plot fresh.
  1020.      */
  1021.  
  1022.     daform_w = XtParent(da_w);
  1023.     get_something (daform_w, XmNuserData, (char *)&di);
  1024.     XClearWindow (XtDisplay(da_w), XtWindow(da_w));
  1025.     rewind (di->fp);
  1026.     if (plot_cartesian (di->fp, da_w, xwa.width, xwa.height,
  1027.                     di->flipx, di->flipy, di->grid) < 0) {
  1028.         /* had trouble, so done with this FormDialog.
  1029.          */
  1030.         char buf[128];
  1031.         (void) sprintf (buf, "Error plotting `%.*s'\n", sizeof(buf)-20,
  1032.                                 di->filename);
  1033.         xe_msg (buf, 0);
  1034.         plt_da_destroy (daform_w);
  1035.     }
  1036. }
  1037.