Diff of /trunk/src/osm-gps-map.c

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

revision 60 by harbaum, Mon Aug 17 19:44:00 2009 UTC revision 238 by harbaum, Sat Dec 12 12:54:37 2009 UTC
# Line 49  Line 49 
49    
50  #define EXTRA_BORDER (TILESIZE / 2)  #define EXTRA_BORDER (TILESIZE / 2)
51    
52    #define OSM_GPS_MAP_SCROLL_STEP 10
53    
54    /* any defined key enables key support */
55    #if (defined(OSM_GPS_MAP_KEY_FULLSCREEN) || \
56         defined(OSM_GPS_MAP_KEY_ZOOMIN) || \
57         defined(OSM_GPS_MAP_KEY_ZOOMOUT) || \
58         defined(OSM_GPS_MAP_KEY_UP) || \
59         defined(OSM_GPS_MAP_KEY_DOWN) || \
60         defined(OSM_GPS_MAP_KEY_LEFT) || \
61         defined(OSM_GPS_MAP_KEY_RIGHT))
62    #define OSM_GPS_MAP_KEYS
63    #endif
64    
65    #ifdef OSM_GPS_MAP_KEYS
66    #include <gdk/gdkkeysyms.h>
67    #endif
68    
69    #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"
70    
71  struct _OsmGpsMapPrivate  struct _OsmGpsMapPrivate
72  {  {
73      GHashTable *tile_queue;      GHashTable *tile_queue;
# Line 78  struct _OsmGpsMapPrivate Line 97  struct _OsmGpsMapPrivate
97      char *proxy_uri;      char *proxy_uri;
98    
99      //where downloaded tiles are cached      //where downloaded tiles are cached
100        char *tile_dir;
101      char *cache_dir;      char *cache_dir;
     gboolean cache_dir_is_full_path;  
102    
103      //contains flags indicating the various special characters      //contains flags indicating the various special characters
104      //the uri string contains, that will be replaced when calculating      //the uri string contains, that will be replaced when calculating
# Line 96  struct _OsmGpsMapPrivate Line 115  struct _OsmGpsMapPrivate
115      gboolean show_trip_history;      gboolean show_trip_history;
116      GSList *trip_history;      GSList *trip_history;
117      coord_t *gps;      coord_t *gps;
118        float gps_heading;
119      gboolean gps_valid;      gboolean gps_valid;
120    
121      //a balloon with additional info  #ifdef ENABLE_OSD
122      struct {      //the osd controls (if present)
123          coord_t *coo;      osm_gps_map_osd_t *osd;
124          gboolean valid;  #ifdef OSD_DOUBLE_BUFFER
125          OsmGpsMapRect_t rect;      GdkPixmap *dbuf_pixmap;
126          OsmGpsMapBalloonCallback cb;  #endif
127          gpointer data;  #endif
     } balloon;  
128    
129    #ifdef OSM_GPS_MAP_KEY_FULLSCREEN
130        gboolean fullscreen;
131    #endif
132    
133      //additional images or tracks added to the map      //additional images or tracks added to the map
134      GSList *tracks;      GSList *tracks;
135      GSList *images;      GSList *images;
# Line 126  struct _OsmGpsMapPrivate Line 149  struct _OsmGpsMapPrivate
149      int drag_start_mouse_y;      int drag_start_mouse_y;
150      int drag_start_map_x;      int drag_start_map_x;
151      int drag_start_map_y;      int drag_start_map_y;
152        guint drag_expose;
153    
154      //for customizing the redering of the gps track      //for customizing the redering of the gps track
155      int ui_gps_track_width;      int ui_gps_track_width;
# Line 134  struct _OsmGpsMapPrivate Line 158  struct _OsmGpsMapPrivate
158    
159      guint is_disposed : 1;      guint is_disposed : 1;
160      guint dragging : 1;      guint dragging : 1;
     guint center_coord_set : 1;  
161  };  };
162    
163  #define OSM_GPS_MAP_PRIVATE(o)  (OSM_GPS_MAP (o)->priv)  #define OSM_GPS_MAP_PRIVATE(o)  (OSM_GPS_MAP (o)->priv)
# Line 158  enum Line 181  enum
181      PROP_REPO_URI,      PROP_REPO_URI,
182      PROP_PROXY_URI,      PROP_PROXY_URI,
183      PROP_TILE_CACHE_DIR,      PROP_TILE_CACHE_DIR,
     PROP_TILE_CACHE_DIR_IS_FULL_PATH,  
