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