Contents of /trunk/src/map-tool.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 48 - (show annotations)
Fri Aug 7 07:57:33 2009 UTC (14 years, 9 months ago) by harbaum
File MIME type: text/plain
File size: 22175 byte(s)
Save map position
1 /*
2 * Copyright (C) 2008 Till Harbaum <till@harbaum.org>.
3 *
4 * This file is part of GPXView.
5 *
6 * GPXView is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * GPXView 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 GPXView. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "gpxview.h"
21 #include <math.h> // for isnan
22
23 #ifdef ENABLE_OSM_GPS_MAP
24 #include "osm-gps-map.h"
25 #endif
26
27 #define GPS_DEFAULT_ZOOM 13
28
29 /* equatorial radius in meters */
30 #define EQ_RADIUS (6378137.0)
31
32 #define RAD2DEG(a) (((a)*180.0)/M_PI)
33 #define DEG2RAD(a) (((a)*M_PI)/180.0)
34
35 typedef struct {
36 appdata_t *appdata;
37 GtkWidget *widget;
38 GtkWidget *zoomin, *zoomout, *gps;
39 gint handler_id;
40 cache_t *press_on;
41 #if MAEMO_VERSION_MAJOR == 5
42 GtkWidget *old_view;
43 #endif
44 } map_context_t;
45
46 #define PROXY_KEY "/system/http_proxy/"
47
48 static const char *get_proxy_uri(appdata_t *appdata) {
49 static char proxy_buffer[64] = "";
50
51 /* use environment settings if preset */
52 const char *proxy = g_getenv("http_proxy");
53 if(proxy) {
54 printf("http_proxy: %s\n", proxy);
55 return proxy;
56 }
57
58 /* ------------- get proxy settings -------------------- */
59 if(gconf_client_get_bool(appdata->gconf_client,
60 PROXY_KEY "use_http_proxy", NULL)) {
61
62 /* we can savely ignore things like "ignore_hosts" since we */
63 /* are pretty sure not inside the net of one of our map renderers */
64 /* (unless the user works at google :-) */
65
66 /* get basic settings */
67 char *host =
68 gconf_client_get_string(appdata->gconf_client, PROXY_KEY "host", NULL);
69 if(host) {
70 int port =
71 gconf_client_get_int(appdata->gconf_client, PROXY_KEY "port", NULL);
72
73 snprintf(proxy_buffer, sizeof(proxy_buffer),
74 "http://%s:%u", host, port);
75
76 g_free(host);
77 }
78 return proxy_buffer;
79 }
80
81 return NULL;
82 }
83
84 static void map_zoom(map_context_t *context, int step) {
85 gint zoom;
86 OsmGpsMap *map = OSM_GPS_MAP(context->widget);
87 g_object_get(map, "zoom", &zoom, NULL);
88 zoom = osm_gps_map_set_zoom(map, zoom+step);
89
90 /* enable/disable zoom buttons as required */
91 gtk_widget_set_sensitive(context->zoomin, zoom<17);
92 gtk_widget_set_sensitive(context->zoomout, zoom>1);
93
94 /* save new zoom */
95 context->appdata->map.zoom = zoom;
96 }
97
98 static gboolean
99 cb_map_zoomin(GtkButton *button, map_context_t *context) {
100 map_zoom(context, +1);
101 return FALSE;
102 }
103
104 static gboolean
105 cb_map_zoomout(GtkButton *button, map_context_t *context) {
106 map_zoom(context, -1);
107 return FALSE;
108 }
109
110 static gboolean
111 cb_map_gps(GtkButton *button, map_context_t *context) {
112 pos_t *refpos = get_pos(context->appdata);
113 if(refpos && !isnan(refpos->lat) && !isnan(refpos->lon)) {
114 osm_gps_map_set_mapcenter(OSM_GPS_MAP(context->widget),
115 refpos->lat, refpos->lon, GPS_DEFAULT_ZOOM);
116 } else {
117 /* no coordinates given: display the entire world */
118 osm_gps_map_set_mapcenter(OSM_GPS_MAP(context->widget),
119 0.0, 0.0, 1);
120 }
121
122 return FALSE;
123 }
124
125 static GtkWidget
126 *map_add_button(const gchar *icon, GCallback cb, gpointer data,
127 char *tooltip) {
128 GtkWidget *button = gtk_button_new();
129 gtk_button_set_image(GTK_BUTTON(button),
130 gtk_image_new_from_stock(icon, GTK_ICON_SIZE_BUTTON));
131 g_signal_connect(button, "clicked", cb, data);
132 #ifndef USE_MAEMO
133 gtk_widget_set_tooltip_text(button, tooltip);
134 #endif
135 return button;
136 }
137
138 static gboolean map_gps_update(gpointer data) {
139 map_context_t *context = (map_context_t*)data;
140
141 pos_t *refpos = get_pos(context->appdata);
142 gboolean ok = (refpos!= NULL) && !isnan(refpos->lat) && !isnan(refpos->lon);
143
144 /* get reference position and go there */
145 gtk_widget_set_sensitive(context->gps, ok);
146
147 return TRUE;
148 }
149
150 static gboolean on_map_configure(GtkWidget *widget,
151 GdkEventConfigure *event,
152 map_context_t *context) {
153
154 /* set default values if they are invalid */
155 if(!context->appdata->map.zoom ||
156 isnan(context->appdata->map.pos.lat) ||
157 isnan(context->appdata->map.pos.lon)) {
158 printf("no valid map position found\n");
159
160 pos_t *refpos = get_pos(context->appdata);
161 if(refpos && !isnan(refpos->lat) && !isnan(refpos->lon)) {
162 /* use gps position if present */
163 context->appdata->map.pos = *refpos;
164 context->appdata->map.zoom = GPS_DEFAULT_ZOOM;
165 } else {
166 /* use world map otherwise */
167 context->appdata->map.pos.lat = 0.0;
168 context->appdata->map.pos.lon = 0.0;
169 context->appdata->map.zoom = 1;
170 }
171 }
172
173 /* jump to initial position */
174 osm_gps_map_set_mapcenter(OSM_GPS_MAP(context->widget),
175 context->appdata->map.pos.lat,
176 context->appdata->map.pos.lon,
177 context->appdata->map.zoom);
178
179 return FALSE;
180 }
181
182 static void map_draw_cachelist(GtkWidget *map, cache_t *cache) {
183 while(cache) {
184 GdkPixbuf *icon = icon_get(ICON_CACHE_TYPE, cache->type);
185
186 osm_gps_map_add_image(OSM_GPS_MAP(map),
187 cache->pos.lat, cache->pos.lon, icon);
188
189 cache = cache->next;
190 }
191 }
192
193 /* draw a nice popup */
194 typedef struct {
195 appdata_t *appdata;
196 GtkWidget *window;
197 GMainLoop *loop;
198 } popup_context_t;
199
200 /* draw shape */
201 #define ARROW_BORDER 20
202 #define CORNER_RADIUS 10
203
204 #ifndef USE_MAEMO
205 #define POPUP_WIDTH 300
206 #define POPUP_HEIGHT 100
207 #else
208 #define POPUP_WIDTH 350
209 #define POPUP_HEIGHT 120
210 #endif
211
212 static gboolean
213 pointer_in_window(GtkWidget *widget, gint x_root, gint y_root) {
214 if(GTK_WIDGET_MAPPED(gtk_widget_get_toplevel(widget))) {
215 gint window_x, window_y;
216
217 gdk_window_get_position(gtk_widget_get_toplevel(widget)->window,
218 &window_x, &window_y);
219
220 if(x_root >= window_x && x_root < window_x + widget->allocation.width &&
221 y_root >= window_y && y_root < window_y + widget->allocation.height)
222 return TRUE;
223 }
224
225 return FALSE;
226 }
227
228 static gboolean
229 on_button_press_event(GtkWidget *widget,
230 GdkEventButton *event, popup_context_t *context) {
231 gboolean in = pointer_in_window(widget, event->x_root, event->y_root);
232
233 printf("overlay button press (in = %d)\n", in);
234 return !in;
235 }
236
237 static gboolean
238 on_button_release_event(GtkWidget *widget,
239 GdkEventButton *event, popup_context_t *context) {
240 gboolean in = pointer_in_window(widget, event->x_root, event->y_root);
241
242 printf("overlay button release (in = %d)\n", in);
243
244 if(!in) {
245 printf("destroying popup\n");
246 gtk_widget_destroy(gtk_widget_get_toplevel(widget));
247 }
248
249 return !in;
250 }
251
252 static void
253 shutdown_loop(popup_context_t *context) {
254 if(g_main_loop_is_running(context->loop))
255 g_main_loop_quit(context->loop);
256 }
257
258 static gint
259 run_delete_handler(GtkWindow *window, GdkEventAny *event,
260 popup_context_t *context) {
261 shutdown_loop(context);
262 return TRUE; /* Do not destroy */
263 }
264
265 static void
266 run_destroy_handler(GtkWindow *window, popup_context_t *context) {
267 /* shutdown_loop will be called by run_unmap_handler */
268 printf("popup destroyed\n");
269 }
270
271 static void
272 run_unmap_handler(GtkWindow *window, popup_context_t *context) {
273 shutdown_loop(context);
274 }
275
276 static void popup_window_shape(GtkWidget *window, int tip_x, int tip_y) {
277 GdkBitmap *mask = gdk_pixmap_new(NULL, POPUP_WIDTH, POPUP_HEIGHT, 1);
278
279 GdkGC *gc = gdk_gc_new(mask);
280 GdkColormap *colormap;
281 GdkColor black;
282 GdkColor white;
283
284 /* get black/white color values */
285 colormap = gdk_colormap_get_system();
286 gdk_color_black(colormap, &black);
287 gdk_color_white(colormap, &white);
288
289 /* erase */
290 gdk_gc_set_foreground(gc, &black);
291 gdk_gc_set_background(gc, &white);
292
293 /* erase background */
294 gdk_draw_rectangle(mask, gc, TRUE, 0, 0, POPUP_WIDTH, POPUP_HEIGHT);
295
296 gdk_gc_set_foreground(gc, &white);
297 gdk_gc_set_background(gc, &black);
298
299 /* the tip is always above or below the "bubble" but never at its side */
300 guint tip_offset = (tip_y == 0)?ARROW_BORDER:0;
301
302 gdk_draw_rectangle(mask, gc, TRUE,
303 0, tip_offset + CORNER_RADIUS,
304 POPUP_WIDTH,
305 POPUP_HEIGHT - 2*CORNER_RADIUS - ARROW_BORDER);
306
307 gdk_draw_rectangle(mask, gc, TRUE,
308 CORNER_RADIUS, tip_offset,
309 POPUP_WIDTH - 2*CORNER_RADIUS,
310 POPUP_HEIGHT - ARROW_BORDER);
311
312 int off[][2] = {
313 { CORNER_RADIUS, tip_offset + CORNER_RADIUS },
314 { POPUP_WIDTH - CORNER_RADIUS, tip_offset + CORNER_RADIUS },
315 { POPUP_WIDTH - CORNER_RADIUS,
316 POPUP_HEIGHT - CORNER_RADIUS - ARROW_BORDER + tip_offset},
317 { CORNER_RADIUS,
318 POPUP_HEIGHT - CORNER_RADIUS - ARROW_BORDER + tip_offset}};
319
320 int i;
321 for(i=0;i<4;i++) {
322 gdk_draw_arc(mask, gc, TRUE,
323 off[i][0]-CORNER_RADIUS, off[i][1]-CORNER_RADIUS,
324 2*CORNER_RADIUS, 2*CORNER_RADIUS,
325 0, 360*64);
326 }
327
328 GdkPoint points[3] = { {POPUP_WIDTH*1/3, POPUP_HEIGHT/2},
329 {POPUP_WIDTH*2/3, POPUP_HEIGHT/2},
330 {tip_x,tip_y} };
331 gdk_draw_polygon(mask, gc, TRUE, points, 3);
332
333
334 gdk_window_shape_combine_mask(window->window, mask, 0, 0);
335 }
336
337 /* create a left aligned label (normal ones are centered) */
338 static GtkWidget *gtk_label_left_new(char *str) {
339 GtkWidget *label = gtk_label_new(str);
340 gtk_misc_set_alignment(GTK_MISC(label), 0.f, .5f);
341 return label;
342 }
343
344 /* the small labels are actually only on maemo small */
345 #ifdef USE_MAEMO
346 #define MARKUP_SMALL "<span size='small'>%s</span>"
347 GtkWidget *gtk_label_small_left_new(char *str) {
348 GtkWidget *label = gtk_label_new("");
349 char *markup = g_markup_printf_escaped(MARKUP_SMALL, str);
350 gtk_label_set_markup(GTK_LABEL(label), markup);
351 g_free(markup);
352 gtk_misc_set_alignment(GTK_MISC(label), 0.f, .5f);
353 return label;
354 }
355 #define gtk_label_big_left_new(a) gtk_label_left_new(a)
356 #else
357 #define gtk_label_small_left_new(a) gtk_label_left_new(a)
358 #define MARKUP_BIG "<span size='x-large'>%s</span>"
359 GtkWidget *gtk_label_big_left_new(char *str) {
360 GtkWidget *label = gtk_label_new("");
361 char *markup = g_markup_printf_escaped(MARKUP_BIG, str);
362 gtk_label_set_markup(GTK_LABEL(label), markup);
363 g_free(markup);
364 gtk_misc_set_alignment(GTK_MISC(label), 0.f, .5f);
365 return label;
366 }
367 #endif
368
369 void cache_popup(map_context_t *mcontext, cache_t *cache) {
370 popup_context_t pcontext;
371 pcontext.appdata = mcontext->appdata;
372
373 pcontext.window = gtk_window_new(GTK_WINDOW_POPUP);
374 gtk_widget_realize(pcontext.window);
375 gtk_window_set_default_size(GTK_WINDOW(pcontext.window),
376 POPUP_WIDTH, POPUP_HEIGHT);
377 gtk_window_resize(GTK_WINDOW(pcontext.window), POPUP_WIDTH, POPUP_HEIGHT);
378 // gtk_window_set_resizable(GTK_WINDOW(pcontext.window), FALSE);
379 gtk_window_set_transient_for(GTK_WINDOW(pcontext.window),
380 GTK_WINDOW(mcontext->appdata->window));
381 gtk_window_set_keep_above(GTK_WINDOW(pcontext.window), TRUE);
382 gtk_window_set_destroy_with_parent(GTK_WINDOW(pcontext.window), TRUE);
383 gtk_window_set_gravity(GTK_WINDOW(pcontext.window), GDK_GRAVITY_STATIC);
384 gtk_window_set_modal(GTK_WINDOW(pcontext.window), TRUE);
385
386 /* connect events */
387 g_signal_connect(G_OBJECT(pcontext.window), "button-press-event",
388 G_CALLBACK(on_button_press_event), &pcontext);
389 g_signal_connect(G_OBJECT(pcontext.window), "button-release-event",
390 G_CALLBACK(on_button_release_event), &pcontext);
391 g_signal_connect(G_OBJECT(pcontext.window), "delete-event",
392 G_CALLBACK(run_delete_handler), &pcontext);
393 g_signal_connect(G_OBJECT(pcontext.window), "destroy",
394 G_CALLBACK(run_destroy_handler), &pcontext);
395 g_signal_connect(G_OBJECT(pcontext.window), "unmap",
396 G_CALLBACK(run_unmap_handler), &pcontext);
397
398 gdk_pointer_grab(pcontext.window->window, TRUE,
399 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_MOTION_MASK,
400 NULL, NULL, GDK_CURRENT_TIME);
401 gtk_grab_add(pcontext.window);
402
403 /* check whether cache is in upper or lower half of window */
404 gint x, y, sx, sy;
405 osm_gps_map_geographic_to_screen(OSM_GPS_MAP(mcontext->widget),
406 cache->pos.lat, cache->pos.lon,
407 &sx, &sy);
408
409 gdk_window_get_origin(mcontext->widget->window, &x, &y);
410
411 gint ax = 0, ay = 0;
412 if(sx > mcontext->widget->allocation.width/2)
413 ax = POPUP_WIDTH;
414
415 if(sy > mcontext->widget->allocation.height/2)
416 ay = POPUP_HEIGHT;
417
418 #if !defined(USE_MAEMO) || (MAEMO_VERSION_MAJOR < 5)
419 GdkColor color;
420 gdk_color_parse("darkgray", &color);
421 gtk_widget_modify_bg(GTK_WIDGET(pcontext.window), GTK_STATE_NORMAL, &color);
422 #endif
423
424 gtk_window_move(GTK_WINDOW(pcontext.window),
425 x + mcontext->widget->allocation.x + sx - ax,
426 y + mcontext->widget->allocation.y + sy - ay);
427
428
429 GtkWidget *alignment = gtk_alignment_new(0.5, 0.5, 1.0, 1.0);
430 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment),
431 CORNER_RADIUS/2 + (ay?0:ARROW_BORDER),
432 CORNER_RADIUS/2 + (ay?ARROW_BORDER:0),
433 CORNER_RADIUS, CORNER_RADIUS);
434
435 /* --- actual content ---- */
436 GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
437
438 if(cache->id) {
439 GtkWidget *ihbox = gtk_hbox_new(FALSE, 0);
440
441 gtk_box_pack_start(GTK_BOX(ihbox),
442 icon_get_widget(ICON_CACHE_TYPE, cache->type),
443 FALSE, FALSE, 5);
444
445 gtk_box_pack_start_defaults(GTK_BOX(ihbox),
446 gtk_label_big_left_new(cache->id));
447
448 gtk_box_pack_start_defaults(GTK_BOX(vbox), ihbox);
449 }
450
451 if(cache->name) {
452 GtkWidget *label = gtk_label_small_left_new(cache->name);
453 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
454 gtk_box_pack_start_defaults(GTK_BOX(vbox), label);
455 }
456
457 GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
458 if(cache->terrain) {
459 GtkWidget *ihbox = gtk_hbox_new(FALSE, 0);
460 gtk_box_pack_start(GTK_BOX(ihbox),
461 gtk_label_small_left_new(_("Terrain:")), FALSE, FALSE, 0);
462 gtk_box_pack_start(GTK_BOX(ihbox),
463 icon_get_widget(ICON_STARS, (int)(cache->terrain*2-2)),
464 FALSE, FALSE, 5);
465 gtk_box_pack_start_defaults(GTK_BOX(hbox), ihbox);
466 }
467
468 if(cache->difficulty) {
469 GtkWidget *ihbox = gtk_hbox_new(FALSE, 0);
470 gtk_box_pack_start(GTK_BOX(ihbox),
471 gtk_label_small_left_new(_("Difficulty:")), FALSE, FALSE, 0);
472 gtk_box_pack_start(GTK_BOX(ihbox),
473 icon_get_widget(ICON_STARS, (int)(cache->difficulty*2-2)),
474 FALSE, FALSE, 5);
475 gtk_box_pack_start_defaults(GTK_BOX(hbox), ihbox);
476 }
477
478 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
479
480 gtk_container_add(GTK_CONTAINER(alignment), vbox);
481 /* ----------------------- */
482
483
484 gtk_container_add(GTK_CONTAINER(pcontext.window), alignment);
485
486 /* give window its shape */
487 popup_window_shape(pcontext.window, ax, ay);
488
489 gtk_widget_show_all(pcontext.window);
490
491 /* handle this popup until it's gone */
492
493 pcontext.loop = g_main_loop_new(NULL, FALSE);
494
495 GDK_THREADS_LEAVE();
496 g_main_loop_run(pcontext.loop);
497 GDK_THREADS_ENTER();
498
499 g_main_loop_unref(pcontext.loop);
500
501 printf("cache popup removed\n");
502 }
503
504 static void
505 map_cachelist_nearest(cache_t *cache, pos_t *pos,
506 cache_t **result, float *distance) {
507 while(cache) {
508 float dist =
509 pow(cache->pos.lat - pos->lat, 2) +
510 pow(cache->pos.lon - pos->lon, 2);
511
512 if(!(dist > *distance)) {
513 *result = cache;
514 *distance = dist;
515 }
516
517 cache = cache->next;
518 }
519 }
520
521 static cache_t *map_closest(map_context_t *context, pos_t *pos) {
522 cache_t *result = NULL;
523 float distance = NAN;
524
525 #ifdef USE_MAEMO
526 if(!context->appdata->cur_gpx) {
527 #endif
528 /* search all geocaches */
529 gpx_t *gpx = context->appdata->gpx;
530 while(gpx) {
531 map_cachelist_nearest(gpx->cache, pos, &result, &distance);
532 gpx = gpx->next;
533 }
534 #ifdef USE_MAEMO
535 } else {
536 map_cachelist_nearest(context->appdata->cur_gpx->cache,
537 pos, &result, &distance);
538 }
539 #endif
540
541 return result;
542 }
543
544 /* translate between osm-gps-map positions and gpxview ones */
545 pos_t coord2pos(coord_t coo) {
546 pos_t pos;
547 pos.lat = RAD2DEG(coo.rlat);
548 pos.lon = RAD2DEG(coo.rlon);
549 return pos;
550 }
551
552 static int dist2pixel(map_context_t *context, float km, float lat) {
553 gint zoom;
554 g_object_get(OSM_GPS_MAP(context->widget), "zoom", &zoom, NULL);
555
556 /* world at zoom 1 == 512 pixels */
557 float m_per_pix =
558 cos(DEG2RAD(lat))*2*M_PI*EQ_RADIUS/(1<<(8+zoom));
559
560 return 1000.0*km/m_per_pix;
561 }
562
563 #define CLICK_FUZZ (24)
564
565 static gboolean
566 on_map_button_press_event(GtkWidget *widget,
567 GdkEventButton *event, map_context_t *context) {
568 OsmGpsMap *map = OSM_GPS_MAP(context->widget);
569
570 /* got a press event without release event? eat it! */
571 if(context->press_on != NULL) {
572 printf("PRESS: already\n");
573 return TRUE;
574 }
575
576 pos_t pos =
577 coord2pos(osm_gps_map_get_co_ordinates(map, event->x, event->y));
578
579 cache_t *nearest = map_closest(context, &pos);
580 if(nearest) {
581 float dist = gpx_pos_get_distance(pos, nearest->pos, FALSE);
582 if(dist2pixel(context, dist, nearest->pos.lat) < CLICK_FUZZ)
583 context->press_on = nearest;
584 }
585
586 return FALSE;
587 }
588
589 static gboolean
590 on_map_button_release_event(GtkWidget *widget,
591 GdkEventButton *event, map_context_t *context) {
592 OsmGpsMap *map = OSM_GPS_MAP(context->widget);
593
594 if(context->press_on) {
595 pos_t pos =
596 coord2pos(osm_gps_map_get_co_ordinates(map, event->x, event->y));
597
598 cache_t *nearest = map_closest(context, &pos);
599 if(nearest && nearest == context->press_on) {
600 float dist = gpx_pos_get_distance(pos, nearest->pos, FALSE);
601 if(dist2pixel(context, dist, nearest->pos.lat) < CLICK_FUZZ)
602 cache_popup(context, nearest);
603 }
604 context->press_on = NULL;
605 } else {
606 /* save new map position */
607 gfloat lat, lon;
608 g_object_get(map, "latitude", &lat, "longitude", &lon, NULL);
609 context->appdata->map.pos.lat = lat;
610 context->appdata->map.pos.lon = lon;
611 }
612
613 return FALSE;
614 }
615
616 static void save_map_state(map_context_t *context) {
617 /* save map parameters */
618 OsmGpsMap *map = OSM_GPS_MAP(context->widget);
619 gint zoom;
620 g_object_get(map, "zoom", &zoom, NULL);
621 context->appdata->map.zoom = zoom;
622
623 gfloat lat, lon;
624 g_object_get(map, "latitude", &lat, "longitude", &lon, NULL);
625 context->appdata->map.pos.lat = lat;
626 context->appdata->map.pos.lon = lon;
627 }
628
629 #if MAEMO_VERSION_MAJOR == 5
630 static void on_window_destroy(GtkWidget *widget, map_context_t *context) {
631 printf("destroy map view\n");
632
633 save_map_state(context);
634
635 /* restore cur_view */
636 context->appdata->cur_view = context->old_view;
637
638 gtk_timeout_remove(context->handler_id);
639 g_free(context);
640 }
641 #endif
642
643 void map(appdata_t *appdata) {
644 map_context_t *context = g_new0(map_context_t, 1);
645 context->appdata = appdata;
646
647 GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
648
649 char *path = g_strdup_printf("%s/map/", appdata->image_path);
650 const char *proxy = get_proxy_uri(appdata);
651
652 context->widget = g_object_new(OSM_TYPE_GPS_MAP,
653 "repo-uri", MAP_SOURCE_OPENSTREETMAP,
654 "tile-cache", path,
655 proxy?"proxy-uri":NULL, proxy,
656 NULL);
657
658 g_free(path);
659
660 char *name = NULL;
661 #ifdef USE_MAEMO
662 if(!appdata->cur_gpx) {
663 #endif
664 /* draw all geocaches */
665 gpx_t *gpx = appdata->gpx;
666 while(gpx) {
667 map_draw_cachelist(context->widget, gpx->cache);
668 gpx = gpx->next;
669 }
670 name = g_strdup(_("all geocaches"));
671 #ifdef USE_MAEMO
672 } else {
673 map_draw_cachelist(context->widget, appdata->cur_gpx->cache);
674 name = g_strdup(appdata->cur_gpx->name);
675 }
676 #endif
677
678 char *title = g_strdup_printf(_("Map - %s"), name);
679 g_free(name);
680
681 #if MAEMO_VERSION_MAJOR == 5
682 GtkWidget *window = hildon_stackable_window_new();
683 gtk_window_set_title(GTK_WINDOW(window), title);
684 #else
685 GtkWidget *dialog = gtk_dialog_new_with_buttons(title,
686 GTK_WINDOW(appdata->window),
687 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
688 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
689 NULL);
690
691 #ifndef USE_MAEMO
692 gtk_window_set_default_size(GTK_WINDOW(dialog), 640, 480);
693 #else
694 gtk_window_set_default_size(GTK_WINDOW(dialog), 800, 480);
695 #endif
696 #endif
697
698 g_free(title);
699
700 g_signal_connect(G_OBJECT(context->widget), "configure-event",
701 G_CALLBACK(on_map_configure), context);
702
703 g_signal_connect(G_OBJECT(context->widget), "button-press-event",
704 G_CALLBACK(on_map_button_press_event), context);
705
706 g_signal_connect(G_OBJECT(context->widget), "button-release-event",
707 G_CALLBACK(on_map_button_release_event), context);
708
709 gtk_box_pack_start_defaults(GTK_BOX(hbox), context->widget);
710 /* zoom button box */
711 GtkWidget *vbox = gtk_vbox_new(FALSE,0);
712
713 context->zoomin =
714 map_add_button(GTK_STOCK_ZOOM_IN, G_CALLBACK(cb_map_zoomin),
715 context, _("Zoom in"));
716 gtk_box_pack_start(GTK_BOX(vbox), context->zoomin, FALSE, FALSE, 0);
717
718 context->zoomout =
719 map_add_button(GTK_STOCK_ZOOM_OUT, G_CALLBACK(cb_map_zoomout),
720 context, _("Zoom out"));
721 gtk_box_pack_start(GTK_BOX(vbox), context->zoomout, FALSE, FALSE, 0);
722
723 context->gps =
724 map_add_button(GTK_STOCK_HOME, G_CALLBACK(cb_map_gps),
725 context, _("Jump to GPS position"));
726 gtk_widget_set_sensitive(context->gps, FALSE);
727 /* install handler for timed updates of the gps button */
728 context->handler_id = gtk_timeout_add(1000, map_gps_update, context);
729 gtk_box_pack_start(GTK_BOX(vbox), context->gps, FALSE, FALSE, 0);
730
731 gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
732
733 #if MAEMO_VERSION_MAJOR == 5
734 /* prevent some of the main screen things */
735 context->old_view = appdata->cur_view;
736 appdata->cur_view = NULL;
737
738 g_signal_connect(G_OBJECT(window), "destroy",
739 G_CALLBACK(on_window_destroy), context);
740
741 gtk_container_add(GTK_CONTAINER(window), hbox);
742 gtk_widget_show_all(GTK_WIDGET(window));
743
744 #else
745 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox);
746 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CLOSE);
747 gtk_widget_show_all(dialog);
748 gtk_dialog_run(GTK_DIALOG(dialog));
749 save_map_state(context);
750 gtk_timeout_remove(context->handler_id);
751 gtk_widget_destroy(dialog);
752 g_free(context);
753 #endif
754 }