--- trunk/src/osm-gps-map.c 2010/05/21 14:12:36 279 +++ trunk/src/osm-gps-map.c 2010/05/21 19:28:16 280 @@ -4,22 +4,22 @@ * osm-gps-map.c * Copyright (C) Marcus Bauer 2008 * Copyright (C) John Stowers 2009 + * Copyright (C) Till Harbaum 2009 * * Contributions by * Everaldo Canuto 2009 * * osm-gps-map.c is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2. * - * osm-gps-map.c is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . */ #include "config.h" @@ -36,36 +36,18 @@ #include #include #include +#include #include "converter.h" #include "osm-gps-map-types.h" #include "osm-gps-map.h" -#ifdef USE_CAIRO -#include -#endif - #define ENABLE_DEBUG 0 #define EXTRA_BORDER (TILESIZE / 2) #define OSM_GPS_MAP_SCROLL_STEP 10 -/* any defined key enables key support */ -#if (defined(OSM_GPS_MAP_KEY_FULLSCREEN) || \ - defined(OSM_GPS_MAP_KEY_ZOOMIN) || \ - defined(OSM_GPS_MAP_KEY_ZOOMOUT) || \ - defined(OSM_GPS_MAP_KEY_UP) || \ - defined(OSM_GPS_MAP_KEY_DOWN) || \ - defined(OSM_GPS_MAP_KEY_LEFT) || \ - defined(OSM_GPS_MAP_KEY_RIGHT)) -#define OSM_GPS_MAP_KEYS -#endif - -#ifdef OSM_GPS_MAP_KEYS -#include -#endif - #define USER_AGENT "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11" struct _OsmGpsMapPrivate @@ -98,6 +80,7 @@ //where downloaded tiles are cached char *tile_dir; + char *tile_base_dir; char *cache_dir; //contains flags indicating the various special characters @@ -124,12 +107,7 @@ #ifdef OSD_DOUBLE_BUFFER GdkPixmap *dbuf_pixmap; #endif -#endif - -#ifdef OSM_GPS_MAP_KEY_FULLSCREEN - gboolean fullscreen; -#endif - +#endif //additional images or tracks added to the map GSList *tracks; GSList *images; @@ -149,6 +127,7 @@ int drag_start_mouse_y; int drag_start_map_x; int drag_start_map_y; + int drag_limit; guint drag_expose; //for customizing the redering of the gps track @@ -156,8 +135,15 @@ int ui_gps_point_inner_radius; int ui_gps_point_outer_radius; + //For storing keybindings + guint keybindings[OSM_GPS_MAP_KEY_MAX]; + + guint fullscreen : 1; + guint keybindings_enabled : 1; guint is_disposed : 1; guint dragging : 1; + guint button_down : 1; + guint double_pixel : 1; }; #define OSM_GPS_MAP_PRIVATE(o) (OSM_GPS_MAP (o)->priv) @@ -174,6 +160,7 @@ { PROP_0, + PROP_DOUBLE_PIXEL, PROP_AUTO_CENTER, PROP_RECORD_TRIP_HISTORY, PROP_SHOW_TRIP_HISTORY, @@ -181,6 +168,8 @@ PROP_REPO_URI, PROP_PROXY_URI, PROP_TILE_CACHE_DIR, + PROP_TILE_CACHE_BASE_DIR, + PROP_TILE_CACHE_DIR_IS_FULL_PATH, PROP_ZOOM, PROP_MAX_ZOOM, PROP_MIN_ZOOM, @@ -193,7 +182,8 @@ PROP_GPS_POINT_R1, PROP_GPS_POINT_R2, PROP_MAP_SOURCE, - PROP_IMAGE_FORMAT + PROP_IMAGE_FORMAT, + PROP_DRAG_LIMIT, }; G_DEFINE_TYPE (OsmGpsMap, osm_gps_map, GTK_TYPE_DRAWING_AREA); @@ -207,7 +197,7 @@ static void osm_gps_map_print_images (OsmGpsMap *map); static void osm_gps_map_draw_gps_point (OsmGpsMap *map); static void osm_gps_map_blit_tile(OsmGpsMap *map, GdkPixbuf *pixbuf, int offset_x, int offset_y); -#ifdef LIBSOUP22 +#if USE_LIBSOUP22 static void osm_gps_map_tile_download_complete (SoupMessage *msg, gpointer user_data); #else static void osm_gps_map_tile_download_complete (SoupSession *session, SoupMessage *msg, gpointer user_data); @@ -551,7 +541,7 @@ priv->gc_map, im->image, 0,0, - x-(im->w/2),y-(im->h/2), + x-im->xoffset,y-im->yoffset, im->w,im->h, GDK_RGB_DITHER_NONE, 0, 0); @@ -585,15 +575,9 @@ map_y0 = priv->map_y - EXTRA_BORDER; x = lon2pixel(priv->map_zoom, priv->gps->rlon) - map_x0; y = lat2pixel(priv->map_zoom, priv->gps->rlat) - map_y0; -#ifdef USE_CAIRO cairo_t *cr; cairo_pattern_t *pat; -#else - GdkColor color; - GdkGC *marker; -#endif -#ifdef USE_CAIRO cr = gdk_cairo_create(priv->pixmap); // draw transparent area @@ -639,67 +623,54 @@ cairo_arc (cr, x, y, r, 0, 2 * M_PI); cairo_stroke(cr); } - + cairo_destroy(cr); gtk_widget_queue_draw_area (GTK_WIDGET(map), x-mr, y-mr, mr*2, mr*2); -#else - marker = gdk_gc_new(priv->pixmap); - color.red = 5000; - color.green = 5000; - color.blue = 55000; - gdk_gc_set_rgb_fg_color(marker, &color); - gdk_gc_set_line_attributes(marker, lw, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND); - - if (r2 > 0) { - gdk_draw_arc (priv->pixmap, - marker, - FALSE, //filled - x-r2, y-r2, // x,y - r2*2,r2*2, // width, height - 0, 360*64); // start-end angle 64th, from 3h, anti clockwise - } - if (r > 0) { - gdk_draw_arc (priv->pixmap, - marker, - TRUE, //filled - x-r, y-r, // x,y - r*2,r*2, // width, height - 0, 360*64); // start-end angle 64th, from 3h, anti clockwise - } - - g_object_unref(marker); - gtk_widget_queue_draw_area (GTK_WIDGET(map), - x-(mr+lw), - y-(mr+lw), - (mr*2)+lw+lw, - (mr*2)+lw+lw); -#endif } -} +} static void osm_gps_map_blit_tile(OsmGpsMap *map, GdkPixbuf *pixbuf, int offset_x, int offset_y) { OsmGpsMapPrivate *priv = map->priv; - g_debug("Queing redraw @ %d,%d (w:%d h:%d)", offset_x,offset_y, TILESIZE,TILESIZE); + if (priv->double_pixel) { + g_debug("Queing redraw @ %d,%d (w:%d h:%d)", offset_x,offset_y, TILESIZE*2,TILESIZE*2); + + GdkPixbuf *double_pixbuf = gdk_pixbuf_scale_simple (pixbuf, TILESIZE*2, TILESIZE*2, + GDK_INTERP_NEAREST); - /* draw pixbuf onto pixmap */ - gdk_draw_pixbuf (priv->pixmap, - priv->gc_map, - pixbuf, - 0,0, - offset_x,offset_y, - TILESIZE,TILESIZE, - GDK_RGB_DITHER_NONE, 0, 0); + /* draw pixbuf onto pixmap */ + gdk_draw_pixbuf (priv->pixmap, + priv->gc_map, + double_pixbuf, + 0,0, + offset_x,offset_y, + TILESIZE*2,TILESIZE*2, + GDK_RGB_DITHER_NONE, 0, 0); + g_object_unref (double_pixbuf); + } + else + { + g_debug("Queing redraw @ %d,%d (w:%d h:%d)", offset_x,offset_y, TILESIZE,TILESIZE); + + /* draw pixbuf onto pixmap */ + gdk_draw_pixbuf (priv->pixmap, + priv->gc_map, + pixbuf, + 0,0, + offset_x,offset_y, + TILESIZE,TILESIZE, + GDK_RGB_DITHER_NONE, 0, 0); + } } /* libsoup-2.2 and libsoup-2.4 use different ways to store the body data */ -#ifdef LIBSOUP22 +#if USE_LIBSOUP22 #define soup_message_headers_append(a,b,c) soup_message_add_header(a,b,c) #define MSG_RESPONSE_BODY(a) ((a)->response.body) #define MSG_RESPONSE_LEN(a) ((a)->response.length) @@ -710,7 +681,7 @@ #define MSG_RESPONSE_LEN_FORMAT "%lld" #endif -#ifdef LIBSOUP22 +#if USE_LIBSOUP22 static void osm_gps_map_tile_download_complete (SoupMessage *msg, gpointer user_data) #else @@ -826,7 +797,7 @@ } else { -#ifdef LIBSOUP22 +#if USE_LIBSOUP22 soup_session_requeue_message(dl->session, msg); #else soup_session_requeue_message(session, msg); @@ -848,7 +819,7 @@ //calculate the uri to download dl->uri = replace_map_uri(map, priv->repo_uri, zoom, x, y); -#ifdef LIBSOUP22 +#if USE_LIBSOUP22 dl->session = priv->soup_session; #endif @@ -892,7 +863,7 @@ } } -#ifdef LIBSOUP22 +#if USE_LIBSOUP22 soup_message_headers_append(msg->request_headers, "User-Agent", USER_AGENT); #endif @@ -938,6 +909,10 @@ tile->pixbuf = pixbuf; g_hash_table_insert (priv->tile_cache, filename, tile); } + else + { + g_free (filename); + } } /* set/update the redraw_cycle timestamp on the tile */ @@ -1005,12 +980,28 @@ return osm_gps_map_render_missing_tile_upscaled (map, zoom, x, y); } +/* default tile lifetime is one week */ +#ifndef OSD_GPS_MAP_TILE_TTL +#define OSD_GPS_MAP_TILE_TTL (60*60*24*7) +#endif + +static gboolean +osm_gps_map_tile_age_exceeded(char *filename) +{ + struct stat buf; + + if(!g_stat(filename, &buf)) + return(time(NULL) - buf.st_mtime > OSD_GPS_MAP_TILE_TTL); + + return FALSE; +} + static void osm_gps_map_load_tile (OsmGpsMap *map, int zoom, int x, int y, int offset_x, int offset_y) { OsmGpsMapPrivate *priv = map->priv; gchar *filename; - GdkPixbuf *pixbuf; + GdkPixbuf *pixbuf = NULL; g_debug("Load tile %d,%d (%d,%d) z:%d", x, y, offset_x, offset_y, zoom); @@ -1026,9 +1017,14 @@ y, priv->image_format); - /* try to get file from internal cache first */ - if(!(pixbuf = osm_gps_map_load_cached_tile(map, zoom, x, y))) - pixbuf = gdk_pixbuf_new_from_file (filename, NULL); + gboolean needs_refresh = FALSE; + if (g_file_test(filename, G_FILE_TEST_EXISTS)) { + /* try to get file from internal cache first */ + if(!(pixbuf = osm_gps_map_load_cached_tile(map, zoom, x, y))) + pixbuf = gdk_pixbuf_new_from_file (filename, NULL); + + needs_refresh = osm_gps_map_tile_age_exceeded(filename); + } if(pixbuf) { @@ -1036,31 +1032,29 @@ osm_gps_map_blit_tile(map, pixbuf, offset_x,offset_y); g_object_unref (pixbuf); } - else + + + if(!pixbuf || needs_refresh) { if (priv->map_auto_download) osm_gps_map_download_tile(map, zoom, x, y, TRUE); - /* try to render the tile by scaling cached tiles from other zoom - * levels */ - pixbuf = osm_gps_map_render_missing_tile (map, zoom, x, y); - if (pixbuf) - { - gdk_draw_pixbuf (priv->pixmap, - priv->gc_map, - pixbuf, - 0,0, - offset_x,offset_y, - TILESIZE,TILESIZE, - GDK_RGB_DITHER_NONE, 0, 0); - g_object_unref (pixbuf); - } - else - { - //prevent some artifacts when drawing not yet loaded areas. - gdk_draw_rectangle (priv->pixmap, - GTK_WIDGET(map)->style->white_gc, - TRUE, offset_x, offset_y, TILESIZE, TILESIZE); + if(!needs_refresh) { + /* try to render the tile by scaling cached tiles from other zoom + * levels */ + pixbuf = osm_gps_map_render_missing_tile (map, zoom, x, y); + if (pixbuf) + { + osm_gps_map_blit_tile (map, pixbuf, offset_x,offset_y); + g_object_unref (pixbuf); + } + else + { + //prevent some artifacts when drawing not yet loaded areas. + gdk_draw_rectangle (priv->pixmap, + GTK_WIDGET(map)->style->white_gc, + TRUE, offset_x, offset_y, TILESIZE, TILESIZE); + } } } g_free(filename); @@ -1078,47 +1072,94 @@ g_debug("Fill tiles: %d,%d z:%d", priv->map_x, priv->map_y, priv->map_zoom); - offset_x = - priv->map_x % TILESIZE; - offset_y = - priv->map_y % TILESIZE; - if (offset_x > 0) offset_x -= TILESIZE; - if (offset_y > 0) offset_y -= TILESIZE; + if (priv->double_pixel) + { + width = GTK_WIDGET(map)->allocation.width; + height = GTK_WIDGET(map)->allocation.height; - offset_xn = offset_x + EXTRA_BORDER; - offset_yn = offset_y + EXTRA_BORDER; + offset_x = - priv->map_x % (TILESIZE*2); + offset_y = - priv->map_y % (TILESIZE*2); + if (offset_x > 0) offset_x -= (TILESIZE*2); + if (offset_y > 0) offset_y -= (TILESIZE*2); - width = GTK_WIDGET(map)->allocation.width; - height = GTK_WIDGET(map)->allocation.height; + offset_xn = offset_x + EXTRA_BORDER; + offset_yn = offset_y + EXTRA_BORDER; - tiles_nx = (width - offset_x) / TILESIZE + 1; - tiles_ny = (height - offset_y) / TILESIZE + 1; + tiles_nx = (width - offset_x) / (TILESIZE*2) + 1; + tiles_ny = (height - offset_y) / (TILESIZE*2) + 1; - tile_x0 = floor((float)priv->map_x / (float)TILESIZE); - tile_y0 = floor((float)priv->map_y / (float)TILESIZE); + tile_x0 = floor((float)priv->map_x / (float)(TILESIZE*2)); + tile_y0 = floor((float)priv->map_y / (float)(TILESIZE*2)); - //TODO: implement wrap around - for (i=tile_x0; i<(tile_x0+tiles_nx);i++) - { - for (j=tile_y0; j<(tile_y0+tiles_ny); j++) + for (i=tile_x0; i<(tile_x0+tiles_nx);i++) { - if( j<0 || i<0 || i>=exp(priv->map_zoom * M_LN2) || j>=exp(priv->map_zoom * M_LN2)) + for (j=tile_y0; j<(tile_y0+tiles_ny); j++) { - gdk_draw_rectangle (priv->pixmap, - GTK_WIDGET(map)->style->white_gc, - TRUE, - offset_xn, offset_yn, - TILESIZE,TILESIZE); + if( j<0 || i<0 || i>=exp(priv->map_zoom * M_LN2) || j>=exp(priv->map_zoom * M_LN2)) + { + gdk_draw_rectangle (priv->pixmap, + GTK_WIDGET(map)->style->white_gc, + TRUE, + offset_xn, offset_yn, + TILESIZE*2, TILESIZE*2); + } + else + { + osm_gps_map_load_tile(map, + priv->map_zoom - 1, + i,j, + offset_xn,offset_yn); + } + offset_yn += TILESIZE*2; } - else + offset_xn += TILESIZE*2; + offset_yn = offset_y + EXTRA_BORDER; + } + } + else + { + offset_x = - priv->map_x % TILESIZE; + offset_y = - priv->map_y % TILESIZE; + if (offset_x > 0) offset_x -= TILESIZE; + if (offset_y > 0) offset_y -= TILESIZE; + + offset_xn = offset_x + EXTRA_BORDER; + offset_yn = offset_y + EXTRA_BORDER; + + width = GTK_WIDGET(map)->allocation.width; + height = GTK_WIDGET(map)->allocation.height; + + tiles_nx = (width - offset_x) / TILESIZE + 1; + tiles_ny = (height - offset_y) / TILESIZE + 1; + + tile_x0 = floor((float)priv->map_x / (float)TILESIZE); + tile_y0 = floor((float)priv->map_y / (float)TILESIZE); + + //TODO: implement wrap around + for (i=tile_x0; i<(tile_x0+tiles_nx);i++) + { + for (j=tile_y0; j<(tile_y0+tiles_ny); j++) { - osm_gps_map_load_tile(map, - priv->map_zoom, - i,j, - offset_xn,offset_yn); + if( j<0 || i<0 || i>=exp(priv->map_zoom * M_LN2) || j>=exp(priv->map_zoom * M_LN2)) + { + gdk_draw_rectangle (priv->pixmap, + GTK_WIDGET(map)->style->white_gc, + TRUE, + offset_xn, offset_yn, + TILESIZE,TILESIZE); + } + else + { + osm_gps_map_load_tile(map, + priv->map_zoom, + i,j, + offset_xn,offset_yn); + } + offset_yn += TILESIZE; } - offset_yn += TILESIZE; + offset_xn += TILESIZE; + offset_yn = offset_y + EXTRA_BORDER; } - offset_xn += TILESIZE; - offset_yn = offset_y + EXTRA_BORDER; } } @@ -1132,28 +1173,13 @@ int min_x = 0,min_y = 0,max_x = 0,max_y = 0; int lw = priv->ui_gps_track_width; int map_x0, map_y0; -#ifdef USE_CAIRO cairo_t *cr; -#else - int last_x = 0, last_y = 0; - GdkColor color; - GdkGC *gc; -#endif -#ifdef USE_CAIRO cr = gdk_cairo_create(priv->pixmap); cairo_set_line_width (cr, lw); cairo_set_source_rgba (cr, 60000.0/65535.0, 0.0, 0.0, 0.6); cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); -#else - gc = gdk_gc_new(priv->pixmap); - color.green = 0; - color.blue = 0; - color.red = 60000; - gdk_gc_set_rgb_fg_color(gc, &color); - gdk_gc_set_line_attributes(gc, lw, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND); -#endif map_x0 = priv->map_x - EXTRA_BORDER; map_y0 = priv->map_y - EXTRA_BORDER; @@ -1166,21 +1192,10 @@ // first time through loop if (list == trackpoint_list) { -#ifdef USE_CAIRO cairo_move_to(cr, x, y); -#else - last_x = x; - last_y = y; -#endif } -#ifdef USE_CAIRO cairo_line_to(cr, x, y); -#else - gdk_draw_line (priv->pixmap, gc, x, y, last_x, last_y); - last_x = x; - last_y = y; -#endif max_x = MAX(x,max_x); min_x = MIN(x,min_x); @@ -1195,12 +1210,8 @@ max_x + (lw * 2), max_y + (lw * 2)); -#ifdef USE_CAIRO cairo_stroke(cr); cairo_destroy(cr); -#else - g_object_unref(gc); -#endif } /* Prints the gps trip history, and any other tracks */ @@ -1318,8 +1329,10 @@ } static void -center_coord_update(GtkWidget *widget) { - OsmGpsMapPrivate *priv = OSM_GPS_MAP_PRIVATE(widget); +center_coord_update(OsmGpsMap *map) { + + GtkWidget *widget = GTK_WIDGET(map); + OsmGpsMapPrivate *priv = OSM_GPS_MAP_PRIVATE(map); // pixel_x,y, offsets gint pixel_x = priv->map_x + widget->allocation.width/2; @@ -1327,91 +1340,87 @@ priv->center_rlon = pixel2lon(priv->map_zoom, pixel_x); priv->center_rlat = pixel2lat(priv->map_zoom, pixel_y); + + g_signal_emit_by_name(widget, "changed"); } -#ifdef OSM_GPS_MAP_KEYS static gboolean -on_window_key_press(GtkWidget *widget, - GdkEventKey *event, OsmGpsMapPrivate *priv) { - gboolean handled = FALSE; - int step = GTK_WIDGET(widget)->allocation.width/OSM_GPS_MAP_SCROLL_STEP; - - // the map handles some keys on its own ... - switch(event->keyval) { -#ifdef OSM_GPS_MAP_KEY_FULLSCREEN - case OSM_GPS_MAP_KEY_FULLSCREEN: { - GtkWidget *toplevel = gtk_widget_get_toplevel(GTK_WIDGET(widget)); - if(!priv->fullscreen) - gtk_window_fullscreen(GTK_WINDOW(toplevel)); - else - gtk_window_unfullscreen(GTK_WINDOW(toplevel)); - - priv->fullscreen = !priv->fullscreen; - handled = TRUE; - } break; -#endif - -#ifdef OSM_GPS_MAP_KEY_ZOOMIN - case OSM_GPS_MAP_KEY_ZOOMIN: - osm_gps_map_set_zoom(OSM_GPS_MAP(widget), priv->map_zoom+1); - handled = TRUE; - break; -#endif - -#ifdef OSM_GPS_MAP_KEY_ZOOMOUT - case OSM_GPS_MAP_KEY_ZOOMOUT: - osm_gps_map_set_zoom(OSM_GPS_MAP(widget), priv->map_zoom-1); - handled = TRUE; - break; -#endif - -#ifdef OSM_GPS_MAP_KEY_UP - case OSM_GPS_MAP_KEY_UP: - priv->map_y -= step; - center_coord_update(widget); - osm_gps_map_map_redraw_idle(OSM_GPS_MAP(widget)); - handled = TRUE; - break; -#endif - -#ifdef OSM_GPS_MAP_KEY_DOWN - case OSM_GPS_MAP_KEY_DOWN: - priv->map_y += step; - center_coord_update(widget); - osm_gps_map_map_redraw_idle(OSM_GPS_MAP(widget)); - handled = TRUE; - break; -#endif - -#ifdef OSM_GPS_MAP_KEY_LEFT - case OSM_GPS_MAP_KEY_LEFT: - priv->map_x -= step; - center_coord_update(widget); - osm_gps_map_map_redraw_idle(OSM_GPS_MAP(widget)); - handled = TRUE; - break; -#endif - -#ifdef OSM_GPS_MAP_KEY_RIGHT - case OSM_GPS_MAP_KEY_RIGHT: - priv->map_x += step; - center_coord_update(widget); - osm_gps_map_map_redraw_idle(OSM_GPS_MAP(widget)); - handled = TRUE; - break; -#endif - - default: - break; - } +on_window_key_press(GtkWidget *widget, GdkEventKey *event, OsmGpsMapPrivate *priv) +{ + int i; + int step; + gboolean handled; + OsmGpsMap *map; + + //if no keybindings are set, let the app handle them... + if (!priv->keybindings_enabled) + return FALSE; + + handled = FALSE; + map = OSM_GPS_MAP(widget); + step = GTK_WIDGET(widget)->allocation.width/OSM_GPS_MAP_SCROLL_STEP; + + //the map handles some keys on its own + for (i = 0; i < OSM_GPS_MAP_KEY_MAX; i++) { + //not the key we have a binding for + if (map->priv->keybindings[i] != event->keyval) + continue; + + switch(i) { + case OSM_GPS_MAP_KEY_FULLSCREEN: { + GtkWidget *toplevel = gtk_widget_get_toplevel(GTK_WIDGET(widget)); + if(!priv->fullscreen) + gtk_window_fullscreen(GTK_WINDOW(toplevel)); + else + gtk_window_unfullscreen(GTK_WINDOW(toplevel)); + + priv->fullscreen = !priv->fullscreen; + handled = TRUE; + } break; + case OSM_GPS_MAP_KEY_ZOOMIN: + osm_gps_map_zoom_in(map); + handled = TRUE; + break; + case OSM_GPS_MAP_KEY_ZOOMOUT: + osm_gps_map_zoom_out(map); + handled = TRUE; + break; + case OSM_GPS_MAP_KEY_UP: + priv->map_y -= step; + center_coord_update(map); + osm_gps_map_map_redraw_idle(map); + handled = TRUE; + break; + case OSM_GPS_MAP_KEY_DOWN: + priv->map_y += step; + center_coord_update(map); + osm_gps_map_map_redraw_idle(map); + handled = TRUE; + break; + case OSM_GPS_MAP_KEY_LEFT: + priv->map_x -= step; + center_coord_update(map); + osm_gps_map_map_redraw_idle(map); + handled = TRUE; + break; + case OSM_GPS_MAP_KEY_RIGHT: + priv->map_x += step; + center_coord_update(map); + osm_gps_map_map_redraw_idle(OSM_GPS_MAP(widget)); + handled = TRUE; + break; + default: + break; + } + } - return handled; + return handled; } -#endif static void osm_gps_map_init (OsmGpsMap *object) { + int i; OsmGpsMapPrivate *priv; priv = G_TYPE_INSTANCE_GET_PRIVATE (object, OSM_TYPE_GPS_MAP, OsmGpsMapPrivate); @@ -1427,11 +1436,6 @@ #ifdef ENABLE_OSD priv->osd = NULL; #endif - -#ifdef OSM_GPS_MAP_BUTTON_FULLSCREEN - priv->fullscreen = FALSE; -#endif - priv->tracks = NULL; priv->images = NULL; @@ -1446,15 +1450,21 @@ priv->map_source = -1; -#ifndef LIBSOUP22 - //Change naumber of concurrent connections option? - priv->soup_session = - soup_session_async_new_with_options(SOUP_SESSION_USER_AGENT, - USER_AGENT, NULL); -#else + priv->keybindings_enabled = FALSE; + for (i = 0; i < OSM_GPS_MAP_KEY_MAX; i++) + priv->keybindings[i] = 0; + + +#if USE_LIBSOUP22 /* libsoup-2.2 has no special way to set the user agent, so we */ /* set it seperately as an extra header field for each reuest */ priv->soup_session = soup_session_async_new(); +#else + /* set the user agent */ + priv->soup_session = + soup_session_async_new_with_options(SOUP_SESSION_USER_AGENT, + USER_AGENT, NULL); + #endif //Hash table which maps tile d/l URIs to SoupMessage requests priv->tile_queue = g_hash_table_new (g_str_hash, g_str_equal); @@ -1476,17 +1486,36 @@ g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_MASK, my_log_handler, NULL); -#ifdef OSM_GPS_MAP_KEYS + //Setup signal handlers g_signal_connect(G_OBJECT(object), "key_press_event", - G_CALLBACK(on_window_key_press), priv); -#endif + G_CALLBACK(on_window_key_press), priv); } +static char* +osm_gps_map_get_cache_dir(OsmGpsMapPrivate *priv) +{ + if (priv->tile_base_dir) + return g_strdup(priv->tile_base_dir); + return osm_gps_map_get_default_cache_directory(); +} + +/* strcmp0 was introduced with glib 2.16 */ +#if ! GLIB_CHECK_VERSION (2, 16, 0) +int g_strcmp0(const char *str1, const char *str2) +{ + if( str1 == NULL && str2 == NULL ) return 0; + if( str1 == NULL ) return -1; + if( str2 == NULL ) return 1; + return strcmp(str1, str2); +} +#endif + static void -osm_gps_map_setup(OsmGpsMapPrivate *priv) { +osm_gps_map_setup(OsmGpsMapPrivate *priv) +{ const char *uri; - //user can specify a map source ID, or a repo URI as the map source + //user can specify a map source ID, or a repo URI as the map source uri = osm_gps_map_source_get_repo_uri(OSM_GPS_MAP_SOURCE_NULL); if ( (priv->map_source == 0) || (strcmp(priv->repo_uri, uri) == 0) ) { g_debug("Using null source"); @@ -1510,14 +1539,30 @@ } } - const char *fname = osm_gps_map_source_get_friendly_name(priv->map_source); - if(!fname) fname = "_unknown_"; + if (priv->tile_dir == NULL) + priv->tile_dir = g_strdup(OSM_GPS_MAP_CACHE_DISABLED); - if (priv->tile_dir) { - //the new cachedir is the given cache dir + the friendly name of the repo_uri - priv->cache_dir = g_strdup_printf("%s%c%s", priv->tile_dir, G_DIR_SEPARATOR, fname); - g_debug("Adjusting cache dir %s -> %s", priv->tile_dir, priv->cache_dir); + if ( g_strcmp0(priv->tile_dir, OSM_GPS_MAP_CACHE_DISABLED) == 0 ) { + priv->cache_dir = NULL; + } else if ( g_strcmp0(priv->tile_dir, OSM_GPS_MAP_CACHE_AUTO) == 0 ) { + char *base = osm_gps_map_get_cache_dir(priv); +#if GLIB_CHECK_VERSION (2, 16, 0) + char *md5 = g_compute_checksum_for_string (G_CHECKSUM_MD5, priv->repo_uri, -1); +#else + char *md5 = g_strdup(osm_gps_map_source_get_friendly_name(priv->map_source)); +#endif + priv->cache_dir = g_strdup_printf("%s%c%s", base, G_DIR_SEPARATOR, md5); + g_free(base); + g_free(md5); + } else if ( g_strcmp0(priv->tile_dir, OSM_GPS_MAP_CACHE_FRIENDLY) == 0 ) { + char *base = osm_gps_map_get_cache_dir(priv); + const char *fname = osm_gps_map_source_get_friendly_name(priv->map_source); + priv->cache_dir = g_strdup_printf("%s%c%s", base, G_DIR_SEPARATOR, fname); + g_free(base); + } else { + priv->cache_dir = g_strdup(priv->tile_dir); } + g_debug("Cache dir: %s", priv->cache_dir); } static GObject * @@ -1552,6 +1597,7 @@ g_hash_table_destroy(priv->missing_tiles); g_hash_table_destroy(priv->tile_cache); + /* images and layers contain GObjects which need unreffing, so free here */ osm_gps_map_free_images(map); if(priv->pixmap) @@ -1572,8 +1618,10 @@ g_free(priv->gps); #ifdef ENABLE_OSD - if(priv->osd) + if(priv->osd) { priv->osd->free(priv->osd); + priv->osd = NULL; + } #ifdef OSD_DOUBLE_BUFFER if(priv->dbuf_pixmap) @@ -1590,15 +1638,16 @@ OsmGpsMap *map = OSM_GPS_MAP(object); OsmGpsMapPrivate *priv = map->priv; - if(priv->tile_dir) + if (priv->tile_dir) g_free(priv->tile_dir); - if(priv->cache_dir) + if (priv->cache_dir) g_free(priv->cache_dir); g_free(priv->repo_uri); g_free(priv->image_format); + /* trip and tracks contain simple non GObject types, so free them here */ osm_gps_map_free_trip(map); osm_gps_map_free_tracks(map); @@ -1617,6 +1666,10 @@ case PROP_AUTO_CENTER: priv->map_auto_center = g_value_get_boolean (value); break; + case PROP_DOUBLE_PIXEL: + priv->double_pixel = g_value_get_boolean (value); + osm_gps_map_map_redraw_idle(map); + break; case PROP_RECORD_TRIP_HISTORY: priv->record_trip_history = g_value_get_boolean (value); break; @@ -1634,26 +1687,29 @@ priv->proxy_uri = g_value_dup_string (value); g_debug("Setting proxy server: %s", priv->proxy_uri); -#ifndef LIBSOUP22 +#if USE_LIBSOUP22 + SoupUri* uri = soup_uri_new(priv->proxy_uri); + g_object_set(G_OBJECT(priv->soup_session), SOUP_SESSION_PROXY_URI, uri, NULL); +#else GValue val = {0}; - SoupURI* uri = soup_uri_new(priv->proxy_uri); g_value_init(&val, SOUP_TYPE_URI); g_value_take_boxed(&val, uri); - g_object_set_property(G_OBJECT(priv->soup_session),SOUP_SESSION_PROXY_URI,&val); -#else - SoupUri* uri = soup_uri_new(priv->proxy_uri); - g_object_set(G_OBJECT(priv->soup_session), SOUP_SESSION_PROXY_URI, uri, NULL); #endif } else priv->proxy_uri = NULL; break; case PROP_TILE_CACHE_DIR: - if ( g_value_get_string(value) ) - priv->tile_dir = g_value_dup_string (value); + priv->tile_dir = g_value_dup_string (value); + break; + case PROP_TILE_CACHE_BASE_DIR: + priv->tile_base_dir = g_value_dup_string (value); break; + case PROP_TILE_CACHE_DIR_IS_FULL_PATH: + g_warning("GObject property tile-cache-is-full-path depreciated"); + break; case PROP_ZOOM: priv->map_zoom = g_value_get_int (value); break; @@ -1665,11 +1721,11 @@ break; case PROP_MAP_X: priv->map_x = g_value_get_int (value); - center_coord_update(GTK_WIDGET(object)); + center_coord_update(map); break; case PROP_MAP_Y: priv->map_y = g_value_get_int (value); - center_coord_update(GTK_WIDGET(object)); + center_coord_update(map); break; case PROP_GPS_TRACK_WIDTH: priv->ui_gps_track_width = g_value_get_int (value); @@ -1708,6 +1764,9 @@ case PROP_IMAGE_FORMAT: priv->image_format = g_value_dup_string (value); break; + case PROP_DRAG_LIMIT: + priv->drag_limit = g_value_get_int (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1718,12 +1777,14 @@ osm_gps_map_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { g_return_if_fail (OSM_IS_GPS_MAP (object)); - float lat,lon; OsmGpsMap *map = OSM_GPS_MAP(object); OsmGpsMapPrivate *priv = map->priv; switch (prop_id) { + case PROP_DOUBLE_PIXEL: + g_value_set_boolean(value, priv->double_pixel); + break; case PROP_AUTO_CENTER: g_value_set_boolean(value, priv->map_auto_center); break; @@ -1745,6 +1806,12 @@ case PROP_TILE_CACHE_DIR: g_value_set_string(value, priv->cache_dir); break; + case PROP_TILE_CACHE_BASE_DIR: + g_value_set_string(value, priv->tile_base_dir); + break; + case PROP_TILE_CACHE_DIR_IS_FULL_PATH: + g_value_set_boolean(value, FALSE); + break; case PROP_ZOOM: g_value_set_int(value, priv->map_zoom); break; @@ -1755,14 +1822,10 @@ g_value_set_int(value, priv->min_zoom); break; case PROP_LATITUDE: - lat = pixel2lat(priv->map_zoom, - priv->map_y + (GTK_WIDGET(map)->allocation.height / 2)); - g_value_set_float(value, rad2deg(lat)); + g_value_set_float(value, rad2deg(priv->center_rlat)); break; case PROP_LONGITUDE: - lon = pixel2lon(priv->map_zoom, - priv->map_x + (GTK_WIDGET(map)->allocation.width / 2)); - g_value_set_float(value, rad2deg(lon)); + g_value_set_float(value, rad2deg(priv->center_rlon)); break; case PROP_MAP_X: g_value_set_int(value, priv->map_x); @@ -1788,6 +1851,9 @@ case PROP_IMAGE_FORMAT: g_value_set_string(value, priv->image_format); break; + case PROP_DRAG_LIMIT: + g_value_set_int(value, priv->drag_limit); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1798,16 +1864,11 @@ osm_gps_map_scroll_event (GtkWidget *widget, GdkEventScroll *event) { OsmGpsMap *map = OSM_GPS_MAP(widget); - OsmGpsMapPrivate *priv = map->priv; if (event->direction == GDK_SCROLL_UP) - { - osm_gps_map_set_zoom(map, priv->map_zoom+1); - } - else - { - osm_gps_map_set_zoom(map, priv->map_zoom-1); - } + osm_gps_map_zoom_in(map); + else if (event->direction == GDK_SCROLL_DOWN) + osm_gps_map_zoom_out(map); return FALSE; } @@ -1815,7 +1876,8 @@ static gboolean osm_gps_map_button_press (GtkWidget *widget, GdkEventButton *event) { - OsmGpsMapPrivate *priv = OSM_GPS_MAP_PRIVATE(widget); + OsmGpsMap *map = OSM_GPS_MAP(widget); + OsmGpsMapPrivate *priv = map->priv; #ifdef ENABLE_OSD /* pressed inside OSD control? */ @@ -1832,28 +1894,28 @@ switch(but) { case OSD_UP: priv->map_y -= step; - center_coord_update(widget); + center_coord_update(map); g_object_set(G_OBJECT(widget), "auto-center", FALSE, NULL); osm_gps_map_map_redraw_idle(OSM_GPS_MAP(widget)); break; case OSD_DOWN: priv->map_y += step; - center_coord_update(widget); + center_coord_update(map); g_object_set(G_OBJECT(widget), "auto-center", FALSE, NULL); osm_gps_map_map_redraw_idle(OSM_GPS_MAP(widget)); break; case OSD_LEFT: priv->map_x -= step; - center_coord_update(widget); + center_coord_update(map); g_object_set(G_OBJECT(widget), "auto-center", FALSE, NULL); osm_gps_map_map_redraw_idle(OSM_GPS_MAP(widget)); break; case OSD_RIGHT: priv->map_x += step; - center_coord_update(widget); + center_coord_update(map); g_object_set(G_OBJECT(widget), "auto-center", FALSE, NULL); osm_gps_map_map_redraw_idle(OSM_GPS_MAP(widget)); break; @@ -1878,6 +1940,7 @@ } #endif + priv->button_down = TRUE; priv->drag_counter = 0; priv->drag_start_mouse_x = (int) event->x; priv->drag_start_mouse_y = (int) event->y; @@ -1890,8 +1953,12 @@ static gboolean osm_gps_map_button_release (GtkWidget *widget, GdkEventButton *event) { + OsmGpsMap *map = OSM_GPS_MAP(widget); OsmGpsMapPrivate *priv = OSM_GPS_MAP_PRIVATE(widget); + if(!priv->button_down) + return FALSE; + if (priv->dragging) { priv->dragging = FALSE; @@ -1902,9 +1969,9 @@ priv->map_x += (priv->drag_start_mouse_x - (int) event->x); priv->map_y += (priv->drag_start_mouse_y - (int) event->y); - center_coord_update(widget); + center_coord_update(map); - osm_gps_map_map_redraw_idle(OSM_GPS_MAP(widget)); + osm_gps_map_map_redraw_idle(map); } #ifdef ENABLE_OSD /* pressed inside OSD control? */ @@ -1917,6 +1984,7 @@ #endif priv->drag_counter = -1; + priv->button_down = 0; return FALSE; } @@ -1941,6 +2009,9 @@ GdkModifierType state; OsmGpsMapPrivate *priv = OSM_GPS_MAP_PRIVATE(widget); + if(!priv->button_down) + return FALSE; + if (event->is_hint) gdk_window_get_pointer (event->window, &x, &y, &state); else @@ -1961,7 +2032,7 @@ if(!priv->drag_counter && ( (x - priv->drag_start_mouse_x) * (x - priv->drag_start_mouse_x) + (y - priv->drag_start_mouse_y) * (y - priv->drag_start_mouse_y) < - 10*10)) + priv->drag_limit*priv->drag_limit)) return FALSE; priv->drag_counter++; @@ -2030,15 +2101,18 @@ osm_gps_map_map_redraw(OSM_GPS_MAP(widget)); + g_signal_emit_by_name(widget, "changed"); + return FALSE; } static gboolean osm_gps_map_expose (GtkWidget *widget, GdkEventExpose *event) { - OsmGpsMapPrivate *priv = OSM_GPS_MAP_PRIVATE(widget); + OsmGpsMap *map = OSM_GPS_MAP(widget); + OsmGpsMapPrivate *priv = map->priv; -#if defined(ENABLE_OSD) && defined(OSD_DOUBLE_BUFFER) +#ifdef OSD_DOUBLE_BUFFER GdkDrawable *drawable = priv->dbuf_pixmap; #else GdkDrawable *drawable = widget->window; @@ -2155,6 +2229,15 @@ widget_class->scroll_event = osm_gps_map_scroll_event; g_object_class_install_property (object_class, + PROP_DOUBLE_PIXEL, + g_param_spec_boolean ("double-pixel", + "double pixel", + "double map pixels for better readability", + FALSE, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)); + + + g_object_class_install_property (object_class, PROP_AUTO_CENTER, g_param_spec_boolean ("auto-center", "auto center", @@ -2207,14 +2290,30 @@ g_param_spec_string ("tile-cache", "tile cache", "osm local tile cache dir", + OSM_GPS_MAP_CACHE_AUTO, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property (object_class, + PROP_TILE_CACHE_BASE_DIR, + g_param_spec_string ("tile-cache-base", + "tile cache-base", + "base directory to which friendly and auto paths are appended", NULL, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, + PROP_TILE_CACHE_DIR_IS_FULL_PATH, + g_param_spec_boolean ("tile-cache-is-full-path", + "tile cache is full path", + "DEPRECIATED", + FALSE, + G_PARAM_READABLE | G_PARAM_WRITABLE)); + g_object_class_install_property (object_class, PROP_ZOOM, g_param_spec_int ("zoom", "zoom", - "zoom level", + "initial zoom level", MIN_ZOOM, /* minimum property value */ MAX_ZOOM, /* maximum property value */ 3, @@ -2307,7 +2406,7 @@ "radius of the gps point inner circle", 0, /* minimum property value */ G_MAXINT, /* maximum property value */ - 10, + 5, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, @@ -2325,7 +2424,7 @@ g_param_spec_int ("map-source", "map source", "map source ID", - -1, /* minimum property value */ + -1, /* minimum property value */ G_MAXINT, /* maximum property value */ -1, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)); @@ -2337,6 +2436,20 @@ "map source tile repository image format (jpg, png)", OSM_IMAGE_FORMAT, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property (object_class, + PROP_DRAG_LIMIT, + g_param_spec_int ("drag-limit", + "drag limit", + "the number of pixels the user has to move the pointer in order to start dragging", + 0, /* minimum property value */ + G_MAXINT, /* maximum property value */ + 10, + G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + + g_signal_new ("changed", OSM_TYPE_GPS_MAP, + G_SIGNAL_RUN_FIRST, 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } const char* @@ -2350,8 +2463,12 @@ return "OpenStreetMap I"; case OSM_GPS_MAP_SOURCE_OPENSTREETMAP_RENDERER: return "OpenStreetMap II"; + case OSM_GPS_MAP_SOURCE_OPENAERIALMAP: + return "OpenAerialMap"; case OSM_GPS_MAP_SOURCE_OPENCYCLEMAP: return "OpenCycleMap"; + case OSM_GPS_MAP_SOURCE_OSM_PUBLIC_TRANSPORT: + return "Public Transport"; case OSM_GPS_MAP_SOURCE_OSMC_TRAILS: return "OSMC Trails"; case OSM_GPS_MAP_SOURCE_MAPS_FOR_FREE: @@ -2374,6 +2491,7 @@ return "Yahoo Satellite"; case OSM_GPS_MAP_SOURCE_YAHOO_HYBRID: return "Yahoo Hybrid"; + case OSM_GPS_MAP_SOURCE_LAST: default: return NULL; } @@ -2393,20 +2511,28 @@ return "none://"; case OSM_GPS_MAP_SOURCE_OPENSTREETMAP: return OSM_REPO_URI; + case OSM_GPS_MAP_SOURCE_OPENAERIALMAP: + /* OpenAerialMap is down, offline till furthur notice + http://openaerialmap.org/pipermail/talk_openaerialmap.org/2008-December/000055.html */ + return NULL; case OSM_GPS_MAP_SOURCE_OPENSTREETMAP_RENDERER: return "http://tah.openstreetmap.org/Tiles/tile/#Z/#X/#Y.png"; case OSM_GPS_MAP_SOURCE_OPENCYCLEMAP: return "http://c.andy.sandbox.cloudmade.com/tiles/cycle/#Z/#X/#Y.png"; + case OSM_GPS_MAP_SOURCE_OSM_PUBLIC_TRANSPORT: + return "http://tile.xn--pnvkarte-m4a.de/tilegen/#Z/#X/#Y.png"; case OSM_GPS_MAP_SOURCE_OSMC_TRAILS: return "http://topo.geofabrik.de/trails/#Z/#X/#Y.png"; case OSM_GPS_MAP_SOURCE_MAPS_FOR_FREE: return "http://maps-for-free.com/layer/relief/z#Z/row#Y/#Z_#X-#Y.jpg"; case OSM_GPS_MAP_SOURCE_GOOGLE_STREET: return "http://mt#R.google.com/vt/v=w2.97&x=#X&y=#Y&z=#Z"; - case OSM_GPS_MAP_SOURCE_GOOGLE_SATELLITE: - return "http://khm#R.google.com/kh?n=404&v=3&t=#Q"; case OSM_GPS_MAP_SOURCE_GOOGLE_HYBRID: - return NULL; /* No longer working "http://mt#R.google.com/mt?n=404&v=w2t.99&x=#X&y=#Y&zoom=#S" */ + /* No longer working + "http://mt#R.google.com/mt?n=404&v=w2t.99&x=#X&y=#Y&zoom=#S" */ + return NULL; + case OSM_GPS_MAP_SOURCE_GOOGLE_SATELLITE: + return "http://khm#R.google.com/kh/v=51&x=#X&y=#Y&z=#Z"; case OSM_GPS_MAP_SOURCE_VIRTUAL_EARTH_STREET: return "http://a#R.ortho.tiles.virtualearth.net/tiles/r#W.jpeg?g=50"; case OSM_GPS_MAP_SOURCE_VIRTUAL_EARTH_SATELLITE: @@ -2423,6 +2549,7 @@ * z = zoom - (MAX_ZOOM - 17)); */ return NULL; + case OSM_GPS_MAP_SOURCE_LAST: default: return NULL; } @@ -2437,11 +2564,11 @@ case OSM_GPS_MAP_SOURCE_OPENSTREETMAP: case OSM_GPS_MAP_SOURCE_OPENSTREETMAP_RENDERER: case OSM_GPS_MAP_SOURCE_OPENCYCLEMAP: + case OSM_GPS_MAP_SOURCE_OSM_PUBLIC_TRANSPORT: case OSM_GPS_MAP_SOURCE_OSMC_TRAILS: return "png"; - case OSM_GPS_MAP_SOURCE_MAPS_FOR_FREE: + case OSM_GPS_MAP_SOURCE_OPENAERIALMAP: case OSM_GPS_MAP_SOURCE_GOOGLE_STREET: - case OSM_GPS_MAP_SOURCE_GOOGLE_SATELLITE: case OSM_GPS_MAP_SOURCE_GOOGLE_HYBRID: case OSM_GPS_MAP_SOURCE_VIRTUAL_EARTH_STREET: case OSM_GPS_MAP_SOURCE_VIRTUAL_EARTH_SATELLITE: @@ -2449,7 +2576,10 @@ case OSM_GPS_MAP_SOURCE_YAHOO_STREET: case OSM_GPS_MAP_SOURCE_YAHOO_SATELLITE: case OSM_GPS_MAP_SOURCE_YAHOO_HYBRID: + case OSM_GPS_MAP_SOURCE_MAPS_FOR_FREE: + case OSM_GPS_MAP_SOURCE_GOOGLE_SATELLITE: return "jpg"; + case OSM_GPS_MAP_SOURCE_LAST: default: return "bin"; } @@ -2471,8 +2601,10 @@ return 18; case OSM_GPS_MAP_SOURCE_OPENSTREETMAP: case OSM_GPS_MAP_SOURCE_OPENCYCLEMAP: + case OSM_GPS_MAP_SOURCE_OSM_PUBLIC_TRANSPORT: return OSM_MAX_ZOOM; case OSM_GPS_MAP_SOURCE_OPENSTREETMAP_RENDERER: + case OSM_GPS_MAP_SOURCE_OPENAERIALMAP: case OSM_GPS_MAP_SOURCE_GOOGLE_STREET: case OSM_GPS_MAP_SOURCE_GOOGLE_HYBRID: case OSM_GPS_MAP_SOURCE_VIRTUAL_EARTH_STREET: @@ -2488,12 +2620,19 @@ return 11; case OSM_GPS_MAP_SOURCE_GOOGLE_SATELLITE: return 18; + case OSM_GPS_MAP_SOURCE_LAST: default: return 17; } return 17; } +gboolean +osm_gps_map_source_is_valid(OsmGpsMapSource_t source) +{ + return osm_gps_map_source_get_repo_uri(source) != NULL; +} + void osm_gps_map_download_maps (OsmGpsMap *map, coord_t *pt1, coord_t *pt2, int zoom_start, int zoom_end) { @@ -2530,11 +2669,14 @@ i, G_DIR_SEPARATOR, j, priv->image_format); - if (!g_file_test(filename, G_FILE_TEST_EXISTS)) + + if ((!g_file_test(filename, G_FILE_TEST_EXISTS)) || + osm_gps_map_tile_age_exceeded(filename)) { osm_gps_map_download_tile(map, zoom, i, j, FALSE); num_tiles++; - } + } + g_free(filename); } } @@ -2574,6 +2716,8 @@ g_return_if_fail (OSM_IS_GPS_MAP (map)); priv = map->priv; + g_object_set(G_OBJECT(map), "auto-center", FALSE, NULL); + priv->center_rlat = deg2rad(latitude); priv->center_rlon = deg2rad(longitude); @@ -2585,6 +2729,8 @@ priv->map_y = pixel_y - GTK_WIDGET(map)->allocation.height/2; osm_gps_map_map_redraw_idle(map); + + g_signal_emit_by_name(map, "changed"); } int @@ -2610,9 +2756,13 @@ priv->map_x = lon2pixel(priv->map_zoom, priv->center_rlon) - width_center; priv->map_y = lat2pixel(priv->map_zoom, priv->center_rlat) - height_center; + factor = pow(2, priv->map_zoom-zoom_old); g_debug("Zoom changed from %d to %d factor:%f x:%d", zoom_old, priv->map_zoom, factor, priv->map_x); + /* adjust gps precision indicator */ + priv->ui_gps_point_outer_radius *= factor; + #ifdef ENABLE_OSD /* OSD may contain a scale, so we may have to re-render it */ if(priv->osd && OSM_IS_GPS_MAP (priv->osd->widget)) @@ -2620,10 +2770,26 @@ #endif osm_gps_map_map_redraw_idle(map); + + g_signal_emit_by_name(map, "changed"); } return priv->map_zoom; } +int +osm_gps_map_zoom_in (OsmGpsMap *map) +{ + g_return_val_if_fail (OSM_IS_GPS_MAP (map), 0); + return osm_gps_map_set_zoom(map, map->priv->map_zoom+1); +} + +int +osm_gps_map_zoom_out (OsmGpsMap *map) +{ + g_return_val_if_fail (OSM_IS_GPS_MAP (map), 0); + return osm_gps_map_set_zoom(map, map->priv->map_zoom-1); +} + void osm_gps_map_add_track (OsmGpsMap *map, GSList *track) { @@ -2639,6 +2805,29 @@ } void +osm_gps_map_replace_track (OsmGpsMap *map, GSList *old_track, GSList *new_track) +{ + OsmGpsMapPrivate *priv; + + if(!old_track) { + osm_gps_map_add_track (map, new_track); + return; + } + + g_return_if_fail (OSM_IS_GPS_MAP (map)); + priv = map->priv; + + GSList *old = g_slist_find(priv->tracks, old_track); + if(!old) { + g_warning("track to be replaced not found"); + return; + } + + old->data = new_track; + osm_gps_map_map_redraw_idle(map); +} + +void osm_gps_map_clear_tracks (OsmGpsMap *map) { g_return_if_fail (OSM_IS_GPS_MAP (map)); @@ -2648,7 +2837,7 @@ } void -osm_gps_map_add_image (OsmGpsMap *map, float latitude, float longitude, GdkPixbuf *image) +osm_gps_map_add_image_with_alignment (OsmGpsMap *map, float latitude, float longitude, GdkPixbuf *image, float xalign, float yalign) { g_return_if_fail (OSM_IS_GPS_MAP (map)); @@ -2663,6 +2852,10 @@ im->pt.rlat = deg2rad(latitude); im->pt.rlon = deg2rad(longitude); + //handle alignment + im->xoffset = xalign * im->w; + im->yoffset = yalign * im->h; + g_object_ref(image); im->image = image; @@ -2672,6 +2865,12 @@ } } +void +osm_gps_map_add_image (OsmGpsMap *map, float latitude, float longitude, GdkPixbuf *image) +{ + osm_gps_map_add_image_with_alignment (map, latitude, longitude, image, 0.5, 0.5); +} + gboolean osm_gps_map_remove_image (OsmGpsMap *map, GdkPixbuf *image) { @@ -2746,7 +2945,7 @@ priv->map_x = pixel_x - GTK_WIDGET(map)->allocation.width/2; priv->map_y = pixel_y - GTK_WIDGET(map)->allocation.height/2; - center_coord_update(GTK_WIDGET(map)); + center_coord_update(map); } } @@ -2805,10 +3004,10 @@ priv = map->priv; if (pixel_x) - *pixel_x = lon2pixel(priv->map_zoom, deg2rad(longitude)) - + *pixel_x = lon2pixel(priv->map_zoom, deg2rad(longitude)) - priv->map_x + priv->drag_mouse_dx; if (pixel_y) - *pixel_y = lat2pixel(priv->map_zoom, deg2rad(latitude)) - + *pixel_y = lat2pixel(priv->map_zoom, deg2rad(latitude)) - priv->map_y + priv->drag_mouse_dy; } @@ -2822,7 +3021,7 @@ priv->map_x += dx; priv->map_y += dy; - center_coord_update(GTK_WIDGET(map)); + center_coord_update(map); #ifdef ENABLE_OSD /* OSD may contain a coordinate, so we may have to re-render it */ @@ -2844,6 +3043,23 @@ return osm_gps_map_get_scale_at_point(priv->map_zoom, priv->center_rlat, priv->center_rlon); } +char * osm_gps_map_get_default_cache_directory(void) +{ + return g_build_filename( + g_get_user_cache_dir(), + "osmgpsmap", + NULL); +} + +void osm_gps_map_set_keyboard_shortcut(OsmGpsMap *map, OsmGpsMapKey_t key, guint keyval) +{ + g_return_if_fail (OSM_IS_GPS_MAP (map)); + g_return_if_fail(key < OSM_GPS_MAP_KEY_MAX); + + map->priv->keybindings[key] = keyval; + map->priv->keybindings_enabled = TRUE; +} + #ifdef ENABLE_OSD void