]> Pileus Git - aweather/commitdiff
Update formatting to match other plugins
authorAndy Spencer <andy753421@gmail.com>
Tue, 7 Feb 2012 08:41:02 +0000 (08:41 +0000)
committerAndy Spencer <andy753421@gmail.com>
Tue, 7 Feb 2012 08:41:02 +0000 (08:41 +0000)
- Group functions together and remove function prototypes.

- Add headings above similar sections of code

- Use typedefed CamelCase format for GpsUi and GpsTrack

- Vertically align a few things

src/plugins/gps-plugin.c
src/plugins/gps-plugin.h

index 2b6265d2d364609cbde510b9b11e15915c372188..9f92526a9a9d2891414374333827268f5700cfd2 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
- /* TODO:
 *    If gpsd connection fails, try to connect again periodically.
 *    If gps stops sending data there should be an indication that it's stale.
 */
+/* TODO:
+ *    If gpsd connection fails, try to connect again periodically.
+ *    If gps stops sending data there should be an indication that it's stale.
+ */
 
 #define _XOPEN_SOURCE
+#include <config.h>
+
 #include <stdio.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <time.h>
-#include <config.h>
 #include <string.h>
 #include <glib/gstdio.h>
 #include <gtk/gtk.h>
 #include "../aweather-location.h"
 
 /* interval to update map with new gps data in seconds. */
-#define GPS_UPDATE_INTERVAL (2)
+#define GPS_UPDATE_INTERVAL     (2)
 
 /* Filename and search path to use for gps marker, should be configurable */
-#define GPS_MARKER_ICON_PATH ".:" PKGDATADIR
-#define GPS_MARKER_ICON "arrow.png"
+#define GPS_MARKER_ICON_PATH    ".:" PKGDATADIR
+#define GPS_MARKER_ICON         "arrow.png"
 
 /* number of track points per group and number of groups to maintain */
-#define NUM_TRACK_POINTS (6)
-#define NUM_TRACK_GROUPS (4)
+#define NUM_TRACK_POINTS        (6)
+#define NUM_TRACK_GROUPS        (4)
 #define NUM_TRACK_POINTS_FACTOR (1.5)
 
 /* interval to update log file in seconds (default value for slider) */
 #define GPS_LOG_DEFAULT_UPDATE_INTERVAL (30)
-#define GPS_LOG_EXT "csv"
+#define GPS_LOG_EXT             "csv"
 
 /* For updating the status bar conveniently */
-#define GPS_STATUSBAR_CONTEXT "GPS"
+#define GPS_STATUSBAR_CONTEXT   "GPS"
+
 #if 0
 #define GPS_STATUS(gps, format, args...) \
        do { \
        } while (0)
 
 
-static gboolean gps_data_is_valid(struct gps_data_t *gps_data);
-static gchar *gps_get_time_string(time_t gps_time);
-static gchar *gps_get_date_string(double gps_time);
-static void process_gps( gpointer, gint, GdkInputCondition);
-
-#ifdef GPS_RANGE_RINGS
-static void gps_init_range_rings(GritsPluginGps *gps, GtkWidget *gbox);
-static gboolean on_gps_rangering_clicked_event(GtkWidget *widget, gpointer user_data);
-#endif
-
-static void gps_init_status_info(GritsPluginGps *gps, GtkWidget *gbox);
-static void gps_init_control_frame(GritsPluginGps *gps, GtkWidget *gbox);
-static gboolean on_gps_follow_clicked_event(GtkWidget *widget, gpointer user_data);
-
-/* GPS logging support */
-static void gps_init_track_log_frame(GritsPluginGps *gps, GtkWidget *gbox);
-static gboolean on_gps_log_clicked_event(GtkWidget *widget, gpointer user_data);
-
-/* Track management */
-static void gps_track_init(struct gps_track_t *track);
-static void gps_track_free(struct gps_track_t *track);
-static void gps_track_clear(struct gps_track_t *track);
-static void gps_track_add_point(struct gps_track_t *track, gdouble lat,
-    gdouble lon, gdouble elevation);
-static void gps_track_group_incr(struct gps_track_t *track);
-
-static gboolean on_gps_track_enable_clicked_event(GtkWidget *widget,
-    gpointer user_data);
-static gboolean on_gps_track_clear_clicked_event(GtkWidget *widget,
-    gpointer user_data);
-static gboolean gps_write_log(gpointer data);
-
-static gchar *gps_get_status(struct gps_data_t *);
-static gchar *gps_get_latitude(struct gps_data_t *);
-static gchar *gps_get_longitude(struct gps_data_t *);
-static gchar *gps_get_elevation(struct gps_data_t *);
-static gchar *gps_get_heading(struct gps_data_t *);
-static gchar *gps_get_speed(struct gps_data_t *);
-
-/* Describes a line in the gps table */
-struct gps_status_info {
-       gchar *label;
-       gchar *initial_val;
-       gchar *(*get_data)(struct gps_data_t *);
-       guint font_size;
-       GtkWidget *label_widget;
-       GtkWidget *value_widget;
-};
-
-struct gps_status_info gps_table[] = {
-       {"Status:", "No Data", gps_get_status, 14, NULL, NULL},
-//     {"Online:", "No Data", gps_get_online, 14, NULL, NULL},
-       {"Latitude:", "No Data", gps_get_latitude, 14, NULL, NULL},
-       {"Longitude:", "No Data", gps_get_longitude, 14, NULL, NULL},
-       {"Elevation:", "No Data", gps_get_elevation, 14, NULL, NULL},
-       {"Heading:", "No Data", gps_get_heading, 14, NULL, NULL},
-       {"Speed:", "No Data", gps_get_speed, 14, NULL, NULL},
-};
+/********************
+ * Helper functions *
+ ********************/
 
 /* Find a readable file in a colon delimeted path */
 static gchar *find_path(const gchar *path, const gchar *filename)
@@ -162,175 +109,285 @@ static gchar *find_path(const gchar *path, const gchar *filename)
        }
 }
 
-static gboolean gps_data_is_valid(struct gps_data_t *gps_data)
+
+/********************
+ * GPS Status Table *
+ ********************/
+
+static gchar *gps_get_status(struct gps_data_t *gps_data)
 {
-       if (gps_data != NULL && gps_data->online != -1.0 &&
-               gps_data->fix.mode >= MODE_2D &&
-               gps_data->status > STATUS_NO_FIX) {
-               return TRUE;
-       }
+       gchar *status_color;
+       gchar *status_text;
 
-       return FALSE;
+       switch (gps_data->fix.mode) {
+       case MODE_NOT_SEEN:
+               status_color = "red";
+               status_text = "No Signal";
+               break;
+       case MODE_NO_FIX:
+               status_color = "red";
+               status_text = "No Fix";
+               break;
+       case MODE_2D:
+               status_color = "yellow";
+               status_text = "2D Mode";
+               break;
+       case MODE_3D:
+               status_color = "green";
+               status_text = "3D Mode";
+               break;
+       default:
+               status_color = "black";
+               status_text = "Unknown";
+               break;
+       }
+       return g_strdup_printf("<span foreground=\"%s\">%s</span>",
+                               status_color, status_text);
 }
 
