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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 33 by harbaum, Tue Jul 28 13:21:40 2009 UTC revision 41 by harbaum, Mon Aug 3 14:21:57 2009 UTC
# Line 18  Line 18 
18   */   */
19    
20  #include "gpxview.h"  #include "gpxview.h"
21    #include <math.h>    // for isnan
22    
23  #ifdef ENABLE_OSM_GPS_MAP  #ifdef ENABLE_OSM_GPS_MAP
24  #include "osm-gps-map.h"  #include "osm-gps-map.h"
25  #endif  #endif
26    
27  typedef struct {  typedef struct {
28      appdata_t *appdata;
29    GtkWidget *widget;    GtkWidget *widget;
30    GtkWidget *zoomin, *zoomout, *gps;    GtkWidget *zoomin, *zoomout, *gps;
31    gint handler_id;    gint handler_id;
32    #if MAEMO_VERSION_MAJOR == 5
33      GtkWidget *old_view;
34    #endif
35  } map_context_t;  } map_context_t;
36    
37  static const char *get_proxy_uri(void) {  #define PROXY_KEY  "/system/http_proxy/"
38    static char proxy_buffer[64];  
39    static const char *get_proxy_uri(appdata_t *appdata) {
40      static char proxy_buffer[64] = "";
41    
42    /* use environment settings if preset */    /* use environment settings if preset */
43    const char *proxy = g_getenv("http_proxy");    const char *proxy = g_getenv("http_proxy");
# Line 39  static const char *get_proxy_uri(void) { Line 46  static const char *get_proxy_uri(void) {
46      return proxy;      return proxy;
47    }    }
48    
49  #if 0    /* ------------- get proxy settings -------------------- */
50    /* otherwise try settings */    if(gconf_client_get_bool(appdata->gconf_client,
51    if(!settings || !settings->proxy ||                             PROXY_KEY "use_http_proxy", NULL)) {
52       !settings->proxy->host) return NULL;  
53        /* we can savely ignore things like "ignore_hosts" since we */
54    snprintf(proxy_buffer, sizeof(proxy_buffer), "%s%s:%u",      /* are pretty sure not inside the net of one of our map renderers */
55             strncmp(settings->proxy->host, "http://", 7)?"http://":"",      /* (unless the user works at google :-) */
56             settings->proxy->host, settings->proxy->port);  
57        /* get basic settings */
58    proxy_buffer[sizeof(proxy_buffer)-1] = 0;      char *host =
59    printf("gconf_proxy: %s\n", proxy_buffer);        gconf_client_get_string(appdata->gconf_client, PROXY_KEY "host", NULL);
60  #endif      if(host) {
61          int port =
62            gconf_client_get_int(appdata->gconf_client, PROXY_KEY "port", NULL);
63    
64          snprintf(proxy_buffer, sizeof(proxy_buffer),
65                   "http://%s:%u", host, port);
66    
67          g_free(host);
68        }
69        return proxy_buffer;
70      }
71    
72    return proxy_buffer;    return NULL;
73  }  }
74    
75  static void map_zoom(map_context_t *context, int step) {  static void map_zoom(map_context_t *context, int step) {
# Line 80  cb_map_zoomout(GtkButton *button, map_co Line 97  cb_map_zoomout(GtkButton *button, map_co
97    
98  static gboolean  static gboolean
99  cb_map_gps(GtkButton *button, map_context_t *context) {  cb_map_gps(GtkButton *button, map_context_t *context) {
100      pos_t *refpos = get_pos(context->appdata);
101    //  osm_gps_map_set_center(OSM_GPS_MAP(context->widget),    if(refpos && !isnan(refpos->lat) && !isnan(refpos->lon)) {
102    //                     DEG2RAD(pos.lat), DEG2RAD(pos.lon));      osm_gps_map_set_mapcenter(OSM_GPS_MAP(context->widget),
103                                  refpos->lat, refpos->lon, 14);
104      } else {
105        /* no coordinates given: display the entire world */
106        osm_gps_map_set_mapcenter(OSM_GPS_MAP(context->widget),
107                                  0.0, 0.0, 1);
108      }
109    
110    return FALSE;    return FALSE;
111  }  }
# Line 103  static GtkWidget Line 126  static GtkWidget
126  static gboolean map_gps_update(gpointer data) {  static gboolean map_gps_update(gpointer data) {
127    map_context_t *context = (map_context_t*)data;    map_context_t *context = (map_context_t*)data;
128    
129    //  gtk_widget_set_sensitive(context->map.gps, gps_fix);    pos_t *refpos = get_pos(context->appdata);
130      gboolean ok = (refpos!= NULL) && !isnan(refpos->lat) && !isnan(refpos->lon);
131    
132      /* get reference position and go there */
133      gtk_widget_set_sensitive(context->gps, ok);
134    
135    return TRUE;    return TRUE;
136  }  }
137    
138    static gboolean on_map_configure(GtkWidget *widget,
139                                     GdkEventConfigure *event,
140                                     map_context_t *context) {
141    
142  void map(appdata_t *appdata) {    cb_map_gps(NULL, context);
   map_context_t context;  
143    
144    GtkWidget *dialog = gtk_dialog_new_with_buttons(_("Map"),    return FALSE;
145                            GTK_WINDOW(appdata->window),  }
                           GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,  
                           GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,  
                           NULL);  
146    
147  #ifndef USE_MAEMO  static void map_draw_cachelist(GtkWidget *map, cache_t *cache) {
148    gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 350);    while(cache) {
149        GdkPixbuf *icon = icon_get(ICON_CACHE_TYPE, cache->type);
150    
151        osm_gps_map_add_image(OSM_GPS_MAP(map),
152                              cache->pos.lat, cache->pos.lon, icon);
153    
154        cache = cache->next;
155      }
156    }
157    
158    /* draw a nice popup */
159    typedef struct {
160      appdata_t *appdata;
161      GtkWidget *window;
162      GMainLoop *loop;
163    } popup_context_t;
164    
165    
166    #ifndef USE_HILDON
167    #define POPUP_WIDTH  300
168    #define POPUP_HEIGHT 100
169  #else  #else
170    gtk_window_set_default_size(GTK_WINDOW(dialog), 800, 480);  #define POPUP_WIDTH  600
171    #define POPUP_HEIGHT 200
172  #endif  #endif
173    
174    static gboolean
175    pointer_in_window(GtkWidget *widget, gint x_root, gint y_root) {
176      if(GTK_WIDGET_MAPPED(gtk_widget_get_toplevel(widget))) {
177        gint window_x, window_y;
178    
179        gdk_window_get_position(gtk_widget_get_toplevel(widget)->window,
180                                &window_x, &window_y);
181    
182        if(x_root >= window_x && x_root < window_x + widget->allocation.width &&
183            y_root >= window_y && y_root < window_y + widget->allocation.height)
184          return TRUE;
185      }
186    
187      return FALSE;
188    }
189    
190    static gboolean
191    on_button_press_event(GtkWidget *widget,
192                              GdkEventButton *event, popup_context_t *context) {
193      gboolean in = pointer_in_window(widget, event->x_root, event->y_root);
194    
195      printf("overlay button press(in = %d)\n", in);
196      return !in;
197    }
198    
199    static gboolean
200    on_button_release_event(GtkWidget *widget,
201                              GdkEventButton *event, popup_context_t *context) {
202      gboolean in = pointer_in_window(widget, event->x_root, event->y_root);
203    
204      printf("overlay button release(in = %d)\n", in);
205    
206      if(!in) {
207        printf("destroying popup\n");
208        gtk_widget_destroy(gtk_widget_get_toplevel(widget));
209      }
210    
211      return !in;
212    }
213    
214    static void
215    shutdown_loop(popup_context_t *context) {
216      if(g_main_loop_is_running(context->loop))
217        g_main_loop_quit(context->loop);
218    }
219    
220    static gint
221    run_delete_handler(GtkWindow *window, GdkEventAny *event,
222                       popup_context_t *context) {
223      shutdown_loop(context);
224      return TRUE; /* Do not destroy */
225    }
226    
227    static void
228    run_destroy_handler(GtkWindow *window, popup_context_t *context) {
229      /* shutdown_loop will be called by run_unmap_handler */
230      printf("popup destroyed\n");
231    }
232    
233    static void
234    run_unmap_handler(GtkWindow *window, popup_context_t *context) {
235      shutdown_loop(context);
236    }
237    
238    void cache_popup(appdata_t *appdata, cache_t *cache) {
239      popup_context_t context;
240      context.appdata = appdata;
241    
242      context.window = gtk_window_new(GTK_WINDOW_POPUP);
243      gtk_widget_realize(context.window);
244      gtk_window_set_default_size(GTK_WINDOW(context.window),
245                                  POPUP_WIDTH, POPUP_HEIGHT);
246      gtk_window_resize(GTK_WINDOW(context.window),
247                        POPUP_WIDTH, POPUP_HEIGHT);
248      //  gtk_window_set_resizable(GTK_WINDOW(context.window), FALSE);
249      gtk_window_set_transient_for(GTK_WINDOW(context.window),
250                                   GTK_WINDOW(appdata->window));
251      gtk_window_set_keep_above(GTK_WINDOW(context.window), TRUE);
252      gtk_window_set_destroy_with_parent(GTK_WINDOW(context.window), TRUE);
253      gtk_window_set_gravity(GTK_WINDOW(context.window), GDK_GRAVITY_STATIC);
254      gtk_window_set_modal(GTK_WINDOW(context.window), TRUE);
255    
256      /* connect events */
257      g_signal_connect(G_OBJECT(context.window), "button-press-event",
258                       G_CALLBACK(on_button_press_event), &context);
259      g_signal_connect(G_OBJECT(context.window), "button-release-event",
260                       G_CALLBACK(on_button_release_event), &context);
261      g_signal_connect(G_OBJECT(context.window), "delete-event",
262                       G_CALLBACK(run_delete_handler), &context);
263      g_signal_connect(G_OBJECT(context.window), "destroy",
264                       G_CALLBACK(run_destroy_handler), &context);
265      g_signal_connect(G_OBJECT(context.window), "unmap",
266                       G_CALLBACK(run_unmap_handler), &context);
267    
268      gdk_pointer_grab(context.window->window, TRUE,
269         GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_MOTION_MASK,
270                       NULL, NULL, GDK_CURRENT_TIME);
271      gtk_grab_add(context.window);
272    
273      //  gint x, y;
274      //  gdk_window_get_origin(button->window, &x, &y);
275    
276      //  gtk_window_move(GTK_WINDOW(context.window),
277      //              x + button->allocation.x,
278      //              y + button->allocation.y - HEIGHT);
279    
280    
281      gtk_window_move(GTK_WINDOW(context.window),
282                      100,
283                      100);
284    
285      /* a frame with a vscale inside */
286      GtkWidget *frame = gtk_frame_new(NULL);
287      gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
288    
289      gtk_container_add(GTK_CONTAINER(frame), gtk_label_new(cache->name));
290      gtk_container_add(GTK_CONTAINER(context.window), frame);
291    
292      gtk_widget_show_all(context.window);
293    
294      /* handle this popup until it's gone */
295    
296      context.loop = g_main_loop_new(NULL, FALSE);
297    
298      GDK_THREADS_LEAVE();
299      g_main_loop_run(context.loop);
300      GDK_THREADS_ENTER();
301    
302      g_main_loop_unref(context.loop);
303    
304      printf("cache popup removed\n");
305    }
306    
307    #define RAD2DEG(a)  (((a)*180.0)/M_PI)
308    
309    static void
310    map_cachelist_nearest(cache_t *cache, pos_t *pos,
311                          cache_t **result, float *distance) {
312      while(cache) {
313        float dist =
314          pow(cache->pos.lat - pos->lat, 2) +
315          pow(cache->pos.lon - pos->lon, 2);
316    
317        if(!(dist > *distance)) {
318          *result = cache;
319          *distance = dist;
320        }
321    
322        cache = cache->next;
323      }
324    }
325    
326    static cache_t *map_closest(map_context_t *context, pos_t *pos) {
327      cache_t *result = NULL;
328      float distance = NAN;
329    
330    #ifdef USE_MAEMO
331      if(!context->appdata->cur_gpx) {
332    #endif
333        /* search all geocaches */
334        gpx_t *gpx = context->appdata->gpx;
335        while(gpx) {
336          map_cachelist_nearest(gpx->cache, pos, &result, &distance);
337          gpx = gpx->next;
338        }
339    #ifdef USE_MAEMO
340      } else {
341        map_cachelist_nearest(context->appdata->cur_gpx->cache,
342                              pos, &result, &distance);
343      }
344    #endif
345    
346      return result;
347    }
348    
349    /* translate between osm-gps-map positions and gpxview ones */
350    pos_t coord2pos(coord_t coo) {
351      pos_t pos;
352      pos.lat = RAD2DEG(coo.rlat);
353      pos.lon = RAD2DEG(coo.rlon);
354      return pos;
355    }
356    
357    static gboolean
358    on_map_button_press_event(GtkWidget *widget,
359                                GdkEventButton *event, map_context_t *context) {
360      OsmGpsMap *map = OSM_GPS_MAP(context->widget);
361    
362      pos_t pos =
363        coord2pos(osm_gps_map_get_co_ordinates(map, (int)event->x, (int)event->y));
364    
365      printf("clicked at %f/%f\n", pos.lat, pos.lon);
366    
367      return FALSE;
368    }
369    
370    static gboolean
371    on_map_button_release_event(GtkWidget *widget,
372                                GdkEventButton *event, map_context_t *context) {
373      OsmGpsMap *map = OSM_GPS_MAP(context->widget);
374    
375      pos_t pos =
376        coord2pos(osm_gps_map_get_co_ordinates(map, (int)event->x, (int)event->y));
377    
378      printf("released at %f/%f\n", pos.lat, pos.lon);
379    
380      /* return true if we clicked a cache */
381      /* ... */
382    
383      cache_t *nearest = map_closest(context, &pos);
384    
385      if(nearest) {
386        float dist = gpx_pos_get_distance(pos, nearest->pos, FALSE);
387    
388        printf("nearest = %s, distance = %fkm\n", nearest->name, dist);
389    
390        cache_popup(context->appdata, nearest);
391    
392        return TRUE;
393      }
394    
395      return FALSE;
396    }
397    
398    #if MAEMO_VERSION_MAJOR == 5
399    static void on_window_destroy(GtkWidget *widget, map_context_t *context) {
400      printf("destroy map view\n");
401    
402      /* restore cur_view */
403      context->appdata->cur_view = context->old_view;
404    
405      gtk_timeout_remove(context->handler_id);
406      g_free(context);
407    }
408    #endif
409    
410    void map(appdata_t *appdata) {
411      map_context_t *context = g_new0(map_context_t, 1);
412      context->appdata = appdata;
413    
414    GtkWidget *hbox = gtk_hbox_new(FALSE, 0);    GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
415    
416    char *path = g_strdup_printf("%s/map/", appdata->image_path);    char *path = g_strdup_printf("%s/map/", appdata->image_path);
417      const char *proxy = get_proxy_uri(appdata);
418    
419    context.widget = g_object_new(OSM_TYPE_GPS_MAP,    context->widget = g_object_new(OSM_TYPE_GPS_MAP,
420                  "repo-uri", MAP_SOURCE_OPENSTREETMAP,                  "repo-uri", MAP_SOURCE_OPENSTREETMAP,
                 "proxy-uri", get_proxy_uri(),  
421                  "tile-cache", path,                  "tile-cache", path,
422                    proxy?"proxy-uri":NULL, proxy,
423                   NULL);                   NULL);
424    
425    g_free(path);    g_free(path);
426    
427  #if 0    char *name = NULL;
428    g_signal_connect(G_OBJECT(context.widget), "button-release-event",  #ifdef USE_MAEMO
429                     G_CALLBACK(on_map_button_release_event), &context);    if(!appdata->cur_gpx) {
430    #endif
431        /* draw all geocaches */
432        gpx_t *gpx = appdata->gpx;
433        while(gpx) {
434          map_draw_cachelist(context->widget, gpx->cache);
435          gpx = gpx->next;
436        }
437        name = g_strdup(_("all geocaches"));
438    #ifdef USE_MAEMO
439      } else {
440        map_draw_cachelist(context->widget, appdata->cur_gpx->cache);
441        name = g_strdup(_("appdata->cur_gpx->name"));
442      }
443    #endif
444    
445      char *title = g_strdup_printf(_("Map - %s"), name);
446      g_free(name);
447    
448    #if MAEMO_VERSION_MAJOR == 5
449      GtkWidget *window = hildon_stackable_window_new();
450      gtk_window_set_title(GTK_WINDOW(window), title);
451    #else
452      GtkWidget *dialog = gtk_dialog_new_with_buttons(title,
453                              GTK_WINDOW(appdata->window),
454                              GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
455                              GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
456                              NULL);
457    
458    #ifndef USE_MAEMO
459      gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 350);
460    #else
461      gtk_window_set_default_size(GTK_WINDOW(dialog), 800, 480);
462  #endif  #endif
463    #endif
464    
465      g_free(title);
466    
467      g_signal_connect(G_OBJECT(context->widget), "configure-event",
468                       G_CALLBACK(on_map_configure), context);
469    
470      g_signal_connect(G_OBJECT(context->widget), "button-press-event",
471                       G_CALLBACK(on_map_button_press_event), context);
472    
473    gtk_box_pack_start_defaults(GTK_BOX(hbox), context.widget);    g_signal_connect(G_OBJECT(context->widget), "button-release-event",
474                       G_CALLBACK(on_map_button_release_event), context);
475    
476      gtk_box_pack_start_defaults(GTK_BOX(hbox), context->widget);
477    /* zoom button box */    /* zoom button box */
478    GtkWidget *vbox = gtk_vbox_new(FALSE,0);    GtkWidget *vbox = gtk_vbox_new(FALSE,0);
479    
480    context.zoomin =    context->zoomin =
481      map_add_button(GTK_STOCK_ZOOM_IN, G_CALLBACK(cb_map_zoomin),      map_add_button(GTK_STOCK_ZOOM_IN, G_CALLBACK(cb_map_zoomin),
482                     &context, _("Zoom in"));                     context, _("Zoom in"));
483    gtk_box_pack_start(GTK_BOX(vbox), context.zoomin, FALSE, FALSE, 0);    gtk_box_pack_start(GTK_BOX(vbox), context->zoomin, FALSE, FALSE, 0);
484    
485    context.zoomout =    context->zoomout =
486      map_add_button(GTK_STOCK_ZOOM_OUT, G_CALLBACK(cb_map_zoomout),      map_add_button(GTK_STOCK_ZOOM_OUT, G_CALLBACK(cb_map_zoomout),
487                     &context, _("Zoom out"));                     context, _("Zoom out"));
488    gtk_box_pack_start(GTK_BOX(vbox), context.zoomout, FALSE, FALSE, 0);    gtk_box_pack_start(GTK_BOX(vbox), context->zoomout, FALSE, FALSE, 0);
489    
490    context.gps =    context->gps =
491      map_add_button(GTK_STOCK_HOME, G_CALLBACK(cb_map_gps),      map_add_button(GTK_STOCK_HOME, G_CALLBACK(cb_map_gps),
492                     &context, _("Jump to GPS position"));                     context, _("Jump to GPS position"));
493    gtk_widget_set_sensitive(context.gps, FALSE);    gtk_widget_set_sensitive(context->gps, FALSE);
494    /* install handler for timed updates of the gps button */    /* install handler for timed updates of the gps button */
495    context.handler_id = gtk_timeout_add(1000, map_gps_update, &context);    context->handler_id = gtk_timeout_add(1000, map_gps_update, context);
496    gtk_box_pack_start(GTK_BOX(vbox), context.gps, FALSE, FALSE, 0);    gtk_box_pack_start(GTK_BOX(vbox), context->gps, FALSE, FALSE, 0);
497    
498    gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);    gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
499    
500    #if MAEMO_VERSION_MAJOR == 5
501      /* prevent some of the main screen things */
502      context->old_view = appdata->cur_view;
503      appdata->cur_view = NULL;
504    
505      g_signal_connect(G_OBJECT(window), "destroy",
506                       G_CALLBACK(on_window_destroy), context);
507    
508      gtk_container_add(GTK_CONTAINER(window), hbox);
509      gtk_widget_show_all(GTK_WIDGET(window));
510    
511    #else
512    gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox);    gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox);
   
513    gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CLOSE);    gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CLOSE);
   
514    gtk_widget_show_all(dialog);    gtk_widget_show_all(dialog);
   
515    gtk_dialog_run(GTK_DIALOG(dialog));    gtk_dialog_run(GTK_DIALOG(dialog));
516      gtk_timeout_remove(context->handler_id);
517    gtk_widget_destroy(dialog);    gtk_widget_destroy(dialog);
518      g_free(context);
519    #endif
520  }  }

Legend:
Removed from v.33  
changed lines
  Added in v.41