1 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*- */
2 /* vim:set et sw=4 ts=4 cino=t0,(0: */
3 /*
4  * main.c
5  * Copyright (C) John Stowers 2008 <john.stowers@gmail.com>
6  *
7  * This is free software: you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; version 2.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <stdlib.h>
21 #include <math.h>
22 #include <glib.h>
23 #include <gtk/gtk.h>
24 #include <gdk/gdkkeysyms.h>
25 
26 #include "osm-gps-map.h"
27 
28 static OsmGpsMapSource_t opt_map_provider = OSM_GPS_MAP_SOURCE_OPENSTREETMAP;
29 static gboolean opt_friendly_cache = FALSE;
30 static gboolean opt_no_cache = FALSE;
31 static gboolean opt_debug = FALSE;
32 static char *opt_cache_base_dir = NULL;
33 static gboolean opt_editable_tracks = FALSE;
34 static GOptionEntry entries[] =
35 {
36   { "friendly-cache", 'f', 0, G_OPTION_ARG_NONE, &opt_friendly_cache, "Store maps using friendly cache style (source name)", NULL },
37   { "no-cache", 'n', 0, G_OPTION_ARG_NONE, &opt_no_cache, "Disable cache", NULL },
38   { "cache-basedir", 'b', 0, G_OPTION_ARG_FILENAME, &opt_cache_base_dir, "Cache basedir", NULL },
39   { "debug", 'd', 0, G_OPTION_ARG_NONE, &opt_debug, "Enable debugging", NULL },
40   { "map", 'm', 0, G_OPTION_ARG_INT, &opt_map_provider, "Map source", "N" },
41   { "editable-tracks", 'e', 0, G_OPTION_ARG_NONE, &opt_editable_tracks, "Make the tracks editable", NULL },
42   { NULL }
43 };
44 
45 static GdkPixbuf *g_star_image = NULL;
46 static OsmGpsMapImage *g_last_image = NULL;
47 
48 static gboolean
on_button_press_event(GtkWidget * widget,GdkEventButton * event,gpointer user_data)49 on_button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer user_data)
50 {
51     OsmGpsMapPoint coord;
52     float lat, lon;
53     OsmGpsMap *map = OSM_GPS_MAP(widget);
54     OsmGpsMapTrack *othertrack = OSM_GPS_MAP_TRACK(user_data);
55 
56     int left_button =   (event->button == 1) && (event->state == 0);
57     int middle_button = (event->button == 2) || ((event->button == 1) && (event->state & GDK_SHIFT_MASK));
58     int right_button =  (event->button == 3) || ((event->button == 1) && (event->state & GDK_CONTROL_MASK));
59 
60     osm_gps_map_convert_screen_to_geographic(map, event->x, event->y, &coord);
61     osm_gps_map_point_get_degrees(&coord, &lat, &lon);
62 
63     if (event->type == GDK_3BUTTON_PRESS) {
64         if (middle_button) {
65             if (g_last_image)
66                 osm_gps_map_image_remove (map, g_last_image);
67         }
68         if (right_button) {
69             osm_gps_map_track_remove(map, othertrack);
70         }
71     } else if (event->type == GDK_2BUTTON_PRESS) {
72         if (left_button) {
73             osm_gps_map_gps_add (map,
74                                  lat,
75                                  lon,
76                                  g_random_double_range(0,360));
77         }
78         if (middle_button) {
79             g_last_image = osm_gps_map_image_add (map,
80                                                   lat,
81                                                   lon,
82                                                   g_star_image);
83         }
84         if (right_button) {
85             osm_gps_map_track_add_point(othertrack, &coord);
86         }
87     }
88 
89     return FALSE;
90 }
91 
92 static gboolean
on_button_release_event(GtkWidget * widget,GdkEventButton * event,gpointer user_data)93 on_button_release_event (GtkWidget *widget, GdkEventButton *event, gpointer user_data)
94 {
95     float lat,lon;
96     GtkEntry *entry = GTK_ENTRY(user_data);
97     OsmGpsMap *map = OSM_GPS_MAP(widget);
98 
99     g_object_get(map, "latitude", &lat, "longitude", &lon, NULL);
100     gchar *msg = g_strdup_printf("Map Centre: lattitude %f longitude %f",lat,lon);
101     gtk_entry_set_text(entry, msg);
102     g_free(msg);
103 
104     return FALSE;
105 }
106 
107 static gboolean
on_zoom_in_clicked_event(GtkWidget * widget,gpointer user_data)108 on_zoom_in_clicked_event (GtkWidget *widget, gpointer user_data)
109 {
110     int zoom;
111     OsmGpsMap *map = OSM_GPS_MAP(user_data);
112     g_object_get(map, "zoom", &zoom, NULL);
113     osm_gps_map_set_zoom(map, zoom+1);
114     return FALSE;
115 }
116 
117 static gboolean
on_zoom_out_clicked_event(GtkWidget * widget,gpointer user_data)118 on_zoom_out_clicked_event (GtkWidget *widget, gpointer user_data)
119 {
120     int zoom;
121     OsmGpsMap *map = OSM_GPS_MAP(user_data);
122     g_object_get(map, "zoom", &zoom, NULL);
123     osm_gps_map_set_zoom(map, zoom-1);
124     return FALSE;
125 }
126 
127 static gboolean
on_home_clicked_event(GtkWidget * widget,gpointer user_data)128 on_home_clicked_event (GtkWidget *widget, gpointer user_data)
129 {
130     OsmGpsMap *map = OSM_GPS_MAP(user_data);
131     osm_gps_map_set_center_and_zoom(map, -43.5326,172.6362,12);
132     return FALSE;
133 }
134 
135 static gboolean
on_cache_clicked_event(GtkWidget * widget,gpointer user_data)136 on_cache_clicked_event (GtkWidget *widget, gpointer user_data)
137 {
138     OsmGpsMap *map = OSM_GPS_MAP(user_data);
139     if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) {
140         int zoom,max_zoom;
141         OsmGpsMapPoint pt1, pt2;
142         osm_gps_map_get_bbox(map, &pt1, &pt2);
143         g_object_get(map, "zoom", &zoom, "max-zoom", &max_zoom, NULL);
144         osm_gps_map_download_maps(map, &pt1, &pt2, zoom, max_zoom);
145     } else {
146         osm_gps_map_download_cancel_all(map);
147     }
148     return FALSE;
149 }
150 
151 static void
on_tiles_queued_changed(OsmGpsMap * image,GParamSpec * pspec,gpointer user_data)152 on_tiles_queued_changed (OsmGpsMap *image, GParamSpec *pspec, gpointer user_data)
153 {
154     gchar *s;
155     int tiles;
156     GtkLabel *label = GTK_LABEL(user_data);
157     g_object_get(image, "tiles-queued", &tiles, NULL);
158     s = g_strdup_printf("%d", tiles);
159     gtk_label_set_text(label, s);
160     g_free(s);
161 }
162 
163 static void
on_gps_alpha_changed(GtkAdjustment * adjustment,gpointer user_data)164 on_gps_alpha_changed (GtkAdjustment *adjustment, gpointer user_data)
165 {
166     OsmGpsMap *map = OSM_GPS_MAP(user_data);
167     OsmGpsMapTrack *track = osm_gps_map_gps_get_track (map);
168     float f = gtk_adjustment_get_value(adjustment);
169     g_object_set (track, "alpha", f, NULL);}
170 
171 static void
on_gps_width_changed(GtkAdjustment * adjustment,gpointer user_data)172 on_gps_width_changed (GtkAdjustment *adjustment, gpointer user_data)
173 {
174     OsmGpsMap *map = OSM_GPS_MAP(user_data);
175     OsmGpsMapTrack *track = osm_gps_map_gps_get_track (map);
176     float f = gtk_adjustment_get_value(adjustment);
177     g_object_set (track, "line-width", f, NULL);
178 }
179 
180 static void
on_star_align_changed(GtkAdjustment * adjustment,gpointer user_data)181 on_star_align_changed (GtkAdjustment *adjustment, gpointer user_data)
182 {
183     const char *propname = user_data;
184     float f = gtk_adjustment_get_value(adjustment);
185     if (g_last_image)
186         g_object_set (g_last_image, propname, f, NULL);
187 }
188 
189 #if GTK_CHECK_VERSION(3,4,0)
190 static void
on_gps_color_changed(GtkColorChooser * widget,gpointer user_data)191 on_gps_color_changed (GtkColorChooser *widget, gpointer user_data)
192 {
193     GdkRGBA c;
194     OsmGpsMapTrack *track = OSM_GPS_MAP_TRACK(user_data);
195     gtk_color_chooser_get_rgba (widget, &c);
196     osm_gps_map_track_set_color(track, &c);
197 }
198 #else
199 static void
on_gps_color_changed(GtkColorButton * widget,gpointer user_data)200 on_gps_color_changed (GtkColorButton *widget, gpointer user_data)
201 {
202     GdkRGBA c;
203     OsmGpsMapTrack *track = OSM_GPS_MAP_TRACK(user_data);
204     gtk_color_button_get_rgba (widget, &c);
205     osm_gps_map_track_set_color(track, &c);
206 }
207 
208 #endif
209 
210 static void
on_close(GtkWidget * widget,gpointer user_data)211 on_close (GtkWidget *widget, gpointer user_data)
212 {
213     gtk_widget_destroy(widget);
214     gtk_main_quit();
215 }
216 
217 static void
usage(GOptionContext * context)218 usage (GOptionContext *context)
219 {
220     int i;
221 
222     puts(g_option_context_get_help(context, TRUE, NULL));
223 
224     printf("Valid map sources:\n");
225     for(i=OSM_GPS_MAP_SOURCE_NULL; i <= OSM_GPS_MAP_SOURCE_LAST; i++)
226     {
227         const char *name = osm_gps_map_source_get_friendly_name(i);
228         const char *uri = osm_gps_map_source_get_repo_uri(i);
229         if (uri != NULL)
230             printf("\t%d:\t%s\n",i,name);
231     }
232 }
233 
234 int
main(int argc,char ** argv)235 main (int argc, char **argv)
236 {
237     GtkBuilder *builder;
238     GtkWidget *widget;
239     GtkAccelGroup *ag;
240     OsmGpsMap *map;
241     OsmGpsMapLayer *osd;
242     OsmGpsMapTrack *rightclicktrack;
243     const char *repo_uri;
244     char *cachedir, *cachebasedir;
245     GError *error = NULL;
246     GOptionContext *context;
247 
248     gtk_init (&argc, &argv);
249 
250     context = g_option_context_new ("- Map browser");
251     g_option_context_set_help_enabled(context, FALSE);
252     g_option_context_add_main_entries (context, entries, NULL);
253 
254     if (!g_option_context_parse (context, &argc, &argv, &error)) {
255         usage(context);
256         return 1;
257     }
258 
259     /* Only use the repo_uri to check if the user has supplied a
260     valid map source ID */
261     repo_uri = osm_gps_map_source_get_repo_uri(opt_map_provider);
262     if ( repo_uri == NULL ) {
263         usage(context);
264         return 2;
265     }
266 
267     cachebasedir = osm_gps_map_get_default_cache_directory();
268 
269     if (opt_cache_base_dir && g_file_test(opt_cache_base_dir, G_FILE_TEST_IS_DIR)) {
270         cachedir = g_strdup(OSM_GPS_MAP_CACHE_AUTO);
271         cachebasedir = g_strdup(opt_cache_base_dir);
272     } else if (opt_friendly_cache) {
273         cachedir = g_strdup(OSM_GPS_MAP_CACHE_FRIENDLY);
274     } else if (opt_no_cache) {
275         cachedir = g_strdup(OSM_GPS_MAP_CACHE_DISABLED);
276     } else {
277         cachedir = g_strdup(OSM_GPS_MAP_CACHE_AUTO);
278     }
279 
280     if (opt_debug)
281         gdk_window_set_debug_updates(TRUE);
282 
283     g_debug("Map Cache Dir: %s", cachedir);
284     g_debug("Map Provider: %s (%d)", osm_gps_map_source_get_friendly_name(opt_map_provider), opt_map_provider);
285 
286     map = g_object_new (OSM_TYPE_GPS_MAP,
287                         "map-source",opt_map_provider,
288                         "tile-cache",cachedir,
289                         "tile-cache-base", cachebasedir,
290                         "proxy-uri",g_getenv("http_proxy"),
291                         NULL);
292 
293     osd = g_object_new (OSM_TYPE_GPS_MAP_OSD,
294                         "show-scale",TRUE,
295                         "show-coordinates",TRUE,
296                         "show-crosshair",TRUE,
297                         "show-dpad",TRUE,
298                         "show-zoom",TRUE,
299                         "show-gps-in-dpad",TRUE,
300                         "show-gps-in-zoom",FALSE,
301                         "dpad-radius", 30,
302                         NULL);
303     osm_gps_map_layer_add(OSM_GPS_MAP(map), osd);
304     g_object_unref(G_OBJECT(osd));
305 
306     //Add a second track for right clicks
307     rightclicktrack = osm_gps_map_track_new();
308 
309     if(opt_editable_tracks)
310         g_object_set(rightclicktrack, "editable", TRUE, NULL);
311     osm_gps_map_track_add(OSM_GPS_MAP(map), rightclicktrack);
312 
313     g_free(cachedir);
314     g_free(cachebasedir);
315 
316     //Enable keyboard navigation
317     osm_gps_map_set_keyboard_shortcut(map, OSM_GPS_MAP_KEY_FULLSCREEN, GDK_KEY_F11);
318     osm_gps_map_set_keyboard_shortcut(map, OSM_GPS_MAP_KEY_UP, GDK_KEY_Up);
319     osm_gps_map_set_keyboard_shortcut(map, OSM_GPS_MAP_KEY_DOWN, GDK_KEY_Down);
320     osm_gps_map_set_keyboard_shortcut(map, OSM_GPS_MAP_KEY_LEFT, GDK_KEY_Left);
321     osm_gps_map_set_keyboard_shortcut(map, OSM_GPS_MAP_KEY_RIGHT, GDK_KEY_Right);
322 
323     //Build the UI
324     g_star_image = gdk_pixbuf_new_from_file_at_size ("poi.png", 24,24,NULL);
325 
326     builder = gtk_builder_new();
327     gtk_builder_add_from_file (builder, "mapviewer.ui", &error);
328     if (error)
329         g_error ("ERROR: %s\n", error->message);
330 
331     gtk_box_pack_start (
332                 GTK_BOX(gtk_builder_get_object(builder, "map_box")),
333                 GTK_WIDGET(map), TRUE, TRUE, 0);
334 
335     //Init values
336     float lw,a;
337     GdkRGBA c;
338     OsmGpsMapTrack *gpstrack = osm_gps_map_gps_get_track (map);
339     g_object_get (gpstrack, "line-width", &lw, "alpha", &a, NULL);
340     osm_gps_map_track_get_color(gpstrack, &c);
341     gtk_adjustment_set_value (
342                 GTK_ADJUSTMENT(gtk_builder_get_object(builder, "gps_width_adjustment")),
343                 lw);
344     gtk_adjustment_set_value (
345                 GTK_ADJUSTMENT(gtk_builder_get_object(builder, "gps_alpha_adjustment")),
346                 a);
347     gtk_adjustment_set_value (
348                 GTK_ADJUSTMENT(gtk_builder_get_object(builder, "star_xalign_adjustment")),
349                 0.5);
350     gtk_adjustment_set_value (
351                 GTK_ADJUSTMENT(gtk_builder_get_object(builder, "star_yalign_adjustment")),
352                 0.5);
353 #if GTK_CHECK_VERSION(3,4,0)
354     gtk_color_chooser_set_rgba (
355                 GTK_COLOR_CHOOSER(gtk_builder_get_object(builder, "gps_colorbutton")),
356                 &c);
357 #else
358     gtk_color_button_set_rgba (
359                 GTK_COLOR_BUTTON(gtk_builder_get_object(builder, "gps_colorbutton")),
360                 &c);
361 #endif
362 
363     //Connect to signals
364     g_signal_connect (
365                 gtk_builder_get_object(builder, "gps_colorbutton"), "color-set",
366                 G_CALLBACK (on_gps_color_changed), (gpointer) gpstrack);
367     g_signal_connect (
368                 gtk_builder_get_object(builder, "zoom_in_button"), "clicked",
369                 G_CALLBACK (on_zoom_in_clicked_event), (gpointer) map);
370     g_signal_connect (
371                 gtk_builder_get_object(builder, "zoom_out_button"), "clicked",
372                 G_CALLBACK (on_zoom_out_clicked_event), (gpointer) map);
373     g_signal_connect (
374                 gtk_builder_get_object(builder, "home_button"), "clicked",
375                 G_CALLBACK (on_home_clicked_event), (gpointer) map);
376     g_signal_connect (
377                 gtk_builder_get_object(builder, "cache_button"), "clicked",
378                 G_CALLBACK (on_cache_clicked_event), (gpointer) map);
379     g_signal_connect (
380                 gtk_builder_get_object(builder, "gps_alpha_adjustment"), "value-changed",
381                 G_CALLBACK (on_gps_alpha_changed), (gpointer) map);
382     g_signal_connect (
383                 gtk_builder_get_object(builder, "gps_width_adjustment"), "value-changed",
384                 G_CALLBACK (on_gps_width_changed), (gpointer) map);
385     g_signal_connect (
386                 gtk_builder_get_object(builder, "star_xalign_adjustment"), "value-changed",
387                 G_CALLBACK (on_star_align_changed), (gpointer) "x-align");
388     g_signal_connect (
389                 gtk_builder_get_object(builder, "star_yalign_adjustment"), "value-changed",
390                 G_CALLBACK (on_star_align_changed), (gpointer) "y-align");
391     g_signal_connect (G_OBJECT (map), "button-press-event",
392                 G_CALLBACK (on_button_press_event), (gpointer) rightclicktrack);
393     g_signal_connect (G_OBJECT (map), "button-release-event",
394                 G_CALLBACK (on_button_release_event),
395                 (gpointer) gtk_builder_get_object(builder, "text_entry"));
396     g_signal_connect (G_OBJECT (map), "notify::tiles-queued",
397                 G_CALLBACK (on_tiles_queued_changed),
398                 (gpointer) gtk_builder_get_object(builder, "cache_label"));
399 
400     widget = GTK_WIDGET(gtk_builder_get_object(builder, "window1"));
401     g_signal_connect (widget, "destroy",
402                       G_CALLBACK (on_close), (gpointer) map);
403     //Setup accelerators.
404     ag = gtk_accel_group_new();
405     gtk_accel_group_connect(ag, GDK_KEY_w, GDK_CONTROL_MASK, GTK_ACCEL_MASK,
406                     g_cclosure_new(gtk_main_quit, NULL, NULL));
407     gtk_accel_group_connect(ag, GDK_KEY_q, GDK_CONTROL_MASK, GTK_ACCEL_MASK,
408                     g_cclosure_new(gtk_main_quit, NULL, NULL));
409     gtk_window_add_accel_group(GTK_WINDOW(widget), ag);
410 
411     gtk_widget_show_all (widget);
412 
413     g_log_set_handler ("OsmGpsMap", G_LOG_LEVEL_MASK, g_log_default_handler, NULL);
414     gtk_main ();
415 
416     return 0;
417 }
418