--- trunk/src/map-tool.c 2009/08/12 19:20:00 54 +++ trunk/src/map-tool.c 2009/08/16 19:29:01 57 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Till Harbaum . + * Copyright (C) 2008-2009 Till Harbaum . * * This file is part of GPXView. * @@ -24,6 +24,7 @@ #include "osm-gps-map.h" #endif +#define MAP_SOURCE OSM_GPS_MAP_SOURCE_OPENSTREETMAP #define GPS_DEFAULT_ZOOM 13 /* equatorial radius in meters */ @@ -32,17 +33,6 @@ #define RAD2DEG(a) (((a)*180.0)/M_PI) #define DEG2RAD(a) (((a)*M_PI)/180.0) -typedef struct { - appdata_t *appdata; - GtkWidget *widget; - GtkWidget *zoomin, *zoomout, *gps; - gint handler_id; - cache_t *press_on; -#if MAEMO_VERSION_MAJOR == 5 - GtkWidget *old_view; -#endif -} map_context_t; - #define PROXY_KEY "/system/http_proxy/" static const char *get_proxy_uri(appdata_t *appdata) { @@ -88,8 +78,13 @@ zoom = osm_gps_map_set_zoom(map, zoom+step); /* enable/disable zoom buttons as required */ - gtk_widget_set_sensitive(context->zoomin, zoom<17); - gtk_widget_set_sensitive(context->zoomout, zoom>1); + gtk_widget_set_sensitive(context->zoomin, + zoom < osm_gps_map_source_get_max_zoom(MAP_SOURCE)); + gtk_widget_set_sensitive(context->zoomout, + zoom > osm_gps_map_source_get_min_zoom(MAP_SOURCE)); + + /* hmm ... this doesn't really work */ + osm_gps_map_osd_speed(map, zoom); /* save new zoom */ context->appdata->map.zoom = zoom; @@ -134,6 +129,10 @@ return button; } +static int dist2pixel(map_context_t *context, float km, float lat) { + return 1000.0*km/osm_gps_map_get_scale(OSM_GPS_MAP(context->widget)); +} + static gboolean map_gps_update(gpointer data) { map_context_t *context = (map_context_t*)data; @@ -153,16 +152,8 @@ /* get error */ float eph = gps_get_eph(context->appdata); - if(!isnan(eph)) { - - /* world at zoom 1 == 512 pixels */ - gint zoom; - g_object_get(OSM_GPS_MAP(context->widget), "zoom", &zoom, NULL); - float m_per_pix = - cos(DEG2RAD(refpos->lat))*2*M_PI*EQ_RADIUS/(1<<(8+zoom)); - - radius = eph/m_per_pix; - } + if(!isnan(eph)) + radius = dist2pixel(context, eph/1000, refpos->lat); } g_object_set(context->widget, "gps-track-highlight-radius", radius, NULL); @@ -217,317 +208,6 @@ } } -/* draw a nice popup */ -typedef struct { - appdata_t *appdata; - GtkWidget *window; - GMainLoop *loop; -} popup_context_t; - -/* draw shape */ -#define ARROW_BORDER 20 -#define CORNER_RADIUS 10 - -#ifndef USE_MAEMO -#define POPUP_WIDTH 300 -#define POPUP_HEIGHT 100 -#else -#define POPUP_WIDTH 350 -#define POPUP_HEIGHT 120 -#endif - -static gboolean -pointer_in_window(GtkWidget *widget, gint x_root, gint y_root) { - if(GTK_WIDGET_MAPPED(gtk_widget_get_toplevel(widget))) { - gint window_x, window_y; - - gdk_window_get_position(gtk_widget_get_toplevel(widget)->window, - &window_x, &window_y); - - if(x_root >= window_x && x_root < window_x + widget->allocation.width && - y_root >= window_y && y_root < window_y + widget->allocation.height) - return TRUE; - } - - return FALSE; -} - -static gboolean -on_button_press_event(GtkWidget *widget, - GdkEventButton *event, popup_context_t *context) { - gboolean in = pointer_in_window(widget, event->x_root, event->y_root); - - printf("overlay button press (in = %d)\n", in); - return !in; -} - -static gboolean -on_button_release_event(GtkWidget *widget, - GdkEventButton *event, popup_context_t *context) { - gboolean in = pointer_in_window(widget, event->x_root, event->y_root); - - printf("overlay button release (in = %d)\n", in); - - if(!in) { - printf("destroying popup\n"); - gtk_widget_destroy(gtk_widget_get_toplevel(widget)); - } - - return !in; -} - -static void -shutdown_loop(popup_context_t *context) { - if(g_main_loop_is_running(context->loop)) - g_main_loop_quit(context->loop); -} - -static gint -run_delete_handler(GtkWindow *window, GdkEventAny *event, - popup_context_t *context) { - shutdown_loop(context); - return TRUE; /* Do not destroy */ -} - -static void -run_destroy_handler(GtkWindow *window, popup_context_t *context) { - /* shutdown_loop will be called by run_unmap_handler */ - printf("popup destroyed\n"); -} - -static void -run_unmap_handler(GtkWindow *window, popup_context_t *context) { - shutdown_loop(context); -} - -static void popup_window_shape(GtkWidget *window, int tip_x, int tip_y) { - GdkBitmap *mask = gdk_pixmap_new(NULL, POPUP_WIDTH, POPUP_HEIGHT, 1); - - GdkGC *gc = gdk_gc_new(mask); - GdkColormap *colormap; - GdkColor black; - GdkColor white; - - /* get black/white color values */ - colormap = gdk_colormap_get_system(); - gdk_color_black(colormap, &black); - gdk_color_white(colormap, &white); - - /* erase */ - gdk_gc_set_foreground(gc, &black); - gdk_gc_set_background(gc, &white); - - /* erase background */ - gdk_draw_rectangle(mask, gc, TRUE, 0, 0, POPUP_WIDTH, POPUP_HEIGHT); - - gdk_gc_set_foreground(gc, &white); - gdk_gc_set_background(gc, &black); - - /* the tip is always above or below the "bubble" but never at its side */ - guint tip_offset = (tip_y == 0)?ARROW_BORDER:0; - - gdk_draw_rectangle(mask, gc, TRUE, - 0, tip_offset + CORNER_RADIUS, - POPUP_WIDTH, - POPUP_HEIGHT - 2*CORNER_RADIUS - ARROW_BORDER); - - gdk_draw_rectangle(mask, gc, TRUE, - CORNER_RADIUS, tip_offset, - POPUP_WIDTH - 2*CORNER_RADIUS, - POPUP_HEIGHT - ARROW_BORDER); - - int off[][2] = { - { CORNER_RADIUS, tip_offset + CORNER_RADIUS }, - { POPUP_WIDTH - CORNER_RADIUS, tip_offset + CORNER_RADIUS }, - { POPUP_WIDTH - CORNER_RADIUS, - POPUP_HEIGHT - CORNER_RADIUS - ARROW_BORDER + tip_offset}, - { CORNER_RADIUS, - POPUP_HEIGHT - CORNER_RADIUS - ARROW_BORDER + tip_offset}}; - - int i; - for(i=0;i<4;i++) { - gdk_draw_arc(mask, gc, TRUE, - off[i][0]-CORNER_RADIUS, off[i][1]-CORNER_RADIUS, - 2*CORNER_RADIUS, 2*CORNER_RADIUS, - 0, 360*64); - } - - GdkPoint points[3] = { {POPUP_WIDTH*1/3, POPUP_HEIGHT/2}, - {POPUP_WIDTH*2/3, POPUP_HEIGHT/2}, - {tip_x,tip_y} }; - gdk_draw_polygon(mask, gc, TRUE, points, 3); - - - gdk_window_shape_combine_mask(window->window, mask, 0, 0); -} - -/* create a left aligned label (normal ones are centered) */ -static GtkWidget *gtk_label_left_new(char *str) { - GtkWidget *label = gtk_label_new(str); - gtk_misc_set_alignment(GTK_MISC(label), 0.f, .5f); - return label; -} - -/* the small labels are actually only on maemo small */ -#ifdef USE_MAEMO -#define MARKUP_SMALL "%s" -GtkWidget *gtk_label_small_left_new(char *str) { - GtkWidget *label = gtk_label_new(""); - char *markup = g_markup_printf_escaped(MARKUP_SMALL, str); - gtk_label_set_markup(GTK_LABEL(label), markup); - g_free(markup); - gtk_misc_set_alignment(GTK_MISC(label), 0.f, .5f); - return label; -} -#define gtk_label_big_left_new(a) gtk_label_left_new(a) -#else -#define gtk_label_small_left_new(a) gtk_label_left_new(a) -#define MARKUP_BIG "%s" -GtkWidget *gtk_label_big_left_new(char *str) { - GtkWidget *label = gtk_label_new(""); - char *markup = g_markup_printf_escaped(MARKUP_BIG, str); - gtk_label_set_markup(GTK_LABEL(label), markup); - g_free(markup); - gtk_misc_set_alignment(GTK_MISC(label), 0.f, .5f); - return label; -} -#endif - -void cache_popup(map_context_t *mcontext, cache_t *cache) { - popup_context_t pcontext; - pcontext.appdata = mcontext->appdata; - - pcontext.window = gtk_window_new(GTK_WINDOW_POPUP); - gtk_widget_realize(pcontext.window); - gtk_window_set_default_size(GTK_WINDOW(pcontext.window), - POPUP_WIDTH, POPUP_HEIGHT); - gtk_window_resize(GTK_WINDOW(pcontext.window), POPUP_WIDTH, POPUP_HEIGHT); - // gtk_window_set_resizable(GTK_WINDOW(pcontext.window), FALSE); - gtk_window_set_transient_for(GTK_WINDOW(pcontext.window), - GTK_WINDOW(mcontext->appdata->window)); - gtk_window_set_keep_above(GTK_WINDOW(pcontext.window), TRUE); - gtk_window_set_destroy_with_parent(GTK_WINDOW(pcontext.window), TRUE); - gtk_window_set_gravity(GTK_WINDOW(pcontext.window), GDK_GRAVITY_STATIC); - gtk_window_set_modal(GTK_WINDOW(pcontext.window), TRUE); - - /* connect events */ - g_signal_connect(G_OBJECT(pcontext.window), "button-press-event", - G_CALLBACK(on_button_press_event), &pcontext); - g_signal_connect(G_OBJECT(pcontext.window), "button-release-event", - G_CALLBACK(on_button_release_event), &pcontext); - g_signal_connect(G_OBJECT(pcontext.window), "delete-event", - G_CALLBACK(run_delete_handler), &pcontext); - g_signal_connect(G_OBJECT(pcontext.window), "destroy", - G_CALLBACK(run_destroy_handler), &pcontext); - g_signal_connect(G_OBJECT(pcontext.window), "unmap", - G_CALLBACK(run_unmap_handler), &pcontext); - - gdk_pointer_grab(pcontext.window->window, TRUE, - GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_MOTION_MASK, - NULL, NULL, GDK_CURRENT_TIME); - gtk_grab_add(pcontext.window); - - /* check whether cache is in upper or lower half of window */ - gint x, y, sx, sy; - osm_gps_map_geographic_to_screen(OSM_GPS_MAP(mcontext->widget), - cache->pos.lat, cache->pos.lon, - &sx, &sy); - - gdk_window_get_origin(mcontext->widget->window, &x, &y); - - gint ax = 0, ay = 0; - if(sx > mcontext->widget->allocation.width/2) - ax = POPUP_WIDTH; - - if(sy > mcontext->widget->allocation.height/2) - ay = POPUP_HEIGHT; - -#if !defined(USE_MAEMO) || (MAEMO_VERSION_MAJOR < 5) - GdkColor color; - gdk_color_parse("darkgray", &color); - gtk_widget_modify_bg(GTK_WIDGET(pcontext.window), GTK_STATE_NORMAL, &color); -#endif - - gtk_window_move(GTK_WINDOW(pcontext.window), - x + mcontext->widget->allocation.x + sx - ax, - y + mcontext->widget->allocation.y + sy - ay); - - - GtkWidget *alignment = gtk_alignment_new(0.5, 0.5, 1.0, 1.0); - gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), - CORNER_RADIUS/2 + (ay?0:ARROW_BORDER), - CORNER_RADIUS/2 + (ay?ARROW_BORDER:0), - CORNER_RADIUS, CORNER_RADIUS); - - /* --- actual content ---- */ - GtkWidget *vbox = gtk_vbox_new(FALSE, 0); - - if(cache->id) { - GtkWidget *ihbox = gtk_hbox_new(FALSE, 0); - - gtk_box_pack_start(GTK_BOX(ihbox), - icon_get_widget(ICON_CACHE_TYPE, cache->type), - FALSE, FALSE, 5); - - gtk_box_pack_start_defaults(GTK_BOX(ihbox), - gtk_label_big_left_new(cache->id)); - - gtk_box_pack_start_defaults(GTK_BOX(vbox), ihbox); - } - - if(cache->name) { - GtkWidget *label = gtk_label_small_left_new(cache->name); - gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END); - gtk_box_pack_start_defaults(GTK_BOX(vbox), label); - } - - GtkWidget *hbox = gtk_hbox_new(FALSE, 0); - if(cache->terrain) { - GtkWidget *ihbox = gtk_hbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(ihbox), - gtk_label_small_left_new(_("Terrain:")), FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(ihbox), - icon_get_widget(ICON_STARS, (int)(cache->terrain*2-2)), - FALSE, FALSE, 5); - gtk_box_pack_start_defaults(GTK_BOX(hbox), ihbox); - } - - if(cache->difficulty) { - GtkWidget *ihbox = gtk_hbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(ihbox), - gtk_label_small_left_new(_("Difficulty:")), FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(ihbox), - icon_get_widget(ICON_STARS, (int)(cache->difficulty*2-2)), - FALSE, FALSE, 5); - gtk_box_pack_start_defaults(GTK_BOX(hbox), ihbox); - } - - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - - gtk_container_add(GTK_CONTAINER(alignment), vbox); - /* ----------------------- */ - - - gtk_container_add(GTK_CONTAINER(pcontext.window), alignment); - - /* give window its shape */ - popup_window_shape(pcontext.window, ax, ay); - - gtk_widget_show_all(pcontext.window); - - /* handle this popup until it's gone */ - - pcontext.loop = g_main_loop_new(NULL, FALSE); - - GDK_THREADS_LEAVE(); - g_main_loop_run(pcontext.loop); - GDK_THREADS_ENTER(); - - g_main_loop_unref(pcontext.loop); - - printf("cache popup removed\n"); -} - static void map_cachelist_nearest(cache_t *cache, pos_t *pos, cache_t **result, float *distance) { @@ -576,17 +256,6 @@ return pos; } -static int dist2pixel(map_context_t *context, float km, float lat) { - gint zoom; - g_object_get(OSM_GPS_MAP(context->widget), "zoom", &zoom, NULL); - - /* world at zoom 1 == 512 pixels */ - float m_per_pix = - cos(DEG2RAD(lat))*2*M_PI*EQ_RADIUS/(1<<(8+zoom)); - - return 1000.0*km/m_per_pix; -} - #define CLICK_FUZZ (24) static gboolean @@ -619,14 +288,19 @@ OsmGpsMap *map = OSM_GPS_MAP(context->widget); if(context->press_on) { + coord_t coo; + coo = osm_gps_map_get_co_ordinates(map, event->x, event->y); + pos_t pos = coord2pos(osm_gps_map_get_co_ordinates(map, event->x, event->y)); cache_t *nearest = map_closest(context, &pos); if(nearest && nearest == context->press_on) { float dist = gpx_pos_get_distance(pos, nearest->pos, FALSE); - if(dist2pixel(context, dist, nearest->pos.lat) < CLICK_FUZZ) - cache_popup(context, nearest); + if(dist2pixel(context, dist, nearest->pos.lat) < CLICK_FUZZ) { + + osm_gps_map_draw_balloon(map, nearest->pos.lat, nearest->pos.lon); + } } context->press_on = NULL; } else { @@ -640,7 +314,11 @@ return FALSE; } -static void save_map_state(map_context_t *context) { +static void on_window_destroy(GtkWidget *widget, map_context_t *context) { + appdata_t *appdata = context->appdata; + + printf("destroy map window\n"); + /* save map parameters */ OsmGpsMap *map = OSM_GPS_MAP(context->widget); gint zoom; @@ -651,24 +329,28 @@ g_object_get(map, "latitude", &lat, "longitude", &lon, NULL); context->appdata->map.pos.lat = lat; context->appdata->map.pos.lon = lon; -} #if MAEMO_VERSION_MAJOR == 5 -static void on_window_destroy(GtkWidget *widget, map_context_t *context) { - printf("destroy map view\n"); - - save_map_state(context); - /* restore cur_view */ context->appdata->cur_view = context->old_view; +#endif gtk_timeout_remove(context->handler_id); + g_free(context); + appdata->map.context = NULL; } -#endif void map(appdata_t *appdata) { - map_context_t *context = g_new0(map_context_t, 1); + map_context_t *context = NULL; + + /* if the map window already exists, just raise it */ + if(appdata->map.context) { + gtk_window_present(GTK_WINDOW(appdata->map.context->window)); + return; + } + + context = appdata->map.context = g_new0(map_context_t, 1); context->appdata = appdata; GtkWidget *hbox = gtk_hbox_new(FALSE, 0); @@ -677,16 +359,14 @@ const char *proxy = get_proxy_uri(appdata); context->widget = g_object_new(OSM_TYPE_GPS_MAP, - "repo-uri", MAP_SOURCE_OPENSTREETMAP, - "tile-cache", path, - "auto-center", FALSE, - "record-trip-history", FALSE, - "show-trip-history", FALSE, + "map-source", MAP_SOURCE, + "tile-cache", path, + "auto-center", FALSE, + "record-trip-history", FALSE, + "show-trip-history", FALSE, + proxy?"proxy-uri":NULL, proxy, NULL); - if(proxy) - g_object_set(OSM_GPS_MAP(context->widget), "proxy-uri", proxy, NULL); - g_free(path); char *name = NULL; @@ -710,21 +390,20 @@ char *title = g_strdup_printf(_("Map - %s"), name); g_free(name); -#if MAEMO_VERSION_MAJOR == 5 - GtkWidget *window = hildon_stackable_window_new(); - gtk_window_set_title(GTK_WINDOW(window), title); +#ifdef USE_MAEMO +#ifdef USE_STACKABLE_WINDOW + context->window = hildon_stackable_window_new(); #else - GtkWidget *dialog = gtk_dialog_new_with_buttons(title, - GTK_WINDOW(appdata->window), - GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, - NULL); - -#ifndef USE_MAEMO - gtk_window_set_default_size(GTK_WINDOW(dialog), 640, 480); + context->window = hildon_window_new(); +#endif #else - gtk_window_set_default_size(GTK_WINDOW(dialog), 800, 480); + context->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); #endif + + gtk_window_set_title(GTK_WINDOW(context->window), title); + +#ifndef USE_MAEMO + gtk_window_set_default_size(GTK_WINDOW(context->window), 640, 480); #endif g_free(title); @@ -756,6 +435,7 @@ map_add_button(9, G_CALLBACK(cb_map_gps), context, _("Jump to GPS position")); gtk_widget_set_sensitive(context->gps, FALSE); + /* install handler for timed updates of the gps button */ context->handler_id = gtk_timeout_add(1000, map_gps_update, context); gtk_box_pack_start(GTK_BOX(vbox), context->gps, FALSE, FALSE, 0); @@ -766,21 +446,11 @@ /* prevent some of the main screen things */ context->old_view = appdata->cur_view; appdata->cur_view = NULL; +#endif - g_signal_connect(G_OBJECT(window), "destroy", + g_signal_connect(G_OBJECT(context->window), "destroy", G_CALLBACK(on_window_destroy), context); - gtk_container_add(GTK_CONTAINER(window), hbox); - gtk_widget_show_all(GTK_WIDGET(window)); - -#else - gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox); - gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CLOSE); - gtk_widget_show_all(dialog); - gtk_dialog_run(GTK_DIALOG(dialog)); - save_map_state(context); - gtk_timeout_remove(context->handler_id); - gtk_widget_destroy(dialog); - g_free(context); -#endif + gtk_container_add(GTK_CONTAINER(context->window), hbox); + gtk_widget_show_all(GTK_WIDGET(context->window)); }