184      PROP_ZOOM,      PROP_ZOOM,
185      PROP_MAX_ZOOM,      PROP_MAX_ZOOM,
186      PROP_MIN_ZOOM,      PROP_MIN_ZOOM,
# Line 319  static void Line 341  static void
341  inspect_map_uri(OsmGpsMap *map)  inspect_map_uri(OsmGpsMap *map)
342  {  {
343      OsmGpsMapPrivate *priv = map->priv;      OsmGpsMapPrivate *priv = map->priv;
344        priv->uri_format = 0;
345        priv->the_google = FALSE;
346    
347      if (g_strrstr(priv->repo_uri, URI_MARKER_X))      if (g_strrstr(priv->repo_uri, URI_MARKER_X))
348          priv->uri_format |= URI_HAS_X;          priv->uri_format |= URI_HAS_X;
# Line 555  osm_gps_map_draw_gps_point (OsmGpsMap *m Line 579  osm_gps_map_draw_gps_point (OsmGpsMap *m
579          int x, y;          int x, y;
580          int r = priv->ui_gps_point_inner_radius;          int r = priv->ui_gps_point_inner_radius;
581          int r2 = priv->ui_gps_point_outer_radius;          int r2 = priv->ui_gps_point_outer_radius;
582          // int lw = priv->ui_gps_track_width;          int mr = MAX(3*r,r2);
         int mr = MAX(r,r2);  
583    
584          map_x0 = priv->map_x - EXTRA_BORDER;          map_x0 = priv->map_x - EXTRA_BORDER;
585          map_y0 = priv->map_y - EXTRA_BORDER;          map_y0 = priv->map_y - EXTRA_BORDER;
# Line 587  osm_gps_map_draw_gps_point (OsmGpsMap *m Line 610  osm_gps_map_draw_gps_point (OsmGpsMap *m
610    
611          // draw ball gradient          // draw ball gradient
612          if (r > 0) {          if (r > 0) {
613                // draw direction arrow
614                if(!isnan(priv->gps_heading))
615                {
616                    cairo_move_to (cr, x-r*cos(priv->gps_heading), y-r*sin(priv->gps_heading));
617                    cairo_line_to (cr, x+3*r*sin(priv->gps_heading), y-3*r*cos(priv->gps_heading));
618                    cairo_line_to (cr, x+r*cos(priv->gps_heading), y+r*sin(priv->gps_heading));
619                    cairo_close_path (cr);
620    
621                    cairo_set_source_rgba (cr, 0.3, 0.3, 1.0, 0.5);
622                    cairo_fill_preserve (cr);
623    
624                    cairo_set_line_width (cr, 1.0);
625                    cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.5);
626                    cairo_stroke(cr);
627                }
628    
629              pat = cairo_pattern_create_radial (x-(r/5), y-(r/5), (r/5), x,  y, r);              pat = cairo_pattern_create_radial (x-(r/5), y-(r/5), (r/5), x,  y, r);
630              cairo_pattern_add_color_stop_rgba (pat, 0, 1, 1, 1, 1.0);              cairo_pattern_add_color_stop_rgba (pat, 0, 1, 1, 1, 1.0);
631              cairo_pattern_add_color_stop_rgba (pat, 1, 0, 0, 1, 1.0);              cairo_pattern_add_color_stop_rgba (pat, 1, 0, 0, 1, 1.0);
# Line 600  osm_gps_map_draw_gps_point (OsmGpsMap *m Line 639  osm_gps_map_draw_gps_point (OsmGpsMap *m
639              cairo_arc (cr, x, y, r, 0, 2 * M_PI);              cairo_arc (cr, x, y, r, 0, 2 * M_PI);
640              cairo_stroke(cr);              cairo_stroke(cr);
641          }          }
642    
643          cairo_destroy(cr);          cairo_destroy(cr);
644          gtk_widget_queue_draw_area (GTK_WIDGET(map),          gtk_widget_queue_draw_area (GTK_WIDGET(map),
645                                      x-mr,                                      x-mr,
# Line 642  osm_gps_map_draw_gps_point (OsmGpsMap *m Line 681  osm_gps_map_draw_gps_point (OsmGpsMap *m
681      }      }
682  }  }
683    
 /* most visual effects are hardcoded by now, but may be made */  
 /* available via properties later */  
 #define BALLOON_AREA_WIDTH           290  
 #define BALLOON_AREA_HEIGHT           75  
   
 #define BALLOON_CORNER_RADIUS         20  
 #define BALLOON_BORDER               (BALLOON_CORNER_RADIUS/4)  
 #define BALLOON_WIDTH                (BALLOON_AREA_WIDTH + 2 * BALLOON_BORDER)  
 #define BALLOON_HEIGHT               (BALLOON_AREA_HEIGHT + 2 * BALLOON_BORDER)  
 #define BALLOON_TRANSPARENCY         0.8  
 #define POINTER_HEIGHT                20  
 #define POINTER_FOOT_WIDTH            20  
 #define POINTER_OFFSET               (BALLOON_CORNER_RADIUS*3/4)  
 #define BALLOON_SHADOW                5  
 #define BALLOON_SHADOW_TRANSPARENCY  0.2  
   
 #define CLOSE_BUTTON_RADIUS   (BALLOON_CORNER_RADIUS/3)  
   
   
 /* draw the bubble shape. this is used twice, once for the shape and once */  
 /* for the shadow */  
 static void  
 osm_gps_map_draw_balloon_shape (cairo_t *cr, int x0, int y0, int x1, int y1,  
        gboolean bottom, int px, int py, int px0, int px1) {  
   
     cairo_move_to (cr, x0, y0 + BALLOON_CORNER_RADIUS);  
     cairo_curve_to (cr, x0 , y0, x0 , y0, x0 + BALLOON_CORNER_RADIUS, y0);  
     if(!bottom) {  
         /* insert top pointer */  
         cairo_line_to (cr, px1, y0);  
         cairo_line_to (cr, px, py);  
         cairo_line_to (cr, px0, y0);  
     }  
   
     cairo_line_to (cr, x1 - BALLOON_CORNER_RADIUS, y0);  
     cairo_curve_to (cr, x1, y0, x1, y0, x1, y0 + BALLOON_CORNER_RADIUS);  
     cairo_line_to (cr, x1 , y1 - BALLOON_CORNER_RADIUS);  
     cairo_curve_to (cr, x1, y1, x1, y1, x1 - BALLOON_CORNER_RADIUS, y1);  
     if(bottom) {  
         /* insert bottom pointer */  
         cairo_line_to (cr, px0, y1);  
         cairo_line_to (cr, px, py);  
         cairo_line_to (cr, px1, y1);  
     }  
   
     cairo_line_to (cr, x0 + BALLOON_CORNER_RADIUS, y1);  
     cairo_curve_to (cr, x0, y1, x0, y1, x0, y1 - BALLOON_CORNER_RADIUS);  
   
     cairo_close_path (cr);  
 }  
   
 /* http://cairographics.org/samples/ */  
 static void  
 osm_gps_map_draw_balloon_int (OsmGpsMap *map)  
 {  
     OsmGpsMapPrivate *priv = map->priv;  
   
     if (priv->balloon.valid) {  
   
         /* ------- convert given coordinate into screen position --------- */  
         int x0 = lon2pixel(priv->map_zoom, priv->balloon.coo->rlon) -  
             priv->map_x + EXTRA_BORDER;  
         int y0 = lat2pixel(priv->map_zoom, priv->balloon.coo->rlat) -  
             priv->map_y + EXTRA_BORDER;  
   
         /* check position of this relative to screen center to determine */  
         /* pointer direction ... */  
         int pointer_x = x0, pointer_x0, pointer_x1;  
         int pointer_y = y0;  
   
         /* ... and calculate position */  
         if((x0 - EXTRA_BORDER) > GTK_WIDGET(map)->allocation.width/2) {  
             x0 -= BALLOON_WIDTH - POINTER_OFFSET;  
             pointer_x0 = pointer_x - (BALLOON_CORNER_RADIUS - POINTER_OFFSET);  
             pointer_x1 = pointer_x0 - POINTER_FOOT_WIDTH;  
         } else {  
             x0 -= POINTER_OFFSET;  
             pointer_x1 = pointer_x + (BALLOON_CORNER_RADIUS - POINTER_OFFSET);  
             pointer_x0 = pointer_x1 + POINTER_FOOT_WIDTH;  
         }  
   
         gboolean bottom = FALSE;  
         if((y0 - EXTRA_BORDER) > GTK_WIDGET(map)->allocation.height/2) {  
             bottom = TRUE;  
             y0 -= BALLOON_HEIGHT + POINTER_HEIGHT;  
         } else  
             y0 += POINTER_HEIGHT;  
   
         /* calculate bottom/right of box */  
         int x1 = x0 + BALLOON_WIDTH, y1 = y0 + BALLOON_HEIGHT;  
   
         /* save balloon screen coordinates for later use */  
         priv->balloon.rect.x = x0 + BALLOON_BORDER;  
         priv->balloon.rect.y = y0 + BALLOON_BORDER;  
         priv->balloon.rect.w = x1 - x0 - 2*BALLOON_BORDER;  
         priv->balloon.rect.h = y1 - y0 - 2*BALLOON_BORDER;  
   
 #ifdef USE_CAIRO  
         cairo_t *cr = gdk_cairo_create(priv->pixmap);  
   
         /* --------- draw shadow --------------- */  
         osm_gps_map_draw_balloon_shape (cr,  
                     x0 + BALLOON_SHADOW, y0 + BALLOON_SHADOW,  
                     x1 + BALLOON_SHADOW, y1 + BALLOON_SHADOW,  
                     bottom, pointer_x, pointer_y,  
                     pointer_x0 + BALLOON_SHADOW, pointer_x1 + BALLOON_SHADOW);  
   
         cairo_set_source_rgba (cr, 0, 0, 0, BALLOON_SHADOW_TRANSPARENCY);  
         cairo_fill_preserve (cr);  
         cairo_set_source_rgba (cr, 1, 0, 0, 1.0);  
         cairo_set_line_width (cr, 0);  
         cairo_stroke (cr);  
   
         /* --------- draw main shape ----------- */  
         osm_gps_map_draw_balloon_shape (cr, x0, y0, x1, y1,  
                     bottom, pointer_x, pointer_y, pointer_x0, pointer_x1);  
   
         cairo_set_source_rgba (cr, 1, 1, 1, BALLOON_TRANSPARENCY);  
         cairo_fill_preserve (cr);  
         cairo_set_source_rgba (cr, 0, 0, 0, BALLOON_TRANSPARENCY);  
         cairo_set_line_width (cr, 1);  
         cairo_stroke (cr);  
   
   
         /* ---------- draw close button --------- */  
   
         int cx = x1 - BALLOON_BORDER - CLOSE_BUTTON_RADIUS;  
         int cy = y0 + BALLOON_BORDER + CLOSE_BUTTON_RADIUS;  
         int crad = CLOSE_BUTTON_RADIUS;  
   
         cairo_arc (cr, cx, cy, crad, 0, 2 * M_PI);  
         cairo_set_source_rgba (cr, 0.8, 0, 0, 1.0);  
         cairo_fill_preserve (cr);  
         cairo_set_source_rgba (cr, 0.3, 0, 0, 1.0);  
         cairo_set_line_width (cr, 2);  
         cairo_stroke(cr);  
   
         cairo_set_source_rgba (cr, 1, 1, 1, 1.0);  
         cairo_set_line_width (cr, 3);  
         cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);  
         cairo_move_to (cr, cx - crad/2, cy - crad/2);  
         cairo_line_to (cr, cx + crad/2, cy + crad/2);  
         cairo_stroke (cr);  
         cairo_move_to (cr, cx + crad/2, cy - crad/2);  
         cairo_line_to (cr, cx - crad/2, cy + crad/2);  
         cairo_stroke (cr);  
   
         if (priv->balloon.cb) {  
             /* clip in case application tries to draw in */  
             /* exceed of the balloon */  
             cairo_rectangle (cr, priv->balloon.rect.x, priv->balloon.rect.y,  
                              priv->balloon.rect.w, priv->balloon.rect.h);  
             cairo_clip (cr);  
             cairo_new_path (cr);  /* current path is not  
                                      consumed by cairo_clip() */  
   
             priv->balloon.cb(cr, &priv->balloon.rect, priv->balloon.data);  
         }  
   
         gtk_widget_queue_draw_area (GTK_WIDGET(map),  
                                     x0, y0, BALLOON_WIDTH,  
                                     BALLOON_HEIGHT + POINTER_HEIGHT);  
 #else  
 #warning "Balloon display lacks a non-cairo implementation!"  
 #endif  
     }  
 }  
   
 /* the user clicked into the balloons main area. handle this */  
 static void  
 osm_gps_map_handle_balloon_click(OsmGpsMap *map, gint x, gint y)  
 {  
     OsmGpsMapPrivate *priv = map->priv;  
   
     if (!priv->balloon.valid)  
         return;  
   
     /* check if the close button was clicked */  
     if ((x > priv->balloon.rect.w - 2*CLOSE_BUTTON_RADIUS) &&  
         (x < priv->balloon.rect.w) &&  
         (y > 0) && (y < 2*CLOSE_BUTTON_RADIUS)) {  
   
         priv->balloon.valid = FALSE;  
         osm_gps_map_map_redraw_idle(map);  
     }  
 }  
   
 /* return true if balloon is being displayed and if */  
 /* the given coordinate is within this balloon */  
 static gboolean  
 osm_gps_map_in_balloon(OsmGpsMapPrivate *priv, gint x, gint y)  
 {  
     return (priv->balloon.valid &&  
             (x > priv->balloon.rect.x) &&  
             (x < priv->balloon.rect.x + priv->balloon.rect.w) &&  
             (y > priv->balloon.rect.y) &&  
             (y < priv->balloon.rect.y + priv->balloon.rect.h));  
 }  
   
