home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume19 / xephem / part12 / solsysmenu.c < prev   
Encoding:
C/C++ Source or Header  |  1993-05-15  |  42.0 KB  |  1,474 lines

  1. /* code to manage the stuff on the solar system display.
  2.  * functions and data to support the main display begin with ss_.
  3.  * function and data to support the stereo display begin with st_.
  4.  */
  5.  
  6. #include <stdio.h>
  7. #include <ctype.h>
  8. #include <math.h>
  9. #if defined(__STDC__)
  10. #include <stdlib.h>
  11. #endif
  12. #include <X11/Xlib.h>
  13. #include <Xm/Xm.h>
  14. #include <Xm/Form.h>
  15. #include <Xm/Frame.h>
  16. #include <Xm/DrawingA.h>
  17. #include <Xm/RowColumn.h>
  18. #include <Xm/Label.h>
  19. #include <Xm/PushB.h>
  20. #include <Xm/ToggleB.h>
  21. #include <Xm/Text.h>
  22. #include <Xm/Scale.h>
  23. #include "astro.h"
  24. #include "circum.h"
  25.  
  26. /* heliocentric coordinates, and enough info to locate it on screen */
  27. typedef struct {
  28.     Obj o;        /* copy of Obj at the given moment */
  29.     double smjd;    /* mjd when Obj was valid */
  30.     int sx, sy;        /* main view window coords of object */
  31.     int stx;        /* stereo view x coord (y is the same in both) */
  32.     float x, y, z;    /* heliocentric cartesian coords */
  33. } HLoc;
  34.  
  35. #if defined(__STDC__) || defined(__cplusplus)
  36. #define P_(s) s
  37. #define    Const const
  38. #else
  39. #define P_(s) ()
  40. #define    Const
  41. #endif
  42.  
  43. extern Now *mm_get_now P_((void));
  44. extern Obj *db_basic P_((int id));
  45. extern double mjd_hr P_((double jd));
  46. extern void db_update P_((Obj *op));
  47. extern void f_angle P_((Widget w, double a));
  48. extern void f_date P_((Widget w, double jd));
  49. extern void f_double P_((Widget w, char *fmt, double f));
  50. extern void f_ra P_((Widget w, double ra));
  51. extern void f_string P_((Widget w, char *s));
  52. extern void f_time P_((Widget w, double t));
  53. extern void get_something P_((Widget w, char *resource, char *value));
  54. extern void hlp_dialog P_((char *tag, char *deflt[], int ndeflt));
  55. extern void obj_pickgc P_((Obj *op, Widget w, GC *gcp));
  56. extern void set_something P_((Widget w, char *resource, char *value));
  57. extern void set_xmstring P_((Widget w, char *resource, char *txt));
  58. extern void timestamp P_((Now *np, Widget w));
  59.  
  60. void ss_manage P_((void));
  61. void ss_newobj P_((int dbidx));
  62. int ss_ison P_((void));
  63. void ss_update P_((Now *np, int how_much));
  64. void ss_cursor P_((Cursor c));
  65. static void ss_create_form P_((void));
  66. static void st_create_form P_((void));
  67. static Widget ss_create_pot P_((Widget form_w, Widget bot_w));
  68. static void ss_activate_cb P_((Widget w, XtPointer client, XtPointer call));
  69. static void ss_obj_cb P_((Widget w, XtPointer client, XtPointer call));
  70. static void ss_changed_cb P_((Widget w, XtPointer client, XtPointer call));
  71. static void ss_close_cb P_((Widget w, XtPointer client, XtPointer call));
  72. static void ss_help_cb P_((Widget w, XtPointer client, XtPointer call));
  73. static void ss_da_exp_cb P_((Widget w, XtPointer client, XtPointer call));
  74. static void ss_da_input_cb P_((Widget w, XtPointer client, XtPointer call));
  75. static void st_parallax_cb P_((Widget w, XtPointer client, XtPointer call));
  76. static void st_map_cb P_((Widget wid, XtPointer client, XtPointer call));
  77. static void st_da_exp_cb P_((Widget w, XtPointer client, XtPointer call));
  78. static void st_da_input_cb P_((Widget w, XtPointer client, XtPointer call));
  79. static void ss_popup P_((XEvent *ev, HLoc *lp));
  80. static void ss_create_popup P_((void));
  81. static int cmpHLoc P_((Const void *lp1, Const void *lp2));
  82. static void ss_all P_((int preclr));
  83. static void solar_system P_((HLoc *lp, double scale, double elt, double elg, unsigned nx, unsigned ny));
  84.  
  85. #undef P_
  86.  
  87. extern Widget toplevel_w;
  88. #define    XtD    XtDisplay(toplevel_w)
  89.  
  90. static Widget ssform_w;        /* main solar system form dialog */
  91. static Widget hr_w, hlng_w, hlat_w; /* scales for heliocentric R, long, lat */
  92. static Widget ssda_w;        /* solar system drawring area */
  93. static Widget dt_w;        /* date/time stamp label widget */
  94.  
  95. static Widget stform_w;        /* main stereo form dialog */
  96. static Widget parallax_w;    /* scale to set amount of parallax */
  97. static Widget stda_w;        /* stereo solar system drawring area */
  98.  
  99. enum {TRAILS, BIGDOTS, CONNECT, TAGS, STEREO};    /* toggle button ids */
  100.  
  101. #define    MINMAG    3.0    /* minimum mag factor, pixels/AU */
  102. #define    MAXMAG    250.0    /* maximum mag factor, pixels/AU */
  103.  
  104. /* whether each option is currently on */
  105. static int trails;
  106. static int bigdots;
  107. static int connectdots;
  108. static int nametags;
  109. static int stereo;
  110.  
  111. /* current value of desired parallax */
  112. static int parallax;
  113.  
  114. static HLoc *points[NOBJ];    /* malloc'd set of points on screen now */
  115. static int npoints[NOBJ];    /* number of points */
  116.  
  117. static char obj_on[NOBJ];    /* 1 of object is on */
  118. static Widget obj_w[NOBJ];    /* toggle buttons for each object */
  119.  
  120. /* info about the popup widget */
  121. typedef struct {
  122.     Widget pu_w;
  123.     Widget name_w;
  124.     Widget ud_w, udl_w;
  125.     Widget ut_w, utl_w;
  126.     Widget ra_w, ral_w;
  127.     Widget dec_w, decl_w;
  128.     Widget hlong_w, hlongl_w;
  129.     Widget hlat_w, hlatl_w;
  130.     Widget eadst_w, eadstl_w;
  131.     Widget sndst_w, sndstl_w;
  132.     Widget elong_w, elongl_w;
  133. } Popup;
  134. static Popup pu;
  135.  
  136. static char earthname[] = "Earth";
  137.  
  138. /* called when the solar system view is activated via the main menu pulldown.
  139.  * if never called before, create and manage all the widgets as a child of a
  140.  * form. otherwise, just toggle whether the form is managed.
  141.  */
  142. void
  143. ss_manage ()
  144. {
  145.     if (!ssform_w) {
  146.         ss_create_form();
  147.         ss_create_popup();
  148.         st_create_form();
  149.     }
  150.     
  151.     if (XtIsManaged(ssform_w)) {
  152.         if (XtIsManaged(stform_w))
  153.         XtUnmanageChild(stform_w);
  154.         XtUnmanageChild (ssform_w);
  155.     } else {
  156.         XtManageChild (ssform_w);
  157.         if (stereo)
  158.         XtManageChild (stform_w);
  159.     }
  160. }
  161.  
  162. /* called when one of the user defined objects has changed.
  163.  * discard the points for that object.
  164.  * if the object is now defined in the SS manage the toggle button.
  165.  * N.B. no need to rebuild the scene -- ss_update() will be called for us.
  166.  */
  167. void
  168. ss_newobj (dbidx)
  169. int dbidx;
  170. {
  171.     static char me[] = "ss_newobj()";
  172.     Obj *op;
  173.  
  174.     /* we might get called before we are ever brought up the first time */
  175.     if (!ssform_w)
  176.         return;
  177.  
  178.     if (dbidx >= NOBJ) {
  179.         printf ("%s: dbidx=%d but NOBJ=%d\n", me, dbidx, NOBJ);
  180.         exit (1);
  181.     }
  182.  
  183.     if (points[dbidx])
  184.         XtFree ((char *)points[dbidx]);
  185.     points[dbidx] = NULL;
  186.     npoints[dbidx] = 0;
  187.  
  188.     op = db_basic(dbidx);
  189.     switch (op->type) {
  190.     case ELLIPTICAL: case HYPERBOLIC: case PARABOLIC:
  191.         XtManageChild (obj_w[dbidx]);
  192.         XmToggleButtonSetState (obj_w[dbidx], True, False);
  193.         set_xmstring (obj_w[dbidx], XmNlabelString, op->o_name);
  194.         obj_on[dbidx] = 1;
  195.         break;
  196.     default:
  197.         XtUnmanageChild (obj_w[dbidx]);
  198.         XmToggleButtonSetState (obj_w[dbidx], False, False);
  199.         obj_on[dbidx] = 0;
  200.         break;
  201.     }
  202.         
  203. }
  204.  
  205. ss_ison()
  206. {
  207.     return (ssform_w && XtIsManaged(ssform_w));
  208. }
  209.  
  210. /* called when we are to update our view.
  211.  * don't bother if we are unmanaged unless trails is on - in that case,
  212.  * compute the new locations but don't display them.
  213.  */
  214. /* ARGSUSED */
  215. void
  216. ss_update (np, how_much)
  217. Now *np;
  218. int how_much;
  219. {
  220.     HLoc *lp;
  221.     int up;
  222.     int dbidx;
  223.  
  224.     up = ssform_w && XtIsManaged(ssform_w);
  225.     if (!up && !trails)
  226.         return;
  227.  
  228.     /* tag earth's data (from SUN object) as object MOON */
  229.     for (dbidx = 0; dbidx < NOBJ; dbidx++) {
  230.         Obj *op;
  231.         double sd;
  232.         int inss;
  233.  
  234.         /* see if object is still a solar system object */
  235.         op = db_basic(dbidx);
  236.         switch (op->type) {
  237.         case PLANET: case ELLIPTICAL: case HYPERBOLIC: case PARABOLIC:
  238.         inss = 1;
  239.         break;
  240.         default:
  241.         inss = 0;
  242.         break;
  243.         }
  244.  
  245.         /* discard previous set if not leaving trails or obj no longer 
  246.          * in solar system.
  247.          */
  248.         if (!inss || !trails) {
  249.         if (points[dbidx])
  250.             XtFree ((char*)points[dbidx]);
  251.         points[dbidx] = NULL;
  252.         npoints[dbidx] = 0;
  253.         }
  254.  
  255.         if (!inss)
  256.         continue;
  257.  
  258.         /* just one SUN will do */
  259.         if (dbidx == SUN && npoints[SUN] > 0)
  260.         continue;
  261.  
  262.         npoints[dbidx]++;
  263.         points[dbidx] = (HLoc *) XtRealloc ((char *)points[dbidx],
  264.                         npoints[dbidx]*sizeof(HLoc));
  265.         lp = &points[dbidx][npoints[dbidx]-1];
  266.         if (dbidx == MOON) {
  267.         /* really want earth info here; get it from SUN */
  268.         op = db_basic (SUN);
  269.         db_update(op);
  270.         sd = op->s_edist;
  271.         } else {
  272.         sd = op->s_sdist;
  273.         }
  274.         lp->x = sd*cos(op->s_hlat)*cos(op->s_hlong);
  275.         lp->y = sd*cos(op->s_hlat)*sin(op->s_hlong);
  276.         lp->z = sd*sin(op->s_hlat);
  277.         lp->o = *op;
  278.         if (dbidx == MOON)
  279.         lp->o.pl.code = MOON;
  280.         lp->smjd = mjd;
  281.  
  282.         /* keep points array sorted in increasing time order */
  283.         qsort ((char *)points[dbidx], npoints[dbidx], sizeof(HLoc),
  284.                                     cmpHLoc);
  285.     }
  286.  
  287.     if (up) {
  288.         ss_all(!trails);
  289.         timestamp (np, dt_w);
  290.     }
  291.         
  292. }
  293.  
  294. /* called to put up or remove the watch cursor.  */
  295. void
  296. ss_cursor (c)
  297. Cursor c;
  298. {
  299.     Window win;
  300.  
  301.     if (ssform_w && (win = XtWindow(ssform_w))) {
  302.         Display *dsp = XtDisplay(ssform_w);
  303.         if (c)
  304.         XDefineCursor (dsp, win, c);
  305.         else
  306.         XUndefineCursor (dsp, win);
  307.     }
  308. }
  309.  
  310. /* create the main solarsystem form */
  311. static void
  312. ss_create_form()
  313. {
  314.     Widget close_w;
  315.     Widget stereo_w;
  316.     Widget trails_w;
  317.     Widget frame_w;
  318.     Widget form_w;
  319.     Widget fr_w;
  320.     Widget help_w;
  321.     Widget big_w;
  322.     Widget con_w;
  323.     Widget tags_w;
  324.     Widget pot_w;
  325.     XmString str;
  326.     Arg args[20];
  327.     int n;
  328.  
  329.     /* create form */
  330.     n = 0;
  331.     XtSetArg (args[n], XmNautoUnmanage, False); n++;
  332.     XtSetArg (args[n], XmNdefaultPosition, False); n++;
  333.     XtSetArg (args[n], XmNresizePolicy, XmRESIZE_NONE); n++;
  334.     ssform_w = XmCreateFormDialog (toplevel_w, "SolarSystem", args, n);
  335.  
  336.     /* set some stuff in the parent DialogShell.
  337.      * setting XmNdialogTitle in the Form didn't work..
  338.      */
  339.     n = 0;
  340.     XtSetArg (args[n], XmNtitle, "xephem Solar System"); n++;
  341.     XtSetValues (XtParent(ssform_w), args, n);
  342.  
  343.     /* make a form for the bottom controls */
  344.  
  345.     n = 0;
  346.     XtSetArg (args[n], XmNfractionBase, 13); n++;
  347.     XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  348.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  349.     XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  350.     form_w = XmCreateForm (ssform_w, "CtlForm", args, n);
  351.     XtManageChild (form_w);
  352.  
  353.         /* make the "close" push button */
  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, 1); n++;
  360.         XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
  361.         XtSetArg (args[n], XmNrightPosition, 4); n++;
  362.         close_w = XmCreatePushButton (form_w, "Close", args, n);
  363.         XtAddCallback (close_w, XmNactivateCallback, ss_close_cb, 0);
  364.         XtManageChild (close_w);
  365.  
  366.         /* make the "stereo" toggle button in a frame */
  367.  
  368.         n = 0;
  369.         XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  370.         XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  371.         XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  372.         XtSetArg (args[n], XmNleftPosition, 5); n++;
  373.         XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
  374.         XtSetArg (args[n], XmNrightPosition, 8); n++;
  375.         fr_w = XmCreateFrame (form_w, "StereoFrame", args, n);
  376.         XtManageChild (fr_w);
  377.         stereo_w = XmCreateToggleButton (fr_w, "Stereo", args, n);
  378.         XtAddCallback (stereo_w, XmNvalueChangedCallback, ss_activate_cb, 
  379.                                 (XtPointer)STEREO);
  380.         XtManageChild (stereo_w);
  381.         stereo = XmToggleButtonGetState (stereo_w);
  382.  
  383.         /* make the "help" push button */
  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, 9); n++;
  390.         XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
  391.         XtSetArg (args[n], XmNrightPosition, 12); n++;
  392.         help_w = XmCreatePushButton (form_w, "Help", args, n);
  393.         XtAddCallback (help_w, XmNactivateCallback, ss_help_cb, 0);
  394.         XtManageChild (help_w);
  395.  
  396.     /* make the planet on/off table */
  397.  
  398.     pot_w = ss_create_pot(ssform_w, form_w);
  399.     XtManageChild (pot_w);
  400.  
  401.     /* make the "big dots" toggle button */
  402.  
  403.     str = XmStringCreate("Big dots", XmSTRING_DEFAULT_CHARSET);
  404.     n = 0;
  405.     XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
  406.     XtSetArg (args[n], XmNbottomWidget, pot_w); n++;
  407.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  408.     XtSetArg (args[n], XmNlabelString, str); n++;
  409.     big_w = XmCreateToggleButton(ssform_w, "BigDots", args, n);
  410.     XmStringFree (str);
  411.     XtManageChild (big_w);
  412.     bigdots = XmToggleButtonGetState (big_w);
  413.     XtAddCallback(big_w, XmNvalueChangedCallback, ss_activate_cb,
  414.                             (XtPointer)BIGDOTS);
  415.  
  416.     /* make the "connect" toggle button */
  417.  
  418.     str = XmStringCreate("Connect dots", XmSTRING_DEFAULT_CHARSET);
  419.     n = 0;
  420.     XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
  421.     XtSetArg (args[n], XmNbottomWidget, big_w); n++;
  422.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  423.     XtSetArg (args[n], XmNlabelString, str); n++;
  424.     con_w = XmCreateToggleButton(ssform_w, "ConnectDots", args, n);
  425.     XmStringFree (str);
  426.     XtManageChild (con_w);
  427.     connectdots = XmToggleButtonGetState (con_w);
  428.     XtAddCallback(con_w, XmNvalueChangedCallback, ss_activate_cb,
  429.                                 (XtPointer)CONNECT);
  430.  
  431.     /* make the "leave trails" toggle button */
  432.  
  433.     str = XmStringCreate("Leave trails", XmSTRING_DEFAULT_CHARSET);
  434.     n = 0;
  435.     XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
  436.     XtSetArg (args[n], XmNbottomWidget, pot_w); n++;
  437.     XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  438.     XtSetArg (args[n], XmNlabelString, str); n++;
  439.     trails_w = XmCreateToggleButton(ssform_w, "Trails", args, n);
  440.     XmStringFree (str);
  441.     XtManageChild (trails_w);
  442.     trails = XmToggleButtonGetState (trails_w);
  443.     XtAddCallback(trails_w, XmNvalueChangedCallback, ss_activate_cb,
  444.                                 (XtPointer)TRAILS);
  445.  
  446.     /* make the "tags" toggle button */
  447.  
  448.     str = XmStringCreate("Names", XmSTRING_DEFAULT_CHARSET);
  449.     n = 0;
  450.     XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
  451.     XtSetArg (args[n], XmNbottomWidget, trails_w); n++;
  452.     XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  453.     XtSetArg (args[n], XmNlabelString, str); n++;
  454.     tags_w = XmCreateToggleButton(ssform_w, "Names", args, n);
  455.     XmStringFree (str);
  456.     XtManageChild (tags_w);
  457.     nametags = XmToggleButtonGetState (tags_w);
  458.     XtAddCallback(tags_w, XmNvalueChangedCallback, ss_activate_cb,
  459.                                 (XtPointer)TAGS);
  460.  
  461.     /* make the time/date stamp label */
  462.  
  463.     n = 0;
  464.     XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  465.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  466.     XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
  467.     XtSetArg (args[n], XmNbottomWidget, con_w); n++;
  468.     XtSetArg (args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
  469.     dt_w = XmCreateLabel (ssform_w, "DateStamp", args, n);
  470.     XtManageChild (dt_w);
  471.  
  472.     /* make the bottom scale */
  473.  
  474.     n = 0;
  475.     XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  476.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  477.     XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
  478.     XtSetArg (args[n], XmNbottomWidget, dt_w); n++;
  479.     XtSetArg (args[n], XmNmaximum, 359); n++;
  480.     XtSetArg (args[n], XmNminimum, 0); n++;
  481.     XtSetArg (args[n], XmNscaleMultiple, 1); n++;
  482.     XtSetArg (args[n], XmNorientation, XmHORIZONTAL); n++;
  483.     XtSetArg (args[n], XmNprocessingDirection, XmMAX_ON_RIGHT); n++;
  484.     XtSetArg (args[n], XmNshowValue, True); n++;
  485.     hlng_w = XmCreateScale (ssform_w, "HLongScale", args, n);
  486.     XtAddCallback (hlng_w, XmNdragCallback, ss_changed_cb, 0);
  487.     XtAddCallback (hlng_w, XmNvalueChangedCallback, ss_changed_cb, 0);
  488.     XtManageChild (hlng_w);
  489.  
  490.     /* make the left scale */
  491.  
  492.     n = 0;
  493.     XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  494.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  495.     XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
  496.     XtSetArg (args[n], XmNbottomWidget, hlng_w); n++;
  497.     XtSetArg (args[n], XmNdecimalPoints, 1); n++;
  498.     XtSetArg (args[n], XmNmaximum, 100); n++;
  499.     XtSetArg (args[n], XmNminimum, 0); n++;
  500.     XtSetArg (args[n], XmNscaleMultiple, 1); n++;
  501.     XtSetArg (args[n], XmNorientation, XmVERTICAL); n++;
  502.     XtSetArg (args[n], XmNprocessingDirection, XmMAX_ON_TOP); n++;
  503.     /* XtSetArg (args[n], XmNshowValue, True); n++; */
  504.     hr_w = XmCreateScale (ssform_w, "DistScale", args, n);
  505.     XtAddCallback (hr_w, XmNdragCallback, ss_changed_cb, 0);
  506.     XtAddCallback (hr_w, XmNvalueChangedCallback, ss_changed_cb, 0);
  507.     XtManageChild (hr_w);
  508.  
  509.     /* make the right scale */
  510.  
  511.     n = 0;
  512.     XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  513.     XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  514.     XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
  515.     XtSetArg (args[n], XmNbottomWidget, hlng_w); n++;
  516.     XtSetArg (args[n], XmNmaximum, 90); n++;
  517.     XtSetArg (args[n], XmNminimum, -90); n++;
  518.     XtSetArg (args[n], XmNscaleMultiple, 1); n++;
  519.     XtSetArg (args[n], XmNprocessingDirection, XmMAX_ON_TOP); n++;
  520.     XtSetArg (args[n], XmNprocessingDirection, XmMAX_ON_TOP); n++;
  521.     XtSetArg (args[n], XmNshowValue, True); n++;
  522.     hlat_w = XmCreateScale (ssform_w, "HLatScale", args, n);
  523.     XtAddCallback (hlat_w, XmNdragCallback, ss_changed_cb, 0);
  524.     XtAddCallback (hlat_w, XmNvalueChangedCallback, ss_changed_cb, 0);
  525.     XtManageChild (hlat_w);
  526.  
  527.     /* make a frame for the drawing area */
  528.  
  529.     n = 0;
  530.     XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  531.     XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
  532.     XtSetArg (args[n], XmNbottomWidget, hlng_w); n++;
  533.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
  534.     XtSetArg (args[n], XmNleftWidget, hr_w); n++;
  535.     XtSetArg (args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
  536.     XtSetArg (args[n], XmNrightWidget, hlat_w); n++;
  537.     XtSetArg (args[n], XmNshadowType, XmSHADOW_ETCHED_OUT); n++;
  538.     frame_w = XmCreateFrame (ssform_w, "SolarFrame", args, n);
  539.     XtManageChild (frame_w);
  540.  
  541.     /* make a drawing area for drawing the solar system */
  542.  
  543.     n = 0;
  544.     ssda_w = XmCreateDrawingArea (frame_w, "SolarDA", args, n);
  545.     XtAddCallback (ssda_w, XmNexposeCallback, ss_da_exp_cb, 0);
  546.     XtAddCallback (ssda_w, XmNinputCallback, ss_da_input_cb, 0);
  547.     XtManageChild (ssda_w);
  548. }
  549.  
  550. /* create the stereo solarsystem form */
  551. static void
  552. st_create_form()
  553. {
  554.     Widget frame_w;
  555.     Arg args[20];
  556.     int n;
  557.  
  558.     /* create form */
  559.     n = 0;
  560.     XtSetArg (args[n], XmNautoUnmanage, False); n++;
  561.     XtSetArg (args[n], XmNdefaultPosition, False); n++;
  562.     XtSetArg (args[n], XmNnoResize, True); n++;    /* user can't resize */
  563.     stform_w = XmCreateFormDialog (toplevel_w, "StereoSolarSystem", args,n);
  564.     XtAddCallback (stform_w, XmNmapCallback, st_map_cb, NULL);
  565.  
  566.     /* set some stuff in the parent DialogShell.
  567.      * setting XmNdialogTitle in the Form didn't work..
  568.      */
  569.     n = 0;
  570.     XtSetArg (args[n], XmNtitle, "xephem Stereo Solar System"); n++;
  571.     XtSetValues (XtParent(stform_w), args, n);
  572.  
  573.     /* make the parallax scale at the bottom */
  574.  
  575.     n = 0;
  576.     XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  577.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  578.     XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  579.     XtSetArg (args[n], XmNmaximum, 10); n++;
  580.     XtSetArg (args[n], XmNminimum, -10); n++;
  581.     XtSetArg (args[n], XmNscaleMultiple, 1); n++;
  582.     XtSetArg (args[n], XmNorientation, XmHORIZONTAL); n++;
  583.     XtSetArg (args[n], XmNprocessingDirection, XmMAX_ON_RIGHT); n++;
  584.     parallax_w = XmCreateScale (stform_w, "Parallax", args, n);
  585.     XtAddCallback (parallax_w, XmNdragCallback, st_parallax_cb, 0);
  586.     XtAddCallback (parallax_w, XmNvalueChangedCallback, st_parallax_cb, 0);
  587.     XtManageChild (parallax_w);
  588.     XmScaleGetValue (parallax_w, ¶llax);
  589.  
  590.     /* make a frame for the drawing area */
  591.  
  592.     n = 0;
  593.     XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  594.     XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
  595.     XtSetArg (args[n], XmNbottomWidget, parallax_w); n++;
  596.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  597.     XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  598.     XtSetArg (args[n], XmNshadowType, XmSHADOW_ETCHED_OUT); n++;
  599.     frame_w = XmCreateFrame (stform_w, "StereoFrame", args, n);
  600.     XtManageChild (frame_w);
  601.  
  602.     /* make a drawing area for drawing the stereo solar system */
  603.  
  604.     n = 0;
  605.     stda_w = XmCreateDrawingArea (frame_w, "StereoDA", args, n);
  606.     XtAddCallback (stda_w, XmNexposeCallback, st_da_exp_cb, 0);
  607.     XtAddCallback (stda_w, XmNinputCallback, st_da_input_cb, 0);
  608.     XtManageChild (stda_w);
  609. }
  610.  
  611. /* create the planet on/off table.
  612.  * don't manage it yet; return the outtermost Widget.
  613.  */
  614. static Widget
  615. ss_create_pot (form_w, bot_w)
  616. Widget form_w;    /* form host */
  617. Widget bot_w;    /* attach our bottom to this one */
  618. {
  619.     Widget frame_w;
  620.     Widget rc_w;
  621.     Arg args[20];
  622.     int n;
  623.     int i;
  624.  
  625.     n = 0;
  626.     XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
  627.     XtSetArg (args[n], XmNbottomWidget, bot_w); n++;
  628.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  629.     XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  630.     frame_w = XmCreateFrame (form_w, "ObjTblF", args, n);
  631.  
  632.     n = 0;
  633.     XtSetArg (args[n], XmNpacking, XmPACK_COLUMN); n++;
  634.     XtSetArg (args[n], XmNnumColumns, 4); n++;
  635.     rc_w = XmCreateRowColumn (frame_w, "ObjTblRC", args, n);
  636.     XtManageChild (rc_w);
  637.  
  638.     /* make the toggle buttons.
  639.      * fill in the names we can now.
  640.      * default the planets to all on.
  641.      */
  642.     for (i = 0; i < NOBJ; i++) {
  643.         Obj *op = db_basic(i);
  644.         n = 0;
  645.         obj_w[i] = XmCreateToggleButton (rc_w, "ObjTB", args, n);
  646.         XtAddCallback (obj_w[i], XmNvalueChangedCallback, ss_obj_cb,
  647.                             (XtPointer)i);
  648.         switch (op->type) {
  649.         case ELLIPTICAL: case PARABOLIC: case HYPERBOLIC: case PLANET:
  650.         set_xmstring (obj_w[i], XmNlabelString,
  651.             is_planet(op,MOON)? earthname : op->o_name);
  652.         XtManageChild (obj_w[i]);
  653.         XmToggleButtonSetState (obj_w[i], True, False);
  654.         break;
  655.         }
  656.         obj_on[i] = XmToggleButtonGetState (obj_w[i]);
  657.     }
  658.  
  659.     return (frame_w);
  660. }
  661.  
  662. /* callback from the control toggle buttons
  663.  */
  664. /* ARGSUSED */
  665. static void
  666. ss_activate_cb (w, client, call)
  667. Widget w;
  668. XtPointer client;
  669. XtPointer call;
  670. {
  671.     int what = (int) client;
  672.  
  673.     switch (what) {
  674.     case TRAILS:
  675.         trails = XmToggleButtonGetState(w);
  676.         break;
  677.     case BIGDOTS:
  678.         bigdots = XmToggleButtonGetState(w);
  679.         ss_all (1);
  680.         break;
  681.     case CONNECT:
  682.         connectdots = XmToggleButtonGetState(w);
  683.         ss_all (1);
  684.         break;
  685.     case TAGS:
  686.         nametags = XmToggleButtonGetState(w);
  687.         ss_all (1);
  688.         break;
  689.     case STEREO:
  690.         stereo = XmToggleButtonGetState(w);
  691.         if (stereo) {
  692.         XtManageChild(stform_w);
  693.         ss_all (1);
  694.         } else
  695.         XtUnmanageChild(stform_w);
  696.         break;
  697.     default:
  698.         printf ("solsysmenu.c: unknown toggle button\n");
  699.         exit(1);
  700.     }
  701. }
  702.  
  703. /* callback from the object on/off toggle buttons.
  704.  * client is the dbidx.
  705.  */
  706. /* ARGSUSED */
  707. static void
  708. ss_obj_cb (w, client, call)
  709. Widget w;
  710. XtPointer client;
  711. XtPointer call;
  712. {
  713.     int who = (int) client;
  714.  
  715.     obj_on[who] = XmToggleButtonGetState(w);
  716.     ss_all(1);
  717. }
  718.  
  719. /* callback when any of the scales change value.
  720.  */
  721. /* ARGSUSED */
  722. static void
  723. ss_changed_cb (w, client, call)
  724. Widget w;
  725. XtPointer client;
  726. XtPointer call;
  727. {
  728.     XmScaleCallbackStruct *sp = (XmScaleCallbackStruct *)call;
  729.  
  730.     if (w != hr_w && w != hlng_w && w != hlat_w) {
  731.         printf ("solsysmenu.c: Unknown scaled callback\n");
  732.         exit(1);
  733.     }
  734.  
  735.     ss_all(1);
  736.  
  737.     /* some of these get a bit lengthy, so discard remaining events.
  738.      * TODO: don't discard pending Expose events
  739.      */
  740.     if (sp->reason == XmCR_DRAG)
  741.         XSync (XtDisplay(w), True);
  742. }
  743.  
  744. /* callback from the Close button.
  745.  */
  746. /* ARGSUSED */
  747. static void
  748. ss_close_cb (w, client, call)
  749. Widget w;
  750. XtPointer client;
  751. XtPointer call;
  752. {
  753.     if (XtIsManaged(stform_w))
  754.         XtUnmanageChild (stform_w);
  755.     XtUnmanageChild (ssform_w);
  756. }
  757.  
  758. /* callback from the Help button.
  759.  */
  760. /* ARGSUSED */
  761. static void
  762. ss_help_cb (w, client, call)
  763. Widget w;
  764. XtPointer client;
  765. XtPointer call;
  766. {
  767.     static char *msg[] = {
  768. "This displays the solar system. The sun is always at the center. The left",
  769. "slider controls your distance from the sun - further up is closer. The",
  770. "bottom slider controls your heliocentric longitude. The right slider controls",
  771. "your heliocentric latitude - your angle above the ecliptic."
  772. };
  773.  
  774.     hlp_dialog ("Solar System View", msg, sizeof(msg)/sizeof(msg[0]));
  775. }
  776.  
  777. /* expose of solar system drawing area.
  778.  */
  779. /* ARGSUSED */
  780. static void
  781. ss_da_exp_cb (w, client, call)
  782. Widget w;
  783. XtPointer client;
  784. XtPointer call;
  785. {
  786.     XmDrawingAreaCallbackStruct *c = (XmDrawingAreaCallbackStruct *)call;
  787.  
  788.     switch (c->reason) {
  789.     case XmCR_EXPOSE: {
  790.         /* turn off gravity so we get expose events for either shrink or
  791.          * expand.
  792.          */
  793.         static before;
  794.         XExposeEvent *e = &c->event->xexpose;
  795.  
  796.         if (!before) {
  797.         XSetWindowAttributes swa;
  798.         swa.bit_gravity = ForgetGravity;
  799.         XChangeWindowAttributes (e->display, e->window,
  800.                                 CWBitGravity, &swa);
  801.         before = 1;
  802.         }
  803.         /* wait for the last in the series */
  804.         if (e->count != 0)
  805.         return;
  806.         break;
  807.         }
  808.     default:
  809.         printf ("Unexpected ssda_w event. type=%d\n", c->reason);
  810.         exit(1);
  811.     }
  812.  
  813.     ss_update (mm_get_now(), 1);
  814. }
  815.  
  816. /* a dot has been picked: find what it is and report it. */
  817. /* ARGSUSED */
  818. static void
  819. ss_da_input_cb (w, client, call)
  820. Widget w;
  821. XtPointer client;
  822. XtPointer call;
  823. {
  824.     XmDrawingAreaCallbackStruct *c = (XmDrawingAreaCallbackStruct *)call;
  825.     XEvent *ev;
  826.     
  827. #define    PICKRANGE    100    /* sqr of dist allowed from pointer */
  828.     int x, y, mind;
  829.     int dbidx;
  830.     HLoc *lp;
  831.     int i;
  832.  
  833.     if (c->reason != XmCR_INPUT)
  834.         return;
  835.     ev = c->event;
  836.     if (ev->xany.type != ButtonPress || ev->xbutton.button != Button3)
  837.         return;
  838.  
  839.     x = ((XButtonPressedEvent *)ev)->x;
  840.     y = ((XButtonPressedEvent *)ev)->y;
  841.  
  842.     lp = NULL;
  843.     for (dbidx = 0; dbidx < NOBJ; dbidx++)
  844.         for (i = 0; i < npoints[dbidx]; i++) {
  845.         int d = (x-points[dbidx][i].sx)*(x-points[dbidx][i].sx) +
  846.                 (y-points[dbidx][i].sy)*(y-points[dbidx][i].sy);
  847.         if (!lp || d < mind) {
  848.             lp = &points[dbidx][i];
  849.             mind = d;
  850.         }
  851.         }
  852.  
  853.     if (lp && mind <= PICKRANGE)
  854.         ss_popup (ev, lp);
  855. }
  856.  
  857. /* ARGSUSED */
  858. static void
  859. st_parallax_cb (w, client, call)
  860. Widget w;
  861. XtPointer client;
  862. XtPointer call;
  863. {
  864.     XmScaleCallbackStruct *sp = (XmScaleCallbackStruct *)call;
  865.  
  866.     XmScaleGetValue (w, ¶llax);
  867.     ss_all (1);
  868.  
  869.     /* some of these get a bit lengthy, so discard remaining events.
  870.      * TODO: don't discard pending Expose events
  871.      */
  872.     if (sp->reason == XmCR_DRAG)
  873.         XSync (XtDisplay(w), True);
  874. }
  875.  
  876. /* called whenever the stereo scene is mapped.
  877.  * we set the size of the DrawingArea the same as the main window's.
  878.  * we also try to position it just to the left, but it doesn't always work :-(
  879.  */
  880. /* ARGSUSED */
  881. static void
  882. st_map_cb (wid, client, call)
  883. Widget wid;
  884. XtPointer client;
  885. XtPointer call;
  886. {
  887.     Dimension w, h;
  888.     Position x, y;
  889.     Arg args[20];
  890.     int n;
  891.  
  892.     n = 0;
  893.     XtSetArg (args[n], XmNwidth, &w); n++;
  894.     XtSetArg (args[n], XmNheight, &h); n++;
  895.     XtGetValues (ssda_w, args, n);
  896.  
  897.     n = 0;
  898.     XtSetArg (args[n], XmNwidth, w); n++;
  899.     XtSetArg (args[n], XmNheight, h); n++;
  900.     XtSetValues (stda_w, args, n);
  901.  
  902.     n = 0;
  903.     XtSetArg (args[n], XmNx, &x); n++;
  904.     XtSetArg (args[n], XmNy, &y); n++;
  905.     XtGetValues (ssform_w, args, n);
  906.  
  907.     n = 0;
  908.     XtSetArg (args[n], XmNx, x-w); n++;
  909.     XtSetArg (args[n], XmNy, y); n++;
  910.     XtSetValues (stform_w, args, n);
  911. }
  912.  
  913. /* expose of stereo solar system drawing area.
  914.  */
  915. /* ARGSUSED */
  916. static void
  917. st_da_exp_cb (w, client, call)
  918. Widget w;
  919. XtPointer client;
  920. XtPointer call;
  921. {
  922.     XmDrawingAreaCallbackStruct *c = (XmDrawingAreaCallbackStruct *)call;
  923.  
  924.     switch (c->reason) {
  925.     case XmCR_EXPOSE: {
  926.         /* turn off gravity so we get expose events for either shrink or
  927.          * expand.
  928.          */
  929.         static before;
  930.         XExposeEvent *e = &c->event->xexpose;
  931.  
  932.         if (!before) {
  933.         XSetWindowAttributes swa;
  934.         swa.bit_gravity = ForgetGravity;
  935.         XChangeWindowAttributes (e->display, e->window,
  936.                                 CWBitGravity, &swa);
  937.         before = 1;
  938.         }
  939.         /* wait for the last in the series */
  940.         if (e->count != 0)
  941.         return;
  942.         break;
  943.         }
  944.     default:
  945.         printf ("Unexpected stda_w event. type=%d\n", c->reason);
  946.         exit(1);
  947.     }
  948.  
  949.     ss_update (mm_get_now(), 1);
  950. }
  951.  
  952. /* a dot has been picked on the stereo map: find what it is and report it. */
  953. /* ARGSUSED */
  954. static void
  955. st_da_input_cb (w, client, call)
  956. Widget w;
  957. XtPointer client;
  958. XtPointer call;
  959. {
  960.     XmDrawingAreaCallbackStruct *c = (XmDrawingAreaCallbackStruct *)call;
  961.     XEvent *ev;
  962.     
  963. #define    PICKRANGE    100    /* sqr of dist allowed from pointer */
  964.     int x, y, mind;
  965.     int dbidx;
  966.     HLoc *lp;
  967.     int i;
  968.  
  969.     if (c->reason != XmCR_INPUT)
  970.         return;
  971.     ev = c->event;
  972.     if (ev->xany.type != ButtonPress || ev->xbutton.button != Button3)
  973.         return;
  974.  
  975.     x = ((XButtonPressedEvent *)ev)->x;
  976.     y = ((XButtonPressedEvent *)ev)->y;
  977.  
  978.     lp = NULL;
  979.     for (dbidx = 0; dbidx < NOBJ; dbidx++)
  980.         for (i = 0; i < npoints[dbidx]; i++) {
  981.         int d = (x-points[dbidx][i].stx)*(x-points[dbidx][i].stx) +
  982.                 (y-points[dbidx][i].sy)*(y-points[dbidx][i].sy);
  983.         if (!lp || d < mind) {
  984.             lp = &points[dbidx][i];
  985.             mind = d;
  986.         }
  987.         }
  988.  
  989.     if (lp && mind <= PICKRANGE)
  990.         ss_popup (ev, lp);
  991. }
  992.  
  993. /* fill in the popup with goodies from lp.
  994.  * display fields the same way they are in main data menu.
  995.  * position the popup as indicated by ev and display it.
  996.  * it goes down by itself.
  997.  */
  998. static void
  999. ss_popup (ev, lp)
  1000. XEvent *ev;
  1001. HLoc *lp;
  1002. {
  1003.     Obj *op = &lp->o;
  1004.     double d;
  1005.  
  1006.     if (is_planet(op, MOON)) {
  1007.         /* MOON is used to denote Earth */
  1008.         f_string (pu.name_w, earthname);
  1009.         XtManageChild (pu.ud_w);
  1010.         XtManageChild (pu.udl_w);
  1011.         XtManageChild (pu.ut_w);
  1012.         XtManageChild (pu.utl_w);
  1013.         XtManageChild (pu.ra_w);
  1014.         XtManageChild (pu.ral_w);
  1015.         set_xmstring (pu.ral_w, XmNlabelString, "Sun RA:");
  1016.         XtManageChild (pu.dec_w);
  1017.         XtManageChild (pu.decl_w);
  1018.         set_xmstring (pu.decl_w, XmNlabelString, "Sun Dec:");
  1019.         XtManageChild (pu.hlong_w);
  1020.         XtManageChild (pu.hlongl_w);
  1021.         XtUnmanageChild (pu.hlat_w);
  1022.         XtUnmanageChild (pu.hlatl_w);
  1023.         XtUnmanageChild (pu.eadst_w);
  1024.         XtUnmanageChild (pu.eadstl_w);
  1025.         XtManageChild (pu.sndst_w);
  1026.         XtManageChild (pu.sndstl_w);
  1027.         XtUnmanageChild (pu.elong_w);
  1028.         XtUnmanageChild (pu.elongl_w);
  1029.         set_something (pu.pu_w, XmNnumColumns, (char *)7);
  1030.     } else {
  1031.         f_string (pu.name_w, op->o_name);
  1032.         if (is_planet (op, SUN)) {
  1033.         XtUnmanageChild (pu.ud_w);
  1034.         XtUnmanageChild (pu.udl_w);
  1035.         XtUnmanageChild (pu.ut_w);
  1036.         XtUnmanageChild (pu.utl_w);
  1037.         XtUnmanageChild (pu.ra_w);
  1038.         XtUnmanageChild (pu.ral_w);
  1039.         XtUnmanageChild (pu.dec_w);
  1040.         XtUnmanageChild (pu.decl_w);
  1041.         XtUnmanageChild (pu.hlong_w);
  1042.         XtUnmanageChild (pu.hlongl_w);
  1043.         XtUnmanageChild (pu.hlat_w);
  1044.         XtUnmanageChild (pu.hlatl_w);
  1045.         XtUnmanageChild (pu.eadst_w);
  1046.         XtUnmanageChild (pu.eadstl_w);
  1047.         XtUnmanageChild (pu.sndst_w);
  1048.         XtUnmanageChild (pu.sndstl_w);
  1049.         XtUnmanageChild (pu.elong_w);
  1050.         XtUnmanageChild (pu.elongl_w);
  1051.         set_something (pu.pu_w, XmNnumColumns, (char *)1);
  1052.         } else {
  1053.         XtManageChild (pu.ud_w);
  1054.         XtManageChild (pu.udl_w);
  1055.         XtManageChild (pu.ut_w);
  1056.         XtManageChild (pu.utl_w);
  1057.         XtManageChild (pu.ra_w);
  1058.         XtManageChild (pu.ral_w);
  1059.         set_xmstring (pu.ral_w, XmNlabelString, "RA:");
  1060.         XtManageChild (pu.dec_w);
  1061.         XtManageChild (pu.decl_w);
  1062.         set_xmstring (pu.decl_w, XmNlabelString, "Dec:");
  1063.         XtManageChild (pu.hlong_w);
  1064.         XtManageChild (pu.hlongl_w);
  1065.         XtManageChild (pu.hlat_w);
  1066.         XtManageChild (pu.hlatl_w);
  1067.         XtManageChild (pu.eadst_w);
  1068.         XtManageChild (pu.eadstl_w);
  1069.         XtManageChild (pu.sndst_w);
  1070.         XtManageChild (pu.sndstl_w);
  1071.         XtManageChild (pu.elong_w);
  1072.         XtManageChild (pu.elongl_w);
  1073.         set_something (pu.pu_w, XmNnumColumns, (char *)10);
  1074.         }
  1075.     }
  1076.  
  1077.     f_date (pu.ud_w, lp->smjd);
  1078.     f_time (pu.ut_w, mjd_hr(lp->smjd));
  1079.     f_ra (pu.ra_w, op->s_ra);
  1080.     f_angle (pu.dec_w, op->s_dec);
  1081.     f_angle (pu.hlong_w, op->s_hlong);
  1082.     f_angle (pu.hlat_w, op->s_hlat);
  1083.  
  1084.     d = op->s_edist;
  1085.     f_double (pu.eadst_w, d >= 9.99995 ? "%6.3f" : "%6.4f", d);
  1086.  
  1087.     d = is_planet(op, MOON) ? op->s_edist
  1088.                 : op->s_sdist;
  1089.     f_double (pu.sndst_w, d >= 9.99995 ? "%6.3f" : "%6.4f", d);
  1090.  
  1091.     f_double (pu.elong_w, "%6.1f", op->s_elong);
  1092.  
  1093.     XmMenuPosition (pu.pu_w, (XButtonPressedEvent *)ev);
  1094.     XtManageChild (pu.pu_w);
  1095. }
  1096.  
  1097. /* create the id popup */
  1098. static void
  1099. ss_create_popup()
  1100. {
  1101.     Arg args[20];
  1102.     Widget w;
  1103.     int n;
  1104.  
  1105.     /* create the outer form */
  1106.     n = 0;
  1107.     XtSetArg (args[n], XmNorientation, XmHORIZONTAL); n++;
  1108.     XtSetArg (args[n], XmNpacking, XmPACK_COLUMN); n++;
  1109.     XtSetArg (args[n], XmNisAligned, False); n++;
  1110.     pu.pu_w = XmCreatePopupMenu (toplevel_w, "SSPopup", args, n);
  1111.  
  1112.     /* create the widgets */
  1113.  
  1114.     /* name */
  1115.     n = 0;
  1116.     XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
  1117.     w = XmCreateLabel (pu.pu_w, "SSPopNameL", args, n);
  1118.     set_xmstring (w, XmNlabelString, "Name:");
  1119.     XtManageChild (w);
  1120.     n = 0;
  1121.     XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
  1122.     pu.name_w = XmCreateLabel (pu.pu_w, "SSPopName", args, n);
  1123.     XtManageChild (pu.name_w);
  1124.  
  1125.     /* UT date */
  1126.     n = 0;
  1127.     XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
  1128.     pu.udl_w = XmCreateLabel (pu.pu_w, "SSPopupUTDateL", args, n);
  1129.     set_xmstring (pu.udl_w, XmNlabelString, "UT Date:");
  1130.     XtManageChild (pu.udl_w);
  1131.     n = 0;
  1132.     XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
  1133.     pu.ud_w = XmCreateLabel (pu.pu_w, "SSPopUTDate", args, n);
  1134.     XtManageChild (pu.ud_w);
  1135.  
  1136.     /* UT time */
  1137.     n = 0;
  1138.     XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
  1139.     pu.utl_w = XmCreateLabel (pu.pu_w, "SSPopupUTTimeL", args, n);
  1140.     set_xmstring (pu.utl_w, XmNlabelString, "UT Time:");
  1141.     XtManageChild (pu.utl_w);
  1142.     n = 0;
  1143.     XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
  1144.     pu.ut_w = XmCreateLabel (pu.pu_w, "SSPopUTTime", args, n);
  1145.     XtManageChild (pu.ut_w);
  1146.  
  1147.     /* ra */
  1148.     n = 0;
  1149.     XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
  1150.     pu.ral_w = XmCreateLabel (pu.pu_w, "SSPopRAL", args, n);
  1151.     XtManageChild (pu.ral_w);
  1152.     n = 0;
  1153.     XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
  1154.     pu.ra_w = XmCreateLabel (pu.pu_w, "SSPopRA", args, n);
  1155.     XtManageChild (pu.ra_w);
  1156.  
  1157.     /* dec */
  1158.     n = 0;
  1159.     XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
  1160.     pu.decl_w = XmCreateLabel (pu.pu_w, "SSPopDecL", args, n);
  1161.     XtManageChild (pu.decl_w);
  1162.     n = 0;
  1163.     XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
  1164.     pu.dec_w = XmCreateLabel (pu.pu_w, "SSPopDec", args, n);
  1165.     XtManageChild (pu.dec_w);
  1166.  
  1167.     /* hlong */
  1168.     n = 0;
  1169.     XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
  1170.     pu.hlongl_w = XmCreateLabel (pu.pu_w, "SSPopupHLongL", args, n);
  1171.     set_xmstring (pu.hlongl_w, XmNlabelString, "HeLong:");
  1172.     XtManageChild (pu.hlongl_w);
  1173.     n = 0;
  1174.     XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
  1175.     pu.hlong_w = XmCreateLabel (pu.pu_w, "SSPopHLong", args, n);
  1176.     XtManageChild (pu.hlong_w);
  1177.  
  1178.     /* hlat */
  1179.     n = 0;
  1180.     XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
  1181.     pu.hlatl_w = XmCreateLabel (pu.pu_w, "SSPopupHLatL", args, n);
  1182.     set_xmstring (pu.hlatl_w, XmNlabelString, "HeLat:");
  1183.     XtManageChild (pu.hlatl_w);
  1184.     n = 0;
  1185.     XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
  1186.     pu.hlat_w = XmCreateLabel (pu.pu_w, "SSPopHLat", args, n);
  1187.     XtManageChild (pu.hlat_w);
  1188.  
  1189.     /* earth dist */
  1190.     n = 0;
  1191.     XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
  1192.     pu.eadstl_w = XmCreateLabel (pu.pu_w, "SSPopupEaDstL", args, n);
  1193.     set_xmstring (pu.eadstl_w, XmNlabelString, "EaDst:");
  1194.     XtManageChild (pu.eadstl_w);
  1195.     n = 0;
  1196.     XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
  1197.     pu.eadst_w = XmCreateLabel (pu.pu_w, "SSPopEaDst", args, n);
  1198.     XtManageChild (pu.eadst_w);
  1199.  
  1200.     /* sun dist */
  1201.     n = 0;
  1202.     XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
  1203.     pu.sndstl_w = XmCreateLabel (pu.pu_w, "SSPopupSnDstL", args, n);
  1204.     set_xmstring (pu.sndstl_w, XmNlabelString, "SnDst:");
  1205.     XtManageChild (pu.sndstl_w);
  1206.     n = 0;
  1207.     XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
  1208.     pu.sndst_w = XmCreateLabel (pu.pu_w, "SSPopSnDst", args, n);
  1209.     XtManageChild (pu.sndst_w);
  1210.  
  1211.     /* elong */
  1212.     n = 0;
  1213.     XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
  1214.     pu.elongl_w = XmCreateLabel (pu.pu_w, "SSPopupElongL", args, n);
  1215.     set_xmstring (pu.elongl_w, XmNlabelString, "Elong:");
  1216.     XtManageChild (pu.elongl_w);
  1217.     n = 0;
  1218.     XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
  1219.     pu.elong_w = XmCreateLabel (pu.pu_w, "SSPopElong", args, n);
  1220.     XtManageChild (pu.elong_w);
  1221. }
  1222.  
  1223. /* sort by time.
  1224.  */
  1225. static int
  1226. cmpHLoc (lp1, lp2)
  1227. Const void *lp1, *lp2;
  1228. {
  1229.     double dt = ((HLoc *)lp1)->smjd - ((HLoc *)lp2)->smjd;
  1230.     return (dt < 0 ? -1 : dt > 0 ? 1 : 0);
  1231. }
  1232.  
  1233. /* draw everything in the points arrays from the current vantage to the
  1234.  * current screen size.
  1235.  * always draw the main window; also the stereo one if it's up.
  1236.  */
  1237. /* ARGSUSED */
  1238. static void
  1239. ss_all(preclr)
  1240. int preclr;
  1241. {
  1242. #define    CACHE_SZ    100    /* collect these many X commands */
  1243. #define    CACHE_PAD    10    /* flush when only this many left */
  1244. #define    CACHE_HWM    (CACHE_SZ - CACHE_PAD)    /* hi water mark */
  1245.     static Pixmap ss_pm;
  1246.     static Pixmap st_pm;
  1247.     static GC ss_bgc;
  1248.     static GC st_bgc;
  1249.     static XFontStruct *ss_fs;
  1250.     static XFontStruct *st_fs;
  1251.     static unsigned ss_last_nx, ss_last_ny;
  1252.     static unsigned st_last_nx, st_last_ny;
  1253.     static int ss_cw;
  1254.     static int st_cw;
  1255.     Display *dsp = XtDisplay(ssda_w);
  1256.     Window ss_win = XtWindow(ssda_w);
  1257.     Window st_win = XtWindow(stda_w);
  1258.     Window root;
  1259.     unsigned int ss_nx, ss_ny;
  1260.     unsigned int st_nx, st_ny;
  1261.     int x, y;
  1262.     unsigned int bw, d;
  1263.     int dbidx;
  1264.     int sv;        /* ScaleValue tmp */
  1265.     double scale;
  1266.     double elt;    /* heliocentric lat of eye, rads */
  1267.     double elg;    /* heliocentric lng of eye, rads */
  1268.     int n;
  1269.  
  1270.     if (!ss_bgc) {
  1271.         XGCValues gcv;
  1272.         unsigned int gcm;
  1273.         gcm = GCForeground;
  1274.         get_something (ssda_w, XmNbackground, (char *)&gcv.foreground);
  1275.         ss_bgc = XCreateGC (dsp, ss_win, gcm, &gcv);
  1276.         ss_fs = XQueryFont (dsp, XGContextFromGC (ss_bgc));
  1277.         ss_cw = ss_fs->max_bounds.width;
  1278.     }
  1279.  
  1280.     if (!st_bgc && stereo) {
  1281.         XGCValues gcv;
  1282.         unsigned int gcm;
  1283.         gcm = GCForeground;
  1284.         get_something (stda_w, XmNbackground, (char *)&gcv.foreground);
  1285.         st_bgc = XCreateGC (dsp, st_win, gcm, &gcv);
  1286.         st_fs = XQueryFont (dsp, XGContextFromGC (st_bgc));
  1287.         st_cw = st_fs->max_bounds.width;
  1288.     }
  1289.  
  1290.     XGetGeometry(dsp, ss_win, &root, &x, &y, &ss_nx, &ss_ny, &bw, &d);
  1291.     if (!ss_pm || ss_nx != ss_last_nx || ss_ny != ss_last_ny) {
  1292.         if (ss_pm)
  1293.         XFreePixmap (dsp, ss_pm);
  1294.         ss_pm = XCreatePixmap (dsp, ss_win, ss_nx, ss_ny, d);
  1295.         ss_last_nx = ss_nx;
  1296.         ss_last_ny = ss_ny;
  1297.     }
  1298.  
  1299.     if (stereo) {
  1300.         XGetGeometry(dsp, st_win, &root, &x, &y, &st_nx, &st_ny, &bw, &d);
  1301.         if (!st_pm || st_nx != st_last_nx || st_ny != st_last_ny) {
  1302.         if (st_pm)
  1303.             XFreePixmap (dsp, st_pm);
  1304.         st_pm = XCreatePixmap (dsp, st_win, st_nx, st_ny, d);
  1305.         st_last_nx = st_nx;
  1306.         st_last_ny = st_ny;
  1307.         }
  1308.     }
  1309.  
  1310.     XFillRectangle (dsp, ss_pm, ss_bgc, 0, 0, ss_nx, ss_ny);
  1311.     if (stereo)
  1312.         XFillRectangle (dsp, st_pm, st_bgc, 0, 0, st_nx, st_ny);
  1313.  
  1314.     XmScaleGetValue (hr_w, &sv);
  1315.     scale = MINMAG * pow (MAXMAG/MINMAG, sv/100.);
  1316.     XmScaleGetValue (hlat_w, &sv);
  1317.     elt = degrad(sv);
  1318.     XmScaleGetValue (hlng_w, &sv);
  1319.     elg = degrad(sv);
  1320.  
  1321.     /* display each point and optionally connect with line segments. */
  1322.     for (dbidx = 0; dbidx < NOBJ; dbidx++) {
  1323.         XPoint ss_xpoints[CACHE_SZ], *ss_xp = ss_xpoints;
  1324.         XPoint st_xpoints[CACHE_SZ], *st_xp = st_xpoints;
  1325.         XSegment ss_xsegments[CACHE_SZ], *ss_xs = ss_xsegments;
  1326.         XSegment st_xsegments[CACHE_SZ], *st_xs = st_xsegments;
  1327.         GC gc;
  1328.         obj_pickgc (db_basic(dbidx), ssda_w, &gc);
  1329.         if (npoints[dbidx] > 0 && obj_on[dbidx]) {
  1330.         HLoc *flp, *lp;
  1331.         flp = points[dbidx];
  1332.         for (lp = flp; lp < flp + npoints[dbidx]; lp++) {
  1333.             solar_system(lp, scale, elt, elg, ss_nx, ss_ny);
  1334.             ss_xp->x = lp->sx;        ss_xp->y = lp->sy;    ss_xp++;
  1335.             if (bigdots) {
  1336.             ss_xp->x = lp->sx+1;    ss_xp->y = lp->sy;    ss_xp++;
  1337.             ss_xp->x = lp->sx;    ss_xp->y = lp->sy+1;    ss_xp++;
  1338.             ss_xp->x = lp->sx+1;    ss_xp->y = lp->sy+1;    ss_xp++;
  1339.             }
  1340.             if (connectdots && lp > flp) {
  1341.             ss_xs->x1 = lp[-1].sx;
  1342.             ss_xs->y1 = lp[-1].sy;
  1343.             ss_xs->x2 = lp->sx;
  1344.             ss_xs->y2 = lp->sy;
  1345.             ss_xs++;
  1346.             }
  1347.             if (stereo) {
  1348.             st_xp->x = lp->stx;    st_xp->y = lp->sy;    st_xp++;
  1349.             if (bigdots) {
  1350.                 st_xp->x = lp->stx+1; st_xp->y = lp->sy;    st_xp++;
  1351.                 st_xp->x = lp->stx;   st_xp->y = lp->sy+1;    st_xp++;
  1352.                 st_xp->x = lp->stx+1; st_xp->y = lp->sy+1;    st_xp++;
  1353.             }
  1354.             if (connectdots && lp > flp) {
  1355.                 st_xs->x1 = lp[-1].stx;
  1356.                 st_xs->y1 = lp[-1].sy;
  1357.                 st_xs->x2 = lp->stx;
  1358.                 st_xs->y2 = lp->sy;
  1359.                 st_xs++;
  1360.             }
  1361.             }
  1362.             if (dbidx == SUN) {
  1363.             XDrawArc (dsp, ss_pm, gc, lp->sx-3, lp->sy-3,
  1364.                                 7, 7, 0, 64*360);
  1365.             if (stereo)
  1366.                 XDrawArc (dsp, st_pm, gc, lp->stx-3, lp->sy-3,
  1367.                                 7, 7, 0, 64*360);
  1368.             }
  1369.             if ((n = ss_xp - ss_xpoints) >= CACHE_HWM) {
  1370.             XDrawPoints (dsp,ss_pm,gc,ss_xpoints,n,CoordModeOrigin);
  1371.             ss_xp = ss_xpoints;
  1372.             }
  1373.             if ((n = st_xp - st_xpoints) >= CACHE_HWM) {
  1374.             XDrawPoints (dsp,st_pm,gc,st_xpoints,n,CoordModeOrigin);
  1375.             st_xp = st_xpoints;
  1376.             }
  1377.             if ((n = ss_xs - ss_xsegments) >= CACHE_HWM) {
  1378.             XDrawSegments (dsp, ss_pm, gc, ss_xsegments, n);
  1379.             ss_xs = ss_xsegments;
  1380.             }
  1381.             if ((n = st_xs - st_xsegments) >= CACHE_HWM) {
  1382.             XDrawSegments (dsp, st_pm, gc, st_xsegments, n);
  1383.             st_xs = st_xsegments;
  1384.             }
  1385.         }
  1386.         if (nametags) {
  1387.             char *name;
  1388.             if (dbidx == MOON)
  1389.             name = earthname;
  1390.             else {
  1391.             Obj *op = db_basic (dbidx);
  1392.             name = op->o_name;
  1393.             }
  1394.             XDrawString (dsp, ss_pm, gc, flp->sx+ss_cw, flp->sy,
  1395.                             name, strlen(name));
  1396.             if (stereo)
  1397.             XDrawString (dsp, st_pm, gc, flp->stx+st_cw, flp->sy,
  1398.                             name, strlen(name));
  1399.         }
  1400.         }
  1401.         if ((n = ss_xp - ss_xpoints) > 0) {
  1402.         XDrawPoints (dsp, ss_pm, gc, ss_xpoints, n, CoordModeOrigin);
  1403.         ss_xp = ss_xpoints;
  1404.         }
  1405.         if ((n = st_xp - st_xpoints) > 0) {
  1406.         XDrawPoints (dsp, st_pm, gc, st_xpoints, n, CoordModeOrigin);
  1407.         st_xp = st_xpoints;
  1408.         }
  1409.         if ((n = ss_xs - ss_xsegments) > 0) {
  1410.         XDrawSegments (dsp, ss_pm, gc, ss_xsegments, n);
  1411.         ss_xs = ss_xsegments;
  1412.         }
  1413.         if ((n = st_xs - st_xsegments) > 0) {
  1414.         XDrawSegments (dsp, st_pm, gc, st_xsegments, n);
  1415.         st_xs = st_xsegments;
  1416.         }
  1417.     }
  1418.  
  1419.     XCopyArea (dsp, ss_pm, ss_win, ss_bgc, 0, 0, ss_nx, ss_ny, 0, 0);
  1420.  
  1421.     if (stereo)
  1422.         XCopyArea (dsp, st_pm, st_win, st_bgc, 0, 0, st_nx, st_ny, 0, 0);
  1423. }
  1424.  
  1425. /* compute location of HLoc in window of size [nx,ny] */
  1426. static void
  1427. solar_system(lp, scale, elt, elg, nx, ny)
  1428. HLoc *lp;
  1429. double scale;    /* mag factor */
  1430. double elt;    /* heliocentric lat of eye, rads */
  1431. double elg;    /* heliocentric lng of eye, rads */
  1432. unsigned nx, ny;/* size of drawing area, in pixels */
  1433. {
  1434.     double x, y, z;    /* progressive transform values... */
  1435.     double xp, yp, zp;
  1436.     double xpp, ypp, zpp;
  1437.     double tmp;
  1438.     double back;
  1439.  
  1440.     /* initial loc of points[i] */
  1441.     x = lp->x;
  1442.     y = lp->y;
  1443.     z = lp->z;
  1444.  
  1445.     /* rotate by -elg about z axis to get to xz plane.
  1446.      * once we rotate up about x to the z axis (next step) that will put
  1447.      * +x to the right and +y up.
  1448.      */
  1449.     tmp = -elg;
  1450.     xp = x*cos(tmp) - y*sin(tmp);
  1451.     yp = x*sin(tmp) + y*cos(tmp);
  1452.     zp = z;
  1453.  
  1454.     /* rotate by -(PI/2-elt) about x axis to get to z axis.
  1455.      * +x right, +y up, +z towards, all in AU.
  1456.      */
  1457.     tmp = -(PI/2-elt);
  1458.     xpp = xp;
  1459.     ypp = yp*cos(tmp) - zp*sin(tmp);
  1460.     zpp = yp*sin(tmp) + zp*cos(tmp);
  1461.  
  1462.     /* now, straight ortho projection */
  1463.     lp->sx = nx/2 + xpp*scale;
  1464.     lp->sy = ny/2 - ypp*scale;
  1465.  
  1466.     /* back is y coord, in AU, behind which there is no parallax.
  1467.      */
  1468.     back = -20.0/scale;
  1469.     if (zpp < back)
  1470.         lp->stx = lp->sx;
  1471.     else
  1472.         lp->stx = lp->sx + parallax*(zpp-back)*(scale/50);
  1473. }
  1474.