-static gchar *gps_get_date_string(double gps_time)
+#if 0
+static gchar *gps_get_online(struct gps_data_t *gps_data)
 {
-       static gchar    buf[256];
-       time_t int_time = (time_t)gps_time;
-       struct tm       tm_time;
+       gchar *status_str;
+       gchar *online_str;
 
-       gmtime_r(&int_time, &tm_time);
+       if (gps_data->online == -1.0) {
+               online_str = "Offline";
+       } else {
+               online_str = "Online";
+       }
 
-       snprintf(buf, sizeof(buf), "%04d-%02d-%02d",
-                tm_time.tm_year+1900, tm_time.tm_mon+1, tm_time.tm_mday);
+       switch (gps_data->status) {
+       case 0:
+               status_str = "No Fix";
+               break;
+       case 1:
+               status_str = "Fix Acquired";
+               break;
+       case 2:
+               status_str = "DGPS Fix";
+               break;
+       default:
+               status_str = "Unknown Status";
+               break;
+       }
 
-       return buf;
+       return g_strdup_printf("%lf,%s,%s", gps_data->online, online_str, status_str);
 }
+#endif
 
-static gchar *gps_get_time_string(time_t gps_time)
+static gchar *gps_get_latitude(struct gps_data_t *gps_data)
 {
-       static gchar buf[256];
-       time_t int_time = (time_t)gps_time;
-       struct tm tm_time;
-
-       gmtime_r(&int_time, &tm_time);
-
-       snprintf(buf, sizeof(buf), "%02d:%02d:%02dZ",
-                tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec);
-
-       return buf;
+       return g_strdup_printf("%3.4f", gps_data->fix.latitude);
 }
 
+static gchar *gps_get_longitude(struct gps_data_t *gps_data)
+{
+       return g_strdup_printf("%3.4f", gps_data->fix.longitude);
+}
 
-static void update_gps_status(GritsPluginGps *gps)
+static gchar *gps_get_elevation(struct gps_data_t *gps_data)
 {
-       struct gps_data_t *gps_data = &gps->gps_data;
+       /* XXX Make units (m/ft) settable */
+       return g_strdup_printf("%.1lf %s",
+                   (gps_data->fix.altitude * METERS_TO_FEET), "ft");
+}
 
-       /* gps table update */
-       gint i;
-       gchar *str;
-       for (i = 0; i < sizeof(gps_table)/sizeof(*gps_table); i++) {
-               gtk_label_set_markup (GTK_LABEL(gps_table[i].value_widget),
-                           (str = gps_table[i].get_data(gps_data)));
-               g_free(str);
-       }
+static gchar *gps_get_heading(struct gps_data_t *gps_data)
+{
+       /* XXX Make units (m/ft) settable */
+       return g_strdup_printf("%03.0lf", gps_data->fix.track);
 }
 
-static void gps_init_control_frame(GritsPluginGps *gps, GtkWidget *gbox)
+static gchar *gps_get_speed(struct gps_data_t *gps_data)
 {
-       /* Control checkboxes */
-       GtkWidget *gps_control_frame = gtk_frame_new("GPS Control");
-       GtkWidget *cbox = gtk_vbox_new(FALSE, 2);
-       gtk_container_add(GTK_CONTAINER(gps_control_frame), cbox);
-       gtk_box_pack_start(GTK_BOX(gbox), gps_control_frame, FALSE, FALSE, 0);
+       /* XXX Make units (m/ft) settable */
+       return g_strdup_printf("%1.1f %s",
+               (gps_data->fix.speed*3600.0*METERS_TO_FEET/5280.0), "mph");
+}
 
-       gps->ui.gps_follow_checkbox =
-                     gtk_check_button_new_with_label("Follow GPS");
-       g_signal_connect(G_OBJECT(gps->ui.gps_follow_checkbox), "clicked",
-                     G_CALLBACK (on_gps_follow_clicked_event),
-                     (gpointer)gps);
-       gtk_box_pack_start(GTK_BOX(cbox), gps->ui.gps_follow_checkbox,
-                      FALSE, FALSE, 0);
+struct {
+       const gchar *label;
+       const gchar *initial_val;
+       gchar     *(*get_data)(struct gps_data_t *);
+       guint        font_size;
+       GtkWidget   *label_widget;
+       GtkWidget   *value_widget;
+} gps_table[] = {
+       {"Status:",    "No Data", gps_get_status,    14, NULL, NULL},
+//     {"Online:",    "No Data", gps_get_online,    14, NULL, NULL},
+       {"Latitude:",  "No Data", gps_get_latitude,  14, NULL, NULL},
+       {"Longitude:", "No Data", gps_get_longitude, 14, NULL, NULL},
+       {"Elevation:", "No Data", gps_get_elevation, 14, NULL, NULL},
+       {"Heading:",   "No Data", gps_get_heading,   14, NULL, NULL},
+       {"Speed:",     "No Data", gps_get_speed,     14, NULL, NULL},
+};
 
-       gps->ui.gps_track_checkbox =
-                      gtk_check_button_new_with_label("Record Track");
-       g_signal_connect(G_OBJECT(gps->ui.gps_track_checkbox), "clicked",
-                      G_CALLBACK (on_gps_track_enable_clicked_event),
-                      (gpointer)gps);
-       gtk_box_pack_start(GTK_BOX(cbox), gps->ui.gps_track_checkbox,
-                      FALSE, FALSE, 0);
 
-       gps->ui.gps_clear_button = gtk_button_new_with_label("Clear Track");
-       g_signal_connect(G_OBJECT(gps->ui.gps_clear_button), "clicked",
-                     G_CALLBACK (on_gps_track_clear_clicked_event),
-                     (gpointer)gps);
-       gtk_box_pack_start(GTK_BOX(cbox), gps->ui.gps_clear_button,
-                      FALSE, FALSE, 0);
-}
+/******************
+ * Track handling *
+ ******************/
 
-static gboolean on_gps_track_enable_clicked_event(GtkWidget *widget,
-    gpointer user_data)
+static void gps_track_init(GpsTrack *track)
 {
-       GritsPluginGps *gps = (GritsPluginGps *)user_data;
-
-       g_debug("GritsPluginGps: track_enable_clicked_event");
+       /* Save a spot at the end for the NULL termination */
+       track->points = (gpointer)g_new0(double*, NUM_TRACK_GROUPS + 1);
+       track->cur_point  = 0;
+       track->cur_group  = 0;
+       track->num_points = 1;  /* starts at 1 so realloc logic works */
+       track->line = NULL;
+}
 
