--- trunk/src/map-tool.c 2009/08/02 19:05:24 40 +++ trunk/src/map-tool.c 2009/08/03 14:21:57 41 @@ -155,6 +155,246 @@ } } +/* draw a nice popup */ +typedef struct { + appdata_t *appdata; + GtkWidget *window; + GMainLoop *loop; +} popup_context_t; + + +#ifndef USE_HILDON +#define POPUP_WIDTH 300 +#define POPUP_HEIGHT 100 +#else +#define POPUP_WIDTH 600 +#define POPUP_HEIGHT 200 +#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); +} + +void cache_popup(appdata_t *appdata, cache_t *cache) { + popup_context_t context; + context.appdata = appdata; + + context.window = gtk_window_new(GTK_WINDOW_POPUP); + gtk_widget_realize(context.window); + gtk_window_set_default_size(GTK_WINDOW(context.window), + POPUP_WIDTH, POPUP_HEIGHT); + gtk_window_resize(GTK_WINDOW(context.window), + POPUP_WIDTH, POPUP_HEIGHT); + // gtk_window_set_resizable(GTK_WINDOW(context.window), FALSE); + gtk_window_set_transient_for(GTK_WINDOW(context.window), + GTK_WINDOW(appdata->window)); + gtk_window_set_keep_above(GTK_WINDOW(context.window), TRUE); + gtk_window_set_destroy_with_parent(GTK_WINDOW(context.window), TRUE); + gtk_window_set_gravity(GTK_WINDOW(context.window), GDK_GRAVITY_STATIC); + gtk_window_set_modal(GTK_WINDOW(context.window), TRUE); + + /* connect events */ + g_signal_connect(G_OBJECT(context.window), "button-press-event", + G_CALLBACK(on_button_press_event), &context); + g_signal_connect(G_OBJECT(context.window), "button-release-event", + G_CALLBACK(on_button_release_event), &context); + g_signal_connect(G_OBJECT(context.window), "delete-event", + G_CALLBACK(run_delete_handler), &context); + g_signal_connect(G_OBJECT(context.window), "destroy", + G_CALLBACK(run_destroy_handler), &context); + g_signal_connect(G_OBJECT(context.window), "unmap", + G_CALLBACK(run_unmap_handler), &context); + + gdk_pointer_grab(context.window->window, TRUE, + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_MOTION_MASK, + NULL, NULL, GDK_CURRENT_TIME); + gtk_grab_add(context.window); + + // gint x, y; + // gdk_window_get_origin(button->window, &x, &y); + + // gtk_window_move(GTK_WINDOW(context.window), + // x + button->allocation.x, + // y + button->allocation.y - HEIGHT); + + + gtk_window_move(GTK_WINDOW(context.window), + 100, + 100); + + /* a frame with a vscale inside */ + GtkWidget *frame = gtk_frame_new(NULL); + gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT); + + gtk_container_add(GTK_CONTAINER(frame), gtk_label_new(cache->name)); + gtk_container_add(GTK_CONTAINER(context.window), frame); + + gtk_widget_show_all(context.window); + + /* handle this popup until it's gone */ + + context.loop = g_main_loop_new(NULL, FALSE); + + GDK_THREADS_LEAVE(); + g_main_loop_run(context.loop); + GDK_THREADS_ENTER(); + + g_main_loop_unref(context.loop); + + printf("cache popup removed\n"); +} + +#define RAD2DEG(a) (((a)*180.0)/M_PI) + +static void +map_cachelist_nearest(cache_t *cache, pos_t *pos, + cache_t **result, float *distance) { + while(cache) { + float dist = + pow(cache->pos.lat - pos->lat, 2) + + pow(cache->pos.lon - pos->lon, 2); + + if(!(dist > *distance)) { + *result = cache; + *distance = dist; + } + + cache = cache->next; + } +} + +static cache_t *map_closest(map_context_t *context, pos_t *pos) { + cache_t *result = NULL; + float distance = NAN; + +#ifdef USE_MAEMO + if(!context->appdata->cur_gpx) { +#endif + /* search all geocaches */ + gpx_t *gpx = context->appdata->gpx; + while(gpx) { + map_cachelist_nearest(gpx->cache, pos, &result, &distance); + gpx = gpx->next; + } +#ifdef USE_MAEMO + } else { + map_cachelist_nearest(context->appdata->cur_gpx->cache, + pos, &result, &distance); + } +#endif + + return result; +} + +/* translate between osm-gps-map positions and gpxview ones */ +pos_t coord2pos(coord_t coo) { + pos_t pos; + pos.lat = RAD2DEG(coo.rlat); + pos.lon = RAD2DEG(coo.rlon); + return pos; +} + +static gboolean +on_map_button_press_event(GtkWidget *widget, + GdkEventButton *event, map_context_t *context) { + OsmGpsMap *map = OSM_GPS_MAP(context->widget); + + pos_t pos = + coord2pos(osm_gps_map_get_co_ordinates(map, (int)event->x, (int)event->y)); + + printf("clicked at %f/%f\n", pos.lat, pos.lon); + + return FALSE; +} + +static gboolean +on_map_button_release_event(GtkWidget *widget, + GdkEventButton *event, map_context_t *context) { + OsmGpsMap *map = OSM_GPS_MAP(context->widget); + + pos_t pos = + coord2pos(osm_gps_map_get_co_ordinates(map, (int)event->x, (int)event->y)); + + printf("released at %f/%f\n", pos.lat, pos.lon); + + /* return true if we clicked a cache */ + /* ... */ + + cache_t *nearest = map_closest(context, &pos); + + if(nearest) { + float dist = gpx_pos_get_distance(pos, nearest->pos, FALSE); + + printf("nearest = %s, distance = %fkm\n", nearest->name, dist); + + cache_popup(context->appdata, nearest); + + return TRUE; + } + + return FALSE; +} + #if MAEMO_VERSION_MAJOR == 5 static void on_window_destroy(GtkWidget *widget, map_context_t *context) { printf("destroy map view\n"); @@ -171,11 +411,45 @@ map_context_t *context = g_new0(map_context_t, 1); context->appdata = appdata; + GtkWidget *hbox = gtk_hbox_new(FALSE, 0); + + char *path = g_strdup_printf("%s/map/", appdata->image_path); + const char *proxy = get_proxy_uri(appdata); + + context->widget = g_object_new(OSM_TYPE_GPS_MAP, + "repo-uri", MAP_SOURCE_OPENSTREETMAP, + "tile-cache", path, + proxy?"proxy-uri":NULL, proxy, + NULL); + + g_free(path); + + char *name = NULL; +#ifdef USE_MAEMO + if(!appdata->cur_gpx) { +#endif + /* draw all geocaches */ + gpx_t *gpx = appdata->gpx; + while(gpx) { + map_draw_cachelist(context->widget, gpx->cache); + gpx = gpx->next; + } + name = g_strdup(_("all geocaches")); +#ifdef USE_MAEMO + } else { + map_draw_cachelist(context->widget, appdata->cur_gpx->cache); + name = g_strdup(_("appdata->cur_gpx->name")); + } +#endif + + 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), _("Map")); + gtk_window_set_title(GTK_WINDOW(window), title); #else - GtkWidget *dialog = gtk_dialog_new_with_buttons(_("Map"), + 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, @@ -188,32 +462,16 @@ #endif #endif - GtkWidget *hbox = gtk_hbox_new(FALSE, 0); - - char *path = g_strdup_printf("%s/map/", appdata->image_path); - const char *proxy = get_proxy_uri(appdata); - - context->widget = g_object_new(OSM_TYPE_GPS_MAP, - "repo-uri", MAP_SOURCE_OPENSTREETMAP, - "tile-cache", path, - proxy?"proxy-uri":NULL, proxy, - NULL); - - g_free(path); - - /* draw all geocaches */ - gpx_t *gpx = appdata->gpx; - while(gpx) { - map_draw_cachelist(context->widget, gpx->cache); - gpx = gpx->next; - } + g_free(title); g_signal_connect(G_OBJECT(context->widget), "configure-event", G_CALLBACK(on_map_configure), context); -#if 0 + + g_signal_connect(G_OBJECT(context->widget), "button-press-event", + G_CALLBACK(on_map_button_press_event), context); + g_signal_connect(G_OBJECT(context->widget), "button-release-event", G_CALLBACK(on_map_button_release_event), context); -#endif gtk_box_pack_start_defaults(GTK_BOX(hbox), context->widget); /* zoom button box */