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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 48 - (hide 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 harbaum 33 /*
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 harbaum 34 #include <math.h> // for isnan
22 harbaum 33
23     #ifdef ENABLE_OSM_GPS_MAP
24     #include "osm-gps-map.h"
25     #endif
26    
27 harbaum 48 #define GPS_DEFAULT_ZOOM 13
28    
29 harbaum 42 /* 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 harbaum 33 typedef struct {
36 harbaum 34 appdata_t *appdata;
37 harbaum 33 GtkWidget *widget;
38     GtkWidget *zoomin, *zoomout, *gps;
39     gint handler_id;
40 harbaum 42 cache_t *press_on;
41 harbaum 40 #if MAEMO_VERSION_MAJOR == 5
42     GtkWidget *old_view;
43     #endif
44 harbaum 33 } map_context_t;
45    
46 harbaum 34 #define PROXY_KEY "/system/http_proxy/"
47    
48     static const char *get_proxy_uri(appdata_t *appdata) {
49     static char proxy_buffer[64] = "";
50 harbaum 33
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 harbaum 34 /* ------------- get proxy settings -------------------- */
59     if(gconf_client_get_bool(appdata->gconf_client,
60     PROXY_KEY "use_http_proxy", NULL)) {
61 harbaum 33
62 harbaum 34 /* 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 harbaum 33
73 harbaum 34 snprintf(proxy_buffer, sizeof(proxy_buffer),
74     "http://%s:%u", host, port);
75 harbaum 33
76 harbaum 34 g_free(host);
77     }
78 harbaum 35 return proxy_buffer;
79 harbaum 34 }
80    
81 harbaum 35 return NULL;
82 harbaum 33 }
83    
84     static void map_zoom(map_context_t *context, int step) {
85 harbaum 48 gint zoom;
86 harbaum 33 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 harbaum 48
94     /* save new zoom */
95     context->appdata->map.zoom = zoom;
96 harbaum 33 }
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 harbaum 34 pos_t *refpos = get_pos(context->appdata);
113     if(refpos && !isnan(refpos->lat) && !isnan(refpos->lon)) {
114 harbaum 35 osm_gps_map_set_mapcenter(OSM_GPS_MAP(context->widget),
115 harbaum 48 refpos->lat, refpos->lon, GPS_DEFAULT_ZOOM);
116 harbaum 35 } 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 harbaum 34 }
121 harbaum 33
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 harbaum 45 gtk_image_new_from_stock(icon, GTK_ICON_SIZE_BUTTON));
131 harbaum 33 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 harbaum 34 pos_t *refpos = get_pos(context->appdata);
142     gboolean ok = (refpos!= NULL) && !isnan(refpos->lat) && !isnan(refpos->lon);
143 harbaum 33
144 harbaum 34 /* get reference position and go there */
145     gtk_widget_set_sensitive(context->gps, ok);
146    
147 harbaum 33 return TRUE;
148     }
149    
150 harbaum 35 static gboolean on_map_configure(GtkWidget *widget,
151     GdkEventConfigure *event,
152     map_context_t *context) {
153 harbaum 33
154 harbaum 48 /* 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 harbaum 35
173 harbaum 48 /* 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 harbaum 35 return FALSE;
180     }
181    
182 harbaum 38 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 harbaum 41 /* draw a nice popup */
194     typedef struct {
195     appdata_t *appdata;
196     GtkWidget *window;
197     GMainLoop *loop;
198     } popup_context_t;
199    
200 harbaum 47 /* draw shape */
201     #define ARROW_BORDER 20
202     #define CORNER_RADIUS 10
203 harbaum 41
204 harbaum 47 #ifndef USE_MAEMO
205 harbaum 41 #define POPUP_WIDTH 300
206     #define POPUP_HEIGHT 100
207     #else
208 harbaum 47 #define POPUP_WIDTH 350
209     #define POPUP_HEIGHT 120
210 harbaum 41 #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 harbaum 45 printf("overlay button press (in = %d)\n", in);
234 harbaum 41 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 harbaum 45 printf("overlay button release (in = %d)\n", in);
243 harbaum 41
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 harbaum 46 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 harbaum 47 /* 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 harbaum 46 gdk_draw_rectangle(mask, gc, TRUE,
303 harbaum 47 0, tip_offset + CORNER_RADIUS,
304 harbaum 46 POPUP_WIDTH,
305 harbaum 47 POPUP_HEIGHT - 2*CORNER_RADIUS - ARROW_BORDER);
306 harbaum 46
307     gdk_draw_rectangle(mask, gc, TRUE,
308 harbaum 47 CORNER_RADIUS, tip_offset,
309 harbaum 46 POPUP_WIDTH - 2*CORNER_RADIUS,
310 harbaum 47 POPUP_HEIGHT - ARROW_BORDER);
311 harbaum 46
312     int off[][2] = {
313 harbaum 47 { CORNER_RADIUS, tip_offset + CORNER_RADIUS },
314     { POPUP_WIDTH - CORNER_RADIUS, tip_offset + CORNER_RADIUS },
315 harbaum 46 { POPUP_WIDTH - CORNER_RADIUS,
316 harbaum 47 POPUP_HEIGHT - CORNER_RADIUS - ARROW_BORDER + tip_offset},
317 harbaum 46 { CORNER_RADIUS,
318 harbaum 47 POPUP_HEIGHT - CORNER_RADIUS - ARROW_BORDER + tip_offset}};
319 harbaum 46
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 harbaum 47 /* 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 harbaum 42 void cache_popup(map_context_t *mcontext, cache_t *cache) {
370     popup_context_t pcontext;
371     pcontext.appdata = mcontext->appdata;
372 harbaum 41
373 harbaum 42 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 harbaum 41 POPUP_WIDTH, POPUP_HEIGHT);
377 harbaum 45 gtk_window_resize(GTK_WINDOW(pcontext.window), POPUP_WIDTH, POPUP_HEIGHT);
378 harbaum 42 // 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 harbaum 41
386     /* connect events */
387 harbaum 42 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 harbaum 41
398 harbaum 42 gdk_pointer_grab(pcontext.window->window, TRUE,
399 harbaum 41 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_MOTION_MASK,
400     NULL, NULL, GDK_CURRENT_TIME);
401 harbaum 42 gtk_grab_add(pcontext.window);
402 harbaum 41
403 harbaum 42 /* check whether cache is in upper or lower half of window */
404 harbaum 45 gint x, y, sx, sy;
405 harbaum 42 osm_gps_map_geographic_to_screen(OSM_GPS_MAP(mcontext->widget),
406     cache->pos.lat, cache->pos.lon,
407 harbaum 45 &sx, &sy);
408 harbaum 42
409     gdk_window_get_origin(mcontext->widget->window, &x, &y);
410    
411 harbaum 45 gint ax = 0, ay = 0;
412     if(sx > mcontext->widget->allocation.width/2)
413     ax = POPUP_WIDTH;
414 harbaum 41
415 harbaum 45 if(sy > mcontext->widget->allocation.height/2)
416     ay = POPUP_HEIGHT;
417 harbaum 41
418 harbaum 47 #if !defined(USE_MAEMO) || (MAEMO_VERSION_MAJOR < 5)
419 harbaum 46 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 harbaum 42 gtk_window_move(GTK_WINDOW(pcontext.window),
425 harbaum 45 x + mcontext->widget->allocation.x + sx - ax,
426     y + mcontext->widget->allocation.y + sy - ay);
427 harbaum 41
428 harbaum 46
429 harbaum 47 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 harbaum 41
435 harbaum 47 /* --- 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 harbaum 41
486 harbaum 47 /* give window its shape */
487 harbaum 46 popup_window_shape(pcontext.window, ax, ay);
488    
489 harbaum 42 gtk_widget_show_all(pcontext.window);
490 harbaum 41
491     /* handle this popup until it's gone */
492    
493 harbaum 42 pcontext.loop = g_main_loop_new(NULL, FALSE);
494 harbaum 41
495     GDK_THREADS_LEAVE();
496 harbaum 42 g_main_loop_run(pcontext.loop);
497 harbaum 41 GDK_THREADS_ENTER();
498    
499 harbaum 42 g_main_loop_unref(pcontext.loop);
500 harbaum 41
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 harbaum 42 static int dist2pixel(map_context_t *context, float km, float lat) {
553 harbaum 48 gint zoom;
554 harbaum 42 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 harbaum 47 #define CLICK_FUZZ (24)
564 harbaum 42
565 harbaum 41 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 harbaum 44 /* 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 harbaum 41 pos_t pos =
577 harbaum 42 coord2pos(osm_gps_map_get_co_ordinates(map, event->x, event->y));
578 harbaum 41
579 harbaum 42 cache_t *nearest = map_closest(context, &pos);
580     if(nearest) {
581     float dist = gpx_pos_get_distance(pos, nearest->pos, FALSE);
582 harbaum 44 if(dist2pixel(context, dist, nearest->pos.lat) < CLICK_FUZZ)
583 harbaum 42 context->press_on = nearest;
584     }
585 harbaum 44
586 harbaum 41 return FALSE;
587     }
588    
589     static gboolean
590     on_map_button_release_event(GtkWidget *widget,
591     GdkEventButton *event, map_context_t *context) {
592 harbaum 48 OsmGpsMap *map = OSM_GPS_MAP(context->widget);
593    
594 harbaum 42 if(context->press_on) {
595     pos_t pos =
596     coord2pos(osm_gps_map_get_co_ordinates(map, event->x, event->y));
597 harbaum 41
598 harbaum 42 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 harbaum 44 if(dist2pixel(context, dist, nearest->pos.lat) < CLICK_FUZZ)
602 harbaum 42 cache_popup(context, nearest);
603     }
604 harbaum 44 context->press_on = NULL;
605 harbaum 48 } 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 harbaum 41 }
612    
613     return FALSE;
614     }
615    
616 harbaum 48 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 harbaum 44
623 harbaum 48 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 harbaum 40 #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 harbaum 48 save_map_state(context);
634    
635 harbaum 40 /* 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 harbaum 33 void map(appdata_t *appdata) {
644 harbaum 40 map_context_t *context = g_new0(map_context_t, 1);
645     context->appdata = appdata;
646 harbaum 33
647 harbaum 41 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 harbaum 44 name = g_strdup(appdata->cur_gpx->name);
675 harbaum 41 }
676     #endif
677    
678     char *title = g_strdup_printf(_("Map - %s"), name);
679     g_free(name);
680    
681 harbaum 40 #if MAEMO_VERSION_MAJOR == 5
682     GtkWidget *window = hildon_stackable_window_new();
683 harbaum 41 gtk_window_set_title(GTK_WINDOW(window), title);
684 harbaum 40 #else
685 harbaum 41 GtkWidget *dialog = gtk_dialog_new_with_buttons(title,
686 harbaum 33 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 harbaum 45 gtk_window_set_default_size(GTK_WINDOW(dialog), 640, 480);
693 harbaum 33 #else
694     gtk_window_set_default_size(GTK_WINDOW(dialog), 800, 480);
695     #endif
696 harbaum 40 #endif
697 harbaum 33
698 harbaum 41 g_free(title);
699 harbaum 33
700 harbaum 41 g_signal_connect(G_OBJECT(context->widget), "configure-event",
701     G_CALLBACK(on_map_configure), context);
702 harbaum 33
703 harbaum 41 g_signal_connect(G_OBJECT(context->widget), "button-press-event",
704     G_CALLBACK(on_map_button_press_event), context);
705 harbaum 33
706 harbaum 40 g_signal_connect(G_OBJECT(context->widget), "button-release-event",
707     G_CALLBACK(on_map_button_release_event), context);
708 harbaum 33
709 harbaum 40 gtk_box_pack_start_defaults(GTK_BOX(hbox), context->widget);
710 harbaum 33 /* zoom button box */
711     GtkWidget *vbox = gtk_vbox_new(FALSE,0);
712    
713 harbaum 40 context->zoomin =
714 harbaum 33 map_add_button(GTK_STOCK_ZOOM_IN, G_CALLBACK(cb_map_zoomin),
715 harbaum 40 context, _("Zoom in"));
716     gtk_box_pack_start(GTK_BOX(vbox), context->zoomin, FALSE, FALSE, 0);
717 harbaum 33
718 harbaum 40 context->zoomout =
719 harbaum 33 map_add_button(GTK_STOCK_ZOOM_OUT, G_CALLBACK(cb_map_zoomout),
720 harbaum 40 context, _("Zoom out"));
721     gtk_box_pack_start(GTK_BOX(vbox), context->zoomout, FALSE, FALSE, 0);
722 harbaum 33
723 harbaum 40 context->gps =
724 harbaum 33 map_add_button(GTK_STOCK_HOME, G_CALLBACK(cb_map_gps),
725 harbaum 40 context, _("Jump to GPS position"));
726     gtk_widget_set_sensitive(context->gps, FALSE);
727 harbaum 33 /* install handler for timed updates of the gps button */
728 harbaum 40 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 harbaum 33
731     gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
732    
733 harbaum 40 #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 harbaum 33 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 harbaum 48 save_map_state(context);
750 harbaum 40 gtk_timeout_remove(context->handler_id);
751 harbaum 33 gtk_widget_destroy(dialog);
752 harbaum 40 g_free(context);
753     #endif
754 harbaum 33 }