-       if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) {
-               /* start logging trip history */
-               GPS_STATUS(gps, "Enabled GPS track.");
-               gps->track.active = TRUE;
-       } else {
-               /* stop logging trip history */
-               GPS_STATUS(gps, "Disabled GPS track.");
-               gps->track.active = FALSE;
-               /* advance to the next track group, moving everything down if
-                * it's full.
-                */
-               gps_track_group_incr(&gps->track);
+static void gps_track_clear(GpsTrack *track)
+{
+       gint pi;
+       for (pi = 0; pi < NUM_TRACK_GROUPS; pi++) {
+               if (track->points[pi] != NULL) {
+                       g_free(track->points[pi]);
+                       track->points[pi] = NULL;
+               }
        }
-
-       return FALSE;
+       track->cur_point  = 0;
+       track->cur_group  = 0;
+       track->num_points = 1;  /* starts at 1 so realloc logic works */
 }
 
-static gboolean on_gps_track_clear_clicked_event(GtkWidget *widget, gpointer user_data)
+static void gps_track_free(GpsTrack *track)
 {
-       GritsPluginGps *gps = (GritsPluginGps *)user_data;
-
-       g_debug("GritsPluginGps: track_clear_clicked_event");
-       GPS_STATUS(gps, "Cleared GPS track.");
-       gps_track_clear(&gps->track);
-
-       return FALSE;
+       gps_track_clear(track);
+       g_free(track->points);
 }
 
-static gboolean on_gps_log_interval_changed_event(GtkWidget *widget,
-    gpointer user_data)
+/* add a new track group (points in a track group are connected, and
+ * separated from points in other track groups).  */
+static void gps_track_group_incr(GpsTrack *track)
 {
-       GritsPluginGps *gps = (GritsPluginGps *)user_data;
+       gdouble (**points)[3] = track->points; /* for simplicity */
 
-       g_assert(gps);
+       /* Just return if they increment it again before any points have
+        * been added.
+        */
+       if (points[track->cur_group] == NULL) {
+               return;
+       }
 
-       g_debug("GritsPluginGps: log_interval_changed_event - value = %f",
-       gtk_range_get_value(GTK_RANGE(widget)));
+       g_debug("GritsPluginGps: track_group_incr - track group %u->%u.",
+               track->cur_group, track->cur_group + 1);
 
-       if (gtk_toggle_button_get_active(
-                       GTK_TOGGLE_BUTTON(gps->ui.gps_log_checkbox))) {
-               g_assert(gps->ui.gps_log_timeout_id != 0);
+       track->cur_group++;
+       track->cur_point  = 0;
+       track->num_points = 1;  /* starts at 1 so realloc logic works */
 
-               /* disable old timeout */
-               g_source_remove(gps->ui.gps_log_timeout_id);
-               gps->ui.gps_log_timeout_id = 0;
+       if (track->cur_group >= NUM_TRACK_GROUPS) {
+               g_debug("GritsPluginGps: track_group_incr - track group %u "
+                       "is at max %u, shifting groups",
+                       track->cur_group, NUM_TRACK_GROUPS);
 
-               /* Schedule new log file write */
-               gps->ui.gps_log_timeout_id = g_timeout_add(
-                        gtk_range_get_value(GTK_RANGE(widget))*1000,
-                        gps_write_log, gps);
-               gps_write_log(gps);
-       }
+               /* Free the oldest one which falls off the end */
+               g_free(points[0]);
 
-       return FALSE;
+               /* shift the rest down, last one should be NULL already */
+               /* note we alloc NUM_TRACK_GROUPS+1 */
+               for (int pi = 0; pi < NUM_TRACK_GROUPS; pi++) {
+                       points[pi] = points[pi+1];
+               }
+
+               /* always write into the last group */
+               track->cur_group = NUM_TRACK_GROUPS - 1;
+       }
 }
 
-static gboolean gps_write_log(gpointer data)
+static void gps_track_add_point(GpsTrack *track,
+    gdouble lat, gdouble lon, gdouble elevation)
 {
-       GritsPluginGps *gps = (GritsPluginGps *)data;
-       struct gps_data_t *gps_data = &gps->gps_data;
-       gchar buf[256];
-       gchar filename[256];
-       gint fd;
-       gboolean new_file = FALSE;
+       gdouble (**points)[3] = track->points; /* for simplicity */
 
-       if (gps_data == NULL) {
-               g_warning("Skipped write to GPS log file: "
-                         "can not get GPS coordinates.");
-               GPS_STATUS(gps, "Skipped write to GPS log file: "
-                         "can not get GPS coordinates.");
-               return TRUE;
-       }
+       g_debug("GritsPluginGps: track_add_point");
+
+       g_assert(track->cur_group < NUM_TRACK_GROUPS &&
+               (track->cur_point <= track->num_points));
+
+       /* resize/allocate the point group if the current one is full */
+       if (track->cur_point >= track->num_points - 1) {
+               guint new_size = track->num_points == 1 ?
+                           NUM_TRACK_POINTS :
+                           track->num_points * NUM_TRACK_POINTS_FACTOR;
+               g_debug("GritsPluginGps: track_add_point - reallocating points "
+                       "array from %u points to %u points.\n",
+                       track->num_points, new_size);
+               points[track->cur_group] = (gpointer)g_renew(gdouble,
+                           points[track->cur_group], 3*(new_size+1));
+               track->num_points = new_size;
+       }
+
+       g_assert(points[track->cur_group] != NULL);
+
+       /* Add the coordinate */
+       lle2xyz(lat, lon, elevation,
+           &points[track->cur_group][track->cur_point][0],
+           &points[track->cur_group][track->cur_point][1],
+           &points[track->cur_group][track->cur_point][2]);
+
+       track->cur_point++;
+
+       /* make sure last point is always 0s so the line drawing stops. */
+       points[track->cur_group][track->cur_point][0] = 0.0;
+       points[track->cur_group][track->cur_point][1] = 0.0;
+       points[track->cur_group][track->cur_point][2] = 0.0;
+}
+
+
+/*****************
+ * Track Logging *
+ *****************/
+
+static gchar *gps_get_date_string(double gps_time)
+{
+       static gchar    buf[256];
+       time_t int_time = (time_t)gps_time;
+       struct tm       tm_time;
+
+       gmtime_r(&int_time, &tm_time);
+
+       snprintf(buf, sizeof(buf), "%04d-%02d-%02d",
+                tm_time.tm_year+1900, tm_time.tm_mon+1, tm_time.tm_mday);
+
+       return buf;
+}
+
+static gchar *gps_get_time_string(time_t gps_time)
+{
+       static gchar buf[256];
+       time_t int_time = (time_t)gps_time;
+       struct tm tm_time;
+
+       gmtime_r(&int_time, &tm_time);
+
+       snprintf(buf, sizeof(buf), "%02d:%02d:%02dZ",
+                tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec);
+
+       return buf;
+}
+
+static gboolean gps_write_log(gpointer data)
+{
+       GritsPluginGps *gps = (GritsPluginGps *)data;
+       struct gps_data_t *gps_data = &gps->gps_data;
+       gchar buf[256];
+       gchar filename[256];
+       gint fd;
+       gboolean new_file = FALSE;
+
+       if (gps_data == NULL) {
+               g_warning("Skipped write to GPS log file: "
+                         "can not get GPS coordinates.");
+               GPS_STATUS(gps, "Skipped write to GPS log file: "
+                         "can not get GPS coordinates.");
+               return TRUE;
+       }
 
        /* get filename from text entry box.  If empty, generate a name from
-        * the date and time and set it.
-        */
+        * the date and time and set it. */
        if (strlen(gtk_entry_get_text(
                      GTK_ENTRY(gps->ui.gps_log_filename_entry))) == 0) {
                snprintf(filename, sizeof(filename),
@@ -364,27 +421,27 @@ static gboolean gps_write_log(gpointer data)
                    g_warning("Error writing header to log file %s: %s",
                                    filename, strerror(errno));
                }
-       gps->ui.gps_log_number = 1;
+               gps->ui.gps_log_number = 1;
        }
 
        /* Write log entry.  Make sure this matches the header */
        /* "No,Date,Time,Lat,Lon,Ele,Head,Speed,Fix,RTR\n" */
        /* RTR values: T=time, B=button push, S=speed, D=distance */
        snprintf(buf, sizeof(buf), "%d,%s,%s,%lf,%lf,%lf,%lf,%lf,%c\n",
-       gps->ui.gps_log_number++,
-       gps_get_date_string(gps->gps_data.fix.time),
-       gps_get_time_string(gps->gps_data.fix.time),
-//     gps_data->fix.time,
-       gps_data->fix.latitude,
-       gps_data->fix.longitude,
-       gps_data->fix.altitude * METERS_TO_FEET,
-       gps_data->fix.track,
-       gps_data->fix.speed * METERS_TO_FEET,
-       'T'); /* position due to timer expired  */
+                       gps->ui.gps_log_number++,
+                       gps_get_date_string(gps->gps_data.fix.time),
+                       gps_get_time_string(gps->gps_data.fix.time),
+                       //gps_data->fix.time,
+                       gps_data->fix.latitude,
+                       gps_data->fix.longitude,
+                       gps_data->fix.altitude * METERS_TO_FEET,
+                       gps_data->fix.track,
+                       gps_data->fix.speed * METERS_TO_FEET,
+                       'T'); /* position due to timer expired  */
 
        if (write(fd, buf, strlen(buf)) == -1) {
                g_warning("Could not write log number %d to log file %s: %s",
-                   gps->ui.gps_log_number-1, filename, strerror(errno));
+                               gps->ui.gps_log_number-1, filename, strerror(errno));
        }
        close(fd);
 