684  static void  static void
685  osm_gps_map_blit_tile(OsmGpsMap *map, GdkPixbuf *pixbuf, int offset_x, int offset_y)  osm_gps_map_blit_tile(OsmGpsMap *map, GdkPixbuf *pixbuf, int offset_x, int offset_y)
686  {  {
# Line 903  osm_gps_map_tile_download_complete (Soup Line 743  osm_gps_map_tile_download_complete (Soup
743              }              }
744              else              else
745              {              {
746                  g_warning("Error creating tile download directory: %s", dl->folder);                  g_warning("Error creating tile download directory: %s",
747                              dl->folder);
748                    perror("perror:");
749              }              }
750          }          }
751    
# Line 1050  osm_gps_map_download_tile (OsmGpsMap *ma Line 892  osm_gps_map_download_tile (OsmGpsMap *ma
892                  }                  }
893              }              }
894    
895    #ifdef LIBSOUP22
896                soup_message_headers_append(msg->request_headers,
897                                            "User-Agent", USER_AGENT);
898    #endif
899    
900              g_hash_table_insert (priv->tile_queue, dl->uri, msg);              g_hash_table_insert (priv->tile_queue, dl->uri, msg);
901              soup_session_queue_message (priv->soup_session, msg, osm_gps_map_tile_download_complete, dl);              soup_session_queue_message (priv->soup_session, msg, osm_gps_map_tile_download_complete, dl);
902          } else {          } else {
# Line 1400  osm_gps_map_map_redraw (OsmGpsMap *map) Line 1247  osm_gps_map_map_redraw (OsmGpsMap *map)
1247  {  {
1248      OsmGpsMapPrivate *priv = map->priv;      OsmGpsMapPrivate *priv = map->priv;
1249    
1250        /* on diablo the map comes up at 1x1 pixel size and */
1251        /* isn't really usable. we'll just ignore this ... */
1252        if((GTK_WIDGET(map)->allocation.width < 2) ||
1253           (GTK_WIDGET(map)->allocation.height < 2)) {
1254            printf("not a useful sized map yet ...\n");
1255            return FALSE;
1256        }
1257    
1258      priv->idle_map_redraw = 0;      priv->idle_map_redraw = 0;
1259    
1260    #ifdef ENABLE_OSD
1261        /* don't redraw the entire map while the OSD is doing */
1262        /* some animation or the like. This is to keep the animation */
1263        /* fluid */
1264        if (priv->osd->busy(priv->osd))
1265            return FALSE;
1266    #endif
1267    
1268    #ifdef DRAG_DEBUG
1269        printf("trying redraw\n");
1270    #endif
1271    
1272      /* the motion_notify handler uses priv->pixmap to redraw the area; if we      /* the motion_notify handler uses priv->pixmap to redraw the area; if we
1273       * change it while we are dragging, we will end up showing it in the wrong       * change it while we are dragging, we will end up showing it in the wrong
1274       * place. This could be fixed by carefully recompute the coordinates, but       * place. This could be fixed by carefully recompute the coordinates, but
# Line 1409  osm_gps_map_map_redraw (OsmGpsMap *map) Line 1276  osm_gps_map_map_redraw (OsmGpsMap *map)
1276      if (priv->dragging)      if (priv->dragging)
1277          return FALSE;          return FALSE;
1278    
1279        /* undo all offsets that may have happened when dragging */
1280        priv->drag_mouse_dx = 0;
1281        priv->drag_mouse_dy = 0;
1282    
1283      priv->redraw_cycle++;      priv->redraw_cycle++;
1284    
1285      /* draw white background to initialise pixmap */      /* draw white background to initialise pixmap */
1286      gdk_draw_rectangle (      gdk_draw_rectangle (priv->pixmap,
                         priv->pixmap,  
1287                          GTK_WIDGET(map)->style->white_gc,                          GTK_WIDGET(map)->style->white_gc,
1288                          TRUE,                          TRUE,
1289                          0, 0,                          0, 0,
# Line 1425  osm_gps_map_map_redraw (OsmGpsMap *map) Line 1295  osm_gps_map_map_redraw (OsmGpsMap *map)
1295      osm_gps_map_print_tracks(map);      osm_gps_map_print_tracks(map);
1296      osm_gps_map_draw_gps_point(map);      osm_gps_map_draw_gps_point(map);
1297      osm_gps_map_print_images(map);      osm_gps_map_print_images(map);
     osm_gps_map_draw_balloon_int(map);  
1298    
1299      //osm_gps_map_osd_speed(map, 1.5);  #ifdef ENABLE_OSD
1300        /* OSD may contain a coordinate/scale, so we may have to re-render it */
1301        if(priv->osd && OSM_IS_GPS_MAP (priv->osd->widget))
1302            priv->osd->render (priv->osd);
1303    #endif
1304    
1305      osm_gps_map_purge_cache(map);      osm_gps_map_purge_cache(map);
1306      gtk_widget_queue_draw (GTK_WIDGET (map));      gtk_widget_queue_draw (GTK_WIDGET (map));
1307    
# Line 1444  osm_gps_map_map_redraw_idle (OsmGpsMap * Line 1318  osm_gps_map_map_redraw_idle (OsmGpsMap *
1318  }  }
1319    
1320  static void  static void
1321    center_coord_update(GtkWidget *widget) {
1322        OsmGpsMapPrivate *priv = OSM_GPS_MAP_PRIVATE(widget);
1323    
1324        // pixel_x,y, offsets
1325        gint pixel_x = priv->map_x + widget->allocation.width/2;
1326        gint pixel_y = priv->map_y + widget->allocation.height/2;
1327    
1328        priv->center_rlon = pixel2lon(priv->map_zoom, pixel_x);
1329        priv->center_rlat = pixel2lat(priv->map_zoom, pixel_y);
1330    }
1331    
1332    #ifdef OSM_GPS_MAP_KEYS
1333    static gboolean
1334    on_window_key_press(GtkWidget *widget,
1335                             GdkEventKey *event, OsmGpsMapPrivate *priv) {
1336      gboolean handled = FALSE;
1337      int step = GTK_WIDGET(widget)->allocation.width/OSM_GPS_MAP_SCROLL_STEP;
1338    
1339      // the map handles some keys on its own ...
1340      switch(event->keyval) {
1341    #ifdef OSM_GPS_MAP_KEY_FULLSCREEN
1342      case OSM_GPS_MAP_KEY_FULLSCREEN: {
1343          GtkWidget *toplevel = gtk_widget_get_toplevel(GTK_WIDGET(widget));
1344          if(!priv->fullscreen)
1345              gtk_window_fullscreen(GTK_WINDOW(toplevel));
1346          else
1347              gtk_window_unfullscreen(GTK_WINDOW(toplevel));
1348    
1349          priv->fullscreen = !priv->fullscreen;
1350          handled = TRUE;
1351          } break;
1352    #endif
1353    
1354    #ifdef OSM_GPS_MAP_KEY_ZOOMIN
1355      case OSM_GPS_MAP_KEY_ZOOMIN:
1356          osm_gps_map_set_zoom(OSM_GPS_MAP(widget), priv->map_zoom+1);
1357          handled = TRUE;
1358          break;
1359    #endif
1360    
1361    #ifdef OSM_GPS_MAP_KEY_ZOOMOUT
1362      case OSM_GPS_MAP_KEY_ZOOMOUT:
1363          osm_gps_map_set_zoom(OSM_GPS_MAP(widget), priv->map_zoom-1);
1364          handled = TRUE;
1365          break;
1366    #endif
1367    
1368    #ifdef OSM_GPS_MAP_KEY_UP
1369      case OSM_GPS_MAP_KEY_UP:
1370          priv->map_y -= step;
1371          center_coord_update(widget);
1372          osm_gps_map_map_redraw_idle(OSM_GPS_MAP(widget));
1373          handled = TRUE;
1374          break;
1375    #endif
1376    
1377    #ifdef OSM_GPS_MAP_KEY_DOWN
1378      case OSM_GPS_MAP_KEY_DOWN:
1379          priv->map_y += step;
1380          center_coord_update(widget);
1381          osm_gps_map_map_redraw_idle(OSM_GPS_MAP(widget));
1382          handled = TRUE;
1383          break;
1384    #endif
1385    
1386    #ifdef OSM_GPS_MAP_KEY_LEFT
1387      case OSM_GPS_MAP_KEY_LEFT:
1388          priv->map_x -= step;
1389          center_coord_update(widget);
1390          osm_gps_map_map_redraw_idle(OSM_GPS_MAP(widget));
1391          handled = TRUE;
1392          break;
1393    #endif
1394    
1395    #ifdef OSM_GPS_MAP_KEY_RIGHT
1396      case OSM_GPS_MAP_KEY_RIGHT:
1397          priv->map_x += step;
1398          center_coord_update(widget);
1399          osm_gps_map_map_redraw_idle(OSM_GPS_MAP(widget));
1400          handled = TRUE;
1401          break;
1402    #endif
1403    
1404      default:
1405          break;
1406      }
1407    
1408      return handled;
1409    }
1410    #endif
1411    
1412    static void
1413  osm_gps_map_init (OsmGpsMap *object)  osm_gps_map_init (OsmGpsMap *object)
1414  {  {
1415      OsmGpsMapPrivate *priv;      OsmGpsMapPrivate *priv;
# Line 1456  osm_gps_map_init (OsmGpsMap *object) Line 1422  osm_gps_map_init (OsmGpsMap *object)
1422      priv->trip_history = NULL;      priv->trip_history = NULL;
1423      priv->gps = g_new0(coord_t, 1);      priv->gps = g_new0(coord_t, 1);
1424      priv->gps_valid = FALSE;      priv->gps_valid = FALSE;
1425        priv->gps_heading = OSM_GPS_MAP_INVALID;
1426    
1427      priv->balloon.coo = g_new0(coord_t, 1);  #ifdef ENABLE_OSD
1428      priv->balloon.valid = FALSE;      priv->osd = NULL;
1429      priv->balloon.cb = NULL;  #endif
1430    
1431    #ifdef OSM_GPS_MAP_BUTTON_FULLSCREEN
1432        priv->fullscreen = FALSE;
1433    #endif
1434    
1435      priv->tracks = NULL;      priv->tracks = NULL;
1436      priv->images = NULL;      priv->images = NULL;
# Line 1477  osm_gps_map_init (OsmGpsMap *object) Line 1448  osm_gps_map_init (OsmGpsMap *object)
1448    
1449  #ifndef LIBSOUP22  #ifndef LIBSOUP22
1450      //Change naumber of concurrent connections option?      //Change naumber of concurrent connections option?
1451      priv->soup_session = soup_session_async_new_with_options(      priv->soup_session =
1452                                                               SOUP_SESSION_USER_AGENT,          soup_session_async_new_with_options(SOUP_SESSION_USER_AGENT,
1453                                                               "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11",                                              USER_AGENT, NULL);
                                                              NULL);  
1454  #else  #else
1455      /* libsoup-2.2 seems not to be able to set the user agent */      /* libsoup-2.2 has no special way to set the user agent, so we */
1456        /* set it seperately as an extra header field for each reuest */
1457      priv->soup_session = soup_session_async_new();      priv->soup_session = soup_session_async_new();
1458  #endif  #endif
   
1459      //Hash table which maps tile d/l URIs to SoupMessage requests      //Hash table which maps tile d/l URIs to SoupMessage requests
1460      priv->tile_queue = g_hash_table_new (g_str_hash, g_str_equal);      priv->tile_queue = g_hash_table_new (g_str_hash, g_str_equal);
1461    
# Line 1505  osm_gps_map_init (OsmGpsMap *object) Line 1475  osm_gps_map_init (OsmGpsMap *object)
1475      GTK_WIDGET_SET_FLAGS (object, GTK_CAN_FOCUS);      GTK_WIDGET_SET_FLAGS (object, GTK_CAN_FOCUS);
1476    
1477      g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_MASK, my_log_handler, NULL);      g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_MASK, my_log_handler, NULL);
 }  
1478    
1479  #ifndef G_CHECKSUM_MD5  #ifdef OSM_GPS_MAP_KEYS
1480  /* simple hash algorithm hack if md5 is not present */      g_signal_connect(G_OBJECT(object), "key_press_event",
1481  static char *simple_hash(char *str) {                       G_CALLBACK(on_window_key_press), priv);
     union {  
         char str[4];  
         gulong val;  
     } hash = { .val = 0x55555555 };  
   
     while(*str) {  
         hash.str[(int)str & 3] ^= *str;  
         str++;  
     }  
     return g_strdup_printf("%08lX", hash.val);  
 }  
1482  #endif  #endif
1483    }
1484    
1485  static GObject *  static void
1486  osm_gps_map_constructor (GType gtype, guint n_properties, GObjectConstructParam *properties)  osm_gps_map_setup(OsmGpsMapPrivate *priv) {
 {  
     GObject *object;  
     OsmGpsMapPrivate *priv;  
     OsmGpsMap *map;  
1487      const char *uri;      const char *uri;
1488    
     //Always chain up to the parent constructor  
     object = G_OBJECT_CLASS(osm_gps_map_parent_class)->constructor(gtype, n_properties, properties);  
     map = OSM_GPS_MAP(object);  
     priv = OSM_GPS_MAP_PRIVATE(object);  
   
1489      //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
1490      uri = osm_gps_map_source_get_repo_uri(OSM_GPS_MAP_SOURCE_NULL);      uri = osm_gps_map_source_get_repo_uri(OSM_GPS_MAP_SOURCE_NULL);
1491      if ( (priv->map_source == 0) || (strcmp(priv->repo_uri, uri) == 0) ) {      if ( (priv->map_source == 0) || (strcmp(priv->repo_uri, uri) == 0) ) {
# Line 1560  osm_gps_map_constructor (GType gtype, gu Line 1510  osm_gps_map_constructor (GType gtype, gu
1510          }          }
1511      }      }
1512    
1513      if (!priv->cache_dir_is_full_path) {      const char *fname = osm_gps_map_source_get_friendly_name(priv->map_source);
1514  #ifdef G_CHECKSUM_MD5      if(!fname) fname = "_unknown_";
         char *md5 = g_compute_checksum_for_string (G_CHECKSUM_MD5, priv->repo_uri, -1);  
 #else  
         char *md5 = simple_hash(priv->repo_uri);  
 #endif  
   
         if (priv->cache_dir) {  
             char *old = priv->cache_dir;  
             //the new cachedir is the given cache dir + the md5 of the repo_uri  
             priv->cache_dir = g_strdup_printf("%s%c%s", old, G_DIR_SEPARATOR, md5);  
             g_debug("Adjusting cache dir %s -> %s", old, priv->cache_dir);  
             g_free(old);  
         } else {  
             //the new cachedir is the current dir + the md5 of the repo_uri  
             priv->cache_dir = g_strdup(md5);  
         }  
1515    
1516          g_free(md5);      if (priv->tile_dir) {
1517            //the new cachedir is the given cache dir + the friendly name of the repo_uri
1518            priv->cache_dir = g_strdup_printf("%s%c%s", priv->tile_dir, G_DIR_SEPARATOR, fname);
1519            g_debug("Adjusting cache dir %s -> %s", priv->tile_dir, priv->cache_dir);
1520      }      }
1521    }
1522    
1523    static GObject *
1524    osm_gps_map_constructor (GType gtype, guint n_properties, GObjectConstructParam *properties)
1525    {
1526        //Always chain up to the parent constructor
1527        GObject *object =
1528            G_OBJECT_CLASS(osm_gps_map_parent_class)->constructor(gtype, n_properties, properties);
1529    
1530        osm_gps_map_setup(OSM_GPS_MAP_PRIVATE(object));
1531    
1532      inspect_map_uri(map);      inspect_map_uri(OSM_GPS_MAP(object));
1533    
1534      return object;      return object;
1535  }  }
# Line 1618  osm_gps_map_dispose (GObject *object) Line 1566  osm_gps_map_dispose (GObject *object)
1566      if (priv->idle_map_redraw != 0)      if (priv->idle_map_redraw != 0)
1567          g_source_remove (priv->idle_map_redraw);          g_source_remove (priv->idle_map_redraw);
1568    
1569        if (priv->drag_expose != 0)
1570            g_source_remove (priv->drag_expose);
1571    
1572      g_free(priv->gps);      g_free(priv->gps);
1573      g_free(priv->balloon.coo);  
1574    #ifdef ENABLE_OSD
1575        if(priv->osd)
1576            priv->osd->free(priv->osd);
1577    
1578    #ifdef OSD_DOUBLE_BUFFER
1579        if(priv->dbuf_pixmap)
1580            g_object_unref (priv->dbuf_pixmap);
1581    #endif
1582    #endif
1583    
1584      G_OBJECT_CLASS (osm_gps_map_parent_class)->dispose (object);      G_OBJECT_CLASS (osm_gps_map_parent_class)->dispose (object);
1585  }  }
# Line 1630  osm_gps_map_finalize (GObject *object) Line 1590  osm_gps_map_finalize (GObject *object)
1590      OsmGpsMap *map = OSM_GPS_MAP(object);      OsmGpsMap *map = OSM_GPS_MAP(object);
1591      OsmGpsMapPrivate *priv = map->priv;      OsmGpsMapPrivate *priv = map->priv;
1592    
1593      g_free(priv->cache_dir);      if(priv->tile_dir)
1594            g_free(priv->tile_dir);
1595    
1596        if(priv->cache_dir)
1597            g_free(priv->cache_dir);
1598    
1599      g_free(priv->repo_uri);      g_free(priv->repo_uri);
1600      g_free(priv->image_format);      g_free(priv->image_format);
1601    
# Line 1687  osm_gps_map_set_property (GObject *objec Line 1652  osm_gps_map_set_property (GObject *objec
1652              break;              break;
1653          case PROP_TILE_CACHE_DIR:          case PROP_TILE_CACHE_DIR:
1654              if ( g_value_get_string(value) )              if ( g_value_get_string(value) )
1655                  priv->cache_dir = g_value_dup_string (value);                  priv->tile_dir = g_value_dup_string (value);
             break;  
         case PROP_TILE_CACHE_DIR_IS_FULL_PATH:  
             priv->cache_dir_is_full_path = g_value_get_boolean (value);  
