home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume19 / xephem / part20 / versionmenu.c < prev   
C/C++ Source or Header  |  1993-05-15  |  15KB  |  528 lines

  1. /* code to manage the stuff on the version display.
  2.  * first thing is our modification history, then code to put up the dialog.
  3.  */
  4.  
  5. /* add a note after each change.
  6.  */
  7.  
  8. /*
  9.  * 2.4b 5/10    changed to using memcpy() instead of struct assign (for Alpha).
  10.  * 2.4a 4/23    changed usage of time() (just needed for DEC's Alpha CPUs)
  11.  * 2.4 4/21     fixed blank jup and sat views (unsigned).
  12.  * 2.3 4/12    add ecliptic option to sky view.
  13.  *     4/15    ephem.db: fix Yale names and improve asteroid a/n accuracy.
  14.  *     4/20    add cursor location tracking to sky view.
  15.  *        add "All labels" to sky view.
  16.  *     4/21    add central cross-hair to Earth subsolar view.
  17.  * 2.2 4/3/93    fixed infinite loop when assigning new objx/y with trails on.
  18.  *        removed erroneous grid lines at some pointing directions.
  19.  *        reinstate neglected nutation correction (!) cir_sky().
  20.  *        just show blanks for sun's SnDst and Phase.
  21.  *        fast buttons for 00:00:00 for UT and "Today" under the calendar.
  22.  *        change Epoch-of-date prompts a bit.
  23.  *        cleaned up type casting and add function prototypes.
  24.  *        fixed bad mix of malloc() with XtFree() in db.c
  25.  *     4/5    use pixmap in skyview for much smoother display.
  26.  *     4/6    fix bug that pops up skyfilt when pop down skyview from main.
  27.  *     4/7    improve conversion from helio period to daily motion.
  28.  *     4/8    all datamenu fields are now fixed-width for more stable sizing.
  29.  * 2.1 3/17/93    fixed bug in reading dates from the database.
  30.  *              main menu fields are fixed-width for more stable size.
  31.  * 2.0 3/15/93    major release
  32.  * 2.0A 2/16/93    2.0 alpha put on export and notice posted to sci.astro.
  33.  * 1.1        update sent to export.lcs.mit.edu
  34.  * 1.0 2/24/92    baseline release to comp.sources.x and export.
  35.  * 0.1 12/13/90 first viable beginnings. main three menus working ok.
  36.  */
  37.  
  38. #include <stdio.h>
  39. #include <ctype.h>
  40. #include <math.h>
  41. #if defined(__STDC__)
  42. #include <stdlib.h>
  43. #endif
  44. #include <X11/Xlib.h>
  45. #include <X11/keysym.h>
  46. #include <Xm/Xm.h>
  47. #include <Xm/Form.h>
  48. #include <Xm/Frame.h>
  49. #include <Xm/DrawingA.h>
  50. #include <Xm/Label.h>
  51. #include <Xm/PushB.h>
  52. #include <Xm/ToggleB.h>
  53. #include <Xm/Text.h>
  54. #include <Xm/Scale.h>
  55. #include "astro.h"
  56. #include "circum.h"
  57. #include "patchlevel.h"
  58.  
  59. #if defined(__STDC__) || defined(__cplusplus)
  60. #define P_(s) s
  61. #else
  62. #define P_(s) ()
  63. #endif
  64.  
  65. extern void set_something P_((Widget w, char *resource, char *value));
  66. extern void get_something P_((Widget w, char *resource, char *value));
  67.  
  68. void version P_((void));
  69. void v_cursor P_((Cursor c));
  70. static void v_makew P_((void));
  71. static void fill_msg P_((Widget w));
  72. static void v_unmap_cb P_((Widget w, XtPointer client, XtPointer call));
  73. static void v_da_exp_cb P_((Widget w, XtPointer client, XtPointer call));
  74. static void v_draw P_((void));
  75. static void v_timer_cb P_((XtPointer client, XtIntervalId *id));
  76. static void drawComet P_((Display *dsp, Window win, GC gc, double ang, int rad, int tlen, int w, int h));
  77. static void drawPlanet P_((Display *dsp, Window win, GC gc, int sx, int sy, int w, int h));
  78. static void v_define_fgc P_((void));
  79.  
  80. #undef P_
  81.  
  82. extern Widget toplevel_w;
  83. extern XtAppContext xe_app;
  84.  
  85. static char *msg[] = {
  86. "xephem - An Interactive Astronomical Ephemeris Program for X",
  87. PATCHLEVEL,
  88. "",
  89. "Copyright (c) 1990,1991,1992,1993 by Elwood Charles Downey",
  90. "",
  91. "Permission is granted to make and distribute copies of this program free of",
  92. "charge, provided the copyright notice and this permission notice are",
  93. "preserved on all copies.  All other rights reserved.  No representation is",
  94. "made about the suitability of this software for any purpose.  It is provided",
  95. "\"as is\" without express or implied warranty, to the extent permitted by",
  96. "applicable law.",
  97. };
  98.  
  99.  
  100. #define    NMSGR    (sizeof(msg)/sizeof(msg[0]))
  101.  
  102. /* generate a random number between min and max, of the same type as the
  103.  * highest type of either.
  104.  */
  105. #define    RAND(min,max)    (((rand() & 0xfff)*((max)-(min))/0xfff) + min)
  106.  
  107. static Widget v_w;
  108. static Widget vda_w;
  109. static XtIntervalId v_timer_id;
  110. static GC v_fgc;
  111. static double rotrate;    /* rotation rate constant - filled on first manage */
  112.  
  113. /* table of circular orbit radii to portray and the last screen coords.
  114.  * the real solar system has planet radii from .3 to 30, but the 100:1 ratio is
  115.  * so large we don't try and include everything.
  116.  */
  117. typedef struct {
  118.     double r;        /* radius, AU */
  119.     double theta;    /* angle */
  120.     int x, y;        /* last X x,y coord drawn */
  121. } Orbit;
  122.  
  123. #define    UNDEFX    (-1)        /* value of x when never drawn yet */
  124. static Orbit orbit[] = {
  125.     {1.6, 0.0, UNDEFX, 0},
  126.     {5.4, 0.0, UNDEFX, 0},
  127.     {10., 0.0, UNDEFX, 0},
  128.     {19., 0.0, UNDEFX, 0},
  129.     {30., 0.0, UNDEFX, 0}
  130. };
  131. #define NORBIT    (sizeof(orbit)/sizeof(orbit[0]))
  132. #define    MAXRAD    (orbit[NORBIT-1].r)    /* N.B.use orbit[] with largest radius*/
  133. #define    MINRAD    (orbit[0].r)    /* N.B. use orbit[] with smallest radius */
  134. #define PR     4        /* radius of planet, pixels */
  135. #define    DT    100        /* pause between screen steps, ms */
  136. #define    NSTARS    100        /* number of background stars to sprinkle in */
  137. #define    DPI    30        /* inner orbit motion per step, degrees*/
  138.  
  139. /* comet state and info */
  140. #define    CMAXPERI 30        /* max comet perihelion, pixels */
  141. #define    CMAXTAIL 50        /* max comet tail length, pixels */
  142. #define    CMINTAIL 3        /* min comet tail length, pixels */
  143. #define    CMAXDELA 20        /* max comet area per step, sqr pixels */
  144. #define    CMINDELA 10        /* min comet area per step, sqr pixels */
  145.  
  146. static double angle;        /* angle ccw from straight right, rads */
  147. static double rotation;        /* whole scene rot, rads */
  148. static int radius;        /* dist from sun, pixels (0 means undefined) */
  149. static int taillen;        /* tail length, pixels */
  150. static int delta_area;        /* change in area per step, sqr pixels */
  151. static int perihelion;        /* min dist from sun, pixels */
  152. static int maxtail;        /* max tail len (ie, tail@peri), pixels */
  153.  
  154. /* called when mainmenu "on Version" help is selected.
  155.  */
  156. void
  157. version()
  158. {
  159.     /* make the version form if this is our first time.
  160.      * also take this opportunity to do things once to init the
  161.      * planet locations and set the rotation rate.
  162.      */
  163.     if (!v_w) {
  164.         int i;
  165.         v_makew();
  166.         for (i = 0; i < NORBIT; i++)
  167.         orbit[i].theta = RAND(0,2*PI);
  168.         rotrate = degrad(DPI)/pow(MINRAD/MAXRAD, -3./2.);
  169.     }
  170.         
  171.     /* toggle whether up now.
  172.      * autoUnmanage can bring back down too.
  173.      */
  174.     if (XtIsManaged(v_w))
  175.         XtUnmanageChild (v_w);
  176.     else
  177.         XtManageChild (v_w);
  178. }
  179.  
  180. /* called to put up or remove the watch cursor.  */
  181. void
  182. v_cursor (c)
  183. Cursor c;
  184. {
  185.     Window win;
  186.  
  187.     if (v_w && (win = XtWindow(v_w))) {
  188.         Display *dsp = XtDisplay(v_w);
  189.         if (c)
  190.         XDefineCursor (dsp, win, c);
  191.         else
  192.         XUndefineCursor (dsp, win);
  193.     }
  194. }
  195.  
  196. /* make the v_w widget.
  197.  */
  198. static void
  199. v_makew()
  200. {
  201.     Widget ok_w;
  202.     Widget frame_w;
  203.     Widget text_w;
  204.     XmString str;
  205.     Arg args[20];
  206.     int n;
  207.  
  208.     /* create form */
  209.     n = 0;
  210.     XtSetArg (args[n], XmNresizePolicy, XmRESIZE_ANY); n++;
  211.     XtSetArg (args[n], XmNautoUnmanage, True); n++;
  212.     XtSetArg (args[n], XmNhorizontalSpacing, 5); n++;
  213.     XtSetArg (args[n], XmNverticalSpacing, 5); n++;
  214.     v_w = XmCreateFormDialog (toplevel_w, "Version", args, n);
  215.     XtAddCallback (v_w, XmNunmapCallback, v_unmap_cb, 0);
  216.  
  217.     /* set some stuff in the parent DialogShell.
  218.      * setting XmNdialogTitle in the Form didn't work..
  219.      */
  220.     n = 0;
  221.     XtSetArg (args[n], XmNtitle, "xephem Version"); n++;
  222.     XtSetValues (XtParent(v_w), args, n);
  223.  
  224.     /* make text widget for the version info */
  225.  
  226.     XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  227.     XtSetArg (args[n], XmNbottomAttachment, XmATTACH_POSITION); n++;
  228.     XtSetArg (args[n], XmNbottomPosition, 50); n++;
  229.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  230.     XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  231.     XtSetArg (args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++;
  232.     XtSetArg (args[n], XmNeditable, False); n++;
  233.     XtSetArg (args[n], XmNcolumns, 80); n++;
  234.     XtSetArg (args[n], XmNrows, NMSGR); n++;
  235.     text_w = XmCreateScrolledText (v_w, "VText", args, n);
  236.     fill_msg (text_w);
  237.     XtManageChild (text_w);
  238.  
  239.     /* make the "Ok" push button */
  240.  
  241.     str = XmStringCreate("Ok", XmSTRING_DEFAULT_CHARSET);
  242.     n = 0;
  243.     XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  244.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  245.     XtSetArg (args[n], XmNshowAsDefault, True); n++;
  246.     XtSetArg (args[n], XmNlabelString, str); n++;
  247.     ok_w = XmCreatePushButton (v_w, "VOk", args, n);
  248.     XtManageChild (ok_w);
  249.     XmStringFree (str);
  250.     set_something (v_w, XmNdefaultButton, (char *)ok_w);
  251.  
  252.     /* make a frame for the drawing area */
  253.  
  254.     n = 0;
  255.     XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  256.     XtSetArg (args[n], XmNtopWidget, XtParent(text_w)); n++;
  257.     XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
  258.     XtSetArg (args[n], XmNbottomWidget, ok_w); n++;
  259.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  260.     XtSetArg (args[n], XmNleftPosition, 20); n++;
  261.     XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
  262.     XtSetArg (args[n], XmNrightPosition, 80); n++;
  263.     XtSetArg (args[n], XmNshadowType, XmSHADOW_ETCHED_OUT); n++;
  264.     frame_w = XmCreateFrame (v_w, "VFrame", args, n);
  265.     XtManageChild (frame_w);
  266.  
  267.     /* make a drawing area for drawing the solar system */
  268.  
  269.     n = 0;
  270.     vda_w = XmCreateDrawingArea (frame_w, "VersionMap", args, n);
  271.     XtAddCallback (vda_w, XmNexposeCallback, v_da_exp_cb, 0);
  272.     XtAddCallback (vda_w, XmNresizeCallback, v_da_exp_cb, 0);
  273.     XtManageChild (vda_w);
  274. }
  275.  
  276. static void
  277. fill_msg (w)
  278. Widget w;
  279. {
  280.     char m[100*NMSGR], *mp = m;
  281.     int i;
  282.  
  283.     /* Generate message to display as one string */
  284.     for (i = 0; i < NMSGR; i++) {
  285.         (void) sprintf (mp, "%*s%s\n", (78 - (int)strlen(msg[i]))/2, "",
  286.                                     msg[i]);
  287.         mp += strlen(mp);
  288.     }
  289.  
  290.     /* remove final \n to avoid extra blank line at end */
  291.     *--mp = '\0';
  292.  
  293.     XmTextSetString (w, m);
  294. }
  295.  
  296. /* version dialog is going away.
  297.  * stop the rotation timer.
  298.  */
  299. /* ARGSUSED */
  300. static void
  301. v_unmap_cb (w, client, call)
  302. Widget w;
  303. XtPointer client;
  304. XtPointer call;
  305. {
  306.     if (v_timer_id) {
  307.         XtRemoveTimeOut (v_timer_id);
  308.         v_timer_id = 0;
  309.     }
  310. }
  311.  
  312. /* expose version drawing area.
  313.  * redraw the scene to the (new?) size.
  314.  */
  315. /* ARGSUSED */
  316. static void
  317. v_da_exp_cb (w, client, call)
  318. Widget w;
  319. XtPointer client;
  320. XtPointer call;
  321. {
  322.     XmDrawingAreaCallbackStruct *c = (XmDrawingAreaCallbackStruct *)call;
  323.  
  324.     switch (c->reason) {
  325.     case XmCR_RESIZE:
  326.         /* seems we can get one resize before the first expose.
  327.          * hence, we don't have a good window to use yet. just let it
  328.          * go; we'll get the expose soon.
  329.          */
  330.         if (!XtWindow(w))
  331.         return;
  332.         break;
  333.     case XmCR_EXPOSE: {
  334.         XExposeEvent *e = &c->event->xexpose;
  335.         /* wait for the last in the series */
  336.         if (e->count != 0)
  337.         return;
  338.         break;
  339.         }
  340.     default:
  341.         printf ("Unexpected v_w event. type=%d\n", c->reason);
  342.         exit(1);
  343.     }
  344.  
  345.     v_draw();
  346. }
  347.  
  348. static void
  349. v_draw()
  350. {
  351.     Display *dsp = XtDisplay(vda_w);
  352.     Window win = XtWindow(vda_w);
  353.     unsigned int w, h;
  354.     Window root;
  355.     int x, y;
  356.     unsigned int bw, d;
  357.     int i;
  358.  
  359.     if (!v_fgc)
  360.         v_define_fgc();
  361.  
  362.     XGetGeometry(dsp, win, &root, &x, &y, &w, &h, &bw, &d);
  363.     XClearWindow (dsp, win);
  364.  
  365.     /* draw the orbit ellipsii and forget last drawn locs */
  366.     for (i = 0; i < NORBIT; i++) {
  367.         int lx, ty;    /* left and top x */
  368.         int nx, ny; /* width and height */
  369.         lx = w/2 - orbit[i].r/MAXRAD*w/2 + 0.5;
  370.         nx = orbit[i].r/MAXRAD*w + 0.5;
  371.         ty = h/2 - orbit[i].r/MAXRAD*h/2 + 0.5;
  372.         ny = orbit[i].r/MAXRAD*h + 0.5;
  373.         XDrawArc (dsp, win, v_fgc, lx, ty, nx-1, ny-1, 0, 360*64);
  374.         orbit[i].x = UNDEFX;
  375.     }
  376.  
  377.     /* forget the comet */
  378.     radius = 0;
  379.  
  380.     /* draw sun at the center */
  381.     drawPlanet (dsp, win, v_fgc, w/2-PR, h/2-PR, 2*PR-1, 2*PR-1);
  382.  
  383.     /* draw some background stars */
  384.     for (i = 0; i < NSTARS; i++) {
  385.         int sx, sy;
  386.         sx = RAND(0,w-1);
  387.         sy = RAND(0,h-1);
  388.         XDrawPoint (dsp, win, v_fgc, sx, sy);
  389.     }
  390.  
  391.     if (!v_timer_id)
  392.         v_timer_cb (0, 0);
  393.  
  394. }
  395.  
  396. /* called whenever the timer goes off.
  397.  * we advance all the planets, draw any that have moved at least a few
  398.  * pixels, and restart a timer.
  399.  */
  400. /* ARGSUSED */
  401. static void
  402. v_timer_cb (client, id)
  403. XtPointer client;
  404. XtIntervalId *id;
  405. {
  406.     Display *dsp = XtDisplay(vda_w);
  407.     Window win = XtWindow(vda_w);
  408.     unsigned int w, h;
  409.     Window root;
  410.     int x, y;
  411.     unsigned int bw, d;
  412.     int i;
  413.  
  414.     XGetGeometry(dsp, win, &root, &x, &y, &w, &h, &bw, &d);
  415.  
  416.     for (i = 0; i < NORBIT; i++) {
  417.         int px, py;    /* planets new center position */
  418.         double f = orbit[i].r/MAXRAD;    /* fraction of largest radius */
  419.         orbit[i].theta += rotrate*pow(f, -3./2.);
  420.         px = w/2 + cos(orbit[i].theta)*w*f/2 + 0.5;
  421.         py = h/2 - sin(orbit[i].theta)*h*f/2 + 0.5;
  422.         if (px != orbit[i].x || py != orbit[i].y) {
  423.         /* erase then redraw at new pos, using the XOR GC */
  424.         if (orbit[i].x != UNDEFX)
  425.             drawPlanet (dsp, win, v_fgc,
  426.                 orbit[i].x-PR, orbit[i].y-PR, 2*PR-1, 2*PR-1);
  427.         drawPlanet (dsp, win, v_fgc, px-PR, py-PR, 2*PR-1, 2*PR-1);
  428.         orbit[i].x = px;
  429.         orbit[i].y = py;
  430.         }
  431.     }
  432.  
  433.     /* erase last comet position.
  434.      * N.B. use radius == 0 to mean the very first loop.
  435.      */
  436.     if (radius != 0)
  437.         drawComet (dsp, win, v_fgc, angle, radius, taillen, w, h);
  438.  
  439.     /* comet is definitely outside scene, set fresh initial conditions.
  440.      */
  441.     if (radius <= 0 || radius > (w+h)/2) {
  442.         radius = (w+h)/2;
  443.         rotation = RAND(0,2*PI);
  444.         perihelion = RAND(PR,CMAXPERI);
  445.         maxtail = RAND(CMINTAIL,CMAXTAIL);
  446.         delta_area = RAND(CMINDELA,CMAXDELA);
  447.         angle = acos(1.0 - 2.0*perihelion/radius) + rotation;
  448. #if 0
  449.         printf ("initial rad=%d rot=%g peri=%d maxt=%d da=%d angle=%g\n",
  450.             radius, rotation, perihelion, maxtail, delta_area, angle);
  451. #endif
  452.     }
  453.  
  454.     /* recompute next step location and draw new comet
  455.      */
  456. #if 0
  457.     printf ("rad=%d rot=%g peri=%d maxt=%d da=%d angle=%g\n",
  458.             radius, rotation, perihelion, maxtail, delta_area, angle);
  459. #endif
  460.     angle += (double)delta_area/(radius*radius);
  461.     radius = 2*perihelion/(1.0 - cos(angle - rotation));
  462.     taillen = (maxtail*perihelion*perihelion)/(radius*radius);
  463.     drawComet (dsp, win, v_fgc, angle, radius, taillen, w, h);
  464.  
  465.     v_timer_id = XtAppAddTimeOut (xe_app, DT, v_timer_cb, 0);
  466. }
  467.  
  468. /* draw the comet
  469.  */
  470. static void
  471. drawComet (dsp, win, gc, ang, rad, tlen, w, h)
  472. Display *dsp;
  473. Window win;
  474. GC gc;
  475. double ang;    /* desired angle ccw from +x, in rads */
  476. int rad;    /* in pixels from center */
  477. int tlen;    /* length of tail, in pixels */
  478. int w, h;    /* window width and height */
  479. {
  480.     double ca, sa;
  481.     int sx, sy;
  482.     int ex, ey;
  483.  
  484.     if (tlen < CMINTAIL)
  485.         tlen = CMINTAIL;
  486.  
  487.     /* angle is made <0 to get ccw rotation with X's y-down coord system */
  488.     ang = -ang;
  489.     ca = cos(ang);
  490.     sa = sin(ang);
  491.  
  492.     sx = w/2 + rad * ca;
  493.     sy = h/2 + rad * sa;
  494.     ex = w/2 + (rad+tlen) * ca;
  495.     ey = h/2 + (rad+tlen) * sa;
  496.  
  497.     XDrawLine (dsp, win, gc, sx, sy, ex, ey);
  498. }
  499.  
  500. /* draw the planet.
  501.  */
  502. static void
  503. drawPlanet (dsp, win, gc, sx, sy, w, h)
  504. Display *dsp;
  505. Window win;
  506. GC gc;
  507. int sx, sy, w, h;
  508. {
  509.     XFillArc (dsp, win, gc, sx, sy, w, h, 0, 360*64);
  510. }
  511.  
  512. static void
  513. v_define_fgc()
  514. {
  515.     Display *dsp = XtDisplay(vda_w);
  516.     Window win = XtWindow(vda_w);
  517.     XGCValues gcv;
  518.     unsigned int gcm;
  519.     Pixel fg, bg;
  520.  
  521.     gcm = GCForeground | GCFunction;
  522.     get_something (vda_w, XmNforeground, (char *)&fg);
  523.     get_something (vda_w, XmNbackground, (char *)&bg);
  524.     gcv.foreground = fg ^ bg;
  525.     gcv.function = GXxor;
  526.     v_fgc = XCreateGC (dsp, win, gcm, &gcv);
  527. }
  528.