@@ -394,136 +451,27 @@ static gboolean gps_write_log(gpointer data)
        return TRUE;
 }
 
-static gboolean on_gps_follow_clicked_event (GtkWidget *widget, gpointer user_data)
-{
-       GritsPluginGps *gps = (GritsPluginGps *)user_data;
-
-       g_debug("GritsPluginGps: follow_clicked_event - button status %d",
-               gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)));
-       if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) {
-               gps->follow_gps = TRUE;
-       } else {
-               gps->follow_gps = FALSE;
-       }
-
-       return FALSE;
-}
-
-
-static void gps_init_track_log_frame(GritsPluginGps *gps, GtkWidget *gbox)
-{
-       /* Track log box with enable checkbox and filename entry */
-       GtkWidget *gps_log_frame = gtk_frame_new ("Track Log");
-       GtkWidget *lbox = gtk_vbox_new (FALSE, 2);
-       gtk_container_add (GTK_CONTAINER (gps_log_frame), lbox);
-       gtk_box_pack_start (GTK_BOX(gbox), gps_log_frame,
-                       FALSE, FALSE, 0);
-
-       gps->ui.gps_log_checkbox =
-              gtk_check_button_new_with_label("Log Position to File");
-       g_signal_connect (G_OBJECT (gps->ui.gps_log_checkbox), "clicked",
-              G_CALLBACK (on_gps_log_clicked_event),
-              (gpointer)gps);
-       gtk_box_pack_start (GTK_BOX(lbox), gps->ui.gps_log_checkbox,
-              FALSE, FALSE, 0);
 
-       /* Set up filename entry box */
-       GtkWidget *fbox = gtk_hbox_new (FALSE, 2);
-       GtkWidget *filename_label = gtk_label_new ("Filename:");
-       gtk_box_pack_start (GTK_BOX(fbox), filename_label, FALSE, FALSE, 0);
-       gps->ui.gps_log_filename_entry = gtk_entry_new();
-       gtk_box_pack_start (GTK_BOX(fbox), gps->ui.gps_log_filename_entry,
-              TRUE, TRUE, 0);
-       gtk_box_pack_start (GTK_BOX(lbox), fbox, FALSE, FALSE, 0);
-
-       /* set up gps log interval slider */
-       GtkWidget *ubox = gtk_hbox_new (FALSE, 4);
-       GtkWidget *interval_label = gtk_label_new ("Update Interval:");
-       gtk_box_pack_start (GTK_BOX(ubox), interval_label, FALSE, FALSE, 0);
-       gps->ui.gps_log_interval_slider =
-                   gtk_hscale_new_with_range(1.0, 600.0, 30.0);
-       gtk_range_set_value (GTK_RANGE(gps->ui.gps_log_interval_slider),
-                   GPS_LOG_DEFAULT_UPDATE_INTERVAL);
-       g_signal_connect (G_OBJECT (gps->ui.gps_log_interval_slider),
-                   "value-changed",
-                   G_CALLBACK(on_gps_log_interval_changed_event),
-                   (gpointer)gps);
-       gtk_range_set_increments(
-                   GTK_RANGE(gps->ui.gps_log_interval_slider),
-                   10.0 /* step */, 30.0 /* page up/down */);
-       gtk_range_set_update_policy(
-                   GTK_RANGE(gps->ui.gps_log_interval_slider),
-                   GTK_UPDATE_DELAYED);
-       gtk_box_pack_start (GTK_BOX(ubox), gps->ui.gps_log_interval_slider,
-                   TRUE, TRUE, 0);
-       gtk_box_pack_start (GTK_BOX(lbox), ubox, FALSE, FALSE, 0);
-}
+/***************
+ * Range rings *
+ ***************/
 
-static gboolean on_gps_log_clicked_event (GtkWidget *widget, gpointer user_data)
+#ifdef GPS_RANGE_RINGS
+static gboolean on_gps_rangering_clicked_event(GtkWidget *widget, gpointer user_data)
 {
        GritsPluginGps *gps = (GritsPluginGps *)user_data;
 
-       g_debug("GritsPluginGps: log_clicked_event");
-
-       if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))  {
-               gps_write_log(gps);
-
-               /* Schedule log file write */
-               gps->ui.gps_log_timeout_id = g_timeout_add(
-                     gtk_range_get_value(
-                       GTK_RANGE(gps->ui.gps_log_interval_slider))*1000,
-                       gps_write_log, gps);
+       if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))  {
+               gps->gps_rangering_active = TRUE;
        } else {
-               /* button unchecked */
-               g_source_remove(gps->ui.gps_log_timeout_id);
-               gps->ui.gps_log_timeout_id = 0;
-               g_debug("GritsPluginGps: log_clicked_event - closed log file.");
-       }
-
-       return FALSE;
-}
-
-
-static void gps_init_status_info(GritsPluginGps *gps, GtkWidget *gbox)
-{
-       gps->ui.gps_status_frame = gtk_frame_new("GPS Data");
-       gps->ui.gps_status_table = gtk_table_new(5, 2, TRUE);
-       gtk_container_add(GTK_CONTAINER (gps->ui.gps_status_frame),
-                  gps->ui.gps_status_table);
-
-       /* gps data table setup */
-       gint i;
-       for (i = 0; i < sizeof(gps_table)/sizeof(*gps_table); i++) {
-               gps_table[i].label_widget = gtk_label_new (gps_table[i].label);
-               gtk_label_set_justify(GTK_LABEL(gps_table[i].label_widget),
-                                     GTK_JUSTIFY_LEFT);
-               gtk_table_attach(GTK_TABLE(gps->ui.gps_status_table),
-                                          gps_table[i].label_widget,
-                                          0, 1, i, i+1, 0, 0, 0, 0);
-               gps_table[i].value_widget = gtk_label_new(gps_table[i].initial_val);
-               gtk_table_attach( GTK_TABLE(gps->ui.gps_status_table),
-                               gps_table[i].value_widget, 1, 2, i, i+1, 0, 0, 0, 0);
-
-               PangoFontDescription *font_desc = pango_font_description_new ();
-               pango_font_description_set_size (font_desc,
-                               gps_table[i].font_size*PANGO_SCALE);
-               gtk_widget_modify_font (gps_table[i].label_widget, font_desc);
-               gtk_widget_modify_font (gps_table[i].value_widget, font_desc);
-               pango_font_description_free (font_desc);
+               gps->gps_rangering_active = FALSE;
        }
-       gtk_box_pack_start(GTK_BOX(gbox), gps->ui.gps_status_frame,
-                           FALSE, FALSE, 0);
 
-       /* Start UI refresh task, which will reschedule itgps. */
-       gps_redraw_all(gps);
-       gps->gps_update_timeout_id = g_timeout_add(
-                   GPS_UPDATE_INTERVAL*1000,
-                   gps_redraw_all, gps);
+       /* XXX force a redraw */
 
+       return FALSE;
 }
 
