diff --git a/src/config-keys.h b/src/config-keys.h index 7647b82f..31288881 100644 --- a/src/config-keys.h +++ b/src/config-keys.h @@ -113,6 +113,7 @@ #define MOD_CFG_MAP_SHADOW_ALPHA "SHADOW_ALPHA" #define MOD_CFG_MAP_SHOWTRACKS "SHOWTRACKS" #define MOD_CFG_MAP_HIDECOVS "HIDECOVS" +#define MOD_CFG_MAP_AUTO_GROUND_TRACK "AUTO_GROUND_TRACK" /* polar view specific */ #define MOD_CFG_POLAR_SECTION "POLAR" diff --git a/src/gtk-sat-map-ground-track.c b/src/gtk-sat-map-ground-track.c index f54d611e..9c43d1cf 100644 --- a/src/gtk-sat-map-ground-track.c +++ b/src/gtk-sat-map-ground-track.c @@ -73,6 +73,11 @@ void ground_track_create(GtkSatMap * satmap, sat_t * sat, qth_t * qth, double t0; /* time when this_orbit starts */ double t; ssp_t *this_ssp; + double track_num; + double target_phase; + double prev_phase; + double total_phase; + gboolean wrap; sat_log_log(SAT_LOG_LEVEL_DEBUG, _("%s: Creating ground track for %s"), @@ -83,76 +88,133 @@ void ground_track_create(GtkSatMap * satmap, sat_t * sat, qth_t * qth, /* get configuration parameters */ this_orbit = sat->orbit; - max_orbit = sat->orbit - 1 + mod_cfg_get_int(satmap->cfgdata, - MOD_CFG_MAP_SECTION, - MOD_CFG_MAP_TRACK_NUM, - SAT_CFG_INT_MAP_TRACK_NUM); - - sat_log_log(SAT_LOG_LEVEL_DEBUG, - _("%s: Start orbit: %d"), __func__, this_orbit); - sat_log_log(SAT_LOG_LEVEL_DEBUG, - _("%s: End orbit %d"), __func__, max_orbit); - - /* find the time when the current orbit started */ - - /* Iterate backwards in time until we reach sat->orbit < this_orbit. - Use predict_calc from predict-tools.c as SGP/SDP driver. - As a built-in safety, we stop iteration if the orbit crossing is - more than 24 hours back in time. - */ - t0 = satmap->tstamp; //get_current_daynum (); - /* use == instead of >= as it is more robust */ - for (t = t0; (sat->orbit == this_orbit) && ((t + 1.0) > t0); t -= 0.0007) - predict_calc(sat, qth, t); - - /* set it so that we are in the same orbit as this_orbit - and not a different one */ - t += 2 * 0.0007; - t0 = t; - predict_calc(sat, qth, t0); + track_num = mod_cfg_get_double(satmap->cfgdata, MOD_CFG_MAP_SECTION, + MOD_CFG_MAP_TRACK_NUM, + SAT_CFG_DOUBLE_MAP_TRACK_NUM); + + /* If number of orbits to draw is less than 2, we start the track 25% or an + * orbit behind the satellites current position. Otherwise it starts at the + * start of the orbit. */ + if (track_num < 2.0) + { + /* Start a quarter of an orbit ago */ + if (sat->phase <= 90.0) + { + target_phase = sat->phase + 360.0 - 90.0; + wrap = TRUE; + } + else + { + target_phase = sat->phase - 90.0; + wrap = FALSE; + } + for (t = satmap->tstamp; (wrap && (sat->phase <= 90.0)) || (sat->phase > target_phase); t -= 0.0007) + predict_calc(sat, qth, t); + t += 0.0007; + + /* Move ahead user-defined number of orbits (or parts of) */ + prev_phase = sat->phase; + total_phase = 0.0; + while ((total_phase < 360.0 * track_num) && (!decayed(sat))) + { + /* We use 30 sec time steps. If resolution is too fine, the + line drawing routine will filter out unnecessary points + */ + t += 0.00035; + predict_calc(sat, qth, t); + if (sat->phase < prev_phase) // have we wrapped? + total_phase += sat->phase + 360.0 - prev_phase; + else + total_phase += sat->phase - prev_phase; + prev_phase = sat->phase; - sat_log_log(SAT_LOG_LEVEL_DEBUG, - _("%s: T0: %f (%d)"), __func__, t0, sat->orbit); + /* store this SSP */ + this_ssp = g_try_new(ssp_t, 1); + if (this_ssp == NULL) + { + sat_log_log(SAT_LOG_LEVEL_ERROR, + _("%s: MAYDAY: Insufficient memory for ground track!"), + __func__); + return; + } - /* calculate (lat,lon) for the required orbits */ - while ((sat->orbit <= max_orbit) && - (sat->orbit >= this_orbit) && (!decayed(sat))) + this_ssp->lat = sat->ssplat; + this_ssp->lon = sat->ssplon; + obj->track_data.latlon = + g_slist_prepend(obj->track_data.latlon, this_ssp); + } + } + else { - /* We use 30 sec time steps. If resolution is too fine, the - line drawing routine will filter out unnecessary points - */ - t += 0.00035; - predict_calc(sat, qth, t); + max_orbit = sat->orbit - 1 + (long)track_num; + + sat_log_log(SAT_LOG_LEVEL_DEBUG, + _("%s: Start orbit: %d"), __func__, this_orbit); + sat_log_log(SAT_LOG_LEVEL_DEBUG, + _("%s: End orbit %d"), __func__, max_orbit); - /* store this SSP */ + /* find the time when the current orbit started */ - /* Note: g_slist_append() has to traverse the entire list to find the end, which - is inefficient when adding multiple elements. Therefore, we use g_slist_prepend() - and reverse the entire list when we are done. + /* Iterate backwards in time until we reach sat->orbit < this_orbit. + Use predict_calc from predict-tools.c as SGP/SDP driver. + As a built-in safety, we stop iteration if the orbit crossing is + more than 24 hours back in time. */ - this_ssp = g_try_new(ssp_t, 1); + t0 = satmap->tstamp; //get_current_daynum (); + /* use == instead of >= as it is more robust */ + for (t = t0; (sat->orbit == this_orbit) && ((t + 1.0) > t0); t -= 0.0007) + predict_calc(sat, qth, t); + + /* set it so that we are in the same orbit as this_orbit + and not a different one */ + t += 2 * 0.0007; + t0 = t; + predict_calc(sat, qth, t0); + + sat_log_log(SAT_LOG_LEVEL_DEBUG, + _("%s: T0: %f (%d)"), __func__, t0, sat->orbit); + + /* calculate (lat,lon) for the required orbits */ + while ((sat->orbit <= max_orbit) && + (sat->orbit >= this_orbit) && (!decayed(sat))) + { + /* We use 30 sec time steps. If resolution is too fine, the + line drawing routine will filter out unnecessary points + */ + t += 0.00035; + predict_calc(sat, qth, t); + + /* store this SSP */ + + /* Note: g_slist_append() has to traverse the entire list to find the end, which + is inefficient when adding multiple elements. Therefore, we use g_slist_prepend() + and reverse the entire list when we are done. + */ + this_ssp = g_try_new(ssp_t, 1); + + if (this_ssp == NULL) + { + sat_log_log(SAT_LOG_LEVEL_ERROR, + _("%s: MAYDAY: Insufficient memory for ground track!"), + __func__); + return; + } - if (this_ssp == NULL) + this_ssp->lat = sat->ssplat; + this_ssp->lon = sat->ssplon; + obj->track_data.latlon = + g_slist_prepend(obj->track_data.latlon, this_ssp); + + } + + /* log if there is a problem with the orbit calculation */ + if (sat->orbit != (max_orbit + 1)) { sat_log_log(SAT_LOG_LEVEL_ERROR, - _("%s: MAYDAY: Insufficient memory for ground track!"), - __func__); + _("%s: Problem computing ground track for %s"), + __func__, sat->nickname); return; } - - this_ssp->lat = sat->ssplat; - this_ssp->lon = sat->ssplon; - obj->track_data.latlon = - g_slist_prepend(obj->track_data.latlon, this_ssp); - - } - /* log if there is a problem with the orbit calculation */ - if (sat->orbit != (max_orbit + 1)) - { - sat_log_log(SAT_LOG_LEVEL_ERROR, - _("%s: Problem computing ground track for %s"), - __func__, sat->nickname); - return; } /* Reset satellite structure to eliminate glitches in single sat @@ -313,6 +375,7 @@ static void create_polylines(GtkSatMap * satmap, sat_t * sat, qth_t * qth, guint start; guint i, j, n, num_points; guint32 col; + gboolean start_not_end; (void)sat; (void)qth; @@ -327,6 +390,10 @@ static void create_polylines(GtkSatMap * satmap, sat_t * sat, qth_t * qth, MOD_CFG_MAP_SECTION, MOD_CFG_MAP_TRACK_COL, SAT_CFG_INT_MAP_TRACK_COL); + /* Determine which end arrow heads should be drawn, depending on direction + satellite is moving in, which is determined by its inclination. */ + start_not_end = sat->tle.xincl > 90.0; + /* loop over each SSP */ for (i = 0; i < n; i++) { @@ -375,6 +442,16 @@ static void create_polylines(GtkSatMap * satmap, sat_t * sat, qth_t * qth, CAIRO_LINE_CAP_SQUARE, "line-join", CAIRO_LINE_JOIN_MITER, + "end-arrow", + !start_not_end, + "start-arrow", + start_not_end, + "arrow-length", + 10.0, + "arrow-tip-length", + 8.0, + "arrow-width", + 8.0, NULL); goo_canvas_points_unref(gpoints); goo_canvas_item_model_lower(line, obj->marker); @@ -438,7 +515,13 @@ static void create_polylines(GtkSatMap * satmap, sat_t * sat, qth_t * qth, "stroke-color-rgba", col, "line-cap", CAIRO_LINE_CAP_SQUARE, "line-join", - CAIRO_LINE_JOIN_MITER, NULL); + CAIRO_LINE_JOIN_MITER, + "end-arrow", !start_not_end, + "start-arrow", start_not_end, + "arrow-length", 10.0, + "arrow-tip-length", 8.0, + "arrow-width", 8.0, + NULL); goo_canvas_points_unref(gpoints); goo_canvas_item_model_lower(line, obj->marker); diff --git a/src/gtk-sat-map.c b/src/gtk-sat-map.c index ea8d38b7..6737e51b 100644 --- a/src/gtk-sat-map.c +++ b/src/gtk-sat-map.c @@ -74,6 +74,8 @@ static gboolean on_button_press(GooCanvasItem * item, static gboolean on_button_release(GooCanvasItem * item, GooCanvasItem * target, GdkEventButton * event, gpointer data); +static void clear_auto_ground_tracks(gpointer key, gpointer val, + gpointer data); static void clear_selection(gpointer key, gpointer val, gpointer data); static void load_map_file(GtkSatMap * satmap, float clon); static GooCanvasItemModel *create_canvas_model(GtkSatMap * satmap); @@ -823,6 +825,8 @@ static gboolean on_button_release(GooCanvasItem * item, gint *catpoint = NULL; sat_map_obj_t *obj = NULL; guint32 col; + sat_t *sat = NULL; + gboolean auto_ground_track; (void)target; @@ -843,6 +847,18 @@ static gboolean on_button_release(GooCanvasItem * item, } else { + auto_ground_track = mod_cfg_get_bool(satmap->cfgdata, + MOD_CFG_MAP_SECTION, + MOD_CFG_MAP_AUTO_GROUND_TRACK, + SAT_CFG_BOOL_MAP_AUTO_GROUND_TRACK); + + if (auto_ground_track) + { + /* Clear auto-enabled ground trackss. */ + g_hash_table_foreach(satmap->obj, clear_auto_ground_tracks, + satmap); + } + obj->selected = !obj->selected; if (obj->selected) @@ -874,6 +890,23 @@ static gboolean on_button_release(GooCanvasItem * item, if (obj->oldrcnum == 2) g_object_set(obj->range2, "stroke-color-rgba", col, NULL); + if (auto_ground_track) + { + /* Create ground track for newly selected satellite. */ + sat = SAT(g_hash_table_lookup(satmap->sats, catpoint)); + if (sat != NULL) + { + if (!obj->showtrack) + { + obj->showtrack = TRUE; + /* create ground track */ + ground_track_create(satmap, sat, satmap->qth, obj); + /* do not add to satmap->showtracks, that's just for + * sats where it has manually been enabled. */ + } + } + } + /* clear other selections */ g_hash_table_foreach(satmap->obj, clear_selection, catpoint); } @@ -887,6 +920,34 @@ static gboolean on_button_release(GooCanvasItem * item, return TRUE; } +/* Delete ground tracks that were automatically enabled for the selected + * satellite. */ + +static void clear_auto_ground_tracks(gpointer key, gpointer val, gpointer data) +{ + GtkSatMap *satmap = GTK_SAT_MAP(data); + sat_map_obj_t *obj = SAT_MAP_OBJ(val); + sat_t *sat = NULL; + gint *catpoint = key; + + if (obj->selected) + { + sat = SAT(g_hash_table_lookup(satmap->sats, catpoint)); + if (sat != NULL) + { + /* If ground track was auto enabled, this sat will not be in + * showtracks hash table. Don't use value in hash table, + * just whether it exists */ + if (!g_hash_table_lookup_extended(satmap->showtracks, + &(sat->tle.catnr), NULL, NULL)) + { + obj->showtrack = FALSE; + ground_track_delete(satmap, sat, satmap->qth, obj, TRUE); + } + } + } +} + static void clear_selection(gpointer key, gpointer val, gpointer data) { gint *old = key; diff --git a/src/mod-cfg-get-param.c b/src/mod-cfg-get-param.c index 79e3da97..ec6fb391 100644 --- a/src/mod-cfg-get-param.c +++ b/src/mod-cfg-get-param.c @@ -155,6 +155,38 @@ gchar *mod_cfg_get_str(GKeyFile * f, const gchar * sec, return param; } +gdouble mod_cfg_get_double(GKeyFile * f, const gchar * sec, const gchar * key, + sat_cfg_double_e p) +{ + GError *error = NULL; + gdouble param; + + /* check whether parameter is present in GKeyFile */ + if (g_key_file_has_key(f, sec, key, NULL)) + { + param = g_key_file_get_double(f, sec, key, &error); + + if (error != NULL) + { + sat_log_log(SAT_LOG_LEVEL_WARN, + _("%s: Failed to read double (%s)"), + __func__, error->message); + + g_clear_error(&error); + + /* get a timeout from global config */ + param = sat_cfg_get_double(p); + } + } + /* get value from sat-cfg */ + else + { + param = sat_cfg_get_double(p); + } + + return param; +} + /** * \brief Load an integer list into a hash table that uses the * existinence of datain the hash as a boolean. diff --git a/src/mod-cfg-get-param.h b/src/mod-cfg-get-param.h index 8a6ffd2e..d93c6d4b 100644 --- a/src/mod-cfg-get-param.h +++ b/src/mod-cfg-get-param.h @@ -35,6 +35,8 @@ gint mod_cfg_get_int(GKeyFile * f, const gchar * sec, const gchar * key, sat_cfg_int_e p); gchar *mod_cfg_get_str(GKeyFile * f, const gchar * sec, const gchar * key, sat_cfg_str_e p); +gdouble mod_cfg_get_double(GKeyFile * f, const gchar * sec, + const gchar * key, sat_cfg_double_e p); void mod_cfg_get_integer_list_boolean(GKeyFile * cfgdata, const gchar * section, const gchar * key, diff --git a/src/sat-cfg.c b/src/sat-cfg.c index f86b7478..fd9a32d1 100644 --- a/src/sat-cfg.c +++ b/src/sat-cfg.c @@ -109,6 +109,13 @@ typedef struct { gchar *defval; /*!< The default value */ } sat_cfg_str_t; +/** Structure representing an double value */ +typedef struct { + gchar *group; /*!< The configration group */ + gchar *key; /*!< The configuration key */ + gdouble defval; /*!< The default value */ +} sat_cfg_double_t; + /** Array containing the boolean configuration values */ sat_cfg_bool_t sat_cfg_bool[SAT_CFG_BOOL_NUM] = { {"GLOBAL", "USE_LOCAL_TIME", FALSE}, @@ -161,7 +168,6 @@ sat_cfg_int_t sat_cfg_int[SAT_CFG_INT_NUM] = { {"MODULES", "MAP_EARTH_SHADOW_COLOUR", 0x00000060}, {"MODULES", "MAP_TICK_COLOUR", 0x7F7F7FC8}, {"MODULES", "MAP_TRACK_COLOUR", 0xFF1200BB}, - {"MODULES", "MAP_TRACK_NUM", 3}, {"MODULES", "MAP_SHADOW_ALPHA", 0xDD}, {"MODULES", "POLAR_REFRESH", 3}, {"MODULES", "POLAR_CHART_ORIENT", POLAR_VIEW_NESW}, @@ -245,6 +251,11 @@ sat_cfg_str_t sat_cfg_str[SAT_CFG_STR_NUM] = { {"PREDICT", "SAVE_DIR", NULL} }; +/** Array containing the double configuration parameters */ +sat_cfg_double_t sat_cfg_double[SAT_CFG_DOUBLE_NUM] = { + {"MODULES", "MAP_TRACK_NUM", 3.0}, +}; + /* The configuration data buffer */ static GKeyFile *config = NULL; @@ -727,3 +738,107 @@ void sat_cfg_reset_int(sat_cfg_int_e param) _("%s: Unknown INT param index (%d)\n"), __func__, param); } } + +gdouble sat_cfg_get_double(sat_cfg_double_e param) +{ + gdouble value = 0.0; + GError *error = NULL; + + if (param < SAT_CFG_DOUBLE_NUM) + { + if (config == NULL) + { + sat_log_log(SAT_LOG_LEVEL_ERROR, + _("%s: Module not initialised\n"), __func__); + + /* return default value */ + value = sat_cfg_double[param].defval; + } + else + { + /* fetch value */ + value = g_key_file_get_double(config, + sat_cfg_double[param].group, + sat_cfg_double[param].key, &error); + + if (error != NULL) + { + g_clear_error(&error); + value = sat_cfg_double[param].defval; + } + } + + } + else + { + sat_log_log(SAT_LOG_LEVEL_ERROR, + _("%s: Unknown INT param index (%d)\n"), __func__, param); + } + + return value; +} + +gdouble sat_cfg_get_double_def(sat_cfg_double_e param) +{ + gdouble value = 0.0; + + if (param < SAT_CFG_DOUBLE_NUM) + { + value = sat_cfg_double[param].defval; + } + else + { + sat_log_log(SAT_LOG_LEVEL_ERROR, + _("%s: Unknown double param index (%d)\n"), __func__, param); + } + + return value; +} + +void sat_cfg_set_double(sat_cfg_double_e param, gdouble value) +{ + if (param < SAT_CFG_DOUBLE_NUM) + { + if (config == NULL) + { + sat_log_log(SAT_LOG_LEVEL_ERROR, + _("%s: Module not initialised\n"), __func__); + } + else + { + g_key_file_set_double(config, + sat_cfg_double[param].group, + sat_cfg_double[param].key, value); + } + + } + else + { + sat_log_log(SAT_LOG_LEVEL_ERROR, + _("%s: Unknown double param index (%d)\n"), __func__, param); + } +} + +void sat_cfg_reset_double(sat_cfg_double_e param) +{ + if (param < SAT_CFG_DOUBLE_NUM) + { + if (config == NULL) + { + sat_log_log(SAT_LOG_LEVEL_ERROR, + _("%s: Module not initialised\n"), __func__); + } + else + { + g_key_file_remove_key(config, + sat_cfg_double[param].group, + sat_cfg_double[param].key, NULL); + } + + } + else + { + sat_log_log(SAT_LOG_LEVEL_ERROR, + _("%s: Unknown double param index (%d)\n"), __func__, param); + } +} diff --git a/src/sat-cfg.h b/src/sat-cfg.h index 446e19fa..b40a5fc1 100644 --- a/src/sat-cfg.h +++ b/src/sat-cfg.h @@ -43,6 +43,7 @@ typedef enum { SAT_CFG_BOOL_MAP_SHOW_CURS_TRACK, /*!< Track mouse cursor on map. */ SAT_CFG_BOOL_MAP_SHOW_GRID, /*!< Show grid on map. */ SAT_CFG_BOOL_MAP_KEEP_RATIO, /*!< Keep original aspect ratio */ + SAT_CFG_BOOL_MAP_AUTO_GROUND_TRACK, /*!< Whether to automatically show ground track for selected satellite */ SAT_CFG_BOOL_POL_SHOW_QTH_INFO, /*!< Show QTH info on polar plot */ SAT_CFG_BOOL_POL_SHOW_NEXT_EV, /*!< Show next event on polar plot */ SAT_CFG_BOOL_POL_SHOW_CURS_TRACK, /*!< Track mouse cursor on polar plot. */ @@ -82,7 +83,6 @@ typedef enum { SAT_CFG_INT_MAP_GLOBAL_SHADOW_COL, /*!< Earth shadow colour. */ SAT_CFG_INT_MAP_TICK_COL, /*!< Tick labels colour. */ SAT_CFG_INT_MAP_TRACK_COL, /*!< Ground Track colour. */ - SAT_CFG_INT_MAP_TRACK_NUM, /*!< Number of orbits to show ground track for */ SAT_CFG_INT_MAP_SHADOW_ALPHA, /*!< Tranparency of shadow under satellite marker. */ SAT_CFG_INT_POLAR_REFRESH, /*!< Polar refresh rate (cycle). */ SAT_CFG_INT_POLAR_ORIENTATION, /*!< Orientation of the polar charts. */ @@ -154,6 +154,12 @@ typedef enum { SAT_CFG_STR_NUM /*!< Number of string parameters */ } sat_cfg_str_e; +/** Symbolic references for double config values. */ +typedef enum { + SAT_CFG_DOUBLE_MAP_TRACK_NUM, /*!< Number of orbits to show ground track for */ + SAT_CFG_DOUBLE_NUM +} sat_cfg_double_e; + guint sat_cfg_load(void); guint sat_cfg_save(void); void sat_cfg_close(void); @@ -169,5 +175,9 @@ gint sat_cfg_get_int(sat_cfg_int_e param); gint sat_cfg_get_int_def(sat_cfg_int_e param); void sat_cfg_set_int(sat_cfg_int_e param, gint value); void sat_cfg_reset_int(sat_cfg_int_e param); +gdouble sat_cfg_get_double(sat_cfg_double_e param); +gdouble sat_cfg_get_double_def(sat_cfg_double_e param); +void sat_cfg_set_double(sat_cfg_double_e param, gdouble value); +void sat_cfg_reset_double(sat_cfg_double_e param); #endif diff --git a/src/sat-pref-map-view.c b/src/sat-pref-map-view.c index c107a326..fcd161a9 100644 --- a/src/sat-pref-map-view.c +++ b/src/sat-pref-map-view.c @@ -44,6 +44,7 @@ static GtkWidget *satc, *ssatc, *trackc; static GtkWidget *covc, *infofg, *infobg; static GtkWidget *terminator, *globe_shadow; static GtkWidget *shadow; +static GtkWidget *auto_ground_track; /* ground track orbit number selector */ static GtkWidget *orbit; @@ -92,10 +93,20 @@ static void colour_changed(GtkWidget * but, gpointer data) static void orbit_changed(GtkWidget * spin, gpointer data) { + gdouble value; + (void)spin; (void)data; dirty = TRUE; + + /* We allow fractional values <2 and integer values above. */ + value = gtk_spin_button_get_value(GTK_SPIN_BUTTON(orbit)); + if (value >= 2.0) + { + /* Round to integer */ + gtk_spin_button_set_value(GTK_SPIN_BUTTON(orbit), (double)(int)value); + } } static void center_changed(GtkWidget * spin, gpointer data) @@ -248,10 +259,14 @@ static void reset_cb(GtkWidget * button, gpointer cfg) gtk_range_set_value(GTK_RANGE(shadow), sat_cfg_get_int_def(SAT_CFG_INT_MAP_SHADOW_ALPHA)); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(auto_ground_track), + sat_cfg_get_bool_def + (SAT_CFG_BOOL_MAP_AUTO_GROUND_TRACK)); + /* ground track orbits */ gtk_spin_button_set_value(GTK_SPIN_BUTTON(orbit), - sat_cfg_get_int_def - (SAT_CFG_INT_MAP_TRACK_NUM)); + sat_cfg_get_double_def + (SAT_CFG_DOUBLE_MAP_TRACK_NUM)); /* center longitude */ gtk_spin_button_set_value(GTK_SPIN_BUTTON(center), @@ -329,9 +344,13 @@ static void reset_cb(GtkWidget * button, gpointer cfg) gtk_range_set_value(GTK_RANGE(shadow), sat_cfg_get_int(SAT_CFG_INT_MAP_SHADOW_ALPHA)); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(auto_ground_track), + sat_cfg_get_bool + (SAT_CFG_BOOL_MAP_AUTO_GROUND_TRACK)); + /* ground track orbits */ gtk_spin_button_set_value(GTK_SPIN_BUTTON(orbit), - sat_cfg_get_int(SAT_CFG_INT_MAP_TRACK_NUM)); + sat_cfg_get_double(SAT_CFG_DOUBLE_MAP_TRACK_NUM)); /* center longitude */ gtk_spin_button_set_value(GTK_SPIN_BUTTON(center), @@ -454,11 +473,16 @@ void sat_pref_map_view_ok(GKeyFile * cfg) (gint) gtk_range_get_value(GTK_RANGE(shadow))); + g_key_file_set_boolean(cfg, MOD_CFG_MAP_SECTION, + MOD_CFG_MAP_AUTO_GROUND_TRACK, + gtk_toggle_button_get_active + (GTK_TOGGLE_BUTTON(auto_ground_track))); + /* orbit */ - g_key_file_set_integer(cfg, MOD_CFG_MAP_SECTION, - MOD_CFG_MAP_TRACK_NUM, - gtk_spin_button_get_value_as_int - (GTK_SPIN_BUTTON(orbit))); + g_key_file_set_double(cfg, MOD_CFG_MAP_SECTION, + MOD_CFG_MAP_TRACK_NUM, + gtk_spin_button_get_value + (GTK_SPIN_BUTTON(orbit))); /* map center */ g_key_file_set_integer(cfg, MOD_CFG_MAP_SECTION, @@ -539,10 +563,13 @@ void sat_pref_map_view_ok(GKeyFile * cfg) sat_cfg_set_int(SAT_CFG_INT_MAP_SHADOW_ALPHA, (gint) gtk_range_get_value(GTK_RANGE(shadow))); + sat_cfg_set_bool(SAT_CFG_BOOL_MAP_AUTO_GROUND_TRACK, + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON + (auto_ground_track))); /* orbit */ - sat_cfg_set_int(SAT_CFG_INT_MAP_TRACK_NUM, - gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON - (orbit))); + sat_cfg_set_double(SAT_CFG_DOUBLE_MAP_TRACK_NUM, + gtk_spin_button_get_value(GTK_SPIN_BUTTON + (orbit))); /* map center */ sat_cfg_set_int(SAT_CFG_INT_MAP_CENTER, @@ -602,6 +629,9 @@ void sat_pref_map_view_ok(GKeyFile * cfg) g_key_file_remove_key(cfg, MOD_CFG_MAP_SECTION, MOD_CFG_MAP_SHADOW_ALPHA, NULL); + g_key_file_remove_key(cfg, + MOD_CFG_MAP_SECTION, + MOD_CFG_MAP_AUTO_GROUND_TRACK, NULL); g_key_file_remove_key(cfg, MOD_CFG_MAP_SECTION, MOD_CFG_MAP_TRACK_NUM, NULL); @@ -634,8 +664,10 @@ void sat_pref_map_view_ok(GKeyFile * cfg) sat_cfg_reset_int(SAT_CFG_INT_MAP_INFO_BGD_COL); sat_cfg_reset_int(SAT_CFG_INT_MAP_SHADOW_ALPHA); + sat_cfg_reset_bool(SAT_CFG_BOOL_MAP_AUTO_GROUND_TRACK); + /* orbit */ - sat_cfg_reset_int(SAT_CFG_INT_MAP_TRACK_NUM); + sat_cfg_reset_double(SAT_CFG_DOUBLE_MAP_TRACK_NUM); /* map center */ sat_cfg_reset_int(SAT_CFG_INT_MAP_CENTER); @@ -1194,6 +1226,50 @@ static void create_colour_selectors(GKeyFile * cfg, GtkBox * vbox) NULL); } +/** + * Create auto ground track display selector widget. + * + * @param cfg The module configuration or NULL in global mode. + * @param vbox The container box in which the widgets should be packed into. + * + * This function creates the widgets for determining if ground tracks should + * be displayed when a satellite is selected. + * + */ +static void create_auto_ground_track(GKeyFile * cfg, GtkBox * vbox) +{ + GtkWidget *label; + GtkWidget *hbox; + + hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); + gtk_box_set_homogeneous(GTK_BOX(hbox), FALSE); + gtk_box_pack_start(vbox, hbox, FALSE, TRUE, 0); + + auto_ground_track = gtk_check_button_new_with_label( + _("Always display ground track for selected satellite")); + gtk_widget_set_tooltip_text(auto_ground_track, + _("Ground track will be enabled for a satellite " + "when selected and cleared when another is selected " + "(unless manually enabled via the menu)")); + if (cfg != NULL) + { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(auto_ground_track), + mod_cfg_get_bool(cfg, + MOD_CFG_MAP_SECTION, + MOD_CFG_MAP_AUTO_GROUND_TRACK, + SAT_CFG_BOOL_MAP_AUTO_GROUND_TRACK)); + } + else + { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(auto_ground_track), + sat_cfg_get_bool + (SAT_CFG_BOOL_MAP_AUTO_GROUND_TRACK)); + } + g_signal_connect(auto_ground_track, "toggled", G_CALLBACK(content_changed), NULL); + gtk_box_pack_start(GTK_BOX(hbox), auto_ground_track, FALSE, TRUE, 0); + +} + /** * Create orbit number selector widget. * @@ -1208,7 +1284,7 @@ static void create_orbit_selector(GKeyFile * cfg, GtkBox * vbox) { GtkWidget *label; GtkWidget *hbox; - gint onum; + gdouble onum; hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); gtk_box_set_homogeneous(GTK_BOX(hbox), FALSE); @@ -1217,20 +1293,23 @@ static void create_orbit_selector(GKeyFile * cfg, GtkBox * vbox) label = gtk_label_new(_("Display ground track for")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - orbit = gtk_spin_button_new_with_range(1, 10, 1); - gtk_spin_button_set_digits(GTK_SPIN_BUTTON(orbit), 0); + orbit = gtk_spin_button_new_with_range(0.5, 10.0, 1.0); + gtk_spin_button_set_digits(GTK_SPIN_BUTTON(orbit), 1); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(orbit), TRUE); + gtk_widget_set_tooltip_text(orbit, + _("Value can be a fraction between 0.5-1.9 or an integer 2-10")); + if (cfg != NULL) { - onum = mod_cfg_get_int(cfg, - MOD_CFG_MAP_SECTION, - MOD_CFG_MAP_TRACK_NUM, - SAT_CFG_INT_MAP_TRACK_NUM); + onum = mod_cfg_get_double(cfg, + MOD_CFG_MAP_SECTION, + MOD_CFG_MAP_TRACK_NUM, + SAT_CFG_DOUBLE_MAP_TRACK_NUM); } else { - onum = sat_cfg_get_int(SAT_CFG_INT_MAP_TRACK_NUM); + onum = sat_cfg_get_double(SAT_CFG_DOUBLE_MAP_TRACK_NUM); } gtk_spin_button_set_value(GTK_SPIN_BUTTON(orbit), onum); g_signal_connect(G_OBJECT(orbit), "value-changed", @@ -1355,6 +1434,7 @@ GtkWidget *sat_pref_map_view_create(GKeyFile * cfg) gtk_box_pack_start(GTK_BOX(vbox), gtk_separator_new(GTK_ORIENTATION_HORIZONTAL), FALSE, TRUE, 5); + create_auto_ground_track(cfg, GTK_BOX(vbox)); create_orbit_selector(cfg, GTK_BOX(vbox)); create_center_selector(cfg, GTK_BOX(vbox)); gtk_box_pack_start(GTK_BOX(vbox),