1656              break;              break;
1657          case PROP_ZOOM:          case PROP_ZOOM:
1658              priv->map_zoom = g_value_get_int (value);              priv->map_zoom = g_value_get_int (value);
# Line 1703  osm_gps_map_set_property (GObject *objec Line 1665  osm_gps_map_set_property (GObject *objec
1665              break;              break;
1666          case PROP_MAP_X:          case PROP_MAP_X:
1667              priv->map_x = g_value_get_int (value);              priv->map_x = g_value_get_int (value);
1668              priv->center_coord_set = FALSE;              center_coord_update(GTK_WIDGET(object));
1669              break;              break;
1670          case PROP_MAP_Y:          case PROP_MAP_Y:
1671              priv->map_y = g_value_get_int (value);              priv->map_y = g_value_get_int (value);
1672              priv->center_coord_set = FALSE;              center_coord_update(GTK_WIDGET(object));
1673              break;              break;
1674          case PROP_GPS_TRACK_WIDTH:          case PROP_GPS_TRACK_WIDTH:
1675              priv->ui_gps_track_width = g_value_get_int (value);              priv->ui_gps_track_width = g_value_get_int (value);
# Line 1718  osm_gps_map_set_property (GObject *objec Line 1680  osm_gps_map_set_property (GObject *objec
1680          case PROP_GPS_POINT_R2:          case PROP_GPS_POINT_R2:
1681              priv->ui_gps_point_outer_radius = g_value_get_int (value);              priv->ui_gps_point_outer_radius = g_value_get_int (value);
1682              break;              break;
1683          case PROP_MAP_SOURCE:          case PROP_MAP_SOURCE: {
1684                gint old = priv->map_source;
1685              priv->map_source = g_value_get_int (value);              priv->map_source = g_value_get_int (value);
1686              break;              if(old >= OSM_GPS_MAP_SOURCE_NULL &&
1687                   priv->map_source != old &&
1688                   priv->map_source >= OSM_GPS_MAP_SOURCE_NULL &&
1689                   priv->map_source <= OSM_GPS_MAP_SOURCE_LAST) {
1690    
1691                    /* we now have to switch the entire map */
1692    
1693                    /* flush the ram cache */
1694                    g_hash_table_remove_all(priv->tile_cache);
1695    
1696                    osm_gps_map_setup(priv);
1697    
1698                    inspect_map_uri(map);
1699    
1700                    /* adjust zoom if necessary */
1701                    if(priv->map_zoom > priv->max_zoom)
1702                        osm_gps_map_set_zoom(map, priv->max_zoom);
1703    
1704                    if(priv->map_zoom < priv->min_zoom)
1705                        osm_gps_map_set_zoom(map, priv->min_zoom);
1706    
1707                } } break;
1708          case PROP_IMAGE_FORMAT:          case PROP_IMAGE_FORMAT:
1709              priv->image_format = g_value_dup_string (value);              priv->image_format = g_value_dup_string (value);
1710              break;              break;
# Line 1761  osm_gps_map_get_property (GObject *objec Line 1745  osm_gps_map_get_property (GObject *objec
1745          case PROP_TILE_CACHE_DIR:          case PROP_TILE_CACHE_DIR:
1746              g_value_set_string(value, priv->cache_dir);              g_value_set_string(value, priv->cache_dir);
1747              break;              break;
         case PROP_TILE_CACHE_DIR_IS_FULL_PATH:  
             g_value_set_boolean(value, priv->cache_dir_is_full_path);  
             break;  