-
-#ifdef GPS_RANGE_RINGS
 static void gps_init_range_rings(GritsPluginGps *gps, GtkWidget *gbox)
 {
        GtkWidget *gps_range_ring_frame = gtk_frame_new("Range Rings");
@@ -538,22 +486,37 @@ static void gps_init_range_rings(GritsPluginGps *gps, GtkWidget *gbox)
        gtk_box_pack_start(GTK_BOX(cbox), gps->ui.gps_rangering_checkbox,
                      FALSE, FALSE, 0);
 }
+#endif /* GPS_RANGE_RINGS */
 
-static gboolean on_gps_rangering_clicked_event(GtkWidget *widget, gpointer user_data)
-{
-       GritsPluginGps *gps = (GritsPluginGps *)user_data;
 
-       if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))  {
-               gps->gps_rangering_active = TRUE;
-       } else {
-               gps->gps_rangering_active = FALSE;
-       }
+/****************
+ * Main drawing *
+ ****************/
 
-       /* XXX force a redraw */
+static gboolean gps_data_is_valid(struct gps_data_t *gps_data)
+{
+       if (gps_data != NULL && gps_data->online != -1.0 &&
+               gps_data->fix.mode >= MODE_2D &&
+               gps_data->status > STATUS_NO_FIX) {
+               return TRUE;
+       }
 
        return FALSE;
 }
-#endif /* GPS_RANGE_RINGS */
+
+static void gps_update_status(GritsPluginGps *gps)
+{
+       struct gps_data_t *gps_data = &gps->gps_data;
+
+       /* gps table update */
+       gint i;
+       gchar *str;
+       for (i = 0; i < G_N_ELEMENTS(gps_table); i++) {
+               gtk_label_set_markup (GTK_LABEL(gps_table[i].value_widget),
+                           (str = gps_table[i].get_data(gps_data)));
+               g_free(str);
+       }
+}
 
 /* external interface to update UI from latest GPS data. */
 gboolean gps_redraw_all(gpointer data)
@@ -573,7 +536,7 @@ gboolean gps_redraw_all(gpointer data)
        }
 
        /* update position labels */
-       update_gps_status(gps);
+       gps_update_status(gps);
 
        /* Update track and marker position */
        if (gps_data_is_valid(gps_data) && gps->track.active) {
@@ -613,24 +576,24 @@ gboolean gps_redraw_all(gpointer data)
                        gps->marker = NULL;
                }
 
-       gchar *path = find_path(GPS_MARKER_ICON_PATH, GPS_MARKER_ICON);
-       if (path) {
-               gps->marker = grits_marker_icon_new("GPS", path,
-                             gps_data->fix.track, TRUE, MARKER_DMASK_ICON);
-               g_free(path);
-       } else {
-               /* if icon not found just use a point */
-               g_warning("Could not find GPS marker icon %s in path %s.",
-                         GPS_MARKER_ICON, GPS_MARKER_ICON_PATH);
-               gps->marker = grits_marker_icon_new("GPS", NULL,
-                             gps_data->fix.track, FALSE,
-                             MARKER_DMASK_POINT|MARKER_DMASK_LABEL);
-       }
-               
-       GRITS_OBJECT(gps->marker)->center.lat  = gps_data->fix.latitude;
-       GRITS_OBJECT(gps->marker)->center.lon  = gps_data->fix.longitude;
-       GRITS_OBJECT(gps->marker)->center.elev = 0.0;
-       GRITS_OBJECT(gps->marker)->lod         = EARTH_R;
+               gchar *path = find_path(GPS_MARKER_ICON_PATH, GPS_MARKER_ICON);
+               if (path) {
+                       gps->marker = grits_marker_icon_new("GPS", path,
+                                     gps_data->fix.track, TRUE, MARKER_DMASK_ICON);
+                       g_free(path);
+               } else {
+                       /* if icon not found just use a point */
+                       g_warning("Could not find GPS marker icon %s in path %s.",
+                                 GPS_MARKER_ICON, GPS_MARKER_ICON_PATH);
+                       gps->marker = grits_marker_icon_new("GPS", NULL,
+                                     gps_data->fix.track, FALSE,
+                                     MARKER_DMASK_POINT|MARKER_DMASK_LABEL);
+               }
+
+               GRITS_OBJECT(gps->marker)->center.lat  = gps_data->fix.latitude;
+               GRITS_OBJECT(gps->marker)->center.lon  = gps_data->fix.longitude;
+               GRITS_OBJECT(gps->marker)->center.elev = 0.0;
+               GRITS_OBJECT(gps->marker)->lod         = EARTH_R;
 
                grits_viewer_add(gps->viewer,
                        GRITS_OBJECT(gps->marker),
@@ -658,217 +621,254 @@ gboolean gps_redraw_all(gpointer data)
 }
 
 
-/******************* Track handling routines *****************/
+/***************
+ * Config Area *
+ ***************/
 
-static void gps_track_init(struct gps_track_t *track)
+/* GPS Data Frame */
+static void gps_init_status_info(GritsPluginGps *gps, GtkWidget *gbox)
 {
-       /* Save a spot at the end for the NULL termination */
-       track->points = (gpointer)g_new0(double*, NUM_TRACK_GROUPS + 1);
-       track->cur_point  = 0;
-       track->cur_group  = 0;
-       track->num_points = 1;  /* starts at 1 so realloc logic works */
-       track->line = NULL;
-}
+       gps->ui.gps_status_frame = gtk_frame_new("GPS Data");
+       gps->ui.gps_status_table = gtk_table_new(5, 2, TRUE);
+       gtk_container_add(GTK_CONTAINER (gps->ui.gps_status_frame),
+                  gps->ui.gps_status_table);
 
