mirror of https://github.com/XEphem/XEphem.git
2715 lines
72 KiB
C
2715 lines
72 KiB
C
/* code to manage the stuff on the (permanent) main menu.
|
||
* this is also where the single static Now struct is maintained.
|
||
* the calendar is managed in calmenu.c.
|
||
*/
|
||
|
||
#include <stdio.h>
|
||
#include <ctype.h>
|
||
#include <string.h>
|
||
#include <math.h>
|
||
#include <time.h>
|
||
#include <stdlib.h>
|
||
|
||
#include <X11/Xlib.h>
|
||
#include <Xm/Xm.h>
|
||
#include <Xm/Frame.h>
|
||
#include <Xm/Label.h>
|
||
#include <Xm/PushB.h>
|
||
#include <Xm/Form.h>
|
||
#include <Xm/RowColumn.h>
|
||
#include <Xm/Separator.h>
|
||
#include <Xm/SelectioB.h>
|
||
|
||
#include "xephem.h"
|
||
|
||
/* Category for our widgets in the Save system */
|
||
char maincategory[] = "Main -- Basics";
|
||
|
||
typedef struct {
|
||
char *iname; /* instance name */
|
||
int id; /* see below -- used just as a cross-check */
|
||
int autosav; /* for sr_reg() */
|
||
char *tip; /* tip text */
|
||
char *prompt; /* used when asking for new value or NULL if can't */
|
||
char *label; /* used for the menu label or NULL */
|
||
char *name; /* used when selecting for plotting or NULL if can't */
|
||
char *altp[3]; /* alternate prompts */
|
||
Widget pb_w; /* pushbutton for display and changing/selecting.
|
||
* N.B. but only if id != GAP
|
||
*/
|
||
} Field;
|
||
|
||
#define MAXSITENL 25 /* max site name after abbreviation */
|
||
|
||
static void create_main_form (Widget mainrc);
|
||
static void create_pixmaps (void);
|
||
static void make_prompts (Widget p_w, int pc, char *title, char *tip,
|
||
Field *fp, int nfp);
|
||
static Widget fw (int fid);
|
||
static void mm_step_now (int rev);
|
||
static void mm_set_step_code (char *bp);
|
||
static void mm_set_buttons (int whether);
|
||
static void mm_activate_cb (Widget w, XtPointer client, XtPointer call);
|
||
static void mm_initres (void);
|
||
static void mm_pms (void);
|
||
static void mm_set_alt_prompts (Field *fp);
|
||
static void mm_timer_cb (XtPointer client, XtIntervalId *id);
|
||
static void mm_stop (void);
|
||
static void mm_step_cb (Widget w, XtPointer client, XtPointer call);
|
||
static void mm_go_action (Widget w, XEvent *e, String *args, Cardinal *nargs);
|
||
static void keepnow_cb (Widget w, XtPointer client, XtPointer call);
|
||
static void mm_gostop (int dir);
|
||
static void mm_go (int dir);
|
||
static void print_magdecl (void);
|
||
static void print_tminc (void);
|
||
static void print_updating (void);
|
||
static void print_idle (void);
|
||
static void print_running (int rev);
|
||
static void print_extrunning (void);
|
||
static void print_status (char *s);
|
||
static void print_nstep (void);
|
||
static void print_mspause (void);
|
||
static int chg_fld (char *bp, Field *fp);
|
||
static void prompt_ok_cb (Widget w, XtPointer client, XtPointer call);
|
||
static void prompt (Field *fp);
|
||
static Widget create_prompt_w (Widget *wp);
|
||
static void mm_now (int all);
|
||
static void mm_twilight (void);
|
||
static void mm_newcir (int y);
|
||
static void mm_newcir_cb (XtPointer client, XtIntervalId *id);
|
||
static void ext_fileask (void);
|
||
static int ext_readnext (void);
|
||
static void ext_stop (void);
|
||
static void ext_create_w (void);
|
||
static void ext_ok_cb (Widget w, XtPointer client, XtPointer call);
|
||
static void ext_help_cb (Widget w, XtPointer client, XtPointer call);
|
||
|
||
/* shorthands for fields of a Now structure, now.
|
||
* first undo the ones for a Now pointer from astro.h.
|
||
*/
|
||
#undef mjd
|
||
#undef lat
|
||
#undef lng
|
||
#undef tz
|
||
#undef temp
|
||
#undef pressure
|
||
#undef elev
|
||
#undef dip
|
||
#undef epoch
|
||
#undef tznm
|
||
#undef mjed
|
||
|
||
#define mjd now.n_mjd
|
||
#define lat now.n_lat
|
||
#define lng now.n_lng
|
||
#define tz now.n_tz
|
||
#define temp now.n_temp
|
||
#define pressure now.n_pressure
|
||
#define elev now.n_elev
|
||
#define dip now.n_dip
|
||
#define epoch now.n_epoch
|
||
#define tznm now.n_tznm
|
||
#define mjed mm_mjed(&now)
|
||
|
||
static Now now; /* where when and how, right now */
|
||
static double tminc; /* hrs to inc time each loop (see StepOptions)*/
|
||
static int nstep; /* steps to go before stopping */
|
||
static int mspause; /* msecs to pause between steps */
|
||
static int startnstep; /* nstep at start of 0-pause loop */
|
||
static int newcir = 1; /* new circumstances - don't inc time */
|
||
static int movie; /* true while a movie is running */
|
||
static FILE *ext_fp; /* if set, file to read time/loc from */
|
||
static int autotz; /* whether to use tz_fromsys() each time step */
|
||
static double DeltaT; /* user's specific deltat, unless autodt is on*/
|
||
static int autodt = 1; /* compute delta if on, else use DeltaT. */
|
||
|
||
static XtIntervalId mm_interval_id; /* set while waiting in a pause loop */
|
||
static int mm_selecting; /* set while our fields are being selected */
|
||
|
||
#define NO_PAUSE_DELAY 25 /* min ms delay to use, regardless of mspause */
|
||
#define NC_BLINK_DELAY 200 /* ms between NEW CIRCUMSTANCES state changes */
|
||
#define MANYSTEPS 1000000 /* "many" steps */
|
||
#define MAXPNSTEP 1000 /* max steps for auto showing progress meter */
|
||
#define NOWPAUSE 10000 /* default Pause when staying in sync, ms */
|
||
|
||
/* field ids
|
||
* N.B. must be in same order as they appear in mm_field_map[].
|
||
*/
|
||
typedef enum {
|
||
JD_FID, UD_FID, UT_FID, LST_FID,TZN_FID, TZONE_FID, LD_FID, LT_FID, DT_FID,
|
||
DIP_FID, DAWN_FID, DUSK_FID, LON_FID, LSTM_FID, GAP, STPSZ_FID, NSTEP_FID,
|
||
PAUSE_FID, SITE_FID, LAT_FID, LONG_FID, ELEV_FID, TEMP_FID, PRES_FID,
|
||
EPOCH_FID, MAG_FID
|
||
} FID;
|
||
|
||
/* array of label/button pairs.
|
||
* N.B. these must be in the same order as the _FID enums so the XX_FID may
|
||
* be used as indices into the array.
|
||
* N.B. some of the prompts get set based on preferences or other criteria but
|
||
* we need to put *something* in the prompt field of selectable fields to
|
||
* trigger making a button. See mm_set_alt_prompts().
|
||
* N.B. if add/delete then update mm_field_map[] indices in create_main_form().
|
||
*/
|
||
static char dummy[] = "dummy"; /* placeholder for prompt when several */
|
||
static Field mm_field_map[] = {
|
||
{"JD", JD_FID, 0, "Julian date",
|
||
"Julian Date: ", "Julian:","JD"},
|
||
{"UTCDate", UD_FID, 0, "UTC Date",
|
||
dummy, "UTC Date:","UD",
|
||
{ "UTC date (m/d/y or year.d): ",
|
||
"UTC date (y/m/d or year.d): ",
|
||
"UTC date (d/m/y or year.d): "
|
||
}
|
||
},
|
||
{"UTCTime", UT_FID, 0, "UTC Time",
|
||
"UTC time (h:m:s): ", "UTC Time:", "UT"},
|
||
{"LST", LST_FID, 0, "Local sidereal time",
|
||
"Local sidereal time (h:m:s): ", "Sidereal:", "LST"},
|
||
{"TZName", TZN_FID, 1, "Local timezone name",
|
||
"Fixed Timezone abbreviation:", "TZ Name:", NULL,
|
||
},
|
||
{"TZone", TZONE_FID, 1, "Local hours behind (west of) UTC",
|
||
"Fixed offset behind UTC (h:m:s):", "TZ Offset:", "TZ",
|
||
},
|
||
{"LDate", LD_FID, 0, "Local date",
|
||
dummy, "Local Date:", "LD",
|
||
{ "Local date (m/d/y or year.d): ",
|
||
"Local date (y/m/d or year.d): ",
|
||
"Local date (d/m/y or year.d): "
|
||
}
|
||
},
|
||
{"LTime", LT_FID, 0, "Local time",
|
||
"Local time (h:m:s): ", "Local Time:", "LT"},
|
||
{"DeltaT", DT_FID, 0, "TT - UT1, seconds",
|
||
dummy, "Delta T:", "DeltaT",
|
||
{ "Enter fixed value for TT - UT1, in seconds,\n\
|
||
or press Auto to use model: ",
|
||
"Enter fixed value for TT - UT1, in seconds\n\
|
||
(Automatic model will be turned off): ",
|
||
NULL
|
||
}
|
||
},
|
||
{"TwiDip", DIP_FID, 1, "Sun angle below horizon at edge of twilight",
|
||
"Sun's twilight dip, degrees below", "Sun Dip:", NULL},
|
||
{"DawnT", DAWN_FID, 0, "Time of dawn today",
|
||
NULL, "Dawn:", "Dawn"},
|
||
{"DuskT", DUSK_FID, 0, "Time of dusk today",
|
||
NULL, "Dusk:", "Dusk"},
|
||
{"NightLen", LON_FID, 0, "Hours between dusk and dawn tonight",
|
||
NULL, "Length:", "NiteLen"},
|
||
{"LSTMN", LSTM_FID, 0, "Local Sidereal Time at next local Midnight",
|
||
NULL, "LST@0:","MidnightLST"},
|
||
{NULL, GAP},
|
||
{"StepSz", STPSZ_FID, 0, "Period or event to advance time on next Update",
|
||
"\
|
||
Select one of the above shortcuts\n\
|
||
or enter any time step as follows:\n\
|
||
h m s, or\n\
|
||
<x>d for x days, or\n\
|
||
<x>s for x sidereal days, or\n\
|
||
<x>y for x tropical years", "Step:", NULL},
|
||
{"NSteps", NSTEP_FID, 0, "Number of steps to run on next Update",
|
||
"Number of steps to run: ", "N Steps:", NULL},
|
||
{"Pause", PAUSE_FID, 0, "Seconds to pause after each Update",
|
||
"Seconds to pause between steps: ", "Pause:", NULL},
|
||
{"SiteNm", SITE_FID, 1, "Name of current site.",
|
||
"Search:", NULL, NULL},
|
||
{"Lat", LAT_FID, 1,"Local geographic (geodetic) latitude, degrees, + north",
|
||
"Geographic Latitude (+ north) (d:m:s): ", "Latitude:", "Lat"},
|
||
{"Long", LONG_FID, 1, "Local longitude, degrees, + west",
|
||
"Longitude (+ west) (d:m:s): ", "Longitude:","Long"},
|
||
{"Elev", ELEV_FID, 1, "Local height above sea level",
|
||
dummy, "Elevation:","Elev",
|
||
{ "Elevation above sea level (ft): ",
|
||
"Elevation above sea level (m): "
|
||
}
|
||
},
|
||
{"TempC", TEMP_FID, 1, "Local outdoor air temperature",
|
||
dummy, "Temp:", "Temp",
|
||
{ "Temperature (degrees F): ",
|
||
"Temperature (degrees C): "
|
||
}
|
||
},
|
||
{"Pres", PRES_FID, 1, "Local atmospheric pressure",
|
||
dummy, "Atm Pres:","AtmPr",
|
||
{ "Atmospheric pressure (inches of Mercury):",
|
||
"Atmospheric pressure (hPa):"
|
||
}
|
||
},
|
||
{"Equinox", EPOCH_FID, 1,
|
||
"Precession epoch: EOD for full apparent, fixed year for astrometric",
|
||
"Precession Epoch (decimal year): ", "Equinox:", NULL},
|
||
{"MagDec", MAG_FID, 0,
|
||
"True az = magnetic az + magnetic declination.",
|
||
NULL, "Mag decl:", "MagDec"},
|
||
};
|
||
|
||
#define NFM XtNumber(mm_field_map)
|
||
#define LFM (&mm_field_map[NFM])
|
||
|
||
static Widget newcir_w;
|
||
static Widget status_w;
|
||
static Widget go_w;
|
||
static Widget ext_w;
|
||
static Widget keepnow_w;
|
||
static Widget stepF_w, stepB_w;
|
||
|
||
/* stuff to manage the step control facility.
|
||
* we support a variety of ways time can be incremented.
|
||
* some are fixed but some are variable.
|
||
* the fixed ones set the time change amount in tminc (in hours).
|
||
* the variable ones compute it each iteration and don't use tminc.
|
||
*/
|
||
typedef enum {
|
||
FIXED_SS, STEPDAWN_SS, STEPDUSK_SS, STEPSUNRISE_SS, STEPSUNSET_SS,
|
||
STEPFULLMOON_SS, STEPNEWMOON_SS, RTC_SS, STEPMOONRISE_SS, STEPMOONSET_SS
|
||
} StepCode;
|
||
|
||
typedef struct {
|
||
char *title; /* name of this step option as a string */
|
||
StepCode stepcode; /* one of the StepCodes enum codes */
|
||
double inc; /* if code is FIXED_SS: fixed time step, in hours */
|
||
char *tip; /* quick tip */
|
||
} StepOption;
|
||
/* N.B. leave RT Clock first!! see the RTC_SS_OPTION macro */
|
||
static StepOption step_options[] = {
|
||
{"Clock", RTC_SS, 0.0, "Advance by elapsed time"},
|
||
{"24:00:00", FIXED_SS, 24.0, "Step by 1 day"},
|
||
{" 1:00:00", FIXED_SS, 1.0, "Step by 1 hour"},
|
||
{" 0:05:00", FIXED_SS, 5./60., "Step by 5 minutes"},
|
||
{" 0:01:00", FIXED_SS, 1./60., "Step by 1 minute"},
|
||
{"Dawn", STEPDAWN_SS, 0.0, "Step to next dawn"},
|
||
{"Dusk", STEPDUSK_SS, 0.0, "Step to next dusk"},
|
||
{"Sun rise", STEPSUNRISE_SS, 0.0, "Step to next sun rise"},
|
||
{"Sun set", STEPSUNSET_SS, 0.0, "Step to next sun set"},
|
||
{"Moon rise", STEPMOONRISE_SS, 0.0, "Step to next moon rise"},
|
||
{"Moon set", STEPMOONSET_SS, 0.0, "Step to next moon set"},
|
||
{"Full moon", STEPFULLMOON_SS, 0.0, "Step to next full moon"},
|
||
{"New moon", STEPNEWMOON_SS, 0.0, "Step to next new moon"},
|
||
{"Sidereal Day", FIXED_SS, 24.*SIDRATE, "Step by 1 Earth rotation"},
|
||
{"Sidereal Month", FIXED_SS, 27.3215*24., "Step by 1 Lunar revolution"},
|
||
};
|
||
|
||
/* make a way to refer to the RT clock entry; needed in order to implement
|
||
* remaining compatable with putting "RTC" in resource files for the RT option.
|
||
*/
|
||
#define RTC_SS_OPTION (&step_options[0])
|
||
|
||
/* current step_option.
|
||
* how we init it here determines its default value.
|
||
* if this is 0 it means just use tminc, period.
|
||
*/
|
||
static StepOption *mm_step_option = RTC_SS_OPTION;
|
||
|
||
/* site name, or NULL if none.
|
||
* absitename[] is an abbreviated version for display purposes. it is only
|
||
* considered valid if msitename != NULL.
|
||
* N.B. msitename is a malloced copy. free/malloc whenever change.
|
||
*/
|
||
static char *msitename;
|
||
static char absitename[MAXSITENL];
|
||
static char snres[] = "Sitename"; /* name of X resource */
|
||
static char nosite[] = "<No site defined>"; /* display/save if !msitename */
|
||
|
||
/* map the XeGo action to the mm_go_action() handler function */
|
||
static XtActionsRec mm_actions[] = {
|
||
{"XeGo", mm_go_action}
|
||
};
|
||
|
||
|
||
/* DST bitmap */
|
||
#define dst_width 13
|
||
#define dst_height 13
|
||
static unsigned char dst_bits[] = {
|
||
0xf0, 0x01, 0xcc, 0x07, 0xd2, 0x09, 0xc2, 0x08, 0xc5, 0x14, 0x41, 0x10,
|
||
0x43, 0x18, 0x01, 0x10, 0x05, 0x14, 0x02, 0x08, 0x12, 0x09, 0x4c, 0x06,
|
||
0xf0, 0x01};
|
||
static Pixmap dst_pm; /* pixmap when autotz is on */
|
||
static Widget dst_w; /* label for dst_pm */
|
||
|
||
/* 8 moon bitmaps */
|
||
#define moon_width 13
|
||
#define moon_height 13
|
||
static unsigned char moonwaxc_bits[] = {
|
||
0xf8, 0x03, 0x7e, 0x0c, 0xfe, 0x08, 0xff, 0x10, 0xff, 0x11, 0xff, 0x11,
|
||
0xff, 0x11, 0xff, 0x11, 0xff, 0x11, 0xff, 0x10, 0xfe, 0x08, 0x7e, 0x0c,
|
||
0xf8, 0x03};
|
||
static unsigned char moon1q_bits[] = {
|
||
0xf8, 0x03, 0x7e, 0x0c, 0x7e, 0x08, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10,
|
||
0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7e, 0x08, 0x7e, 0x0c,
|
||
0xf8, 0x03};
|
||
static unsigned char moonwaxg_bits[] = {
|
||
0xf8, 0x03, 0x3e, 0x0c, 0x1e, 0x08, 0x0f, 0x10, 0x0f, 0x10, 0x0f, 0x10,
|
||
0x0f, 0x10, 0x0f, 0x10, 0x0f, 0x10, 0x0f, 0x10, 0x1e, 0x08, 0x3e, 0x0c,
|
||
0xf8, 0x03};
|
||
static unsigned char moonfull_bits[] = {
|
||
0xf8, 0x03, 0x06, 0x0c, 0x02, 0x08, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10,
|
||
0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x02, 0x08, 0x06, 0x0c,
|
||
0xf8, 0x03};
|
||
static unsigned char moonwang_bits[] = {
|
||
0xf8, 0x03, 0x86, 0x0f, 0x02, 0x0f, 0x01, 0x1e, 0x01, 0x1e, 0x01, 0x1e,
|
||
0x01, 0x1e, 0x01, 0x1e, 0x01, 0x1e, 0x01, 0x1e, 0x02, 0x0f, 0x86, 0x0f,
|
||
0xf8, 0x03};
|
||
static unsigned char moon3q_bits[] = {
|
||
0xf8, 0x03, 0xc6, 0x0f, 0xc2, 0x0f, 0xc1, 0x1f, 0xc1, 0x1f, 0xc1, 0x1f,
|
||
0xc1, 0x1f, 0xc1, 0x1f, 0xc1, 0x1f, 0xc1, 0x1f, 0xc2, 0x0f, 0xc6, 0x0f,
|
||
0xf8, 0x03};
|
||
static unsigned char moonwanc_bits[] = {
|
||
0xf8, 0x03, 0xc6, 0x0f, 0xe2, 0x0f, 0xe1, 0x1f, 0xf1, 0x1f, 0xf1, 0x1f,
|
||
0xf1, 0x1f, 0xf1, 0x1f, 0xf1, 0x1f, 0xe1, 0x1f, 0xe2, 0x0f, 0xc6, 0x0f,
|
||
0xf8, 0x03};
|
||
static unsigned char moonnew_bits[] = {
|
||
0xf8, 0x03, 0xfe, 0x0f, 0xfe, 0x0f, 0xff, 0x1f, 0xff, 0x1f, 0xff, 0x1f,
|
||
0xff, 0x1f, 0xff, 0x1f, 0xff, 0x1f, 0xff, 0x1f, 0xfe, 0x0f, 0xfe, 0x0f,
|
||
0xf8, 0x03};
|
||
#define NMOONBM 8
|
||
static Pixmap moon_pm[NMOONBM]; /* bitmaps of basic moon phases, full -> full */
|
||
static Widget moon_w; /* label for a moon_pm */
|
||
|
||
/* sun bitmap */
|
||
#define sun_width 13
|
||
#define sun_height 13
|
||
static unsigned char sun_bits[] = {
|
||
0x48, 0x02, 0xf2, 0x09, 0x0c, 0x06, 0x05, 0x14, 0x02, 0x08, 0x02, 0x08,
|
||
0x03, 0x18, 0x02, 0x08, 0x02, 0x08, 0x05, 0x14, 0x0c, 0x06, 0xf2, 0x09,
|
||
0x48, 0x02};
|
||
static Pixmap sun_pm; /* pixmap when sun is up */
|
||
static Widget sun_w; /* label for sun_pm */
|
||
|
||
/* empty bitmap */
|
||
#define empty_width 13
|
||
#define empty_height 13
|
||
static unsigned char empty_bits[] = {
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00};
|
||
static Pixmap empty_pm; /* empty pixmap */
|
||
|
||
|
||
/* called exactly once when the main form is made.
|
||
* create and manage all the widgets as children of the mainrc.
|
||
*/
|
||
void
|
||
mm_create (mainrc)
|
||
Widget mainrc;
|
||
{
|
||
/* create the main form */
|
||
splashMsg ("Building main form\n");
|
||
create_main_form(mainrc);
|
||
splashMsg ("Building pixmaps\n");
|
||
create_pixmaps();
|
||
|
||
/* init resources and Now */
|
||
splashMsg ("Initializing resources\n");
|
||
mm_initres();
|
||
|
||
/* load the initial set of objects and set checkpoint there. */
|
||
splashMsg ("Loading data\n");
|
||
db_loadinitial();
|
||
|
||
/* setup the initial field star info */
|
||
splashMsg ("Setting up field stars\n");
|
||
fs_create();
|
||
|
||
/* resource used to record whether to initially start RT */
|
||
sr_reg (NULL, mm_autortres(), maincategory, 0);
|
||
}
|
||
|
||
/* connect up an action routine to handle XeUpdate */
|
||
void
|
||
mm_connActions (void)
|
||
{
|
||
XtAppAddActions (xe_app, mm_actions, XtNumber(mm_actions));
|
||
}
|
||
|
||
/* called to update after new resources are installed */
|
||
void
|
||
mm_newres (void)
|
||
{
|
||
Pixel p;
|
||
|
||
/* new pixmaps */
|
||
create_pixmaps();
|
||
|
||
/* keep newcir invisible */
|
||
get_something (newcir_w, XmNbackground, (XtArgVal)&p);
|
||
set_something (newcir_w, XmNforeground, (XtArgVal)p);
|
||
|
||
/* redraw the pixmaps */
|
||
mm_pms();
|
||
|
||
calm_set (&now);
|
||
}
|
||
|
||
/* ask for a file to open and read date/time/lat/long lines from.
|
||
* or stops if currently doing that.
|
||
*/
|
||
void
|
||
mm_external (void)
|
||
{
|
||
if (ext_fp)
|
||
mm_stop();
|
||
else
|
||
ext_fileask();
|
||
}
|
||
|
||
/* callback to update forward or reverse 1 step or just go.
|
||
* see mm_gostop for meaning of client.
|
||
*/
|
||
/* ARGSUSED */
|
||
void
|
||
mm_go_cb (Widget w, XtPointer client, XtPointer call)
|
||
{
|
||
mm_gostop ((long int)client);
|
||
}
|
||
|
||
/* called by the calendar subsystem to set a new UT date.
|
||
* newmjd is the new UT date/time as a modifed Julian date.
|
||
*/
|
||
void
|
||
mm_newcaldate (newmjd)
|
||
double newmjd;
|
||
{
|
||
mjd = newmjd;
|
||
set_t0 (&now);
|
||
if (autotz)
|
||
(void) tz_fromsys (&now);
|
||
if (autodt)
|
||
DeltaT = deltat(mjd);
|
||
mm_now (1);
|
||
mm_newcir(1);
|
||
newcir = 1;
|
||
}
|
||
|
||
/* called by other menus as they want to hear from our buttons or not.
|
||
* the "on"s and "off"s stack - only really redo the buttons if it's the
|
||
* first on or the last off.
|
||
*/
|
||
void
|
||
mm_selection_mode (whether)
|
||
int whether; /* whether setting up for plotting or for not plotting */
|
||
{
|
||
if (whether)
|
||
mm_selecting++;
|
||
else if (mm_selecting > 0)
|
||
--mm_selecting;
|
||
|
||
if ((whether && mm_selecting == 1) /* first one to want on */
|
||
|| (!whether && mm_selecting == 0) /* last one to want off */)
|
||
mm_set_buttons (whether);
|
||
}
|
||
|
||
/* set and save the displayed site name */
|
||
void
|
||
mm_sitename (name)
|
||
char *name;
|
||
{
|
||
setXRes (snres, name);
|
||
if (msitename)
|
||
XtFree(msitename);
|
||
msitename = name ? XtNewString(name) : NULL; /* yes, NULL is OK */
|
||
setXRes (snres, msitename ? msitename : nosite);
|
||
sites_abbrev (msitename, absitename, MAXSITENL);
|
||
mm_now (1);
|
||
}
|
||
|
||
/* called to set new lat/long Now.
|
||
* TZ, TZName and Sitename get something generic.
|
||
* if update we do a full update, else just set NEW CICUMSTANCES.
|
||
*/
|
||
void
|
||
mm_setll (l, L, update)
|
||
double l, L; /* lat, long */
|
||
int update;
|
||
{
|
||
int hr;
|
||
|
||
/* update everything */
|
||
lat = l;
|
||
lng = L;
|
||
mm_sitename (NULL);
|
||
|
||
/* guess a timezone from longitude */
|
||
hr = ((((int)floor((raddeg(-L)+7.5)/15))+24)%24);
|
||
if (hr > 12)
|
||
hr -= 24;
|
||
autotz = 0;
|
||
tz = hr;
|
||
sprintf (tznm, "UTC%c%d", hr > 0 ? '-' : '+', abs(hr));
|
||
|
||
/* ok */
|
||
if (update)
|
||
redraw_screen(1);
|
||
else {
|
||
mm_now (1);
|
||
mm_newcir(1);
|
||
newcir = 1;
|
||
}
|
||
}
|
||
|
||
/* called to set new site information in Now.
|
||
* if update we do a full update, else just set NEW CICUMSTANCES.
|
||
*/
|
||
void
|
||
mm_setsite (sp, update)
|
||
Site *sp;
|
||
int update;
|
||
{
|
||
static char envbuf[64]; /* putenv() wants stable string */
|
||
|
||
/* update everything */
|
||
lat = sp->si_lat;
|
||
lng = sp->si_lng;
|
||
elev = sp->si_elev/ERAD; /* m to earth radii */
|
||
mm_sitename (sp->si_name);
|
||
sprintf (envbuf, "TZ=%s", sp->si_tzdefn);
|
||
autotz = 1;
|
||
putenv (envbuf);
|
||
tzset();
|
||
(void) tz_fromsys (&now);
|
||
|
||
/* ok */
|
||
if (update)
|
||
redraw_screen(1);
|
||
else {
|
||
mm_now (1);
|
||
mm_newcir(1);
|
||
newcir = 1;
|
||
}
|
||
}
|
||
|
||
/* give the caller the current site name.
|
||
* N.B. return NULL if no current site.
|
||
* N.B. caller should not change anything.
|
||
*/
|
||
char *
|
||
mm_getsite (void)
|
||
{
|
||
return (msitename);
|
||
}
|
||
|
||
/* set the current epoch. this is used by sky fits to match the EQUINOX field.
|
||
*/
|
||
void
|
||
mm_setepoch (yr)
|
||
double yr;
|
||
{
|
||
double newepoch;
|
||
|
||
year_mjd (yr, &newepoch);
|
||
|
||
if (epoch != EOD && fabs(newepoch-epoch) < 1e-3)
|
||
return; /* close enough already */
|
||
|
||
epoch = newepoch;
|
||
mm_now (1);
|
||
mm_newcir(1);
|
||
newcir = 1;
|
||
}
|
||
|
||
/* return mjed (Modified Julian Date in ET scale) from mjd (UT scale)
|
||
*/
|
||
double mm_mjed (np)
|
||
Now *np;
|
||
{
|
||
return (np->n_mjd + DeltaT/86400.0); /* do NOT just use mjd macro! */
|
||
}
|
||
|
||
/* a way for anyone to know what now is */
|
||
Now *
|
||
mm_get_now (void)
|
||
{
|
||
return (&now);
|
||
}
|
||
|
||
/* called to start or stop a movie sequence.
|
||
* if a movie is currently running, we stop it, period.
|
||
* then if stepsz != 0 we start one by set movie=1, mspause=0, nstep=MANYSTEPS,
|
||
* tm_inc=stepsz and do about what the Go button does.
|
||
*/
|
||
void
|
||
mm_movie (stepsz)
|
||
double stepsz; /* step size, hours */
|
||
{
|
||
/* stop any current external control */
|
||
ext_stop();
|
||
|
||
/* stop any current movie */
|
||
if (movie) {
|
||
if (mm_interval_id != 0) {
|
||
XtRemoveTimeOut (mm_interval_id);
|
||
mm_interval_id = 0;
|
||
}
|
||
nstep = 1;
|
||
redraw_screen (1);
|
||
print_idle();
|
||
movie = 0;
|
||
return;
|
||
}
|
||
|
||
/* that's it if zero step size */
|
||
if (stepsz == 0.0)
|
||
return;
|
||
|
||
/* note movie is about to be running */
|
||
movie = 1;
|
||
|
||
/* init nstep and mspause to reasonable for long fast looping */
|
||
startnstep = nstep = MANYSTEPS;
|
||
print_nstep();
|
||
mspause = 0;
|
||
print_mspause();
|
||
|
||
/* set the time increment to stepsz */
|
||
mm_step_option = NULL; /* no special increment */
|
||
tminc = stepsz;
|
||
print_tminc();
|
||
print_running(0);
|
||
|
||
/* start fresh looping */
|
||
mm_go(0);
|
||
}
|
||
|
||
/* draw all the stuff on the managed menus.
|
||
* if how_much then redraw all fields, else just redo the graphics.
|
||
*/
|
||
void
|
||
redraw_screen (how_much)
|
||
int how_much;
|
||
{
|
||
watch_cursor(1);
|
||
|
||
/* invalidate any cached values in the database */
|
||
db_invalidate();
|
||
|
||
/* print the single-step message if this is the last loop */
|
||
if (nstep < 1)
|
||
print_updating();
|
||
|
||
/* show nstep to show plot loops to go and
|
||
* show tminc to show search convergence progress.
|
||
*/
|
||
print_nstep();
|
||
print_tminc();
|
||
print_mspause();
|
||
|
||
/* if just updating changed fields while plotting or listing
|
||
* unattended then suppress most screen updates.
|
||
*/
|
||
if (!how_much)
|
||
f_off();
|
||
|
||
/* print all the time-related fields */
|
||
mm_now (how_much);
|
||
|
||
mm_twilight ();
|
||
|
||
/* print stuff on other menus */
|
||
all_update(&now, how_much);
|
||
|
||
/* everything is up to date now */
|
||
newcir = 0;
|
||
mm_newcir(0);
|
||
|
||
f_on();
|
||
|
||
watch_cursor(0);
|
||
}
|
||
|
||
/* name of resource containg whether to start running in real time */
|
||
char *
|
||
mm_autortres (void)
|
||
{
|
||
return ("AutoRT");
|
||
}
|
||
|
||
/* keep XEphem time in sync with computer */
|
||
void
|
||
mm_startrt (void)
|
||
{
|
||
/* RT Clock stepping */
|
||
set_t0 (&now);
|
||
mm_step_option = RTC_SS_OPTION;
|
||
|
||
/* many steps */
|
||
nstep = MANYSTEPS;
|
||
|
||
/* use same pause unless 0 */
|
||
if (mspause == 0)
|
||
mspause = NOWPAUSE;
|
||
|
||
/* set to computer time */
|
||
time_fromsys (&now);
|
||
mm_newcaldate (mjd);
|
||
|
||
print_running(0);
|
||
mm_go(0);
|
||
|
||
/* record we are running RT */
|
||
setXRes (mm_autortres(), "1");
|
||
}
|
||
|
||
/* (re)create the pixmaps.
|
||
* N.B. we use the colors from status_w.
|
||
*/
|
||
static void
|
||
create_pixmaps (void)
|
||
{
|
||
Display *dsp = XtDisplay (toplevel_w);
|
||
Window win = RootWindow (dsp, DefaultScreen(dsp));
|
||
Arg args[20];
|
||
XColor colors[2];
|
||
Pixel fg, bg;
|
||
int d;
|
||
int i, n;
|
||
|
||
n = 0;
|
||
XtSetArg (args[n], XmNforeground, &fg); n++;
|
||
XtSetArg (args[n], XmNbackground, &bg); n++;
|
||
XtSetArg (args[n], XmNdepth, &d); n++;
|
||
XtGetValues (status_w, args, n);
|
||
|
||
/* DST indicator */
|
||
if (dst_pm)
|
||
XFreePixmap (dsp, dst_pm);
|
||
dst_pm = XCreatePixmapFromBitmapData (dsp, win, (char *)dst_bits,
|
||
dst_width, dst_height, fg, bg, d);
|
||
|
||
/* moons; create in full -> full */
|
||
for (n = 0; n < NMOONBM; n++)
|
||
if (moon_pm[n])
|
||
XFreePixmap (dsp, moon_pm[n]);
|
||
moon_pm[0] = XCreatePixmapFromBitmapData(dsp, win, (char*)moonfull_bits,
|
||
moon_width, moon_height, fg, bg, d);
|
||
moon_pm[1] = XCreatePixmapFromBitmapData(dsp, win, (char*)moonwang_bits,
|
||
moon_width, moon_height, fg, bg, d);
|
||
moon_pm[2] = XCreatePixmapFromBitmapData(dsp, win, (char*)moon3q_bits,
|
||
moon_width, moon_height, fg, bg, d);
|
||
moon_pm[3] = XCreatePixmapFromBitmapData(dsp, win, (char*)moonwanc_bits,
|
||
moon_width, moon_height, fg, bg, d);
|
||
moon_pm[4] = XCreatePixmapFromBitmapData(dsp, win, (char*)moonnew_bits,
|
||
moon_width, moon_height, fg, bg, d);
|
||
moon_pm[5] = XCreatePixmapFromBitmapData(dsp, win, (char*)moonwaxc_bits,
|
||
moon_width, moon_height, fg, bg, d);
|
||
moon_pm[6] = XCreatePixmapFromBitmapData(dsp, win, (char*)moon1q_bits,
|
||
moon_width, moon_height, fg, bg, d);
|
||
moon_pm[7] = XCreatePixmapFromBitmapData(dsp, win, (char*)moonwaxg_bits,
|
||
moon_width, moon_height, fg, bg, d);
|
||
|
||
/* bitmaps are drawn assuming fg is darker than bg. if not, rotate by
|
||
* 1/2 phase
|
||
*/
|
||
colors[0].pixel = fg;
|
||
colors[1].pixel = bg;
|
||
XQueryColors (dsp, xe_cm, colors, XtNumber(colors));
|
||
if (colors[0].red + colors[0].green + colors[0].blue >
|
||
colors[1].red + colors[1].green + colors[1].blue) {
|
||
|
||
for (i = 0; i < NMOONBM/2; i++) {
|
||
Pixmap tmp = moon_pm[i];
|
||
Pixmap *nxt = &moon_pm[(i+NMOONBM/2)%NMOONBM];
|
||
moon_pm[i] = *nxt;
|
||
*nxt = tmp;
|
||
}
|
||
}
|
||
|
||
/* Sun */
|
||
if (sun_pm)
|
||
XFreePixmap (dsp, sun_pm);
|
||
sun_pm = XCreatePixmapFromBitmapData (dsp, win, (char *)sun_bits,
|
||
sun_width, sun_height, fg, bg, d);
|
||
|
||
/* empty pixmap */
|
||
if (empty_pm)
|
||
XFreePixmap (dsp, empty_pm);
|
||
empty_pm = XCreatePixmapFromBitmapData (dsp, win, (char *)empty_bits,
|
||
empty_width, empty_height, fg, bg, d);
|
||
}
|
||
|
||
static void
|
||
create_main_form(mainrc)
|
||
Widget mainrc;
|
||
{
|
||
Widget mrc_w, f_w;
|
||
Widget ulfr_w, urfr_w, llfr_w, lrfr_w;
|
||
Widget w;
|
||
Arg args[20];
|
||
int n;
|
||
|
||
n = 0;
|
||
XtSetArg (args[n], XmNisAligned, False); n++;
|
||
mrc_w = XmCreateRowColumn (mainrc, "MainRC", args, n);
|
||
XtManageChild (mrc_w);
|
||
|
||
/* make the status label */
|
||
n = 0;
|
||
XtSetArg (args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
|
||
status_w = XmCreateLabel (mrc_w, "Status", args, n);
|
||
wtip (status_w,
|
||
"Current overall XEphem run-status and what you may do now.");
|
||
XtManageChild (status_w);
|
||
|
||
/* make the "NEW CIRCUMSTANCES" label */
|
||
n = 0;
|
||
XtSetArg (args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
|
||
newcir_w = XmCreateLabel (mrc_w, "NewCir", args, n);
|
||
set_xmstring (newcir_w, XmNlabelString, "NEW CIRCUMSTANCES");
|
||
XtManageChild(newcir_w);
|
||
wtip (newcir_w,
|
||
"Flashes while some fields may be out of date, until Update");
|
||
|
||
/* make a form for the basic areas */
|
||
|
||
n = 0;
|
||
XtSetArg (args[n], XmNallowOverlap, False); n++;
|
||
f_w = XmCreateForm (mrc_w, "MainForm", args, n);
|
||
XtManageChild (f_w);
|
||
|
||
/* make frame in the upper right */
|
||
|
||
n = 0;
|
||
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
|
||
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
||
urfr_w = XmCreateFrame (f_w, "URFr", args, n);
|
||
XtManageChild (urfr_w);
|
||
|
||
w = calm_create (urfr_w);
|
||
XtManageChild (w);
|
||
|
||
/* make frame in the upper left */
|
||
|
||
n = 0;
|
||
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
|
||
XtSetArg (args[n],XmNbottomAttachment,XmATTACH_OPPOSITE_WIDGET);n++;
|
||
XtSetArg (args[n], XmNbottomWidget, urfr_w); n++;
|
||
XtSetArg (args[n], XmNbottomOffset, 0); n++;
|
||
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
|
||
XtSetArg (args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
|
||
XtSetArg (args[n], XmNrightWidget, urfr_w); n++;
|
||
ulfr_w = XmCreateFrame (f_w, "ULFr", args, n);
|
||
XtManageChild (ulfr_w);
|
||
|
||
make_prompts (ulfr_w, 50, "Local",
|
||
"Controls to set up location and observing conditions",
|
||
&mm_field_map[18], NFM-18);
|
||
|
||
/* make frame in lower right */
|
||
|
||
n = 0;
|
||
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
||
XtSetArg (args[n], XmNtopWidget, urfr_w); n++;
|
||
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
|
||
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
||
lrfr_w = XmCreateFrame (f_w, "LRFr", args, n);
|
||
XtManageChild (lrfr_w);
|
||
|
||
make_prompts (lrfr_w, 50, "Night",
|
||
"Information about dusk, dawn and other night time issues",
|
||
&mm_field_map[9], 9);
|
||
|
||
/* make frame in lower left */
|
||
|
||
n = 0;
|
||
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
||
XtSetArg (args[n], XmNtopWidget, urfr_w); n++;
|
||
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
|
||
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
|
||
XtSetArg (args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
|
||
XtSetArg (args[n], XmNrightWidget, lrfr_w); n++;
|
||
llfr_w = XmCreateFrame (f_w, "LLFr", args, n);
|
||
XtManageChild (llfr_w);
|
||
|
||
make_prompts (llfr_w, 45, "Time",
|
||
"Controls to set the time used for all computations",
|
||
&mm_field_map[0], 9);
|
||
|
||
/* put a wide and thick "go" button below all */
|
||
n = 0;
|
||
XtSetArg (args[n], XmNmarginTop, 5); n++;
|
||
XtSetArg (args[n], XmNmarginBottom, 5); n++;
|
||
go_w = XmCreatePushButton (mrc_w, "MainUpdate", args, n);
|
||
XtAddCallback (go_w, XmNactivateCallback, mm_go_cb, 0);
|
||
wtip (go_w, "Run or stop the main execution loop");
|
||
set_xmstring (go_w, XmNlabelString, "Update");
|
||
XtManageChild (go_w);
|
||
}
|
||
|
||
/* build the given Fields in a column */
|
||
static void
|
||
make_prompts (p_w, pc, title, tip, fp, nfp)
|
||
Widget p_w; /* parent */
|
||
int pc;
|
||
char *title;
|
||
char *tip;
|
||
Field *fp;
|
||
int nfp;
|
||
{
|
||
Widget f_w;
|
||
Widget l_w, b_w;
|
||
Field *lfp;
|
||
Arg args[20];
|
||
int n;
|
||
|
||
n = 0;
|
||
XtSetArg (args[n], XmNverticalSpacing, 3); n++;
|
||
f_w = XmCreateForm (p_w, "MF", args, n);
|
||
XtManageChild (f_w);
|
||
|
||
if (!strcmp (title, "Time")) {
|
||
/* make special DST clock kludge */
|
||
|
||
n = 0;
|
||
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
|
||
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
||
XtSetArg (args[n], XmNlabelType, XmPIXMAP); n++;
|
||
dst_w = XmCreateLabel (f_w, "DST", args, n);
|
||
wtip (dst_w, "Shows Clock when auto Savings Time is in effect");
|
||
XtManageChild (dst_w);
|
||
|
||
n = 0;
|
||
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
|
||
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
|
||
XtSetArg (args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
|
||
XtSetArg (args[n], XmNrightWidget, dst_w); n++;
|
||
XtSetArg (args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
|
||
b_w = XmCreateLabel (f_w, "MTL", args, n);
|
||
set_xmstring (b_w, XmNlabelString, title);
|
||
wtip (b_w, tip);
|
||
XtManageChild (b_w);
|
||
|
||
} else if (!strcmp (title, "Night")) {
|
||
/* N.B. hack in sun and moon PMs */
|
||
|
||
n = 0;
|
||
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
|
||
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
|
||
XtSetArg (args[n], XmNlabelType, XmPIXMAP); n++;
|
||
sun_w = XmCreateLabel (f_w, "SunUp", args, n);
|
||
wtip (sun_w, "Shows a Sun when it is above local horizontal");
|
||
XtManageChild (sun_w);
|
||
|
||
n = 0;
|
||
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
|
||
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
||
XtSetArg (args[n], XmNlabelType, XmPIXMAP); n++;
|
||
moon_w = XmCreateLabel (f_w, "MoonUp", args, n);
|
||
wtip (moon_w, "Shows a Moon when it is above local horizontal");
|
||
XtManageChild (moon_w);
|
||
|
||
n = 0;
|
||
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
|
||
XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
|
||
XtSetArg (args[n], XmNleftWidget, sun_w); n++;
|
||
XtSetArg (args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
|
||
XtSetArg (args[n], XmNrightWidget, moon_w); n++;
|
||
XtSetArg (args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
|
||
b_w = XmCreateLabel (f_w, "MTL", args, n);
|
||
set_xmstring (b_w, XmNlabelString, title);
|
||
wtip (b_w, tip);
|
||
XtManageChild (b_w);
|
||
|
||
} else {
|
||
n = 0;
|
||
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
|
||
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
|
||
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
||
XtSetArg (args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
|
||
b_w = XmCreateLabel (f_w, "MTL", args, n);
|
||
set_xmstring (b_w, XmNlabelString, title);
|
||
wtip (b_w, tip);
|
||
XtManageChild (b_w);
|
||
}
|
||
|
||
for (lfp = fp + nfp; fp < lfp; fp++) {
|
||
|
||
/* if GAP just mark a separator */
|
||
if (fp->id == GAP) {
|
||
n = 0;
|
||
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
||
XtSetArg (args[n], XmNtopWidget, b_w); n++;
|
||
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
|
||
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
||
b_w = XmCreateSeparator (f_w, "GapSep", args, n);
|
||
XtManageChild (b_w);
|
||
|
||
if (strcmp (title, "Night"))
|
||
continue;
|
||
|
||
/* N.B. hacks in Looping title for + - and Now PBs. */
|
||
|
||
n = 0;
|
||
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
||
XtSetArg (args[n], XmNtopWidget, b_w); n++;
|
||
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
||
XtSetArg (args[n], XmNmarginWidth, 0); n++;
|
||
XtSetArg (args[n], XmNmarginHeight, 0); n++;
|
||
XtSetArg (args[n], XmNmarginTop, 0); n++;
|
||
XtSetArg (args[n], XmNmarginBottom, 0); n++;
|
||
XtSetArg (args[n], XmNmarginLeft, 0); n++;
|
||
XtSetArg (args[n], XmNmarginRight, 0); n++;
|
||
keepnow_w = XmCreatePushButton (f_w, "RT", args, n);
|
||
XtAddCallback (keepnow_w, XmNactivateCallback, keepnow_cb, 0);
|
||
wtip (keepnow_w,
|
||
"Set looping to stay in sync with computer clock @ Pause intervals");
|
||
XtManageChild (keepnow_w);
|
||
|
||
n = 0;
|
||
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
||
XtSetArg (args[n], XmNtopWidget, b_w); n++;
|
||
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
|
||
XtSetArg (args[n], XmNmarginWidth, 0); n++;
|
||
XtSetArg (args[n], XmNmarginHeight, 0); n++;
|
||
XtSetArg (args[n], XmNmarginTop, 0); n++;
|
||
XtSetArg (args[n], XmNmarginBottom, 0); n++;
|
||
XtSetArg (args[n], XmNmarginLeft, 0); n++;
|
||
XtSetArg (args[n], XmNmarginRight, 0); n++;
|
||
stepB_w = XmCreatePushButton (f_w, "SB", args, n);
|
||
XtAddCallback (stepB_w, XmNactivateCallback, mm_go_cb,
|
||
(XtPointer)-1);
|
||
set_xmstring (stepB_w, XmNlabelString, "-1");
|
||
wtip (stepB_w, "Back one Step");
|
||
XtManageChild (stepB_w);
|
||
|
||
n = 0;
|
||
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
||
XtSetArg (args[n], XmNtopWidget, b_w); n++;
|
||
XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
|
||
XtSetArg (args[n], XmNleftWidget, stepB_w); n++;
|
||
XtSetArg (args[n], XmNmarginWidth, 0); n++;
|
||
XtSetArg (args[n], XmNmarginHeight, 0); n++;
|
||
XtSetArg (args[n], XmNmarginTop, 0); n++;
|
||
XtSetArg (args[n], XmNmarginBottom, 0); n++;
|
||
XtSetArg (args[n], XmNmarginLeft, 0); n++;
|
||
XtSetArg (args[n], XmNmarginRight, 0); n++;
|
||
stepF_w = XmCreatePushButton (f_w, "SF", args, n);
|
||
XtAddCallback (stepF_w, XmNactivateCallback, mm_go_cb,
|
||
(XtPointer)1);
|
||
set_xmstring (stepF_w, XmNlabelString, "+1");
|
||
wtip (stepF_w, "Forward one Step");
|
||
XtManageChild (stepF_w);
|
||
|
||
n = 0;
|
||
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
||
XtSetArg (args[n], XmNtopWidget, b_w); n++;
|
||
XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
|
||
XtSetArg (args[n], XmNleftWidget, stepF_w); n++;
|
||
XtSetArg (args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
|
||
XtSetArg (args[n], XmNrightWidget, keepnow_w); n++;
|
||
XtSetArg (args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
|
||
b_w = XmCreateLabel (f_w, "GL", args, n);
|
||
set_xmstring (b_w, XmNlabelString, "Looping");
|
||
wtip (b_w,
|
||
"Controls to set up automatic time stepping behavior");
|
||
XtManageChild (b_w);
|
||
|
||
b_w = keepnow_w; /* PB is taller than label */
|
||
|
||
continue;
|
||
}
|
||
|
||
/* if no label, center a PB */
|
||
if (!fp->label) {
|
||
n = 0;
|
||
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
||
XtSetArg (args[n], XmNtopWidget, b_w); n++;
|
||
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
|
||
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
||
XtSetArg (args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
|
||
if (fp->name) {
|
||
XtSetArg (args[n], XmNuserData, fp->name); n++;
|
||
};
|
||
b_w = fp->pb_w = XmCreatePushButton (f_w, fp->iname, args, n);
|
||
if (fp->prompt || fp->name)
|
||
XtAddCallback (b_w, XmNactivateCallback, mm_activate_cb,
|
||
(XtPointer)fp);
|
||
XtManageChild(b_w);
|
||
if (fp->tip)
|
||
wtip (b_w, fp->tip);
|
||
continue;
|
||
}
|
||
|
||
/* we have both a label and PB -- put them side by side */
|
||
|
||
n = 0;
|
||
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
||
XtSetArg (args[n], XmNtopWidget, b_w); n++;
|
||
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
|
||
XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
|
||
XtSetArg (args[n], XmNrightPosition, pc-1); n++;
|
||
XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
|
||
l_w = XmCreateLabel (f_w, "MainLabel", args, n);
|
||
XtManageChild(l_w);
|
||
set_xmstring (l_w, XmNlabelString, fp->label);
|
||
|
||
n = 0;
|
||
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
||
XtSetArg (args[n], XmNtopWidget, b_w); n++;
|
||
XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
|
||
XtSetArg (args[n], XmNleftPosition, pc+1); n++;
|
||
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
||
XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
|
||
if (fp->name) {
|
||
XtSetArg (args[n], XmNuserData, fp->name); n++;
|
||
};
|
||
b_w = fp->pb_w = XmCreatePushButton (f_w, fp->iname, args, n);
|
||
if (fp->prompt || fp->name)
|
||
XtAddCallback (b_w, XmNactivateCallback, mm_activate_cb,
|
||
(XtPointer)fp);
|
||
XtManageChild(b_w);
|
||
if (fp->tip)
|
||
wtip (b_w, fp->tip);
|
||
}
|
||
}
|
||
|
||
/* get the widget associated with this _FID.
|
||
* We do some error checking.
|
||
*/
|
||
static Widget
|
||
fw(fid)
|
||
int fid;
|
||
{
|
||
Field *fp = NULL;
|
||
|
||
if (fid < 0 || fid >= NFM || (fp = &mm_field_map[fid])->id != fid) {
|
||
printf ("mainmenu:fw(): bad field id: %d\n", fid);
|
||
abort();
|
||
}
|
||
return (fp->pb_w);
|
||
}
|
||
|
||
/* go through all the buttons just pickable for plotting and set whether they
|
||
* should appear to look like buttons or just flat labels.
|
||
*/
|
||
static void
|
||
mm_set_buttons (whether)
|
||
int whether;
|
||
{
|
||
Field *fp;
|
||
|
||
for (fp = mm_field_map; fp < LFM; fp++) {
|
||
if (fp->id == GAP)
|
||
continue; /* no pb_w */
|
||
if (whether)
|
||
buttonAsButton (fp->pb_w, fp->name != NULL);
|
||
else
|
||
buttonAsButton (fp->pb_w, fp->prompt != NULL);
|
||
}
|
||
|
||
/* also the special Looping PBs */
|
||
buttonAsButton (keepnow_w, !whether);
|
||
buttonAsButton (stepF_w, !whether);
|
||
buttonAsButton (stepB_w, !whether);
|
||
}
|
||
|
||
/* callback from any of the main menu buttons being activated.
|
||
* if we are currently selecting fields to plot and the field has a name
|
||
* then inform all the potentially interested parties;
|
||
* else if the field has a prompt then ask the user for a new value.
|
||
*/
|
||
/* ARGSUSED */
|
||
static void
|
||
mm_activate_cb (Widget w, XtPointer client, XtPointer call)
|
||
{
|
||
Field *fp = (Field *)client;
|
||
|
||
if (mm_selecting) {
|
||
if (fp->name)
|
||
register_selection (fp->name);
|
||
} else {
|
||
if (fp->prompt) {
|
||
mm_set_alt_prompts (fp);
|
||
prompt (fp);
|
||
}
|
||
}
|
||
}
|
||
|
||
/* called when user wants XEphem time to stay in sync with computer */
|
||
/* ARGSUSED */
|
||
static void
|
||
keepnow_cb (Widget w, XtPointer client, XtPointer call)
|
||
{
|
||
mm_startrt();
|
||
}
|
||
|
||
/* set things to their initial resource settings */
|
||
static void
|
||
mm_initres (void)
|
||
{
|
||
/* list of FIDs we get from resources, in order */
|
||
typedef struct {
|
||
FID fid;
|
||
char *res;
|
||
} InitMap;
|
||
static InitMap imap[] = {
|
||
{EPOCH_FID, "Equinox"},
|
||
{LAT_FID, "Lat"},
|
||
{LONG_FID, "Long"},
|
||
{ELEV_FID, "Elevation"},
|
||
{NSTEP_FID, "NSteps"},
|
||
{PAUSE_FID, "Pause"},
|
||
{PRES_FID, "Pressure"},
|
||
{DIP_FID, "TwilightDip"},
|
||
{DT_FID, "DeltaT"},
|
||
{STPSZ_FID, "StepSize"},
|
||
{TEMP_FID, "Temp"},
|
||
{TZONE_FID, "TZone"},
|
||
{TZN_FID, "TZName"},
|
||
{SITE_FID, snres}, /* overrides others if valid */
|
||
|
||
#if 0 /* doing this works but how to /remove/ from res file once saved? */
|
||
{JD_FID, "JD"}, /* overrides Now if valid */
|
||
{UT_FID, "UTCTime"}, /* overrides Now if valid */
|
||
{UD_FID, "UTCDate"}, /* overrides Now if valid */
|
||
{LT_FID, "LTime"}, /* overrides Now if valid */
|
||
{LD_FID, "LDate"}, /* overrides Now if valid */
|
||
{LST_FID, "LST"}, /* overrides Now if valid */
|
||
#endif
|
||
};
|
||
char *sn;
|
||
int i;
|
||
|
||
/* init to now first */
|
||
time_fromsys (&now);
|
||
|
||
/* then scan other fields so they can override.
|
||
* N.B. save Sitename early because Lat/Long will set it to null.
|
||
*/
|
||
sn = XtNewString(getXRes (snres, 0));
|
||
for (i = 0; i < XtNumber(imap); i++) {
|
||
char *cp = imap[i].fid == SITE_FID ? sn : getXRes (imap[i].res, 0);
|
||
if (cp)
|
||
chg_fld (cp, &mm_field_map[imap[i].fid]);
|
||
}
|
||
XtFree (sn);
|
||
|
||
/* go from resources to real widget, then capture in save system.
|
||
* N.B. track Sitename directly; its display widget might be abbrev.
|
||
*/
|
||
redraw_screen (1);
|
||
for (i = 0; i < XtNumber(imap); i++) {
|
||
FID fid = imap[i].fid;
|
||
sr_reg (fid == SITE_FID ? 0 : mm_field_map[fid].pb_w, imap[i].res,
|
||
maincategory, mm_field_map[fid].autosav);
|
||
}
|
||
|
||
/* button info */
|
||
mm_set_buttons (mm_selecting);
|
||
print_idle();
|
||
}
|
||
|
||
/* set up those prompts that use the alternates.
|
||
*/
|
||
static void
|
||
mm_set_alt_prompts(fp)
|
||
Field *fp;
|
||
{
|
||
switch (fp->id) {
|
||
case UD_FID:
|
||
case LD_FID:
|
||
fp->prompt = fp->altp[pref_get(PREF_DATE_FORMAT)];
|
||
break;
|
||
case ELEV_FID:
|
||
case TEMP_FID:
|
||
case PRES_FID:
|
||
fp->prompt = fp->altp[pref_get(PREF_UNITS)];
|
||
break;
|
||
case DT_FID:
|
||
fp->prompt = fp->altp[autodt];
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* function called from the interval timer used to implement the
|
||
* auto repeat feature.
|
||
*/
|
||
/* ARGSUSED */
|
||
static void
|
||
mm_timer_cb (client, id)
|
||
XtPointer client;
|
||
XtIntervalId *id;
|
||
{
|
||
mm_interval_id = 0;
|
||
mm_go(0);
|
||
}
|
||
|
||
/* stop running */
|
||
static void
|
||
mm_stop (void)
|
||
{
|
||
/* close external file if in use */
|
||
ext_stop();
|
||
|
||
/* turn off timer */
|
||
if (mm_interval_id) {
|
||
XtRemoveTimeOut (mm_interval_id);
|
||
mm_interval_id = 0;
|
||
}
|
||
|
||
/* close progress meter, if up */
|
||
pm_down();
|
||
|
||
/* do final screen update if last was partial */
|
||
if (nstep > 1 && mspause == 0)
|
||
redraw_screen (1);
|
||
|
||
/* figure stopping probably means abandon the loop */
|
||
nstep = 1;
|
||
print_nstep ();
|
||
print_idle();
|
||
|
||
/* can't be a movie running now either */
|
||
movie = 0;
|
||
}
|
||
|
||
/* called when any of the canned step size buttons is activated.
|
||
* client contains the StepOption pointer; use it to set mm_step_option and,
|
||
* if it's a fixed value, tminc.
|
||
* when finished, unmanage the dialog (which is the parent of our parent).
|
||
*/
|
||
/* ARGSUSED */
|
||
static void
|
||
mm_step_cb (Widget w, XtPointer client, XtPointer call)
|
||
{
|
||
StepOption *sop = (StepOption *)client;
|
||
|
||
mm_step_option = sop;
|
||
if (sop->stepcode == FIXED_SS)
|
||
tminc = sop->inc;
|
||
else
|
||
tminc = 0.0; /* just to reset things for the next time */
|
||
set_t0 (&now);
|
||
print_tminc ();
|
||
|
||
XtUnmanageChild (XtParent(XtParent(w)));
|
||
}
|
||
|
||
/* action routine associated with the step control accelerators.
|
||
* see mm_gostop() for meaning of arg.
|
||
*/
|
||
static void
|
||
mm_go_action (w, e, p, n)
|
||
Widget w;
|
||
XEvent *e;
|
||
String *p;
|
||
Cardinal *n;
|
||
{
|
||
/* assert */
|
||
if (!(n && *n && p)) {
|
||
printf ("Bad go_action: %p %d %p\n", n, n?*n:0, p);
|
||
abort();
|
||
}
|
||
|
||
/* avoid runaway auto reps */
|
||
XSync (XtD, True);
|
||
|
||
/* ok */
|
||
mm_gostop (atoi(*p));
|
||
}
|
||
|
||
/* common routine to go or stop time.
|
||
* dir is number of steps to go +step (+) or -step (-), or 0 to just GO.
|
||
* bring up pm if running fast and not a crazy number of steps.
|
||
*/
|
||
static void
|
||
mm_gostop(dir)
|
||
int dir;
|
||
{
|
||
if (mm_interval_id) {
|
||
mm_stop();
|
||
/* record we have stopped (running RT for sure) */
|
||
setXRes (mm_autortres(), "0");
|
||
} else {
|
||
if (!dir && nstep > 1) {
|
||
print_running(0);
|
||
startnstep = nstep;
|
||
if (mspause < NO_PAUSE_DELAY && nstep <= MAXPNSTEP)
|
||
pm_up();
|
||
}
|
||
if (!newcir && any_ison())
|
||
mm_now (1); /* update time fields in case of listing/etc */
|
||
mm_go(dir);
|
||
}
|
||
}
|
||
|
||
/* increment, update all fields, and go again if more steps.
|
||
* dir is number of steps to go +step (+) or -step (-), or 0 to just GO.
|
||
*/
|
||
static void
|
||
mm_go(dir)
|
||
int dir;
|
||
{
|
||
int srchdone;
|
||
int drawall;
|
||
|
||
/* next Now unless user just made some relevant changes */
|
||
if (ext_fp) {
|
||
if (ext_readnext() < 0)
|
||
nstep = 0;
|
||
} else if (!newcir)
|
||
mm_step_now(dir < 0);
|
||
|
||
/* update nsteps remaining.
|
||
* N.B. don't want "back" to increment when at 1
|
||
*/
|
||
if (nstep == 1)
|
||
nstep = 0;
|
||
else
|
||
nstep -= dir ? dir : 1;
|
||
|
||
/* recalculate everything and update some fields */
|
||
drawall = newcir || nstep <= 1 || mspause > 0 || dir;
|
||
redraw_screen(drawall);
|
||
|
||
/* let searching functions change tminc and check for done */
|
||
srchdone = srch_eval (mjd, &tminc) < 0;
|
||
print_tminc(); /* to show possibly new search increment */
|
||
|
||
/* update plot and listing files, now that all fields are up
|
||
* to date and search function has been evaluated.
|
||
*/
|
||
plot();
|
||
listing();
|
||
|
||
/* stop loop if a search is done, steps are done or single-stepping */
|
||
if (srchdone || nstep < 1 || dir) {
|
||
if (!dir || nstep < 1)
|
||
nstep = 1;
|
||
print_nstep ();
|
||
print_idle();
|
||
|
||
/* update all fields if last didn't already */
|
||
if (!drawall)
|
||
redraw_screen (1);
|
||
|
||
/* close progress meter, if up */
|
||
pm_down();
|
||
} else {
|
||
long ms;
|
||
|
||
if (mspause < NO_PAUSE_DELAY) {
|
||
/* 0 hogs too much */
|
||
ms = NO_PAUSE_DELAY;
|
||
} else if (mspause >= 1000 && !ext_fp && mm_step_option
|
||
&& mm_step_option->stepcode == RTC_SS) {
|
||
/* advance to next multiple of mspause if internal & realtime */
|
||
long spause = mspause/1000;
|
||
ms = 1000L * (spause - time(NULL)%spause);
|
||
} else {
|
||
/* keep literal */
|
||
ms = mspause;
|
||
}
|
||
|
||
if (mm_interval_id != 0)
|
||
XtRemoveTimeOut (mm_interval_id);
|
||
mm_interval_id = XtAppAddTimeOut (xe_app, ms, mm_timer_cb, 0);
|
||
|
||
/* progress meter, if still running fast */
|
||
if (mspause < NO_PAUSE_DELAY && nstep > 1)
|
||
pm_set (100*(startnstep-nstep)/startnstep);
|
||
}
|
||
|
||
/* XSync (XtD, False); */
|
||
XmUpdateDisplay (toplevel_w);
|
||
}
|
||
|
||
/* set the time (in now.n_mjd) according to the desired step increment
|
||
* as coded in mm_step_option and possibly tminc.
|
||
*/
|
||
static void
|
||
mm_step_now(reverse)
|
||
int reverse;
|
||
{
|
||
#define RSACC (30./3600./24.) /* nominal rise/set accuracy, days */
|
||
#define BADRS (RS_ERROR|RS_CIRCUMPOLAR|RS_NEVERUP)
|
||
StepCode stepcode= mm_step_option ? mm_step_option->stepcode : FIXED_SS;
|
||
double dawn, dusk;
|
||
RiseSet rs;
|
||
int status;
|
||
Obj *op;
|
||
|
||
watch_cursor(1);
|
||
|
||
switch (stepcode) {
|
||
case STEPDAWN_SS:
|
||
twilight_cir (&now, dip, &dawn, &dusk, &status);
|
||
if ((status & (BADRS|RS_NORISE))
|
||
|| (!reverse && mjd > dawn - RSACC)
|
||
|| (reverse && mjd < dawn + RSACC)) {
|
||
/* try another few days */
|
||
Now n;
|
||
(void) memcpy ((void *)&n, (void *)&now, sizeof(Now));
|
||
n.n_mjd += reverse ? -1 : 1;
|
||
twilight_cir (&n, dip, &dawn, &dusk, &status);
|
||
if (status & (BADRS|RS_NORISE)) {
|
||
n.n_mjd += reverse ? -1 : 1;
|
||
twilight_cir (&n, dip, &dawn, &dusk, &status);
|
||
if (status & (BADRS|RS_NORISE)) {
|
||
xe_msg (1, "No dawn within two days.");
|
||
nstep = 0;
|
||
} else
|
||
mjd = dawn;
|
||
} else
|
||
mjd = dawn;
|
||
} else
|
||
mjd = dawn;
|
||
break;
|
||
|
||
case STEPDUSK_SS:
|
||
twilight_cir (&now, dip, &dawn, &dusk, &status);
|
||
if ((status & (BADRS|RS_NOSET))
|
||
|| (!reverse && mjd > dusk - RSACC)
|
||
|| (reverse && mjd < dusk + RSACC)) {
|
||
/* try another few days */
|
||
Now n;
|
||
(void) memcpy ((void *)&n, (void *)&now, sizeof(Now));
|
||
n.n_mjd += reverse ? -1 : 1;
|
||
twilight_cir (&n, dip, &dawn, &dusk, &status);
|
||
if (status & (BADRS|RS_NOSET)) {
|
||
n.n_mjd += reverse ? -1 : 1;
|
||
twilight_cir (&n, dip, &dawn, &dusk, &status);
|
||
if (status & (BADRS|RS_NOSET)) {
|
||
xe_msg (1, "No dusk within two days.");
|
||
nstep = 0;
|
||
} else
|
||
mjd = dusk;
|
||
} else
|
||
mjd = dusk;
|
||
} else
|
||
mjd = dusk;
|
||
break;
|
||
|
||
case STEPSUNRISE_SS:
|
||
op = db_basic(SUN);
|
||
dm_riset (&now, op, &rs);
|
||
if ((rs.rs_flags & (BADRS|RS_NORISE))
|
||
|| (!reverse && mjd > rs.rs_risetm - RSACC)
|
||
|| (reverse && mjd < rs.rs_risetm + RSACC)) {
|
||
/* try another few days */
|
||
Now n;
|
||
(void) memcpy ((void *)&n, (void *)&now, sizeof(Now));
|
||
n.n_mjd += reverse ? -1 : 1;
|
||
dm_riset (&n, op, &rs);
|
||
if (rs.rs_flags & (BADRS|RS_NORISE)) {
|
||
n.n_mjd += reverse ? -1 : 1;
|
||
dm_riset (&n, op, &rs);
|
||
if (rs.rs_flags & (BADRS|RS_NORISE)) {
|
||
xe_msg (1, "No sunrise within two days.");
|
||
nstep = 0;
|
||
} else
|
||
mjd = rs.rs_risetm;
|
||
} else
|
||
mjd = rs.rs_risetm;
|
||
} else
|
||
mjd = rs.rs_risetm;
|
||
break;
|
||
|
||
case STEPSUNSET_SS:
|
||
op = db_basic(SUN);
|
||
dm_riset (&now, op, &rs);
|
||
if ((rs.rs_flags & (BADRS|RS_NOSET))
|
||
|| (!reverse && mjd > rs.rs_settm - RSACC)
|
||
|| (reverse && mjd < rs.rs_settm + RSACC)) {
|
||
/* try another few days */
|
||
Now n;
|
||
(void) memcpy ((void *)&n, (void *)&now, sizeof(Now));
|
||
n.n_mjd += reverse ? -1 : 1;
|
||
dm_riset (&n, op, &rs);
|
||
if (rs.rs_flags & (BADRS|RS_NOSET)) {
|
||
n.n_mjd += reverse ? -1 : 1;
|
||
dm_riset (&n, op, &rs);
|
||
if (rs.rs_flags & (BADRS|RS_NOSET)) {
|
||
xe_msg (1, "No sunset within two days.");
|
||
nstep = 0;
|
||
} else
|
||
mjd = rs.rs_settm;
|
||
} else
|
||
mjd = rs.rs_settm;
|
||
} else
|
||
mjd = rs.rs_settm;
|
||
break;
|
||
|
||
case STEPMOONRISE_SS:
|
||
op = db_basic(MOON);
|
||
dm_riset (&now, op, &rs);
|
||
if ((rs.rs_flags & (BADRS|RS_NORISE))
|
||
|| (!reverse && mjd > rs.rs_risetm - RSACC)
|
||
|| (reverse && mjd < rs.rs_risetm + RSACC)) {
|
||
/* try another few days */
|
||
Now n;
|
||
(void) memcpy ((void *)&n, (void *)&now, sizeof(Now));
|
||
n.n_mjd += reverse ? -1 : 1;
|
||
dm_riset (&n, op, &rs);
|
||
if (rs.rs_flags & (BADRS|RS_NORISE)) {
|
||
n.n_mjd += reverse ? -1 : 1;
|
||
dm_riset (&n, op, &rs);
|
||
if (rs.rs_flags & (BADRS|RS_NORISE)) {
|
||
xe_msg (1, "No moonrise within two days.");
|
||
nstep = 0;
|
||
} else
|
||
mjd = rs.rs_risetm;
|
||
} else
|
||
mjd = rs.rs_risetm;
|
||
} else
|
||
mjd = rs.rs_risetm;
|
||
break;
|
||
|
||
case STEPMOONSET_SS:
|
||
op = db_basic(MOON);
|
||
dm_riset (&now, op, &rs);
|
||
if ((rs.rs_flags & (BADRS|RS_NOSET))
|
||
|| (!reverse && mjd > rs.rs_settm - RSACC)
|
||
|| (reverse && mjd < rs.rs_settm + RSACC)) {
|
||
/* try another few days */
|
||
Now n;
|
||
(void) memcpy ((void *)&n, (void *)&now, sizeof(Now));
|
||
n.n_mjd += reverse ? -1 : 1;
|
||
dm_riset (&n, op, &rs);
|
||
if (rs.rs_flags & (BADRS|RS_NOSET)) {
|
||
n.n_mjd += reverse ? -1 : 1;
|
||
dm_riset (&n, op, &rs);
|
||
if (rs.rs_flags & (BADRS|RS_NOSET)) {
|
||
xe_msg (1, "No moonset within two days.");
|
||
nstep = 0;
|
||
} else
|
||
mjd = rs.rs_settm;
|
||
} else
|
||
mjd = rs.rs_settm;
|
||
} else
|
||
mjd = rs.rs_settm;
|
||
break;
|
||
|
||
case STEPFULLMOON_SS:
|
||
if (reverse) {
|
||
/* start over a month ahead and search for prior full moon */
|
||
double M, mjdn, mjdf;
|
||
M = mjd + 32.0;
|
||
do {
|
||
M -= 1.0;
|
||
moonnf (M, &mjdn, &mjdf);
|
||
} while (mjdf >= mjd);
|
||
mjd = mjdf;
|
||
} else {
|
||
/* start over a month back and search for next full moon */
|
||
double M, mjdn, mjdf;
|
||
M = mjd - 32.0;
|
||
do {
|
||
M += 1.0;
|
||
moonnf (M, &mjdn, &mjdf);
|
||
} while (mjdf <= mjd);
|
||
mjd = mjdf;
|
||
}
|
||
break;
|
||
|
||
case STEPNEWMOON_SS:
|
||
if (reverse) {
|
||
/* start over a month ahead and search for prior new moon */
|
||
double M, mjdn, mjdf;
|
||
M = mjd + 32.0;
|
||
do {
|
||
M -= 1.0;
|
||
moonnf (M, &mjdn, &mjdf);
|
||
} while (mjdn >= mjd);
|
||
mjd = mjdn;
|
||
} else {
|
||
/* start over a month back and search for next new moon */
|
||
double M, mjdn, mjdf;
|
||
M = mjd - 32.0;
|
||
do {
|
||
M += 1.0;
|
||
moonnf (M, &mjdn, &mjdf);
|
||
} while (mjdn <= mjd);
|
||
mjd = mjdn;
|
||
}
|
||
break;
|
||
|
||
/* FIXED_SS step options just use tminc */
|
||
case FIXED_SS:
|
||
inc_mjd (&now, tminc, reverse, 0);
|
||
break;
|
||
|
||
/* increment in real time (wrt last set_t0()) */
|
||
case RTC_SS:
|
||
inc_mjd (&now, tminc, reverse, 1);
|
||
break;
|
||
|
||
default:
|
||
printf ("mm_step_now(): bogus stepcode: %d\n", stepcode);
|
||
abort();
|
||
}
|
||
|
||
if (autotz)
|
||
(void) tz_fromsys (&now);
|
||
if (autodt)
|
||
DeltaT = deltat(mjd);
|
||
|
||
watch_cursor(0);
|
||
|
||
#undef RSACC
|
||
#undef BADRS
|
||
}
|
||
|
||
static void
|
||
print_magdecl (void)
|
||
{
|
||
static int lasts = -100;
|
||
double yr, md;
|
||
char msg[1024];
|
||
char dir[1024];
|
||
int s;
|
||
|
||
mjd_year (mjd, &yr);
|
||
sprintf (dir, "%s/auxil", getShareDir());
|
||
s = magdecl (lat, lng, elev*ERAD, yr, dir, &md, msg);
|
||
if (s < 0) {
|
||
md = 0;
|
||
if (s != lasts)
|
||
xe_msg (0, "%s", msg);
|
||
}
|
||
lasts = s;
|
||
f_dms_angle (fw(MAG_FID), md);
|
||
}
|
||
|
||
static void
|
||
print_tminc (void)
|
||
{
|
||
Widget stpsz_w = fw(STPSZ_FID);
|
||
StepCode stepcode= mm_step_option ? mm_step_option->stepcode : FIXED_SS;
|
||
char buf[32];
|
||
|
||
switch (stepcode) {
|
||
|
||
/* step options that are variable and identified by a name */
|
||
case STEPDAWN_SS: /* same as .. */
|
||
case STEPDUSK_SS: /* same as .. */
|
||
case STEPSUNRISE_SS: /* same as .. */
|
||
case STEPSUNSET_SS: /* same as .. */
|
||
case STEPMOONRISE_SS: /* same as .. */
|
||
case STEPMOONSET_SS: /* same as .. */
|
||
case STEPFULLMOON_SS: /* same as .. */
|
||
case STEPNEWMOON_SS: /* same as .. */
|
||
case RTC_SS:
|
||
sprintf (buf, "%9s", mm_step_option->title);
|
||
f_string (stpsz_w, buf);
|
||
break;
|
||
|
||
/* FIXED_SS step options just use tminc */
|
||
case FIXED_SS:
|
||
if (fabs(tminc) >= 48.0)
|
||
f_double (stpsz_w, "%8.7gd", tminc/24.0);
|
||
else
|
||
f_sexa (stpsz_w, tminc, 3, 3600);
|
||
break;
|
||
|
||
default:
|
||
printf ("print_tminc(): bogus stepcode: %d\n", stepcode);
|
||
abort();
|
||
}
|
||
}
|
||
|
||
static void
|
||
print_updating (void)
|
||
{
|
||
print_status ("Updating...");
|
||
}
|
||
|
||
static void
|
||
print_idle (void)
|
||
{
|
||
print_status ("Make changes then press Update to run.");
|
||
f_string (go_w, "Update");
|
||
}
|
||
|
||
static void
|
||
print_running(reverse)
|
||
int reverse;
|
||
{
|
||
if (reverse)
|
||
print_status ("Running in reverse... press Stop to stop.");
|
||
else
|
||
print_status ("Running... press Stop to stop.");
|
||
f_string (go_w, "Stop");
|
||
}
|
||
|
||
static void
|
||
print_extrunning (void)
|
||
{
|
||
print_status ("External control ... press Stop to stop.");
|
||
f_string (go_w, "Stop");
|
||
}
|
||
|
||
static void
|
||
print_status (s)
|
||
char *s;
|
||
{
|
||
static char *last_s;
|
||
|
||
if (s != last_s) {
|
||
f_string (status_w, s);
|
||
XSync (XtD, False);
|
||
last_s = s;
|
||
}
|
||
}
|
||
|
||
static void
|
||
print_nstep (void)
|
||
{
|
||
static int last = 876476;
|
||
|
||
if (nstep != last) {
|
||
char buf[16];
|
||
(void) sprintf (buf, "%7d", nstep);
|
||
f_string (fw(NSTEP_FID), buf);
|
||
last = nstep;
|
||
}
|
||
}
|
||
|
||
static void
|
||
print_mspause (void)
|
||
{
|
||
static int last = 98764;
|
||
|
||
if (mspause != last) {
|
||
char buf[16];
|
||
(void) sprintf (buf, "%7g", mspause/1000.0);
|
||
f_string (fw(PAUSE_FID), buf);
|
||
last = mspause;
|
||
}
|
||
}
|
||
|
||
/* react to the field at *fp according to the string input at bp.
|
||
* crack the buffer and update the corresponding (global) variable(s)
|
||
* or do whatever a pick at that field should do.
|
||
* return 1 if we change a field that invalidates any of the times or
|
||
* to update all related fields.
|
||
*/
|
||
static int
|
||
chg_fld (bp, fp)
|
||
char *bp;
|
||
Field *fp;
|
||
{
|
||
int new = 0;
|
||
double tmp;
|
||
|
||
if (!bp) {
|
||
printf ("Bug! NULL bp for field %s\n", fp->iname);
|
||
abort();
|
||
}
|
||
|
||
switch (fp->id) {
|
||
case JD_FID:
|
||
mjd = atod(bp) - MJD0;
|
||
set_t0 (&now);
|
||
new = 1;
|
||
break;
|
||
|
||
case UD_FID:
|
||
{
|
||
double day, newmjd0;
|
||
int month, year;
|
||
|
||
mjd_cal (mjd, &month, &day, &year); /* init with now */
|
||
f_sscandate (bp, pref_get(PREF_DATE_FORMAT),
|
||
&month, &day, &year);
|
||
cal_mjd (month, day, year, &newmjd0);
|
||
|
||
/* if don't see a decimal retain current hours */
|
||
if (strchr(bp,'.'))
|
||
mjd = newmjd0;
|
||
else
|
||
mjd = newmjd0 + mjd_hr(mjd)/24.0;
|
||
}
|
||
set_t0 (&now);
|
||
new = 1;
|
||
break;
|
||
|
||
case UT_FID:
|
||
f_scansexa (bp, &tmp);
|
||
mjd = mjd_day(mjd) + tmp/24.0;
|
||
set_t0 (&now);
|
||
new = 1;
|
||
break;
|
||
|
||
case LD_FID:
|
||
{
|
||
double day, newlmjd0;
|
||
int month, year;
|
||
|
||
mjd_cal (mjd-tz/24.0, &month, &day, &year); /* now */
|
||
f_sscandate (bp, pref_get(PREF_DATE_FORMAT),
|
||
&month, &day, &year);
|
||
cal_mjd (month, day, year, &newlmjd0);
|
||
|
||
/* if don't see a decimal retain current hours */
|
||
if (strchr(bp,'.'))
|
||
mjd = newlmjd0;
|
||
else
|
||
mjd = newlmjd0 + mjd_hr(mjd-tz/24.0)/24.0;
|
||
mjd += tz/24.0;
|
||
}
|
||
set_t0 (&now);
|
||
new = 1;
|
||
break;
|
||
|
||
case LT_FID:
|
||
f_scansexa (bp, &tmp);
|
||
mjd = mjd_day(mjd-tz/24.0) + (tmp + tz)/24.0;
|
||
set_t0 (&now);
|
||
new = 1;
|
||
break;
|
||
|
||
case DT_FID:
|
||
if (strchr (bp, 'A') || strchr (bp, 'a')) {
|
||
DeltaT = deltat(mjd);
|
||
autodt = 1;
|
||
} else {
|
||
DeltaT = atod (bp);
|
||
autodt = 0;
|
||
}
|
||
new = 1;
|
||
break;
|
||
|
||
case LST_FID:
|
||
{
|
||
double lst, gst, utc;
|
||
|
||
/* read goal */
|
||
f_scansexa (bp, &lst);
|
||
|
||
/* compute new mjd based on basic transform */
|
||
gst = lst - radhr(lng); /* convert to gst */
|
||
range (&gst, 24.0);
|
||
gst_utc (mjd_day(mjd), gst, &utc);
|
||
mjd = mjd_day(mjd) + utc/24.0;
|
||
|
||
/* repeat to add apparent refinements within now_lst() */
|
||
now_lst (&now, &tmp);
|
||
tmp -= lst;
|
||
if (tmp < -12) tmp += 24;
|
||
if (tmp > 12) tmp -= 24;
|
||
mjd -= tmp*(SIDRATE/24.0);
|
||
}
|
||
set_t0 (&now);
|
||
new = 1;
|
||
break;
|
||
|
||
case TZN_FID:
|
||
(void) strncpy (tznm, bp, sizeof(tznm)-1);
|
||
autotz = 0;
|
||
new = 1;
|
||
break;
|
||
|
||
case TZONE_FID:
|
||
/* TZONE_FID */
|
||
f_scansexa (bp, &tz);
|
||
autotz = 0;
|
||
new = 1;
|
||
break;
|
||
|
||
case SITE_FID:
|
||
new = sites_search (bp);
|
||
if (new >= 0) {
|
||
Site *sip;
|
||
(void) sites_get_list (&sip);
|
||
mm_setsite(&sip[new], 0);
|
||
new = 1;
|
||
} else {
|
||
/* just change name */
|
||
mm_sitename (bp);
|
||
new = 0;
|
||
}
|
||
break;
|
||
|
||
case LONG_FID:
|
||
f_scansexa (bp, &tmp);
|
||
lng = degrad (-tmp); /* want <0 radians west */
|
||
mm_setll (lat, lng, 0);
|
||
new = 1;
|
||
break;
|
||
|
||
case LAT_FID:
|
||
f_scansexa (bp, &tmp);
|
||
lat = degrad (tmp);
|
||
mm_setll (lat, lng, 0);
|
||
new = 1;
|
||
break;
|
||
|
||
case ELEV_FID:
|
||
if (sscanf (bp, "%lf", &elev) == 1) {
|
||
if (pref_get(PREF_UNITS) == PREF_ENGLISH)
|
||
elev /= (ERAD*FTPM); /* ft to earth radii */
|
||
else
|
||
elev /= ERAD; /* m to earth radii */
|
||
new = 1;
|
||
}
|
||
break;
|
||
|
||
case DIP_FID:
|
||
if (f_scansexa (bp, &tmp) == 0) {
|
||
if (tmp < 0)
|
||
xe_msg (1, "Twilight dip must be at least 0");
|
||
else {
|
||
dip = degrad(tmp);
|
||
mm_twilight ();
|
||
}
|
||
}
|
||
break;
|
||
|
||
case NSTEP_FID:
|
||
(void) sscanf (bp, "%d", &nstep);
|
||
print_nstep ();
|
||
break;
|
||
|
||
case PAUSE_FID:
|
||
(void) sscanf (bp, "%lf", &tmp);
|
||
mspause = (int)(tmp*1000 + 0.5);
|
||
print_mspause ();
|
||
break;
|
||
|
||
case TEMP_FID:
|
||
if (sscanf (bp, "%lf", &temp) == 1) {
|
||
if (pref_get(PREF_UNITS) == PREF_ENGLISH)
|
||
temp = 5./9.*(temp - 32.0); /* want degs C */
|
||
if (temp < -100 || temp > 100) {
|
||
xe_msg (0, "NOTICE: very unusual temperature: %g C", temp);
|
||
}
|
||
new = 1;
|
||
}
|
||
break;
|
||
|
||
case PRES_FID:
|
||
if (sscanf (bp, "%lf", &pressure) == 1) {
|
||
if (pref_get(PREF_UNITS) == PREF_ENGLISH)
|
||
pressure *= 33.86; /* want hPa */
|
||
if (pressure < 0 || pressure > 4000) {
|
||
xe_msg (0,
|
||
"NOTICE: very unusual atmospheric pressure: %g hPa",
|
||
pressure);
|
||
}
|
||
new = 1;
|
||
}
|
||
break;
|
||
|
||
case EPOCH_FID:
|
||
if (bp[0] == 'e' || bp[0] == 'E' || bp[0] == 'o' || bp[0] == 'O')
|
||
epoch = EOD;
|
||
else {
|
||
double e;
|
||
e = atod(bp);
|
||
year_mjd (e, &epoch);
|
||
}
|
||
new = 1;
|
||
break;
|
||
|
||
case STPSZ_FID:
|
||
mm_set_step_code (bp);
|
||
set_t0 (&now);
|
||
print_tminc();
|
||
break;
|
||
|
||
default:
|
||
printf ("chg_fld: unknown id: %d\n", fp->id);
|
||
abort();
|
||
}
|
||
|
||
return (new);
|
||
}
|
||
|
||
/* user selected OK or APPLY to a prompt for field at fp (in userData).
|
||
* get his new value and use it.
|
||
*/
|
||
/* ARGSUSED */
|
||
static void
|
||
prompt_ok_cb (w, client, call)
|
||
Widget w; /* PromptDialog "widget" */
|
||
XtPointer client;
|
||
XtPointer call;
|
||
{
|
||
XmSelectionBoxCallbackStruct *s = (XmSelectionBoxCallbackStruct *)call;
|
||
Field *fp;
|
||
char *text;
|
||
Widget apply_w;
|
||
|
||
switch (s->reason) {
|
||
case XmCR_OK:
|
||
/* new value is in the text string */
|
||
get_xmstring(w, XmNtextString, &text);
|
||
break;
|
||
case XmCR_APPLY: /* used for several special short cuts */
|
||
/* new value is in the Apply button text string */
|
||
apply_w = XmSelectionBoxGetChild (w, XmDIALOG_APPLY_BUTTON);
|
||
get_xmstring(apply_w, XmNlabelString, &text);
|
||
break;
|
||
default:
|
||
printf ("main prompt_ok_cb: unknown reason: %d\n", s->reason);
|
||
abort();
|
||
}
|
||
|
||
get_something (w, XmNuserData, (XtArgVal)&fp);
|
||
|
||
if (chg_fld (text, fp)) {
|
||
if (autotz)
|
||
(void) tz_fromsys (&now);
|
||
if (autodt)
|
||
DeltaT = deltat(mjd);
|
||
mm_now (1);
|
||
mm_newcir(1);
|
||
newcir = 1;
|
||
}
|
||
|
||
XtFree (text);
|
||
|
||
/* unmanage the prompt dialog in all cases.
|
||
* (autoUnmanage just does it for the Ok and Cancal buttons).
|
||
*/
|
||
XtUnmanageChild (w);
|
||
}
|
||
|
||
/* put up a prompt dialog near the cursor to ask about fp.
|
||
* use the Apply button for special shortcuts.
|
||
* put up a special one for STPSZ_FID and SITE_FID.
|
||
*/
|
||
static void
|
||
prompt (fp)
|
||
Field *fp;
|
||
{
|
||
static Widget prompt_w, steps_w;
|
||
Widget w, aw;
|
||
|
||
/* sites input is handled all separately */
|
||
if (fp->id == SITE_FID) {
|
||
sites_manage();
|
||
return;
|
||
}
|
||
|
||
if (!prompt_w)
|
||
prompt_w = create_prompt_w (&steps_w);
|
||
|
||
/* set the prompt string */
|
||
set_xmstring (prompt_w, XmNselectionLabelString, fp->prompt);
|
||
|
||
/* we don't use the Apply button except for some special shortcuts.
|
||
* for those, we manage it again.
|
||
*/
|
||
aw = XmSelectionBoxGetChild (prompt_w, XmDIALOG_APPLY_BUTTON);
|
||
XtUnmanageChild (aw);
|
||
|
||
/* similarly, we assume for now we won't be needing steps_w */
|
||
XtUnmanageChild (steps_w);
|
||
|
||
/* preload the text string -- skip any leading blanks */
|
||
if (pref_get (PREF_PRE_FILL) == PREF_PREFILL) {
|
||
char *txt0, *txt;
|
||
|
||
get_xmstring (fp->pb_w, XmNlabelString, &txt0);
|
||
for (txt = txt0; *txt == ' '; txt++)
|
||
continue;
|
||
set_xmstring (prompt_w, XmNtextString, txt);
|
||
XtFree (txt0);
|
||
} else
|
||
set_xmstring (prompt_w, XmNtextString, "");
|
||
|
||
/* save fp in userData for the callbacks to get at */
|
||
set_something (prompt_w, XmNuserData, (XtArgVal)fp);
|
||
|
||
|
||
/* set up for the special shortcuts */
|
||
switch (fp->id) {
|
||
case LT_FID:
|
||
XtManageChild (aw);
|
||
set_xmstring (prompt_w, XmNapplyLabelString, "00:00:00");
|
||
break;
|
||
case UT_FID:
|
||
XtManageChild (aw);
|
||
set_xmstring (prompt_w, XmNapplyLabelString, "00:00:00");
|
||
break;
|
||
case DT_FID:
|
||
if (autodt) {
|
||
if (pref_get (PREF_PRE_FILL) == PREF_PREFILL) {
|
||
/* strip "Auto" from prompt */
|
||
char *txt0, *txt;
|
||
|
||
get_xmstring (fp->pb_w, XmNlabelString, &txt0);
|
||
for (txt = txt0; *txt && !isdigit(*txt); txt++)
|
||
continue;
|
||
set_xmstring (prompt_w, XmNtextString, txt);
|
||
XtFree (txt0);
|
||
}
|
||
} else {
|
||
XtManageChild (aw);
|
||
set_xmstring (prompt_w, XmNapplyLabelString, "Auto");
|
||
}
|
||
break;
|
||
case STPSZ_FID:
|
||
XtManageChild (steps_w);
|
||
break;
|
||
case EPOCH_FID:
|
||
XtManageChild (aw);
|
||
if (epoch == EOD)
|
||
set_xmstring (prompt_w, XmNapplyLabelString, "2000");
|
||
else
|
||
set_xmstring (prompt_w, XmNapplyLabelString, "Of Date");
|
||
break;
|
||
case NSTEP_FID:
|
||
XtManageChild (aw);
|
||
if (nstep >= 25)
|
||
set_xmstring (prompt_w, XmNapplyLabelString, "1");
|
||
else
|
||
set_xmstring (prompt_w, XmNapplyLabelString, "1000000");
|
||
break;
|
||
case PAUSE_FID:
|
||
XtManageChild (aw);
|
||
if (mspause == 0)
|
||
set_xmstring (prompt_w, XmNapplyLabelString, "30");
|
||
else
|
||
set_xmstring (prompt_w, XmNapplyLabelString, "0");
|
||
break;
|
||
case PRES_FID:
|
||
if (pressure > 0) {
|
||
XtManageChild (aw);
|
||
set_xmstring (prompt_w, XmNapplyLabelString,
|
||
"0\n(No refraction)");
|
||
}
|
||
break;
|
||
}
|
||
|
||
XtManageChild (prompt_w);
|
||
|
||
#if XmVersion >= 1001
|
||
w = XmSelectionBoxGetChild (prompt_w, XmDIALOG_TEXT);
|
||
XmProcessTraversal (w, XmTRAVERSE_CURRENT);
|
||
XmProcessTraversal (w, XmTRAVERSE_CURRENT); /* yes, twice!! */
|
||
#endif
|
||
}
|
||
|
||
static Widget
|
||
create_prompt_w(wp)
|
||
Widget *wp;
|
||
{
|
||
XmString title;
|
||
Widget prompt_w;
|
||
Arg args[20];
|
||
Widget w;
|
||
int i;
|
||
int n;
|
||
|
||
/* make the general dialog */
|
||
title = XmStringCreateLtoR ("xephem Main menu Prompt",
|
||
XmSTRING_DEFAULT_CHARSET);
|
||
n = 0;
|
||
XtSetArg(args[n], XmNdialogTitle, title); n++;
|
||
XtSetArg(args[n], XmNdialogStyle, XmDIALOG_APPLICATION_MODAL); n++;
|
||
XtSetArg(args[n], XmNmarginWidth, 10); n++;
|
||
XtSetArg(args[n], XmNmarginHeight, 10); n++;
|
||
prompt_w = XmCreatePromptDialog(toplevel_w, "MainPrompt", args, n);
|
||
XtAddCallback (prompt_w, XmNmapCallback, prompt_map_cb, NULL);
|
||
XtAddCallback (prompt_w, XmNokCallback, prompt_ok_cb, NULL);
|
||
XtAddCallback (prompt_w, XmNapplyCallback, prompt_ok_cb, NULL);
|
||
XmStringFree (title);
|
||
|
||
/* we don't use the Help button at all. */
|
||
w = XmSelectionBoxGetChild (prompt_w, XmDIALOG_HELP_BUTTON);
|
||
XtUnmanageChild (w);
|
||
|
||
/* add the special row/column of step controls.
|
||
* this is only managed for the STPSZ_FID prompt.
|
||
*/
|
||
n = 0;
|
||
XtSetArg (args[n], XmNnumColumns, 3); n++;
|
||
XtSetArg (args[n], XmNpacking, XmPACK_COLUMN); n++;
|
||
XtSetArg (args[n], XmNadjustLast, False); n++;
|
||
XtSetArg (args[n], XmNspacing, 3); n++;
|
||
*wp = XmCreateRowColumn (prompt_w, "MMStepRC", args, n);
|
||
|
||
for (i = 0; i < XtNumber(step_options); i++) {
|
||
StepOption *sop = &step_options[i];
|
||
|
||
n = 0;
|
||
w = XmCreatePushButton (*wp, "MMStepPB", args, n);
|
||
set_xmstring (w, XmNlabelString, sop->title);
|
||
XtAddCallback (w, XmNactivateCallback, mm_step_cb, (XtPointer)sop);
|
||
wtip (w, sop->tip);
|
||
XtManageChild (w);
|
||
}
|
||
|
||
return (prompt_w);
|
||
}
|
||
|
||
/* go through the buffer bp and set the mm_step_option code.
|
||
* if the code is one that defines a fixed tminc, set it too.
|
||
* if bp doesn't match any of the step options, we assume it's a
|
||
* literal time value.
|
||
* N.B. continue to support RTC and rtc as code strings for compatability.
|
||
*/
|
||
static void
|
||
mm_set_step_code (bp)
|
||
char *bp;
|
||
{
|
||
int i;
|
||
|
||
for (i = 0; i < XtNumber(step_options); i++) {
|
||
StepOption *sop = &step_options[i];
|
||
if (strcmp (sop->title, bp) == 0) {
|
||
mm_step_option = sop;
|
||
if (sop->stepcode == FIXED_SS)
|
||
tminc = sop->inc;
|
||
return;
|
||
}
|
||
}
|
||
|
||
if (bp[0] == 'r' || bp[0] == 'R')
|
||
mm_step_option = RTC_SS_OPTION;
|
||
else {
|
||
mm_step_option = NULL;
|
||
if (strpbrk(bp, "dD"))
|
||
tminc = atod(bp) * 24.0;
|
||
else if (strpbrk(bp, "sS"))
|
||
tminc = atod(bp) * 24.0 * SIDRATE;
|
||
else if (strpbrk(bp, "yY"))
|
||
tminc = atod(bp) * 365.2425 * 24.0; /* mean gregorian */
|
||
else
|
||
f_scansexa (bp, &tminc);
|
||
}
|
||
}
|
||
|
||
/* draw the various marker pixmaps */
|
||
static void
|
||
mm_pms (void)
|
||
{
|
||
Obj *op;
|
||
Pixmap moonpm;
|
||
|
||
/* dst */
|
||
set_something (dst_w, XmNlabelPixmap, autotz ? dst_pm : empty_pm);
|
||
|
||
/* moon up/phase */
|
||
op = db_basic(MOON);
|
||
db_update (op);
|
||
moonpm = moon_pm[((int)((op->s_elong+202)/45))%NMOONBM];
|
||
set_something (moon_w, XmNlabelPixmap, op->s_alt>0 ? moonpm : empty_pm);
|
||
|
||
/* sun up */
|
||
op = db_basic(SUN);
|
||
db_update (op);
|
||
set_something (sun_w, XmNlabelPixmap, op->s_alt>0 ? sun_pm : empty_pm);
|
||
}
|
||
|
||
/* print all the time/date/where related stuff: the Now structure.
|
||
* print in a nice order, based on the field locations, as much as possible.
|
||
*/
|
||
static void
|
||
mm_now (all)
|
||
int all;
|
||
{
|
||
double lmjd = mjd - tz/24.0;
|
||
double jd = mjd + MJD0;
|
||
char buf[32];
|
||
double tmp;
|
||
|
||
|
||
mm_pms();
|
||
f_string (fw(TZN_FID), tznm);
|
||
f_sexa (fw(TZONE_FID), tz, 3, 3600);
|
||
f_date (fw(LD_FID), mjd_day(lmjd));
|
||
f_time (fw(LT_FID), mjd_hr(lmjd));
|
||
if (autodt)
|
||
f_double (fw(DT_FID), "(Auto) %6.2f", DeltaT);
|
||
else
|
||
f_double (fw(DT_FID), "%.2f", DeltaT);
|
||
|
||
f_time (fw(UT_FID), mjd_hr(mjd));
|
||
f_date (fw(UD_FID), mjd_day(mjd));
|
||
|
||
f_double (fw(JD_FID), "%13.5f", jd);
|
||
|
||
now_lst (&now, &tmp);
|
||
f_time (fw(LST_FID), tmp);
|
||
|
||
f_showit(fw(SITE_FID), msitename ? absitename : nosite);
|
||
f_dms_angle (fw(LAT_FID), lat);
|
||
f_dms_angle (fw(LONG_FID), -lng); /* + west */
|
||
print_magdecl ();
|
||
if (pref_get(PREF_UNITS) == PREF_ENGLISH) {
|
||
tmp = elev * (ERAD*FTPM); /* want ft, not earth radii*/
|
||
f_double (fw(ELEV_FID), "%7.1f ft", tmp);
|
||
} else {
|
||
tmp = elev * ERAD; /* want m, not earth radii */
|
||
f_double (fw(ELEV_FID), "%8.1f m", tmp);
|
||
}
|
||
|
||
if (all) {
|
||
|
||
tmp = temp;
|
||
if (pref_get(PREF_UNITS) == PREF_ENGLISH) {
|
||
tmp = 9.*temp/5. + 32.0; /* C -> F */
|
||
strcpy (buf, "%5.1f F");
|
||
} else {
|
||
strcpy (buf, "%5.1f C");
|
||
}
|
||
f_double (fw(TEMP_FID), buf, tmp);
|
||
|
||
tmp = pressure;
|
||
if (pref_get(PREF_UNITS) == PREF_ENGLISH) {
|
||
tmp /= 33.86; /* want to see in. Hg, not hPa */
|
||
f_double (fw(PRES_FID), "%5.2f in", tmp);
|
||
} else {
|
||
f_double (fw(PRES_FID), "%5.0f hPa", tmp);
|
||
}
|
||
|
||
if (epoch == EOD)
|
||
f_string (fw(EPOCH_FID), "Of Date");
|
||
else {
|
||
mjd_year (epoch, &tmp);
|
||
f_double (fw(EPOCH_FID), "%7.1f", tmp);
|
||
}
|
||
}
|
||
|
||
calm_set (&now);
|
||
}
|
||
|
||
/* display dawn/dusk/length-of-night times.
|
||
* sneak in LST at midnight too since it too changes daily.
|
||
*/
|
||
/* ARGSUSED */
|
||
static void
|
||
mm_twilight (void)
|
||
{
|
||
static char nope[] = "-----";
|
||
double dusk, dawn;
|
||
Now midnight;
|
||
int status;
|
||
|
||
twilight_cir (&now, dip, &dawn, &dusk, &status);
|
||
|
||
/* twilight_cir gives UTC times; switch to LOCAL if prefered */
|
||
if (pref_get(PREF_ZONE) == PREF_LOCALTZ) {
|
||
dawn -= now.n_tz/24.0;
|
||
dusk -= now.n_tz/24.0;
|
||
}
|
||
|
||
/* print what we can of dusk and dawn */
|
||
if (status & (RS_NORISE|RS_ERROR|RS_CIRCUMPOLAR|RS_NEVERUP))
|
||
f_string (fw(DAWN_FID), nope);
|
||
else
|
||
f_mtime (fw(DAWN_FID), mjd_hr(dawn));
|
||
if (status & (RS_NOSET|RS_ERROR|RS_CIRCUMPOLAR|RS_NEVERUP))
|
||
f_string (fw(DUSK_FID), nope);
|
||
else
|
||
f_mtime (fw(DUSK_FID), mjd_hr(dusk));
|
||
|
||
/* length of night */
|
||
if (status & RS_NEVERUP)
|
||
f_mtime (fw(LON_FID), 24.0);
|
||
else if (status & RS_CIRCUMPOLAR)
|
||
f_mtime (fw(LON_FID), 0.0);
|
||
else if (status & RS_ERROR)
|
||
f_string (fw(LON_FID), nope);
|
||
else if ((status & RS_NORISE) && (status & RS_NOSET))
|
||
f_string (fw(LON_FID), nope);
|
||
else {
|
||
/* at least one of dusk and dawn.
|
||
* if only rise, assume set at prior midnight.
|
||
* if only set, assume rises at next midnight.
|
||
* N.B. dawn+dusk are mjd
|
||
*/
|
||
double tmp;
|
||
if (status & RS_NORISE)
|
||
dawn = .5;
|
||
else if (status & RS_NOSET)
|
||
dusk = -.5;
|
||
tmp = (dawn - dusk)*24.0;
|
||
range (&tmp, 24.0);
|
||
f_mtime (fw(LON_FID), tmp);
|
||
}
|
||
|
||
/* dip */
|
||
f_double (fw(DIP_FID), "%g<>", raddeg(dip));
|
||
|
||
/* LST at midnight tonight */
|
||
midnight = now;
|
||
midnight.n_mjd = mjd_day(mjd+1-tz/24.0) + tz/24.0;
|
||
now_lst (&midnight, &dusk);
|
||
f_time (fw(LSTM_FID), dusk);
|
||
|
||
/* also goose glance */
|
||
ng_update (&now, 1);
|
||
}
|
||
|
||
static void
|
||
mm_newcir (y)
|
||
int y;
|
||
{
|
||
static int flag; /* 0:erase/stop 1:draw/pause 2:erase/pause */
|
||
|
||
if (y) {
|
||
if (!flag) {
|
||
flag = 1;
|
||
(void) XtAppAddTimeOut (xe_app, 1, mm_newcir_cb,
|
||
(XtPointer)&flag);
|
||
}
|
||
} else {
|
||
/* just setting flag to zero will stop the flashing soon */
|
||
flag = 0;
|
||
}
|
||
}
|
||
|
||
/* callback from the timer that makes NEW CIRCUMSTANCES blink.
|
||
* client is a pointer to static state variable.
|
||
*/
|
||
/* ARGSUSED */
|
||
static void
|
||
mm_newcir_cb (client, id)
|
||
XtPointer client;
|
||
XtIntervalId *id;
|
||
{
|
||
int *flag = (int *)client;
|
||
Pixel p;
|
||
|
||
switch (*flag) {
|
||
case 0: /* stop -- make text invisible */
|
||
get_something (newcir_w, XmNbackground, (XtArgVal)&p);
|
||
set_something (newcir_w, XmNforeground, (XtArgVal)p);
|
||
break;
|
||
case 1: /* make the message visible and repeat */
|
||
get_something (status_w, XmNforeground, (XtArgVal)&p);
|
||
set_something (newcir_w, XmNforeground, (XtArgVal)p);
|
||
*flag = 2; /* toggle active state */
|
||
(void) XtAppAddTimeOut (xe_app, NC_BLINK_DELAY, mm_newcir_cb,
|
||
(XtPointer)client);
|
||
break;
|
||
case 2: /* make the message invisible and repeat */
|
||
get_something (newcir_w, XmNbackground, (XtArgVal)&p);
|
||
set_something (newcir_w, XmNforeground, (XtArgVal)p);
|
||
*flag = 1; /* toggle active state */
|
||
(void) XtAppAddTimeOut (xe_app, NC_BLINK_DELAY, mm_newcir_cb,
|
||
(XtPointer)client);
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* ask for name of file to read for external input */
|
||
static void
|
||
ext_fileask (void)
|
||
{
|
||
if (!ext_w)
|
||
ext_create_w();
|
||
XtManageChild (ext_w);
|
||
}
|
||
|
||
/* create the external file input name prompt */
|
||
static void
|
||
ext_create_w (void)
|
||
{
|
||
Arg args[20];
|
||
Widget t_w;
|
||
int n;
|
||
|
||
n = 0;
|
||
XtSetArg (args[n], XmNcolormap, xe_cm); n++;
|
||
XtSetArg (args[n], XmNmarginHeight, 10); n++;
|
||
XtSetArg (args[n], XmNmarginWidth, 10); n++;
|
||
ext_w = XmCreatePromptDialog (toplevel_w, "ExtFile", args, n);
|
||
set_something (ext_w, XmNcolormap, (XtArgVal)xe_cm);
|
||
set_xmstring (ext_w, XmNdialogTitle, "xephem External File Setup");
|
||
set_xmstring (ext_w, XmNselectionLabelString, "File name:");
|
||
t_w = XmSelectionBoxGetChild (ext_w, XmDIALOG_TEXT);
|
||
defaultTextFN (t_w, 1, getPrivateDir(), "external.txt");
|
||
sr_reg (t_w, NULL, maincategory, 1);
|
||
XtAddCallback (ext_w, XmNokCallback, ext_ok_cb, NULL);
|
||
XtAddCallback (ext_w, XmNhelpCallback, ext_help_cb, NULL);
|
||
XtAddCallback (ext_w, XmNmapCallback, prompt_map_cb, NULL);
|
||
}
|
||
|
||
/* read the next entry from ext_fp.
|
||
* if find one, set Now fields and return 0.
|
||
* if can't find any entries, return -1 with ext_fp definitely closed.
|
||
*/
|
||
static int
|
||
ext_readnext (void)
|
||
{
|
||
double rjd, rlat, rlng;
|
||
char buf[1024];
|
||
|
||
if (!ext_fp)
|
||
return (-1);
|
||
|
||
while (fgets (buf, sizeof(buf), ext_fp)) {
|
||
if (sscanf (buf, "%lf %lf %lf", &rjd, &rlat, &rlng) == 3) {
|
||
/* update the new time/lat/long */
|
||
lat = rlat;
|
||
lng = -rlng; /* we want <0 radians west */
|
||
mjd = rjd - MJD0;
|
||
mm_setll (lat, lng, 0);
|
||
set_t0 (&now);
|
||
return (0);
|
||
}
|
||
}
|
||
|
||
fclose (ext_fp);
|
||
ext_fp = NULL;
|
||
return (-1);
|
||
}
|
||
|
||
/* called when the Ok button is hit in the external file input prompt */
|
||
/* ARGSUSED */
|
||
static void
|
||
ext_ok_cb (Widget w, XtPointer client, XtPointer call)
|
||
{
|
||
char *name;
|
||
|
||
/* get the file name */
|
||
get_xmstring(w, XmNtextString, &name);
|
||
if (strlen(name) == 0) {
|
||
xe_msg (1, "Please enter the name of an external input file.");
|
||
XtFree (name);
|
||
return;
|
||
}
|
||
|
||
/* open it */
|
||
ext_fp = fopenh (name, "r");
|
||
if (!ext_fp) {
|
||
xe_msg (1, "%s: %s", name, syserrstr());
|
||
XtFree (name);
|
||
return;
|
||
}
|
||
|
||
/* read one entry just to test */
|
||
if (ext_readnext() < 0) {
|
||
xe_msg (1, "%s: contains no valid entries", name);
|
||
XtFree (name);
|
||
return;
|
||
}
|
||
|
||
/* rewind to start from beginning */
|
||
rewind (ext_fp);
|
||
|
||
/* go */
|
||
print_extrunning();
|
||
nstep = MANYSTEPS;
|
||
mm_go(0);
|
||
}
|
||
|
||
/* stop using an external file, if any */
|
||
static void
|
||
ext_stop (void)
|
||
{
|
||
if (ext_fp) {
|
||
fclose (ext_fp);
|
||
ext_fp = NULL;
|
||
}
|
||
}
|
||
|
||
/* called when the Help button is hit in the external file input prompt */
|
||
/* ARGSUSED */
|
||
static void
|
||
ext_help_cb (Widget w, XtPointer client, XtPointer call)
|
||
{
|
||
static char *hlp[] = {
|
||
"XEphem runs from entries in this file.",
|
||
"Format:",
|
||
" UTCMM/DD/YY UTCHH:MM:SS LATDD:MM:SS LONGDD:MM:SS",
|
||
"Longitude is +W."
|
||
};
|
||
hlp_dialog ("ExternalInput", hlp, XtNumber(hlp));
|
||
}
|
||
|