1748          case PROP_ZOOM:          case PROP_ZOOM:
1749              g_value_set_int(value, priv->map_zoom);              g_value_set_int(value, priv->map_zoom);
1750              break;              break;
# Line 1836  osm_gps_map_button_press (GtkWidget *wid Line 1817  osm_gps_map_button_press (GtkWidget *wid
1817  {  {
1818      OsmGpsMapPrivate *priv = OSM_GPS_MAP_PRIVATE(widget);      OsmGpsMapPrivate *priv = OSM_GPS_MAP_PRIVATE(widget);
1819    
1820      /* don't drag if the user clicked within the balloon */  #ifdef ENABLE_OSD
1821      if (osm_gps_map_in_balloon(priv,      /* pressed inside OSD control? */
1822                     event->x + EXTRA_BORDER,      if(priv->osd) {
1823                     event->y + EXTRA_BORDER))          osd_button_t but =
1824      {              priv->osd->check(priv->osd, TRUE, event->x, event->y);
1825          priv->drag_counter = -1;  
1826          return FALSE;          if(but != OSD_NONE)
1827            {
1828                int step =
1829                    GTK_WIDGET(widget)->allocation.width/OSM_GPS_MAP_SCROLL_STEP;
1830                priv->drag_counter = -1;
1831    
1832                switch(but) {
1833                case OSD_UP:
1834                    priv->map_y -= step;
1835                    center_coord_update(widget);
1836                    g_object_set(G_OBJECT(widget), "auto-center", FALSE, NULL);
1837                    osm_gps_map_map_redraw_idle(OSM_GPS_MAP(widget));
1838                    break;
1839    
1840                case OSD_DOWN:
1841                    priv->map_y += step;
1842                    center_coord_update(widget);
1843                    g_object_set(G_OBJECT(widget), "auto-center", FALSE, NULL);
1844                    osm_gps_map_map_redraw_idle(OSM_GPS_MAP(widget));
1845                    break;
1846    
1847                case OSD_LEFT:
1848                    priv->map_x -= step;
1849                    center_coord_update(widget);
1850                    g_object_set(G_OBJECT(widget), "auto-center", FALSE, NULL);
1851                    osm_gps_map_map_redraw_idle(OSM_GPS_MAP(widget));
1852                    break;
1853    
1854                case OSD_RIGHT:
1855                    priv->map_x += step;
1856                    center_coord_update(widget);
1857                    g_object_set(G_OBJECT(widget), "auto-center", FALSE, NULL);
1858                    osm_gps_map_map_redraw_idle(OSM_GPS_MAP(widget));
1859                    break;
1860    
1861                case OSD_IN:
1862                    osm_gps_map_set_zoom(OSM_GPS_MAP(widget), priv->map_zoom+1);
1863                    break;
1864    
1865                case OSD_OUT:
1866                    osm_gps_map_set_zoom(OSM_GPS_MAP(widget), priv->map_zoom-1);
1867                    break;
1868    
1869                default:
1870                    /* all custom buttons are forwarded to the application */
1871                    if(priv->osd->cb)
1872                        priv->osd->cb(but, priv->osd->data);
1873                    break;
1874                }
1875    
1876                return FALSE;
1877            }
1878      }      }
1879    #endif
1880    
1881      priv->drag_counter = 0;      priv->drag_counter = 0;
1882      priv->drag_start_mouse_x = (int) event->x;      priv->drag_start_mouse_x = (int) event->x;
# Line 1859  osm_gps_map_button_release (GtkWidget *w Line 1892  osm_gps_map_button_release (GtkWidget *w
1892  {  {
1893      OsmGpsMapPrivate *priv = OSM_GPS_MAP_PRIVATE(widget);      OsmGpsMapPrivate *priv = OSM_GPS_MAP_PRIVATE(widget);
1894    
     /* released inside the balloon? */  
     if (osm_gps_map_in_balloon(priv,  
                    event->x + EXTRA_BORDER,  
                    event->y + EXTRA_BORDER))  
     {  
         osm_gps_map_handle_balloon_click(OSM_GPS_MAP(widget),  
              event->x - priv->balloon.rect.x + EXTRA_BORDER,  
              event->y - priv->balloon.rect.y + EXTRA_BORDER);  
         return FALSE;  
     }  
   
     if (priv->drag_counter < 0)  
         return FALSE;  
   
1895      if (priv->dragging)      if (priv->dragging)
1896      {      {
1897          priv->dragging = FALSE;          priv->dragging = FALSE;
# Line 1883  osm_gps_map_button_release (GtkWidget *w Line 1902  osm_gps_map_button_release (GtkWidget *w
1902          priv->map_x += (priv->drag_start_mouse_x - (int) event->x);          priv->map_x += (priv->drag_start_mouse_x - (int) event->x);
1903          priv->map_y += (priv->drag_start_mouse_y - (int) event->y);          priv->map_y += (priv->drag_start_mouse_y - (int) event->y);
1904    
1905          priv->center_coord_set = FALSE;          center_coord_update(widget);
1906    
1907          osm_gps_map_map_redraw_idle(OSM_GPS_MAP(widget));          osm_gps_map_map_redraw_idle(OSM_GPS_MAP(widget));
1908      }      }
1909    #ifdef ENABLE_OSD
1910        /* pressed inside OSD control? */
1911        else if(priv->osd)
1912            priv->osd->check(priv->osd, FALSE, event->x, event->y);
1913    #endif
1914    
1915    #ifdef DRAG_DEBUG
1916        printf("dragging done\n");
1917    #endif
1918    
     priv->drag_mouse_dx = 0;  
     priv->drag_mouse_dy = 0;  
1919      priv->drag_counter = -1;      priv->drag_counter = -1;
1920    
1921      return FALSE;      return FALSE;
1922  }  }
1923    
1924  static gboolean  static gboolean
1925    osm_gps_map_expose (GtkWidget *widget, GdkEventExpose  *event);
1926    
1927    static gboolean
1928    osm_gps_map_map_expose (GtkWidget *widget)
1929    {
1930        OsmGpsMapPrivate *priv = OSM_GPS_MAP(widget)->priv;
1931    
1932        priv->drag_expose = 0;
1933        osm_gps_map_expose (widget, NULL);
1934        return FALSE;
1935    }
1936    
1937    static gboolean
1938  osm_gps_map_motion_notify (GtkWidget *widget, GdkEventMotion  *event)  osm_gps_map_motion_notify (GtkWidget *widget, GdkEventMotion  *event)
1939  {  {
1940      int x, y;      int x, y;
# Line 1918  osm_gps_map_motion_notify (GtkWidget *wi Line 1957  osm_gps_map_motion_notify (GtkWidget *wi
1957      if (priv->drag_counter < 0)      if (priv->drag_counter < 0)
1958          return FALSE;          return FALSE;
1959    
1960      priv->drag_counter++;      /* not yet dragged far enough? */
1961        if(!priv->drag_counter &&
1962      // we havent dragged more than 6 pixels         ( (x - priv->drag_start_mouse_x) * (x - priv->drag_start_mouse_x) +
1963      if (priv->drag_counter < 6)           (y - priv->drag_start_mouse_y) * (y - priv->drag_start_mouse_y) <
1964             10*10))
1965          return FALSE;          return FALSE;
1966    
1967        priv->drag_counter++;
1968    
1969      priv->dragging = TRUE;      priv->dragging = TRUE;
1970    
1971      if (priv->map_auto_center)      if (priv->map_auto_center)
# Line 1932  osm_gps_map_motion_notify (GtkWidget *wi Line 1974  osm_gps_map_motion_notify (GtkWidget *wi
1974      priv->drag_mouse_dx = x - priv->drag_start_mouse_x;      priv->drag_mouse_dx = x - priv->drag_start_mouse_x;
1975      priv->drag_mouse_dy = y - priv->drag_start_mouse_y;      priv->drag_mouse_dy = y - priv->drag_start_mouse_y;
1976    
1977      gdk_draw_drawable (      /* instead of redrawing directly just add an idle function */
1978                         widget->window,      if (!priv->drag_expose)
1979                         widget->style->fg_gc[GTK_WIDGET_STATE (widget)],          priv->drag_expose =
1980                         priv->pixmap,              g_idle_add ((GSourceFunc)osm_gps_map_map_expose, widget);
                        0,0,  
                        priv->drag_mouse_dx - EXTRA_BORDER, priv->drag_mouse_dy - EXTRA_BORDER,  
                        -1,-1);  
   
     //Paint white outside of the map if dragging. Its less  
     //ugly than painting the corrupted map  
     if(priv->drag_mouse_dx>EXTRA_BORDER) {  
         gdk_draw_rectangle (  
                             widget->window,  
                             widget->style->white_gc,  
                             TRUE,  
                             0, 0,  
                             priv->drag_mouse_dx - EXTRA_BORDER,  
                             widget->allocation.height);  
     }  
     else if (-priv->drag_mouse_dx > EXTRA_BORDER)  
     {  
         gdk_draw_rectangle (  
                             widget->window,  
                             widget->style->white_gc,  
                             TRUE,  
                             priv->drag_mouse_dx + widget->allocation.width + EXTRA_BORDER, 0,  
                             -priv->drag_mouse_dx - EXTRA_BORDER,  
                             widget->allocation.height);  
     }  
   
     if (priv->drag_mouse_dy>EXTRA_BORDER) {  
         gdk_draw_rectangle (  
                             widget->window,  
                             widget->style->white_gc,  
                             TRUE,  
                             0, 0,  
                             widget->allocation.width,  
                             priv->drag_mouse_dy - EXTRA_BORDER);  
     }  
     else if (-priv->drag_mouse_dy > EXTRA_BORDER)  
     {  
         gdk_draw_rectangle (  
                             widget->window,  
                             widget->style->white_gc,  
                             TRUE,  
                             0, priv->drag_mouse_dy + widget->allocation.height + EXTRA_BORDER,  
                             widget->allocation.width,  
                             -priv->drag_mouse_dy - EXTRA_BORDER);  
     }  
1981    
1982      return FALSE;      return FALSE;
1983  }  }
# Line 1995  osm_gps_map_configure (GtkWidget *widget Line 1992  osm_gps_map_configure (GtkWidget *widget
1992          g_object_unref (priv->pixmap);          g_object_unref (priv->pixmap);
1993    
1994      priv->pixmap = gdk_pixmap_new (      priv->pixmap = gdk_pixmap_new (
1995                                     widget->window,                          widget->window,
1996                                     widget->allocation.width + EXTRA_BORDER * 2,                          widget->allocation.width + EXTRA_BORDER * 2,
1997                                     widget->allocation.height + EXTRA_BORDER * 2,                          widget->allocation.height + EXTRA_BORDER * 2,
1998                                     -1);                          -1);
1999    
2000        // pixel_x,y, offsets
2001        gint pixel_x = lon2pixel(priv->map_zoom, priv->center_rlon);
2002        gint pixel_y = lat2pixel(priv->map_zoom, priv->center_rlat);
2003    
2004        priv->map_x = pixel_x - widget->allocation.width/2;
2005        priv->map_y = pixel_y - widget->allocation.height/2;
2006    
2007    #ifdef ENABLE_OSD
2008    
2009    #ifdef OSD_DOUBLE_BUFFER
2010        if (priv->dbuf_pixmap)
2011            g_object_unref (priv->dbuf_pixmap);
2012    
2013        priv->dbuf_pixmap = gdk_pixmap_new (
2014                            widget->window,
2015                            widget->allocation.width,
2016                            widget->allocation.height,
2017                            -1);
2018    #endif
2019    
2020        /* the osd needs some references to map internal objects */
2021        if(priv->osd)
2022            priv->osd->widget = widget;
2023    #endif
2024    
2025      /* and gc, used for clipping (I think......) */      /* and gc, used for clipping (I think......) */
2026      if(priv->gc_map)      if(priv->gc_map)
# Line 2016  osm_gps_map_expose (GtkWidget *widget, G Line 2038  osm_gps_map_expose (GtkWidget *widget, G
2038  {  {
2039      OsmGpsMapPrivate *priv = OSM_GPS_MAP_PRIVATE(widget);      OsmGpsMapPrivate *priv = OSM_GPS_MAP_PRIVATE(widget);
2040    
2041      gdk_draw_drawable (  #if defined(ENABLE_OSD) && defined(OSD_DOUBLE_BUFFER)
2042                         widget->window,      GdkDrawable *drawable = priv->dbuf_pixmap;
2043    #else
2044        GdkDrawable *drawable = widget->window;
2045    #endif
2046    
2047    #ifdef DRAG_DEBUG
2048        printf("expose, map %d/%d\n", priv->map_x, priv->map_y);
2049    #endif
2050    
2051        if (!priv->drag_mouse_dx && !priv->drag_mouse_dy && event)
2052        {
2053    #ifdef DRAG_DEBUG
2054            printf("  dragging = %d, event = %p\n", priv->dragging, event);
2055    #endif
2056    
2057            gdk_draw_drawable (drawable,
2058                               widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
2059                               priv->pixmap,
2060                               event->area.x + EXTRA_BORDER, event->area.y + EXTRA_BORDER,
2061                               event->area.x, event->area.y,
2062                               event->area.width, event->area.height);
2063        }
2064        else
2065        {
2066    #ifdef DRAG_DEBUG
2067            printf("  drag_mouse %d/%d\n",
2068                   priv->drag_mouse_dx - EXTRA_BORDER,
2069                   priv->drag_mouse_dy - EXTRA_BORDER);
2070    #endif
2071    
2072            gdk_draw_drawable (drawable,
2073                               widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
2074                               priv->pixmap,
2075                               0,0,
2076                               priv->drag_mouse_dx - EXTRA_BORDER,
2077                               priv->drag_mouse_dy - EXTRA_BORDER,
2078                               -1,-1);
2079    
2080            //Paint white outside of the map if dragging. Its less
2081            //ugly than painting the corrupted map
2082            if(priv->drag_mouse_dx>EXTRA_BORDER) {
2083                gdk_draw_rectangle (drawable,
2084                                    widget->style->white_gc,
2085                                    TRUE,
2086                                    0, 0,
2087                                    priv->drag_mouse_dx - EXTRA_BORDER,
2088                                    widget->allocation.height);
2089            }
2090            else if (-priv->drag_mouse_dx > EXTRA_BORDER)
2091            {
2092                gdk_draw_rectangle (drawable,
2093                                    widget->style->white_gc,
2094                                    TRUE,
2095                                    priv->drag_mouse_dx + widget->allocation.width + EXTRA_BORDER, 0,
2096                                    -priv->drag_mouse_dx - EXTRA_BORDER,
2097                                    widget->allocation.height);
2098            }
2099    
2100            if (priv->drag_mouse_dy>EXTRA_BORDER) {
2101                gdk_draw_rectangle (drawable,
2102                                    widget->style->white_gc,
2103                                    TRUE,
2104                                    0, 0,
2105                                    widget->allocation.width,
2106                                    priv->drag_mouse_dy - EXTRA_BORDER);
2107            }
2108            else if (-priv->drag_mouse_dy > EXTRA_BORDER)
2109            {
2110                gdk_draw_rectangle (drawable,
2111                                    widget->style->white_gc,
2112                                    TRUE,
2113                                    0, priv->drag_mouse_dy + widget->allocation.height + EXTRA_BORDER,
2114                                    widget->allocation.width,
2115                                    -priv->drag_mouse_dy - EXTRA_BORDER);
2116            }
2117        }
2118    
2119    #ifdef ENABLE_OSD
2120        /* draw new OSD */
2121        if(priv->osd)
2122            priv->osd->draw (priv->osd, drawable);
2123    
2124    #ifdef OSD_DOUBLE_BUFFER
2125        gdk_draw_drawable (widget->window,
2126                         widget->style->fg_gc[GTK_WIDGET_STATE (widget)],                         widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
2127                         priv->pixmap,                         priv->dbuf_pixmap,
2128                         event->area.x + EXTRA_BORDER,                         0,0,0,0,-1,-1);
2129                         event->area.y + EXTRA_BORDER,  #endif
                        event->area.x, event->area.y,  
                        event->area.width, event->area.height);  
2130    
2131    #endif
2132    
2133      return FALSE;      return FALSE;
2134  }  }
2135    
# Line 2106  osm_gps_map_class_init (OsmGpsMapClass * Line 2211  osm_gps_map_class_init (OsmGpsMapClass *
2211                                                            G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));                                                            G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
2212    
2213      g_object_class_install_property (object_class,      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",  
                                                            "if true, the path passed to tile-cache is interpreted as the full cache path",  
                                                            FALSE,  
                                                            G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));  
   
     g_object_class_install_property (object_class,  
2214                                       PROP_ZOOM,                                       PROP_ZOOM,
2215                                       g_param_spec_int ("zoom",                                       g_param_spec_int ("zoom",
2216                                                         "zoom",                                                         "zoom",
# Line 2210  osm_gps_map_class_init (OsmGpsMapClass * Line 2307  osm_gps_map_class_init (OsmGpsMapClass *
2307                                                         "radius of the gps point inner circle",                                                         "radius of the gps point inner circle",
2308                                                         0,           /* minimum property value */                                                         0,           /* minimum property value */
2309                                                         G_MAXINT,    /* maximum property value */                                                         G_MAXINT,    /* maximum property value */
2310                                                         5,                                                         10,
2311                                                         G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));                                                         G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
2312    
2313      g_object_class_install_property (object_class,      g_object_class_install_property (object_class,
# Line 2231  osm_gps_map_class_init (OsmGpsMapClass * Line 2328  osm_gps_map_class_init (OsmGpsMapClass *
2328                                                         -1,           /* minimum property value */                                                         -1,           /* minimum property value */
2329                                                         G_MAXINT,    /* maximum property value */                                                         G_MAXINT,    /* maximum property value */
2330                                                         -1,                                                         -1,
2331                                                         G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));                                                         G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
2332    
2333      g_object_class_install_property (object_class,      g_object_class_install_property (object_class,
2334                                       PROP_IMAGE_FORMAT,                                       PROP_IMAGE_FORMAT,
# Line 2250  osm_gps_map_source_get_friendly_name(Osm Line 2347  osm_gps_map_source_get_friendly_name(Osm
2347          case OSM_GPS_MAP_SOURCE_NULL:          case OSM_GPS_MAP_SOURCE_NULL:
2348              return "None";              return "None";
2349          case OSM_GPS_MAP_SOURCE_OPENSTREETMAP:          case OSM_GPS_MAP_SOURCE_OPENSTREETMAP:
2350              return "OpenStreetMap";              return "OpenStreetMap I";
2351          case OSM_GPS_MAP_SOURCE_OPENSTREETMAP_RENDERER:          case OSM_GPS_MAP_SOURCE_OPENSTREETMAP_RENDERER:
2352              return "OpenStreetMap Renderer";              return "OpenStreetMap II";
2353          case OSM_GPS_MAP_SOURCE_OPENAERIALMAP:          case OSM_GPS_MAP_SOURCE_OPENCYCLEMAP:
2354              return "OpenAerialMap";              return "OpenCycleMap";
2355            case OSM_GPS_MAP_SOURCE_OSMC_TRAILS:
2356                return "OSMC Trails";
2357          case OSM_GPS_MAP_SOURCE_MAPS_FOR_FREE:          case OSM_GPS_MAP_SOURCE_MAPS_FOR_FREE:
2358              return "Maps-For-Free";              return "Maps-For-Free";
2359          case OSM_GPS_MAP_SOURCE_GOOGLE_STREET:          case OSM_GPS_MAP_SOURCE_GOOGLE_STREET:
# Line 2296  osm_gps_map_source_get_repo_uri(OsmGpsMa Line 2395  osm_gps_map_source_get_repo_uri(OsmGpsMa
2395              return OSM_REPO_URI;              return OSM_REPO_URI;
2396          case OSM_GPS_MAP_SOURCE_OPENSTREETMAP_RENDERER:          case OSM_GPS_MAP_SOURCE_OPENSTREETMAP_RENDERER:
2397              return "http://tah.openstreetmap.org/Tiles/tile/#Z/#X/#Y.png";              return "http://tah.openstreetmap.org/Tiles/tile/#Z/#X/#Y.png";
2398          case OSM_GPS_MAP_SOURCE_OPENAERIALMAP:          case OSM_GPS_MAP_SOURCE_OPENCYCLEMAP:
2399              return "http://tile.openaerialmap.org/tiles/1.0.0/openaerialmap-900913/#Z/#X/#Y.jpg";              return "http://c.andy.sandbox.cloudmade.com/tiles/cycle/#Z/#X/#Y.png";
2400            case OSM_GPS_MAP_SOURCE_OSMC_TRAILS:
2401                return "http://topo.geofabrik.de/trails/#Z/#X/#Y.png";
2402          case OSM_GPS_MAP_SOURCE_MAPS_FOR_FREE:          case OSM_GPS_MAP_SOURCE_MAPS_FOR_FREE:
2403              return "http://maps-for-free.com/layer/relief/z#Z/row#Y/#Z_#X-#Y.jpg";              return "http://maps-for-free.com/layer/relief/z#Z/row#Y/#Z_#X-#Y.jpg";
2404          case OSM_GPS_MAP_SOURCE_GOOGLE_STREET:          case OSM_GPS_MAP_SOURCE_GOOGLE_STREET:
# Line 2335  osm_gps_map_source_get_image_format(OsmG Line 2436  osm_gps_map_source_get_image_format(OsmG
2436          case OSM_GPS_MAP_SOURCE_NULL:          case OSM_GPS_MAP_SOURCE_NULL:
2437          case OSM_GPS_MAP_SOURCE_OPENSTREETMAP:          case OSM_GPS_MAP_SOURCE_OPENSTREETMAP:
2438          case OSM_GPS_MAP_SOURCE_OPENSTREETMAP_RENDERER:          case OSM_GPS_MAP_SOURCE_OPENSTREETMAP_RENDERER:
2439            case OSM_GPS_MAP_SOURCE_OPENCYCLEMAP:
2440            case OSM_GPS_MAP_SOURCE_OSMC_TRAILS:
2441              return "png";              return "png";
2442          case OSM_GPS_MAP_SOURCE_OPENAERIALMAP:          case OSM_GPS_MAP_SOURCE_MAPS_FOR_FREE:
2443          case OSM_GPS_MAP_SOURCE_GOOGLE_STREET:          case OSM_GPS_MAP_SOURCE_GOOGLE_STREET:
2444            case OSM_GPS_MAP_SOURCE_GOOGLE_SATELLITE:
2445          case OSM_GPS_MAP_SOURCE_GOOGLE_HYBRID:          case OSM_GPS_MAP_SOURCE_GOOGLE_HYBRID:
2446          case OSM_GPS_MAP_SOURCE_VIRTUAL_EARTH_STREET:          case OSM_GPS_MAP_SOURCE_VIRTUAL_EARTH_STREET:
2447          case OSM_GPS_MAP_SOURCE_VIRTUAL_EARTH_SATELLITE:          case OSM_GPS_MAP_SOURCE_VIRTUAL_EARTH_SATELLITE:
# Line 2345  osm_gps_map_source_get_image_format(OsmG Line 2449  osm_gps_map_source_get_image_format(OsmG
2449          case OSM_GPS_MAP_SOURCE_YAHOO_STREET:          case OSM_GPS_MAP_SOURCE_YAHOO_STREET:
2450          case OSM_GPS_MAP_SOURCE_YAHOO_SATELLITE:          case OSM_GPS_MAP_SOURCE_YAHOO_SATELLITE:
2451          case OSM_GPS_MAP_SOURCE_YAHOO_HYBRID:          case OSM_GPS_MAP_SOURCE_YAHOO_HYBRID:
         case OSM_GPS_MAP_SOURCE_MAPS_FOR_FREE:  
         case OSM_GPS_MAP_SOURCE_GOOGLE_SATELLITE:  
2452              return "jpg";              return "jpg";
2453          default:          default:
2454              return "bin";              return "bin";
# Line 2368  osm_gps_map_source_get_max_zoom(OsmGpsMa Line 2470  osm_gps_map_source_get_max_zoom(OsmGpsMa
2470          case OSM_GPS_MAP_SOURCE_NULL:          case OSM_GPS_MAP_SOURCE_NULL:
2471              return 18;              return 18;
2472          case OSM_GPS_MAP_SOURCE_OPENSTREETMAP:          case OSM_GPS_MAP_SOURCE_OPENSTREETMAP:
2473            case OSM_GPS_MAP_SOURCE_OPENCYCLEMAP:
2474              return OSM_MAX_ZOOM;              return OSM_MAX_ZOOM;
2475          case OSM_GPS_MAP_SOURCE_OPENSTREETMAP_RENDERER:          case OSM_GPS_MAP_SOURCE_OPENSTREETMAP_RENDERER:
         case OSM_GPS_MAP_SOURCE_OPENAERIALMAP:  
2476          case OSM_GPS_MAP_SOURCE_GOOGLE_STREET:          case OSM_GPS_MAP_SOURCE_GOOGLE_STREET:
2477          case OSM_GPS_MAP_SOURCE_GOOGLE_HYBRID:          case OSM_GPS_MAP_SOURCE_GOOGLE_HYBRID:
2478          case OSM_GPS_MAP_SOURCE_VIRTUAL_EARTH_STREET:          case OSM_GPS_MAP_SOURCE_VIRTUAL_EARTH_STREET:
# Line 2380  osm_gps_map_source_get_max_zoom(OsmGpsMa Line 2482  osm_gps_map_source_get_max_zoom(OsmGpsMa
2482          case OSM_GPS_MAP_SOURCE_YAHOO_SATELLITE:          case OSM_GPS_MAP_SOURCE_YAHOO_SATELLITE:
2483          case OSM_GPS_MAP_SOURCE_YAHOO_HYBRID:          case OSM_GPS_MAP_SOURCE_YAHOO_HYBRID:
2484              return 17;              return 17;
2485            case OSM_GPS_MAP_SOURCE_OSMC_TRAILS:
2486                return 15;
2487          case OSM_GPS_MAP_SOURCE_MAPS_FOR_FREE:          case OSM_GPS_MAP_SOURCE_MAPS_FOR_FREE:
2488              return 11;              return 11;
2489          case OSM_GPS_MAP_SOURCE_GOOGLE_SATELLITE:          case OSM_GPS_MAP_SOURCE_GOOGLE_SATELLITE:
# Line 2472  osm_gps_map_set_center (OsmGpsMap *map, Line 2576  osm_gps_map_set_center (OsmGpsMap *map,
2576    
2577      priv->center_rlat = deg2rad(latitude);      priv->center_rlat = deg2rad(latitude);
2578      priv->center_rlon = deg2rad(longitude);      priv->center_rlon = deg2rad(longitude);
     priv->center_coord_set = TRUE;  
2579    
2580      // pixel_x,y, offsets      // pixel_x,y, offsets
2581      pixel_x = lon2pixel(priv->map_zoom, priv->center_rlon);      pixel_x = lon2pixel(priv->map_zoom, priv->center_rlon);
# Line 2504  osm_gps_map_set_zoom (OsmGpsMap *map, in Line 2607  osm_gps_map_set_zoom (OsmGpsMap *map, in
2607          //constrain zoom min_zoom -> max_zoom          //constrain zoom min_zoom -> max_zoom
2608          priv->map_zoom = CLAMP(zoom, priv->min_zoom, priv->max_zoom);          priv->map_zoom = CLAMP(zoom, priv->min_zoom, priv->max_zoom);
2609    
2610          if (priv->center_coord_set)          priv->map_x = lon2pixel(priv->map_zoom, priv->center_rlon) - width_center;
2611          {          priv->map_y = lat2pixel(priv->map_zoom, priv->center_rlat) - height_center;
             priv->map_x = lon2pixel(priv->map_zoom, priv->center_rlon) - width_center;  
             priv->map_y = lat2pixel(priv->map_zoom, priv->center_rlat) - height_center;  
         }  
         else  
         {  
             factor = exp(priv->map_zoom * M_LN2)/exp(zoom_old * M_LN2);  
             priv->map_x = ((priv->map_x + width_center) * factor) - width_center;  
             priv->map_y = ((priv->map_y + height_center) * factor) - height_center;  
         }  
2612    
2613          g_debug("Zoom changed from %d to %d factor:%f x:%d",          g_debug("Zoom changed from %d to %d factor:%f x:%d",
2614                  zoom_old, priv->map_zoom, factor, priv->map_x);                  zoom_old, priv->map_zoom, factor, priv->map_x);
2615    
2616    #ifdef ENABLE_OSD
2617            /* OSD may contain a scale, so we may have to re-render it */
2618            if(priv->osd && OSM_IS_GPS_MAP (priv->osd->widget))
2619                priv->osd->render (priv->osd);
2620    #endif
2621    
2622          osm_gps_map_map_redraw_idle(map);          osm_gps_map_map_redraw_idle(map);
2623      }      }
2624      return priv->map_zoom;      return priv->map_zoom;
# Line 2604  osm_gps_map_clear_images (OsmGpsMap *map Line 2704  osm_gps_map_clear_images (OsmGpsMap *map
2704  }  }
2705    
2706  void  void
 osm_gps_map_osd_speed (OsmGpsMap *map, float speed)  
 {  
     OsmGpsMapPrivate *priv;  
   
     PangoContext        *context = NULL;  
     PangoLayout     *layout  = NULL;  
     PangoFontDescription    *desc    = NULL;  
   
     GdkColor color;  
     GdkGC *gc;  
   
     gchar *buffer;  
     //static int x = 10, y = 10;  
     static int width = 0, height = 0;  
   
     g_return_if_fail (OSM_IS_GPS_MAP (map));  
     priv = map->priv;  
   
     buffer = g_strdup_printf("%.0f", speed);  
   
     /* pango initialisation */  
     context = gtk_widget_get_pango_context (GTK_WIDGET(map));  
     layout  = pango_layout_new (context);  
     desc    = pango_font_description_new();  
   
     pango_font_description_set_size (desc, 40 * PANGO_SCALE);  
     pango_layout_set_font_description (layout, desc);  
     pango_layout_set_text (layout, buffer, strlen(buffer));  
   
     gc = gdk_gc_new (GTK_WIDGET(map)->window);  
   
     color.red = (0 > 50) ? 0xffff : 0;  
     color.green = 0;  
     color.blue = 0;  
   
     gdk_gc_set_rgb_fg_color (gc, &color);  
   
     /* faster / less flicker alternative:*/  
     gdk_draw_drawable (  
                        GTK_WIDGET(map)->window,  
                        GTK_WIDGET(map)->style->fg_gc[GTK_WIDGET_STATE(map)],  
                        priv->pixmap,  
                        0,0,  
                        0,0,  
                        width+10,width+10);  
   
     gdk_draw_layout(GTK_WIDGET(map)->window,  
                     gc,  
                     0, 0,  
                     layout);  
   
     /* set width and height */  
     pango_layout_get_pixel_size(layout, &width, &height);  
   
     g_free(buffer);  
     pango_font_description_free (desc);  
     g_object_unref (layout);  
     g_object_unref (gc);  
 }  
   
 void  