-static void gps_track_clear(struct gps_track_t *track)
-{
-       gint pi;
-       for (pi = 0; pi < NUM_TRACK_GROUPS; pi++) {
-               if (track->points[pi] != NULL) {
-                       g_free(track->points[pi]);
-                       track->points[pi] = NULL;
-               }
+       /* gps data table setup */
+       gint i;
+       for (i = 0; i < G_N_ELEMENTS(gps_table); i++) {
+               gps_table[i].label_widget = gtk_label_new (gps_table[i].label);
+               gtk_label_set_justify(GTK_LABEL(gps_table[i].label_widget),
+                                     GTK_JUSTIFY_LEFT);
+               gtk_table_attach(GTK_TABLE(gps->ui.gps_status_table),
+                                          gps_table[i].label_widget,
+                                          0, 1, i, i+1, 0, 0, 0, 0);
+               gps_table[i].value_widget = gtk_label_new(gps_table[i].initial_val);
+               gtk_table_attach( GTK_TABLE(gps->ui.gps_status_table),
+                               gps_table[i].value_widget, 1, 2, i, i+1, 0, 0, 0, 0);
+
+               PangoFontDescription *font_desc = pango_font_description_new ();
+               pango_font_description_set_size (font_desc,
+                               gps_table[i].font_size*PANGO_SCALE);
+               gtk_widget_modify_font (gps_table[i].label_widget, font_desc);
+               gtk_widget_modify_font (gps_table[i].value_widget, font_desc);
+               pango_font_description_free (font_desc);
        }
-       track->cur_point  = 0;
-       track->cur_group  = 0;
-       track->num_points = 1;  /* starts at 1 so realloc logic works */
-}
+       gtk_box_pack_start(GTK_BOX(gbox), gps->ui.gps_status_frame,
+                           FALSE, FALSE, 0);
+
+       /* Start UI refresh task, which will reschedule itgps. */
+       gps_redraw_all(gps);
+       gps->gps_update_timeout_id = g_timeout_add(
+                   GPS_UPDATE_INTERVAL*1000,
+                   gps_redraw_all, gps);
 
-static void gps_track_free(struct gps_track_t *track)
-{
-       gps_track_clear(track);
-       g_free(track->points);
 }
 
-/* add a new track group (points in a track group are connected, and
- * separated from points in other track groups).
- */
-static void gps_track_group_incr(struct gps_track_t *track)
+/* GPS Control Frame */
+static gboolean on_gps_follow_clicked_event (GtkWidget *widget, gpointer user_data)
 {
-       gdouble (**points)[3] = track->points; /* for simplicity */
+       GritsPluginGps *gps = (GritsPluginGps *)user_data;
 
-       /* Just return if they increment it again before any points have
-        * been added.
-        */
-       if (points[track->cur_group] == NULL) {
-               return;
+       g_debug("GritsPluginGps: follow_clicked_event - button status %d",
+               gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)));
+       if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) {
+               gps->follow_gps = TRUE;
+       } else {
+               gps->follow_gps = FALSE;
        }
 
-       g_debug("GritsPluginGps: track_group_incr - track group %u->%u.",
-               track->cur_group, track->cur_group + 1);
-
-       track->cur_group++;
-       track->cur_point  = 0;
-       track->num_points = 1;  /* starts at 1 so realloc logic works */
-
-       if (track->cur_group >= NUM_TRACK_GROUPS) {
-               g_debug("GritsPluginGps: track_group_incr - track group %u "
-                       "is at max %u, shifting groups",
-                       track->cur_group, NUM_TRACK_GROUPS);
+       return FALSE;
+}
 
-               /* Free the oldest one which falls off the end */
-               g_free(points[0]);
+static gboolean on_gps_track_enable_clicked_event(GtkWidget *widget, gpointer user_data)
+{
+       GritsPluginGps *gps = (GritsPluginGps *)user_data;
 
-               /* shift the rest down, last one should be NULL already */
-               /* note we alloc NUM_TRACK_GROUPS+1 */
-               for (int pi = 0; pi < NUM_TRACK_GROUPS; pi++) {
-                       points[pi] = points[pi+1];
-               }
+       g_debug("GritsPluginGps: track_enable_clicked_event");
 
-               /* always write into the last group */
-               track->cur_group = NUM_TRACK_GROUPS - 1;
+       if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) {
+               /* start logging trip history */
+               GPS_STATUS(gps, "Enabled GPS track.");
+               gps->track.active = TRUE;
+       } else {
+               /* stop logging trip history */
+               GPS_STATUS(gps, "Disabled GPS track.");
+               gps->track.active = FALSE;
+               /* advance to the next track group, moving everything down if
+                * it's full. */
+               gps_track_group_incr(&gps->track);
        }
+
+       return FALSE;
 }
 
-static void gps_track_add_point(struct gps_track_t *track,
-    gdouble lat, gdouble lon, gdouble elevation)
+static gboolean on_gps_track_clear_clicked_event(GtkWidget *widget, gpointer user_data)
 {
-       gdouble (**points)[3] = track->points; /* for simplicity */
-
-       g_debug("GritsPluginGps: track_add_point");
+       GritsPluginGps *gps = (GritsPluginGps *)user_data;
 
-       g_assert(track->cur_group < NUM_TRACK_GROUPS &&
-               (track->cur_point <= track->num_points));
+       g_debug("GritsPluginGps: track_clear_clicked_event");
+       GPS_STATUS(gps, "Cleared GPS track.");
+       gps_track_clear(&gps->track);
 
-       /* resize/allocate the point group if the current one is full */
-       if (track->cur_point >= track->num_points - 1) {
-               guint new_size = track->num_points == 1 ?
-                           NUM_TRACK_POINTS :
-                           track->num_points * NUM_TRACK_POINTS_FACTOR;
-               g_debug("GritsPluginGps: track_add_point - reallocating points "
-                       "array from %u points to %u points.\n",
-                       track->num_points, new_size);
-               points[track->cur_group] = (gpointer)g_renew(gdouble,
-                           points[track->cur_group], 3*(new_size+1));
-               track->num_points = new_size;
-       }
+       return FALSE;
+}
 
-       g_assert(points[track->cur_group] != NULL);
+static void gps_init_control_frame(GritsPluginGps *gps, GtkWidget *gbox)
+{
+       /* Control checkboxes */
+       GtkWidget *gps_control_frame = gtk_frame_new("GPS Control");
+       GtkWidget *cbox = gtk_vbox_new(FALSE, 2);
+       gtk_container_add(GTK_CONTAINER(gps_control_frame), cbox);
+       gtk_box_pack_start(GTK_BOX(gbox), gps_control_frame, FALSE, FALSE, 0);
 
-       /* Add the coordinate */
-       lle2xyz(lat, lon, elevation,
-           &points[track->cur_group][track->cur_point][0],
-           &points[track->cur_group][track->cur_point][1],
-           &points[track->cur_group][track->cur_point][2]);
+       gps->ui.gps_follow_checkbox =
+                     gtk_check_button_new_with_label("Follow GPS");
+       g_signal_connect(G_OBJECT(gps->ui.gps_follow_checkbox), "clicked",
+                     G_CALLBACK (on_gps_follow_clicked_event),
+                     (gpointer)gps);
+       gtk_box_pack_start(GTK_BOX(cbox), gps->ui.gps_follow_checkbox,
+                      FALSE, FALSE, 0);
 
-       track->cur_point++;
+       gps->ui.gps_track_checkbox =
+                      gtk_check_button_new_with_label("Record Track");
+       g_signal_connect(G_OBJECT(gps->ui.gps_track_checkbox), "clicked",
+                      G_CALLBACK (on_gps_track_enable_clicked_event),
+                      (gpointer)gps);
+       gtk_box_pack_start(GTK_BOX(cbox), gps->ui.gps_track_checkbox,
+                      FALSE, FALSE, 0);
 
-       /* make sure last point is always 0s so the line drawing stops. */
-       points[track->cur_group][track->cur_point][0] = 0.0;
-       points[track->cur_group][track->cur_point][1] = 0.0;
-       points[track->cur_group][track->cur_point][2] = 0.0;
+       gps->ui.gps_clear_button = gtk_button_new_with_label("Clear Track");
+       g_signal_connect(G_OBJECT(gps->ui.gps_clear_button), "clicked",
+                     G_CALLBACK (on_gps_track_clear_clicked_event),
+                     (gpointer)gps);
+       gtk_box_pack_start(GTK_BOX(cbox), gps->ui.gps_clear_button,
+                      FALSE, FALSE, 0);
 }
 
