summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Dirk Hohndel <dirk@hohndel.org>2013-01-28 07:54:30 -0800
committerGravatar Dirk Hohndel <dirk@hohndel.org>2013-01-28 13:07:08 -0800
commit332d372b809476df48c987b24476801a61e7e0f2 (patch)
tree37fd62e0ffe2ee54636c4f18af84258b7fc5a4ad
parent075aba8f7da8139c1dced48e5c0b8ea60cc7ae8f (diff)
downloadsubsurface-332d372b809476df48c987b24476801a61e7e0f2.tar.gz
Pick GPS coordinates of dive location via map widget
I have some concerns about the way this is implemented - especially the use of gtk_grab_add to make the map widget work has me worried. But it seems to work and survived some test cases that I threw at it. The GtkButton with the Pixmap looks a little off on my screen, but this way it was easy to implement. Feel free to come up with a better design. Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
-rw-r--r--display-gtk.h1
-rw-r--r--dive.h2
-rw-r--r--divelist.c17
-rw-r--r--gps.c77
-rw-r--r--info.c63
5 files changed, 136 insertions, 24 deletions
diff --git a/display-gtk.h b/display-gtk.h
index df29ff1d8..07dc58123 100644
--- a/display-gtk.h
+++ b/display-gtk.h
@@ -71,6 +71,7 @@ extern GtkWidget *weightsystem_list_widget(int w_idx);
extern GtkWidget *dive_list_create(void);
extern void dive_list_destroy(void);
+extern GdkPixbuf *get_gps_icon(void);
extern gboolean icon_click_cb(GtkWidget *w, GdkEventButton *event, gpointer data);
diff --git a/dive.h b/dive.h
index c9f43d81e..6a6ab3eee 100644
--- a/dive.h
+++ b/dive.h
@@ -486,7 +486,7 @@ extern void show_dive_stats(struct dive *);
extern void clear_stats_widgets(void);
extern void show_gps_locations(void);
-extern void show_gps_location(struct dive *);
+extern void show_gps_location(struct dive *, void (*callback)(float, float));
extern void show_yearly_stats(void);
diff --git a/divelist.c b/divelist.c
index 245ff4499..f6ddb0cd3 100644
--- a/divelist.c
+++ b/divelist.c
@@ -980,10 +980,15 @@ static void get_suit(struct dive *dive, char **str)
get_string(str, dive->suit);
}
-static GdkPixbuf *get_gps_icon(struct dive *dive)
+GdkPixbuf *get_gps_icon(void)
+{
+ return gdk_pixbuf_from_pixdata(&my_pixbuf, TRUE, NULL);
+}
+
+GdkPixbuf *get_gps_icon_for_dive(struct dive *dive)
{
if (dive_has_location(dive))
- return gdk_pixbuf_from_pixdata(&my_pixbuf, TRUE, NULL);
+ return get_gps_icon();
else
return NULL;
}
@@ -1010,7 +1015,7 @@ static void fill_one_dive(struct dive *dive,
get_cylinder(dive, &cylinder);
get_location(dive, &location);
get_suit(dive, &suit);
- icon = get_gps_icon(dive);
+ icon = get_gps_icon_for_dive(dive);
gtk_tree_store_set(GTK_TREE_STORE(model), iter,
DIVE_NR, dive->number,
DIVE_LOCATION, location,
@@ -1413,7 +1418,7 @@ static void fill_dive_list(void)
/* store dive */
update_cylinder_related_info(dive);
gtk_tree_store_append(treestore, &iter, parent_ptr);
- icon = get_gps_icon(dive);
+ icon = get_gps_icon_for_dive(dive);
gtk_tree_store_set(treestore, &iter,
DIVE_INDEX, i,
DIVE_NR, dive->number,
@@ -1694,7 +1699,7 @@ void edit_dive_when_cb(GtkWidget *menuitem, struct dive *dive)
#if HAVE_OSM_GPS_MAP
static void show_gps_location_cb(GtkWidget *menuitem, struct dive *dive)
{
- show_gps_location(dive);
+ show_gps_location(dive, NULL);
}
#endif
@@ -1716,7 +1721,7 @@ gboolean icon_click_cb(GtkWidget *w, GdkEventButton *event, gpointer data)
gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_INDEX, &idx, -1);
dive = get_dive(idx);
if (dive && dive_has_location(dive))
- show_gps_location(dive);
+ show_gps_location(dive, NULL);
}
if (path)
gtk_tree_path_free(path);
diff --git a/gps.c b/gps.c
index c3af0522f..4a2b527b8 100644
--- a/gps.c
+++ b/gps.c
@@ -20,10 +20,60 @@ static OsmGpsMapSource_t opt_map_provider = OSM_GPS_MAP_SOURCE_GOOGLE_STREET;
static void on_close(GtkWidget *widget, gpointer user_data)
{
GtkWidget **window = user_data;
+ gtk_grab_remove(widget);
gtk_widget_destroy(widget);
*window = NULL;
}
+struct maplocation {
+ OsmGpsMap *map;
+ double x,y;
+ void (* callback)(float, float);
+ GtkWidget *mapwindow;
+};
+
+static void add_location_cb(GtkWidget *widget, gpointer data)
+{
+ struct maplocation *maplocation = data;
+ OsmGpsMap *map = maplocation->map;
+ OsmGpsMapPoint *pt = osm_gps_map_point_new_degrees(0.0, 0.0);
+ float mark_lat, mark_lon;
+
+ osm_gps_map_convert_screen_to_geographic(map, maplocation->x, maplocation->y, pt);
+ osm_gps_map_point_get_degrees(pt, &mark_lat, &mark_lon);
+ maplocation->callback(mark_lat, mark_lon);
+ gtk_widget_destroy(gtk_widget_get_parent(maplocation->mapwindow));
+}
+
+static void map_popup_menu_cb(GtkWidget *w, gpointer data)
+{
+ GtkWidget *menu, *menuitem, *image;
+
+ menu = gtk_menu_new();
+ menuitem = gtk_image_menu_item_new_with_label(_("Mark location here"));
+ image = gtk_image_new_from_stock(GTK_STOCK_ADD, GTK_ICON_SIZE_MENU);
+ gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), image);
+ g_signal_connect(menuitem, "activate", G_CALLBACK(add_location_cb), data);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
+ gtk_widget_show_all(menu);
+ gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
+ 3, gtk_get_current_event_time());
+}
+
+static gboolean button_cb(GtkWidget *widget, GdkEventButton *event, gpointer data)
+{
+ static struct maplocation maplocation = {};
+ if (data && event->type == GDK_BUTTON_PRESS && event->button == 3) {
+ maplocation.map = (OsmGpsMap *)widget;
+ maplocation.x = event->x;
+ maplocation.y = event->y;
+ maplocation.callback = data;
+ maplocation.mapwindow = widget;
+ map_popup_menu_cb(widget, &maplocation);
+ }
+ return FALSE;
+}
+
/* the osm gps map default is to scroll-and-recenter around the mouse position
* that is BAT SHIT CRAZY.
* So let's do our own scroll handling instead */
@@ -85,7 +135,6 @@ static void add_gps_point(OsmGpsMap *map, float latitude, float longitude)
osm_gps_map_track_add(map, track);
}
-
OsmGpsMap *init_map(void)
{
OsmGpsMap *map;
@@ -117,7 +166,7 @@ OsmGpsMap *init_map(void)
return map;
}
-void show_map(OsmGpsMap *map, GtkWidget **window)
+void show_map(OsmGpsMap *map, GtkWidget **window, struct dive *dive, void (*callback)(float, float))
{
if (!*window) {
/* Enable keyboard navigation */
@@ -137,19 +186,23 @@ void show_map(OsmGpsMap *map, GtkWidget **window)
g_signal_connect(*window, "destroy", G_CALLBACK(on_close), (gpointer)window);
g_signal_connect(G_OBJECT(map), "scroll-event", G_CALLBACK(scroll_cb), NULL);
}
+ if (callback)
+ g_signal_connect(G_OBJECT(map), "button-press-event", G_CALLBACK(button_cb), callback);
gtk_widget_show_all(*window);
gtk_window_present(GTK_WINDOW(*window));
+ if (callback)
+ gtk_grab_add(*window);
}
-void show_gps_location(struct dive *dp)
+void show_gps_location(struct dive *dive, void (*callback)(float, float))
{
static GtkWidget *window = NULL;
static OsmGpsMap *map = NULL;
GdkPixbuf *picture;
GError *gerror = NULL;
- double lat = dp->latitude.udeg / 1000000.0;
- double lng = dp->longitude.udeg / 1000000.0;
+ double lat = dive->latitude.udeg / 1000000.0;
+ double lng = dive->longitude.udeg / 1000000.0;
if (!map || !window)
map = init_map();
@@ -165,26 +218,26 @@ void show_gps_location(struct dive *dp)
} else {
osm_gps_map_set_center_and_zoom(map, 0, 0, 2);
}
- show_map(map, &window);
+ show_map(map, &window, dive, callback);
}
void show_gps_locations()
{
static OsmGpsMap *map = NULL;
static GtkWidget *window = NULL;
- struct dive *dp;
+ struct dive *dive;
int idx;
if (!window || !map)
map = init_map();
- for_each_dive(idx, dp) {
- if (dive_has_location(dp)) {
- add_gps_point(map, dp->latitude.udeg / 1000000.0,
- dp->longitude.udeg / 1000000.0);
+ for_each_dive(idx, dive) {
+ if (dive_has_location(dive)) {
+ add_gps_point(map, dive->latitude.udeg / 1000000.0,
+ dive->longitude.udeg / 1000000.0);
}
}
osm_gps_map_set_center_and_zoom(map, 0, 0, 2);
- show_map(map, &window);
+ show_map(map, &window, NULL, NULL);
}
diff --git a/info.c b/info.c
index 4104b5af5..ed7f954dc 100644
--- a/info.c
+++ b/info.c
@@ -520,6 +520,7 @@ static gboolean gps_changed(struct dive *dive, struct dive *master, const char *
struct dive_info {
GtkComboBoxEntry *location, *divemaster, *buddy, *rating, *suit, *viz;
GtkEntry *airtemp, *gps;
+ GtkWidget *gps_icon;
GtkTextView *notes;
};
@@ -626,12 +627,52 @@ static void dive_trip_widget(GtkWidget *box, dive_trip_t *trip, struct dive_info
gtk_text_buffer_set_text(gtk_text_view_get_buffer(info->notes), trip->notes, -1);
}
+struct location_update {
+ GtkEntry *entry;
+ struct dive *dive;
+ void (*callback)(float, float);
+} location_update;
+
+void print_gps_coordinates(char *buffer, int len, float lat, float lon)
+{
+ unsigned int latdeg, londeg;
+ float latmin, lonmin;
+ char *lath, *lonh;
+
+ lath = lat >= 0.0 ? "N" : "S";
+ lonh = lon >= 0.0 ? "E" : "W";
+ lat = fabs(lat);
+ lon = fabs(lon);
+ latdeg = lat;
+ londeg = lon;
+ latmin = (lat - latdeg) * 60.0;
+ lonmin = (lon - londeg) * 60.0;
+ snprintf(buffer, len, "%s%u%s %6.3f\' , %s%u%s %6.3f\'",
+ lath, latdeg, UTF8_DEGREE, latmin,
+ lonh, londeg, UTF8_DEGREE, lonmin);
+}
+
+void update_gps_entry(float lat, float lon)
+{
+ char gps_text[45];
+
+ print_gps_coordinates(gps_text, 45, lat, lon);
+ gtk_entry_set_text(location_update.entry, gps_text);
+}
+
+static gboolean gps_map_callback(GtkWidget *w, gpointer data)
+{
+ struct dive *dive = location_update.dive;
+ show_gps_location(dive, update_gps_entry);
+ return TRUE;
+}
+
static void dive_info_widget(GtkWidget *box, struct dive *dive, struct dive_info *info, gboolean multi)
{
- GtkWidget *hbox, *label, *frame, *equipment;
+ GtkWidget *hbox, *label, *frame, *equipment, *image;
char buffer[128];
char airtemp[6];
- char gps_text[25] = "";
+ char gps_text[45] = "";
const char *unit;
double value;
@@ -645,9 +686,21 @@ static void dive_info_widget(GtkWidget *box, struct dive *dive, struct dive_info
info->location = text_entry(box, _("Location"), location_list, dive->location);
if (dive_has_location(dive))
- snprintf(gps_text, sizeof(gps_text), "%3.5lf;%3.5lf", dive->latitude.udeg / 1000000.0,
- dive->longitude.udeg / 1000000.0);
- info->gps = single_text_entry(box, _("GPS (WGS84 or GPS format - use ';' as separator)"), gps_text);
+ print_gps_coordinates(gps_text, sizeof(gps_text), dive->latitude.udeg / 1000000.0,
+ dive->longitude.udeg / 1000000.0);
+ hbox = gtk_hbox_new(FALSE, 2);
+ gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, TRUE, 0);
+ info->gps = single_text_entry(hbox, _("GPS (WGS84 or GPS format)"), gps_text);
+ gtk_entry_set_width_chars(info->gps, 30);
+ info->gps_icon = gtk_button_new_with_label(_("Pick on map"));
+ gtk_box_pack_start(GTK_BOX(hbox), info->gps_icon, FALSE, FALSE, 6);
+ image = gtk_image_new_from_pixbuf(get_gps_icon());
+ gtk_image_set_pixel_size(GTK_IMAGE(image), 128);
+ gtk_button_set_image(GTK_BUTTON(info->gps_icon), image);
+
+ location_update.entry = info->gps;
+ location_update.dive = dive;
+ g_signal_connect(G_OBJECT(info->gps_icon), "clicked", G_CALLBACK(gps_map_callback), NULL);
hbox = gtk_hbox_new(FALSE, 3);
gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, TRUE, 0);