2707  osm_gps_map_draw_gps (OsmGpsMap *map, float latitude, float longitude, float heading)  osm_gps_map_draw_gps (OsmGpsMap *map, float latitude, float longitude, float heading)
2708  {  {
2709      int pixel_x, pixel_y;      int pixel_x, pixel_y;
# Line 2676  osm_gps_map_draw_gps (OsmGpsMap *map, fl Line 2715  osm_gps_map_draw_gps (OsmGpsMap *map, fl
2715      priv->gps->rlat = deg2rad(latitude);      priv->gps->rlat = deg2rad(latitude);
2716      priv->gps->rlon = deg2rad(longitude);      priv->gps->rlon = deg2rad(longitude);
2717      priv->gps_valid = TRUE;      priv->gps_valid = TRUE;
2718        priv->gps_heading = deg2rad(heading);
2719    
2720      // pixel_x,y, offsets      // pixel_x,y, offsets
2721      pixel_x = lon2pixel(priv->map_zoom, priv->gps->rlon);      pixel_x = lon2pixel(priv->map_zoom, priv->gps->rlon);
# Line 2706  osm_gps_map_draw_gps (OsmGpsMap *map, fl Line 2746  osm_gps_map_draw_gps (OsmGpsMap *map, fl
2746    
2747              priv->map_x = pixel_x - GTK_WIDGET(map)->allocation.width/2;              priv->map_x = pixel_x - GTK_WIDGET(map)->allocation.width/2;
2748              priv->map_y = pixel_y - GTK_WIDGET(map)->allocation.height/2;              priv->map_y = pixel_y - GTK_WIDGET(map)->allocation.height/2;
2749              priv->center_coord_set = FALSE;              center_coord_update(GTK_WIDGET(map));
2750          }          }
2751      }      }
2752    
# Line 2765  osm_gps_map_geographic_to_screen (OsmGps Line 2805  osm_gps_map_geographic_to_screen (OsmGps
2805      priv = map->priv;      priv = map->priv;
2806    
2807      if (pixel_x)      if (pixel_x)
2808          *pixel_x = lon2pixel(priv->map_zoom, deg2rad(longitude)) - priv->map_x;          *pixel_x = lon2pixel(priv->map_zoom, deg2rad(longitude)) -
2809                priv->map_x + priv->drag_mouse_dx;
2810      if (pixel_y)      if (pixel_y)
2811          *pixel_y = lat2pixel(priv->map_zoom, deg2rad(latitude)) - priv->map_y;          *pixel_y = lat2pixel(priv->map_zoom, deg2rad(latitude)) -
2812                priv->map_y + priv->drag_mouse_dy;
2813  }  }
2814    
2815  void  void
# Line 2778  osm_gps_map_scroll (OsmGpsMap *map, gint Line 2820  osm_gps_map_scroll (OsmGpsMap *map, gint
2820      g_return_if_fail (OSM_IS_GPS_MAP (map));      g_return_if_fail (OSM_IS_GPS_MAP (map));
2821      priv = map->priv;      priv = map->priv;
2822    
     priv->center_coord_set = FALSE;  