-
-static gchar *gps_get_status(struct gps_data_t *gps_data)
+/* Track Log Frame */
+static gboolean on_gps_log_clicked_event(GtkWidget *widget, gpointer user_data)
 {
-       gchar *status_color;
-       gchar *status_text;
+       GritsPluginGps *gps = (GritsPluginGps *)user_data;
 
-       switch (gps_data->fix.mode) {
-       case MODE_NOT_SEEN:
-               status_color = "red";
-               status_text = "No Signal";
-               break;
-       case MODE_NO_FIX:
-               status_color = "red";
-               status_text = "No Fix";
-               break;
-       case MODE_2D:
-               status_color = "yellow";
-               status_text = "2D Mode";
-               break;
-       case MODE_3D:
-               status_color = "green";
-               status_text = "3D Mode";
-               break;
-       default:
-               status_color = "black";
-               status_text = "Unknown";
-               break;
+       g_debug("GritsPluginGps: log_clicked_event");
+
+       if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))  {
+               gps_write_log(gps);
+
+               /* Schedule log file write */
+               gps->ui.gps_log_timeout_id = g_timeout_add(
+                     gtk_range_get_value(
+                       GTK_RANGE(gps->ui.gps_log_interval_slider))*1000,
+                       gps_write_log, gps);
+       } else {
+               /* button unchecked */
+               g_source_remove(gps->ui.gps_log_timeout_id);
+               gps->ui.gps_log_timeout_id = 0;
+               g_debug("GritsPluginGps: log_clicked_event - closed log file.");
        }
-       return g_strdup_printf("<span foreground=\"%s\">%s</span>",
-                               status_color, status_text);
-}
 
-#if 0
-static gchar *gps_get_online(struct gps_data_t *);
+       return FALSE;
+}
 
-static gchar *gps_get_online(struct gps_data_t *gps_data)
+static gboolean on_gps_log_interval_changed_event(GtkWidget *widget, gpointer user_data)
 {
-       gchar *status_str;
-       gchar *online_str;
+       GritsPluginGps *gps = (GritsPluginGps *)user_data;
 
-       if (gps_data->online == -1.0) {
-               online_str = "Offline";
-       } else {
-               online_str = "Online";
-       }
+       g_assert(gps);
 
-       switch (gps_data->status) {
-       case 0:
-               status_str = "No Fix";
-               break;
-       case 1:
-               status_str = "Fix Acquired";
-               break;
-       case 2:
-               status_str = "DGPS Fix";
-               break;
-       default:
-               status_str = "Unknown Status";
-               break;
-       }
+       g_debug("GritsPluginGps: log_interval_changed_event - value = %f",
+       gtk_range_get_value(GTK_RANGE(widget)));
 
-       return g_strdup_printf("%lf,%s,%s", gps_data->online, online_str, status_str);
-}
-#endif
+       if (gtk_toggle_button_get_active(
+                       GTK_TOGGLE_BUTTON(gps->ui.gps_log_checkbox))) {
+               g_assert(gps->ui.gps_log_timeout_id != 0);
 
+               /* disable old timeout */
+               g_source_remove(gps->ui.gps_log_timeout_id);
+               gps->ui.gps_log_timeout_id = 0;
 
+               /* Schedule new log file write */
+               gps->ui.gps_log_timeout_id = g_timeout_add(
+                        gtk_range_get_value(GTK_RANGE(widget))*1000,
+                        gps_write_log, gps);
+               gps_write_log(gps);
+       }
 
-static gchar *gps_get_latitude(struct gps_data_t *gps_data)
-{
-       return g_strdup_printf("%3.4f", gps_data->fix.latitude);
+       return FALSE;
 }
 
-static gchar *gps_get_longitude(struct gps_data_t *gps_data)
+static void gps_init_track_log_frame(GritsPluginGps *gps, GtkWidget *gbox)
 {
-       return g_strdup_printf("%3.4f", gps_data->fix.longitude);
-}
+       /* Track log box with enable checkbox and filename entry */
+       GtkWidget *gps_log_frame = gtk_frame_new ("Track Log");
+       GtkWidget *lbox = gtk_vbox_new (FALSE, 2);
+       gtk_container_add (GTK_CONTAINER (gps_log_frame), lbox);
+       gtk_box_pack_start (GTK_BOX(gbox), gps_log_frame,
+                       FALSE, FALSE, 0);
 
-static gchar *gps_get_elevation(struct gps_data_t *gps_data)
-{
-       /* XXX Make units (m/ft) settable */
-       return g_strdup_printf("%.1lf %s",
-                   (gps_data->fix.altitude * METERS_TO_FEET), "ft");
-}
+       gps->ui.gps_log_checkbox =
+              gtk_check_button_new_with_label("Log Position to File");
+       g_signal_connect (G_OBJECT (gps->ui.gps_log_checkbox), "clicked",
+              G_CALLBACK (on_gps_log_clicked_event),
+              (gpointer)gps);
+       gtk_box_pack_start (GTK_BOX(lbox), gps->ui.gps_log_checkbox,
+              FALSE, FALSE, 0);
 
-static gchar *gps_get_heading(struct gps_data_t *gps_data)
-{
-       /* XXX Make units (m/ft) settable */
-       return g_strdup_printf("%03.0lf", gps_data->fix.track);
+       /* Set up filename entry box */
+       GtkWidget *fbox = gtk_hbox_new (FALSE, 2);
+       GtkWidget *filename_label = gtk_label_new ("Filename:");
+       gtk_box_pack_start (GTK_BOX(fbox), filename_label, FALSE, FALSE, 0);
+       gps->ui.gps_log_filename_entry = gtk_entry_new();
+       gtk_box_pack_start (GTK_BOX(fbox), gps->ui.gps_log_filename_entry,
+              TRUE, TRUE, 0);
+       gtk_box_pack_start (GTK_BOX(lbox), fbox, FALSE, FALSE, 0);
+
+       /* set up gps log interval slider */
+       GtkWidget *ubox = gtk_hbox_new (FALSE, 4);
+       GtkWidget *interval_label = gtk_label_new ("Update Interval:");
+       gtk_box_pack_start (GTK_BOX(ubox), interval_label, FALSE, FALSE, 0);
+       gps->ui.gps_log_interval_slider =
+                   gtk_hscale_new_with_range(1.0, 600.0, 30.0);
+       gtk_range_set_value (GTK_RANGE(gps->ui.gps_log_interval_slider),
+                   GPS_LOG_DEFAULT_UPDATE_INTERVAL);
+       g_signal_connect (G_OBJECT (gps->ui.gps_log_interval_slider),
+                   "value-changed",
+                   G_CALLBACK(on_gps_log_interval_changed_event),
+                   (gpointer)gps);
+       gtk_range_set_increments(
+                   GTK_RANGE(gps->ui.gps_log_interval_slider),
+                   10.0 /* step */, 30.0 /* page up/down */);
+       gtk_range_set_update_policy(
+                   GTK_RANGE(gps->ui.gps_log_interval_slider),
+                   GTK_UPDATE_DELAYED);
+       gtk_box_pack_start (GTK_BOX(ubox), gps->ui.gps_log_interval_slider,
+                   TRUE, TRUE, 0);
+       gtk_box_pack_start (GTK_BOX(lbox), ubox, FALSE, FALSE, 0);
 }
 