2823      priv->map_x += dx;      priv->map_x += dx;
2824      priv->map_y += dy;      priv->map_y += dy;
2825        center_coord_update(GTK_WIDGET(map));
2826    
2827    #ifdef ENABLE_OSD
2828        /* OSD may contain a coordinate, so we may have to re-render it */
2829        if(priv->osd && OSM_IS_GPS_MAP (priv->osd->widget))
2830            priv->osd->render (priv->osd);
2831    #endif
2832    
2833      osm_gps_map_map_redraw_idle (map);      osm_gps_map_map_redraw_idle (map);
2834  }  }
# Line 2790  osm_gps_map_get_scale(OsmGpsMap *map) Line 2838  osm_gps_map_get_scale(OsmGpsMap *map)
2838  {  {
2839      OsmGpsMapPrivate *priv;      OsmGpsMapPrivate *priv;
2840    
2841      g_return_val_if_fail (OSM_IS_GPS_MAP (map), OSM_NAN);      g_return_val_if_fail (OSM_IS_GPS_MAP (map), OSM_GPS_MAP_INVALID);
2842      priv = map->priv;      priv = map->priv;
2843    
2844      return osm_gps_map_get_scale_at_point(priv->map_zoom, priv->center_rlat, priv->center_rlon);      return osm_gps_map_get_scale_at_point(priv->map_zoom, priv->center_rlat, priv->center_rlon);
2845  }  }
2846    
2847    #ifdef ENABLE_OSD
2848    
2849    void
2850    osm_gps_map_redraw (OsmGpsMap *map)
2851    {
2852        osm_gps_map_map_redraw_idle(map);
2853    }
2854    
2855    osm_gps_map_osd_t *
2856    osm_gps_map_osd_get(OsmGpsMap *map)
2857    {
2858        g_return_val_if_fail (OSM_IS_GPS_MAP (map), NULL);
2859        return map->priv->osd;
2860    }
2861    
2862  void  void
2863  osm_gps_map_draw_balloon (OsmGpsMap *map, float latitude, float longitude,  osm_gps_map_register_osd(OsmGpsMap *map, osm_gps_map_osd_t *osd)
                           OsmGpsMapBalloonCallback cb, gpointer data)  
2864  {  {
2865      OsmGpsMapPrivate *priv;      OsmGpsMapPrivate *priv;
2866    
     /* remove and previously installed balloon */  
     osm_gps_map_clear_balloon (map);  
   
2867      g_return_if_fail (OSM_IS_GPS_MAP (map));      g_return_if_fail (OSM_IS_GPS_MAP (map));
     priv = map->priv;  
2868    
2869      priv->balloon.coo->rlat = deg2rad(latitude);      priv = map->priv;
2870      priv->balloon.coo->rlon = deg2rad(longitude);      g_return_if_fail (!priv->osd);
     priv->balloon.valid = TRUE;  
   
     priv->balloon.cb = cb;  
     priv->balloon.data = data;  
2871    
2872      // this redraws the map      priv->osd = osd;
     osm_gps_map_map_redraw_idle(map);  
2873  }  }
2874    
2875  void  void
2876  osm_gps_map_clear_balloon (OsmGpsMap *map)  osm_gps_map_repaint (OsmGpsMap *map)
2877  {  {
2878      OsmGpsMapPrivate *priv;      osm_gps_map_expose (GTK_WIDGET(map), NULL);
2879    }
2880    
2881      g_return_if_fail (OSM_IS_GPS_MAP (map));  coord_t *
2882      priv = map->priv;  osm_gps_map_get_gps (OsmGpsMap *map)
2883    {
2884        g_return_val_if_fail (OSM_IS_GPS_MAP (map), NULL);
2885    
2886      priv->balloon.valid = FALSE;      if(!map->priv->gps_valid)
2887            return NULL;
2888    
2889      osm_gps_map_map_redraw_idle(map);      return map->priv->gps;
2890  }  }
2891    
2892    #endif

Legend:
Removed from v.60  
changed lines
  Added in v.238