-static gchar *gps_get_speed(struct gps_data_t *gps_data)
+
+/*******************
+ * GPSD interfaces *
+ *******************/
+
+static void process_gps(gpointer data, gint source, GdkInputCondition condition)
 {
-       /* XXX Make units (m/ft) settable */
-       return g_strdup_printf("%1.1f %s",
-               (gps_data->fix.speed*3600.0*METERS_TO_FEET/5280.0), "mph");
-}
+       struct gps_data_t *gps_data = (struct gps_data_t *)data;
+
+       g_debug("GritsPluginGps: process_gps");
 
+       /* Process any data from the gps and call the hook function */
+       if (gps_data != NULL) {
+               gint result = gps_read(gps_data);
+               g_debug("GritsPluginGps: process_gps - gps_read returned %d, "
+                       "position %f, %f.", result,
+                       gps_data->fix.latitude, gps_data->fix.longitude);
+       } else {
+               g_warning("GritsPluginGps: process_gps - gps_data == NULL.");
+       }
+}
 
-static gint initialize_gpsd(char *server, gchar *port,
-       struct gps_data_t *gps_data)
+static gint initialize_gpsd(char *server, gchar *port, struct gps_data_t *gps_data)
 {
 #if GPSD_API_MAJOR_VERSION < 5
 #error "GPSD protocol version 5 or greater required."
@@ -888,24 +888,10 @@ static gint initialize_gpsd(char *server, gchar *port,
        return result;
 }
 
-static void process_gps(gpointer data, gint source, GdkInputCondition condition)
-{
-       struct gps_data_t *gps_data = (struct gps_data_t *)data;
 
-       g_debug("GritsPluginGps: process_gps");
-
-       /* Process any data from the gps and call the hook function */
-       if (gps_data != NULL) {
-               gint result = gps_read(gps_data);
-               g_debug("GritsPluginGps: process_gps - gps_read returned %d, "
-                       "position %f, %f.", result,
-                       gps_data->fix.latitude, gps_data->fix.longitude);
-       } else {
-               g_warning("GritsPluginGps: process_gps - gps_data == NULL.");
-       }
-}
-
-/************************** GPS Object Methods *************************/
+/**********************
+ * GPS Plugin Methods *
+ **********************/
 
 /* Methods */
 GritsPluginGps *grits_plugin_gps_new(GritsViewer *viewer, GritsPrefs *prefs)
@@ -918,7 +904,7 @@ GritsPluginGps *grits_plugin_gps_new(GritsViewer *viewer, GritsPrefs *prefs)
 
        initialize_gpsd("localhost", DEFAULT_GPSD_PORT, &gps->gps_data);
        gps->follow_gps = FALSE;
-       
+
        gps_track_init(&gps->track);
        gps_init_status_info(gps, gps->hbox);
        gps_init_control_frame(gps, gps->hbox);
@@ -930,7 +916,6 @@ GritsPluginGps *grits_plugin_gps_new(GritsViewer *viewer, GritsPrefs *prefs)
        return gps;
 }
 
-
 static GtkWidget *grits_plugin_gps_get_config(GritsPlugin *_gps)
 {
        GritsPluginGps *gps = GRITS_PLUGIN_GPS(_gps);
index b2fe36e38bf3f517599f198f8652cdf73fabfd5a..5495b26ff71fc383c6e7397bcce49e964f107f94 100644 (file)
 #ifndef _GPS_PLUGIN_H
 #define _GPS_PLUGIN_H
 
-gpointer gps_init(GtkWidget *gbox, GtkWidget *status_bar);
-
-void gps_set_follow(gpointer state, gboolean track);
-gboolean gps_key_press_event(gpointer state, GdkEventKey *kevent);
-gboolean gps_redraw_all(gpointer data);
-
 #define GRITS_TYPE_PLUGIN_GPS            (grits_plugin_gps_get_type ())
 #define GRITS_PLUGIN_GPS(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),   GRITS_TYPE_PLUGIN_GPS, GritsPluginGps))
 #define GRITS_IS_PLUGIN_GPS(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),   GRITS_TYPE_PLUGIN_GPS))
@@ -34,7 +28,7 @@ typedef struct _GritsPluginGps      GritsPluginGps;
 typedef struct _GritsPluginGpsClass GritsPluginGpsClass;
 
 /* All the User Interface objects we need to keep track of. */
-struct gps_ui_t {
+typedef struct {
        /* gps info frame */
        GtkWidget *gps_status_frame;
        GtkWidget *gps_status_table;
@@ -55,22 +49,22 @@ struct gps_ui_t {
        GtkWidget *gps_log_checkbox;
        GtkWidget *gps_log_filename_entry;
        GtkWidget *gps_log_interval_slider;
-       guint gps_log_timeout_id;               /* id of timeout so we can delete it */
-       guint gps_log_number;   /* sequential log number */
+       guint      gps_log_timeout_id; /* id of timeout so we can delete it */
+       guint      gps_log_number;     /* sequential log number */
 
        /* range ring frame */
        GtkWidget *gps_rangering_checkbox;
-};
+} GpsUi;
 
-struct gps_track_t {
+typedef struct {
        /* track storage */
-       gboolean active;        /* Display track history */
+       gboolean   active;  /* Display track history */
        gdouble (**points)[3];
        GritsLine *line;
-       guint cur_point;
-       guint num_points;
-       guint cur_group;
-};
+       guint      cur_point;
+       guint      num_points;
+       guint      cur_group;
+} GpsTrack;
 
 /* GPS private data */
 struct _GritsPluginGps {
@@ -81,16 +75,17 @@ struct _GritsPluginGps {
        GritsPrefs  *prefs;
        GtkWidget   *config;
        guint        tab_id;
-       GtkWidget *hbox;
+       GtkWidget   *hbox;
        GritsMarker *marker;
 
        struct gps_data_t gps_data;
-       gboolean follow_gps;
-       gboolean gps_rangering_active;  /* range rings are visible or not */
-       guint gps_update_timeout_id;    /* id of timeout so we can delete it */
 
-       struct gps_track_t track;
-       struct gps_ui_t ui;
+       gboolean     follow_gps;
+       gboolean     gps_rangering_active;  /* range rings are visible or not */
+       guint        gps_update_timeout_id; /* id of timeout so we can delete it */
+
+       GpsTrack     track;
+       GpsUi        ui;
 };
 
 struct _GritsPluginGpsClass {