X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fmap.c;h=48f41f02160d2ac6896cc2637a2f4e3027b88d98;hb=75e019b4cb78f21a12118b2bebbda0ec565f5316;hp=147a11e77f6c8a5176ebba624941a4aaae6cbbd5;hpb=aa4e003b794af393a6c20a65baee9a050f4f5aee;p=mapper diff --git a/src/map.c b/src/map.c index 147a11e..48f41f0 100644 --- a/src/map.c +++ b/src/map.c @@ -1,26 +1,43 @@ -#include +/* + * This file is part of mapper + * + * Copyright (C) 2007 Kaj-Michael Lang + * Copyright (C) 2006-2007 John Costigan. + * + * POI and GPS-Info code originally written by Cezary Jackiewicz. + * + * Default map data provided by http://www.openstreetmap.org/ + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ -#define _GNU_SOURCE +#include #include #include #include #include #include -#include #include #include #include #include #include #include -#include -#include -#include -#include #include #include -#include #include "hildon-mapper.h" @@ -31,248 +48,274 @@ #include "osm-db.h" #include "poi.h" #include "route.h" +#include "track.h" #include "gps.h" -#include "bt.h" #include "mapper-types.h" #include "ui-common.h" #include "settings.h" #include "latlon.h" #include "gpx.h" +#include "speak.h" +#include "map-poi.h" +#include "map-download.h" +#include "announcements.h" +#include "gtkcompass.h" +#include "dialogs.h" +#include "image-cache.h" + +#define DEBUG_MAP_TIME 1 + +#define MAP_THUMB_MARGIN_X (100) +#define MAP_THUMB_MARGIN_Y (75) + +/* Initial size */ +#define BUF_WIDTH_TILES (4) +#define BUF_HEIGHT_TILES (3) +#define BUF_WIDTH_PIXELS (1024) +#define BUF_HEIGHT_PIXELS (768) + +static guint buf_width_tiles=BUF_WIDTH_TILES; +static guint buf_height_tiles=BUF_HEIGHT_TILES; +static guint buf_width_pixels=BUF_WIDTH_PIXELS; +static guint buf_height_pixels=BUF_HEIGHT_PIXELS; + +#ifdef WITH_GL +#include +#include +GdkGLConfig* map_gl_config=NULL; +#endif +gboolean map_gl=FALSE; -Point _min_center = { -1, -1 }; -Point _max_center = { -1, -1 }; -Point _focus = { -1, -1 }; +#ifdef WITH_CAIRO +cairo_t *ct_pixmap; +#endif + +/** The backing pixmap of map_widget. */ +static GdkPixmap *map_pixmap; + +/* Tile cache, this might need some adjustment */ +#define MAP_CACHE_MAX (64) +static ImageCache *map_ic; /** The "base tile" is the upper-left tile in the pixmap. */ guint _base_tilex = -5; guint _base_tiley = -5; +static guint map_max_zoom=MAX_ZOOM; guint _zoom = 3; /* zoom level, from 0 to MAX_ZOOM. */ -Point _center = { -1, -1 }; /* current center location, X. */ +Point _min_center = { -1, -1 }; +Point _max_center = { -1, -1 }; +Point _focus = { -1, -1 }; +/* current center location, X. */ +Point _center = { -1, -1 }; + +CenterMode _center_mode = CENTER_LEAD; + +/* Drag */ static guint press[2] = { 0, 0 }; static guint release[2] = { 0, 0 }; static guint before[2] = { 0, 0 }; -static guint _id = 0; +static guint map_drag_id = 0; +static gboolean map_dragged; + +/** VARIABLES FOR ACCESSING THE LOCATION/BOUNDS OF THE CURRENT MARK. */ +static gint mark_x1; +static gint mark_x2; +static gint mark_y1; +static gint mark_y2; +static gint mark_minx; +static gint mark_miny; +static gint mark_width; +static gint mark_height; + +static GdkRectangle scale_rect; +static PangoContext *scale_context; +static PangoFontDescription *scale_font; +static PangoLayout *scale_layout; + +static GdkGC *speed_gc1; +static GdkGC *speed_gc2; +static PangoContext *speed_context; +static PangoLayout *speed_layout; +static PangoFontDescription *speed_fontdesc; + +static gint zoom_timeout_sid=0; +static gint map_mode=0; +static gboolean map_data_needs_refresh=FALSE; + +osm_location map_loc = {NULL, NULL, NULL, FALSE, FALSE, 0, 0, 0.0, 0.0, 0 }; + +static GTimer *map_timer; + +/* Tile max age, 1 week */ +#define TILE_MAX_AGE (604800) + +#define KM10KNOTS (5.39956803) + +static void map_update_location(gdouble lat, gdouble lon, gboolean force); +static void map_speed_draw(void); +static gboolean map_cb_after_realize(GtkWidget *map_widget, gpointer data); +static gboolean map_cb_configure(GtkWidget *widget, GdkEventConfigure *event); +static gboolean map_cb_expose(GtkWidget * widget, GdkEventExpose * event); +static gboolean map_cb_button_press(GtkWidget * widget, GdkEventButton * event); +static gboolean map_cb_button_release(GtkWidget * widget, GdkEventButton * event); +static gboolean map_cb_scroll_event(GtkWidget * widget, GdkEventScroll * event); + +/******************************************************************************/ + +GtkWidget * +map_new(void) +{ +GtkWidget *map_widget; + +map_widget=gtk_drawing_area_new(); +map_timer=g_timer_new(); -static gint _zoom_timeout_sid=0; -static gint _map_mode=0; +map_ic=image_cache_new(MAP_CACHE_MAX); -guint _num_downloads=0; -guint _curr_download=0; +gtk_widget_set_extension_events(GTK_WIDGET(map_widget), GDK_EXTENSION_EVENTS_ALL); -static osm_location map_loc = {NULL, NULL, NULL, FALSE, FALSE, 0, 0, 0.0, 0.0 }; +#ifdef WITH_GL +map_gl_config=gdk_gl_config_new_by_mode(GDK_GL_MODE_RGB | GDK_GL_MODE_DEPTH); +if (map_gl_config) { + g_print("OpenGL version: %s\n", glGetString (GL_VERSION)); + g_print("OpenGL vendor: %s\n", glGetString (GL_VENDOR)); + g_print("OpenGL renderer: %s\n", glGetString (GL_RENDERER)); + gtk_widget_set_gl_capability(map_widget, map_gl_config, NULL, TRUE, GDK_GL_RGBA_TYPE); + map_gl=TRUE; +} +#endif -typedef struct _map_tile_rdata map_tile_rdata; -struct _map_tile_rdata { - guint tilex, tiley, zoom; - guint destx, desty; -}; +g_signal_connect_after(G_OBJECT(map_widget), "realize", G_CALLBACK(map_cb_after_realize), NULL); +g_signal_connect(G_OBJECT(map_widget), "configure_event", G_CALLBACK(map_cb_configure), NULL); -void map_render_paths(); -void map_force_redraw(); -gboolean curl_download_timeout(); -gchar *map_construct_url(guint tilex, guint tiley, guint zoom); -gboolean map_download_idle_refresh(ProgressUpdateInfo * pui); -static void map_update_location(gint x, gint y, gboolean force); +return map_widget; +} -gboolean get_next_pui(gpointer key, gpointer value, ProgressUpdateInfo ** data) +static gboolean +map_cb_after_realize(GtkWidget *map_widget, gpointer data) { -*data = key; +GdkColor color; + +g_debug("MAP: after_realize"); + +scale_context=gtk_widget_get_pango_context(map_widget); +scale_layout=pango_layout_new(scale_context); +scale_font=pango_font_description_new(); +pango_font_description_set_size(scale_font, 12 * PANGO_SCALE); +pango_layout_set_font_description(scale_layout, scale_font); + +/* Speed limit, over limit color */ +speed_gc1=gdk_gc_new(map_widget->window); +color.red=0xffff; +color.green=0; +color.blue=0; +gdk_gc_set_rgb_fg_color(speed_gc1, &color); + +/* Speed limit, under limit color */ +speed_gc2=gdk_gc_new(map_widget->window); +color.red=0; +color.green=0x1000; +color.blue=0; +gdk_gc_set_rgb_fg_color(speed_gc2, &color); + +speed_context=gtk_widget_get_pango_context(map_widget); +speed_layout=pango_layout_new(speed_context); +speed_fontdesc=pango_font_description_new(); +pango_font_description_set_size(speed_fontdesc, 48 * PANGO_SCALE); +pango_layout_set_font_description(speed_layout, speed_fontdesc); +pango_layout_set_alignment(speed_layout, PANGO_ALIGN_CENTER); + +/* Signals */ +g_signal_connect(G_OBJECT(map_widget), "expose_event", G_CALLBACK(map_cb_expose), NULL); +g_signal_connect(G_OBJECT(map_widget), "button_press_event", G_CALLBACK(map_cb_button_press), NULL); +g_signal_connect(G_OBJECT(map_widget), "button_release_event",G_CALLBACK(map_cb_button_release), NULL); +g_signal_connect(G_OBJECT(map_widget), "scroll_event", G_CALLBACK(map_cb_scroll_event), NULL); + +gtk_widget_add_events(map_widget, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + | GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK); + +map_poi_init(map_widget); + return TRUE; } -gboolean curl_download_timeout() +static gboolean +map_cb_configure(GtkWidget *widget, GdkEventConfigure *event) { - static guint destroy_counter = 50; - gint num_transfers = 0, num_msgs = 0; - gint deletes_left = 50; /* only do 50 deletes at a time. */ - CURLMsg *msg; - vprintf("%s()\n", __PRETTY_FUNCTION__); - - if (_curl_multi && CURLM_CALL_MULTI_PERFORM == curl_multi_perform(_curl_multi, &num_transfers)) - return TRUE; /* Give UI a chance first. */ - - while (_curl_multi && (msg = curl_multi_info_read(_curl_multi, &num_msgs))) { - if (msg->msg == CURLMSG_DONE) { - if (msg->easy_handle == _autoroute_data.curl_easy) { - /* This is the autoroute download. */ - /* Now, parse the autoroute and update the display. */ - if (_autoroute_data.enabled - && parse_gpx(&_route, - _autoroute_data.rdl_data.bytes, - _autoroute_data.rdl_data. - bytes_read, 0)) { - /* Find the nearest route point, if we're connected. */ - route_find_nearest_point(); - map_force_redraw(); - } - cancel_autoroute(TRUE); /* We're done. Clean up. */ - } else { - ProgressUpdateInfo *pui = g_hash_table_lookup(_pui_by_easy, msg->easy_handle); - g_queue_push_head(_curl_easy_queue, msg->easy_handle); - g_hash_table_remove(_pui_by_easy, msg->easy_handle); - fclose(pui->file); - if (msg->data.result != CURLE_OK) - g_unlink(pui->dest_str); /* Delete so we try again. */ - curl_multi_remove_handle(_curl_multi, msg->easy_handle); - g_idle_add_full(G_PRIORITY_HIGH_IDLE, - (GSourceFunc)map_download_idle_refresh, pui, NULL); - } - } - } +guint tw, th; - /* Up to 1 transfer per tile. */ - while (num_transfers < (BUF_WIDTH_TILES * BUF_HEIGHT_TILES) - && g_tree_nnodes(_pui_tree)) { - ProgressUpdateInfo *pui; - g_tree_foreach(_pui_tree, (GTraverseFunc) get_next_pui, &pui); - - if (pui->retries) { - /* This is a download. */ - FILE *f; - g_tree_steal(_pui_tree, pui); - g_tree_insert(_downloading_tree, pui, pui); - - pui->src_str = map_construct_url(pui->tilex, pui->tiley, pui->zoom); - pui->dest_str = g_strdup_printf("%s/%u/%u/%u.jpg", - pui->repo->cache_dir, pui->zoom, - pui->tilex, pui->tiley); - - if (!pui->src_str) { - /* Failed to generate URL. */ - g_idle_add_full(G_PRIORITY_HIGH_IDLE,(GSourceFunc)map_download_idle_refresh, pui, NULL); - continue; - } +tw=TILE_SIZE_PIXELS*((widget->allocation.width/TILE_SIZE_PIXELS)+2); +th=TILE_SIZE_PIXELS*((widget->allocation.height/TILE_SIZE_PIXELS)+2); - /* Check to see if we need to overwrite. */ - if (pui->retries > 0) { - /* We're not updating - check if file already exists. */ - if (g_file_test(pui->dest_str, G_FILE_TEST_EXISTS)) { - g_idle_add_full(G_PRIORITY_HIGH_IDLE, - (GSourceFunc)map_download_idle_refresh, pui, NULL); - continue; - } - } +if (map_pixmap==NULL) { + map_pixmap=gdk_pixmap_new(widget->window, tw, th, -1); +} else { + if (tw>buf_width_pixels || th>buf_height_pixels) { + g_object_unref(map_pixmap); + map_pixmap=gdk_pixmap_new(widget->window, tw, th, -1); + } else if (twwindow, tw, th, -1); + } +} +g_assert(map_pixmap); - /* Attempt to open the file for writing. */ - if (!(f = g_fopen(pui->dest_str, "w")) - && errno == ENOENT) { - /* Directory doesn't exist yet - create it, then we'll retry */ - gchar buffer[BUFFER_SIZE]; - snprintf(buffer, sizeof(buffer), "%s/%u/%u", - pui->repo->cache_dir, pui->zoom, - pui->tilex); - g_mkdir_with_parents(buffer, 0775); - f = g_fopen(pui->dest_str, "w"); - } +buf_width_pixels=tw; +buf_height_pixels=th; +buf_width_tiles=buf_width_pixels/TILE_SIZE_PIXELS; +buf_height_tiles=buf_height_pixels/TILE_SIZE_PIXELS; - if (f) { - CURL *curl_easy; - pui->file = f; - curl_easy = g_queue_pop_tail(_curl_easy_queue); - if (!curl_easy) { - /* Need a new curl_easy. */ - MACRO_CURL_EASY_INIT(curl_easy); - } - curl_easy_setopt(curl_easy, CURLOPT_URL, pui->src_str); - curl_easy_setopt(curl_easy, CURLOPT_WRITEDATA, f); - g_hash_table_insert(_pui_by_easy, curl_easy, pui); - if (!_curl_multi) { - /* Initialize CURL. */ - _curl_multi = curl_multi_init(); - /*curl_multi_setopt(_curl_multi, CURLMOPT_PIPELINING, 1); */ - } - curl_multi_add_handle(_curl_multi, curl_easy); - num_transfers++; - } else { - /* Unable to download file. */ - gchar buffer[BUFFER_SIZE]; - snprintf(buffer, sizeof(buffer), "%s:\n%s", - _("Failed to open file for writing"), - pui->dest_str); - MACRO_BANNER_SHOW_INFO(_window, buffer); - g_idle_add_full(G_PRIORITY_HIGH_IDLE, - (GSourceFunc)map_download_idle_refresh, pui, - NULL); - continue; - } - } else if (--deletes_left) { - /* This is a delete. */ - gchar buffer[BUFFER_SIZE]; - g_tree_steal(_pui_tree, pui); - g_tree_insert(_downloading_tree, pui, pui); - - snprintf(buffer, sizeof(buffer), "%s/%u/%u/%u.jpg", - pui->repo->cache_dir, pui->zoom, pui->tilex, - pui->tiley); - g_unlink(buffer); - g_idle_add_full(G_PRIORITY_HIGH_IDLE, - (GSourceFunc)map_download_idle_refresh, - pui, NULL); - } else - break; - } +_screen_width_pixels = widget->allocation.width; +_screen_height_pixels = widget->allocation.height; +_screen_grids_halfwidth = pixel2grid(_screen_width_pixels) / 2; +_screen_grids_halfheight = pixel2grid(_screen_height_pixels) / 2; - if (!(num_transfers || g_tree_nnodes(_pui_tree))) { - /* Destroy curl after 50 counts (5 seconds). */ - if (--destroy_counter) { - /* Clean up curl. */ - CURL *curr; - while ((curr = g_queue_pop_tail(_curl_easy_queue))) - curl_easy_cleanup(curr); +/* Set scale_rect. */ +scale_rect.x = (_screen_width_pixels - SCALE_WIDTH) / 2; +scale_rect.width = SCALE_WIDTH; - curl_multi_cleanup(_curl_multi); - _curl_multi = NULL; +MACRO_RECALC_FOCUS_BASE(_center_ratio); +MACRO_RECALC_FOCUS_SIZE(_center_ratio); - _curl_sid = 0; - vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__); - return FALSE; - } - } else - destroy_counter = 50; +_min_center.unitx = pixel2unit(grid2pixel(_screen_grids_halfwidth)); +_min_center.unity = pixel2unit(grid2pixel(_screen_grids_halfheight)); +_max_center.unitx = WORLD_SIZE_UNITS - grid2unit(_screen_grids_halfwidth) - 1; +_max_center.unity = WORLD_SIZE_UNITS - grid2unit(_screen_grids_halfheight) - 1; - vprintf("%s(): return TRUE (%d, %d)\n", __PRETTY_FUNCTION__, - num_transfers, g_tree_nnodes(_pui_tree)); - return TRUE; +map_force_redraw(); +return TRUE; } /** * Draw the current mark (representing the current GPS location) onto * _map_widget. This method does not queue the draw area. */ -void map_draw_mark() +static void +map_draw_mark(Gps *gps) { - printf("%s()\n", __PRETTY_FUNCTION__); - - gdk_draw_arc(_map_widget->window, _conn_state == RCVR_FIXED ? _gc[COLORABLE_MARK] : _gc[COLORABLE_MARK_OLD], FALSE, /* not filled. */ - _mark_x1 - _draw_width, _mark_y1 - _draw_width, - 2 * _draw_width, 2 * _draw_width, 0, 360 * 64); - gdk_draw_line(_map_widget->window, - _conn_state == RCVR_FIXED ? (_show_velvec ? _gc[COLORABLE_MARK_VELOCITY] : _gc[COLORABLE_MARK]) : _gc[COLORABLE_MARK_OLD], - _mark_x1, _mark_y1, _mark_x2, _mark_y2); - - vprintf("%s(): return\n", __PRETTY_FUNCTION__); +gdk_draw_arc(_map_widget->window, gps->io.conn == RCVR_FIXED ? _gc[COLORABLE_MARK] : _gc[COLORABLE_MARK_OLD], FALSE, + mark_x1 - _draw_width, mark_y1 - _draw_width, 2 * _draw_width, 2 * _draw_width, 0, 360 * 64); +gdk_draw_line(_map_widget->window, gps->io.conn == RCVR_FIXED ? (_show_velvec ? _gc[COLORABLE_MARK_VELOCITY] : _gc[COLORABLE_MARK]) : _gc[COLORABLE_MARK_OLD], + mark_x1, mark_y1, mark_x2, mark_y2); } /** * "Set" the mark, which translates the current GPS position into on-screen * units in preparation for drawing the mark with map_draw_mark(). */ -void map_set_mark() +void +map_set_mark(GpsData *gps) { - printf("%s()\n", __PRETTY_FUNCTION__); - - _mark_x1 = unit2x(_pos.unitx); - _mark_y1 = unit2y(_pos.unity); - _mark_x2 = _mark_x1 + (_show_velvec ? _vel_offsetx : 0); - _mark_y2 = _mark_y1 + (_show_velvec ? _vel_offsety : 0); - _mark_minx = MIN(_mark_x1, _mark_x2) - (2 * _draw_width); - _mark_miny = MIN(_mark_y1, _mark_y2) - (2 * _draw_width); - _mark_width = abs(_mark_x1 - _mark_x2) + (4 * _draw_width); - _mark_height = abs(_mark_y1 - _mark_y2) + (4 * _draw_width); - - vprintf("%s(): return\n", __PRETTY_FUNCTION__); +mark_x1 = unit2x(gps->unitx); +mark_y1 = unit2y(gps->unity); +mark_x2 = mark_x1 + (_show_velvec ? gps->vel_offsetx : 0); +mark_y2 = mark_y1 + (_show_velvec ? gps->vel_offsety : 0); +mark_minx = MIN(mark_x1, mark_x2) - (2 * _draw_width); +mark_miny = MIN(mark_y1, mark_y2) - (2 * _draw_width); +mark_width = abs(mark_x1 - mark_x2) + (4 * _draw_width); +mark_height = abs(mark_y1 - mark_y2) + (4 * _draw_width); } /** @@ -281,457 +324,225 @@ void map_set_mark() * this method, but I guess it's not general-purpose enough. */ static void -map_pixbuf_scale_inplace(GdkPixbuf * pixbuf, guint ratio_p2, guint src_x, guint src_y) +map_pixbuf_scale_inplace(GdkPixbuf *pixbuf, guint ratio_p2, guint src_x, guint src_y) { - guint dest_x = 0, dest_y = 0, dest_dim = TILE_SIZE_PIXELS; - guint rowstride = gdk_pixbuf_get_rowstride(pixbuf); - guint n_channels = gdk_pixbuf_get_n_channels(pixbuf); - guchar *pixels = gdk_pixbuf_get_pixels(pixbuf); +guint dest_x = 0, dest_y = 0, dest_dim = TILE_SIZE_PIXELS; +guint rowstride = gdk_pixbuf_get_rowstride(pixbuf); +guint n_channels = gdk_pixbuf_get_n_channels(pixbuf); +guchar *pixels = gdk_pixbuf_get_pixels(pixbuf); - vprintf("%s(%d, %d, %d)\n", __PRETTY_FUNCTION__, ratio_p2, src_x, src_y); +/* Sweep through the entire dest area, copying as necessary, but + * DO NOT OVERWRITE THE SOURCE AREA. We'll copy it afterward. */ +do { + guint src_dim = dest_dim >> ratio_p2; + guint src_endx = src_x - dest_x + src_dim; + gint x, y; - /* Sweep through the entire dest area, copying as necessary, but - * DO NOT OVERWRITE THE SOURCE AREA. We'll copy it afterward. */ - do { - guint src_dim = dest_dim >> ratio_p2; - guint src_endx = src_x - dest_x + src_dim; - gint x, y; + for (y = dest_dim - 1; y >= 0; y--) { + guint src_offset_y, dest_offset_y; - for (y = dest_dim - 1; y >= 0; y--) { - guint src_offset_y, dest_offset_y; + src_offset_y = (src_y + (y >> ratio_p2)) * rowstride; + dest_offset_y = (dest_y + y) * rowstride; + x = dest_dim - 1; - src_offset_y = (src_y + (y >> ratio_p2)) * rowstride; - dest_offset_y = (dest_y + y) * rowstride; - x = dest_dim - 1; + if ((unsigned)(dest_y + y - src_y) < src_dim && (unsigned)(dest_x + x - src_x) < src_dim) + x -= src_dim; - if ((unsigned)(dest_y + y - src_y) < src_dim - && (unsigned)(dest_x + x - src_x) < src_dim) - x -= src_dim; - - for (; x >= 0; x--) { - guint src_offset, dest_offset, i; + for (; x >= 0; x--) { + guint src_offset, dest_offset, i; - src_offset = src_offset_y + (src_x + (x >> ratio_p2)) * n_channels; - dest_offset = dest_offset_y + (dest_x + x) * n_channels; + src_offset = src_offset_y + (src_x + (x >> ratio_p2)) * n_channels; + dest_offset = dest_offset_y + (dest_x + x) * n_channels; - pixels[dest_offset] = pixels[src_offset]; - for (i = n_channels - 1; i; i--) - pixels[dest_offset + i] = pixels[src_offset + i]; + pixels[dest_offset] = pixels[src_offset]; + for (i = n_channels - 1; i; i--) + pixels[dest_offset + i] = pixels[src_offset + i]; - if ((unsigned)(dest_y + y - src_y) < src_dim && x == src_endx) - x -= src_dim; - } + if ((unsigned)(dest_y + y - src_y) < src_dim && x == src_endx) + x -= src_dim; } - /* Reuse src_dim and src_endx to store new src_x and src_y. */ - src_dim = src_x + ((src_x - dest_x) >> ratio_p2); - src_endx = src_y + ((src_y - dest_y) >> ratio_p2); - dest_x = src_x; - dest_y = src_y; - src_x = src_dim; - src_y = src_endx; } - while ((dest_dim >>= ratio_p2) > 1); - vprintf("%s(): return\n", __PRETTY_FUNCTION__); + /* Reuse src_dim and src_endx to store new src_x and src_y. */ + src_dim = src_x + ((src_x - dest_x) >> ratio_p2); + src_endx = src_y + ((src_y - dest_y) >> ratio_p2); + dest_x = src_x; + dest_y = src_y; + src_x = src_dim; + src_y = src_endx; +} +while ((dest_dim >>= ratio_p2) > 1); } /** * Trim pixbufs that are bigger than tiles. (Those pixbufs result, when * captions should be cut off.) */ -static GdkPixbuf *pixbuf_trim(GdkPixbuf * pixbuf) +static GdkPixbuf * +pixbuf_trim(GdkPixbuf * pixbuf) { - vprintf("%s()\n", __PRETTY_FUNCTION__); - GdkPixbuf *mpixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, gdk_pixbuf_get_has_alpha(pixbuf), - 8, TILE_SIZE_PIXELS, TILE_SIZE_PIXELS); - - gdk_pixbuf_copy_area(pixbuf, - (gdk_pixbuf_get_width(pixbuf) - TILE_SIZE_PIXELS) / 2, - (gdk_pixbuf_get_height(pixbuf) - TILE_SIZE_PIXELS) / 2, - TILE_SIZE_PIXELS, - TILE_SIZE_PIXELS, mpixbuf, 0, 0); - - g_object_unref(pixbuf); - vprintf("%s(): return\n", __PRETTY_FUNCTION__); - return mpixbuf; +GdkPixbuf *mpixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, gdk_pixbuf_get_has_alpha(pixbuf), + 8, TILE_SIZE_PIXELS, TILE_SIZE_PIXELS); + +g_debug("TRIM!!"); +gdk_pixbuf_copy_area(pixbuf, + (gdk_pixbuf_get_width(pixbuf) - TILE_SIZE_PIXELS) / 2, + (gdk_pixbuf_get_height(pixbuf) - TILE_SIZE_PIXELS) / 2, + TILE_SIZE_PIXELS, + TILE_SIZE_PIXELS, mpixbuf, 0, 0); + +g_object_unref(pixbuf); +return mpixbuf; } -/** - * Given a wms uri pattern, compute the coordinate transformation and - * trimming. - * 'proj' is used for the conversion - */ -static gchar *map_convert_wms_to_wms(gint tilex, gint tiley, gint zoomlevel, - gchar * uri) +GdkPixmap * +map_pixmap_get(void) { - gint system_retcode; - gchar cmd[BUFFER_SIZE], srs[BUFFER_SIZE]; - gchar *ret = NULL; - FILE *in; - gdouble lon1, lat1, lon2, lat2; - - gchar *widthstr = strcasestr(uri, "WIDTH="); - gchar *heightstr = strcasestr(uri, "HEIGHT="); - gchar *srsstr = strcasestr(uri, "SRS=EPSG"); - gchar *srsstre = strchr(srsstr, '&'); - vprintf("%s()\n", __PRETTY_FUNCTION__); - - /* missing: test if found */ - strcpy(srs, "epsg"); - strncpy(srs + 4, srsstr + 8, 256); - /* missing: test srsstre-srsstr < 526 */ - srs[srsstre - srsstr - 4] = 0; - /* convert to lower, as WMC is EPSG and cs2cs is epsg */ - - gint dwidth = widthstr ? atoi(widthstr + 6) - TILE_SIZE_PIXELS : 0; - gint dheight = heightstr ? atoi(heightstr + 7) - TILE_SIZE_PIXELS : 0; - - unit2latlon(tile2zunit(tilex, zoomlevel) - - pixel2zunit(dwidth / 2, zoomlevel), - tile2zunit(tiley + 1, zoomlevel) - + pixel2zunit((dheight + 1) / 2, zoomlevel), lat1, lon1); - - unit2latlon(tile2zunit(tilex + 1, zoomlevel) - + pixel2zunit((dwidth + 1) / 2, zoomlevel), - tile2zunit(tiley, zoomlevel) - - pixel2zunit(dheight / 2, zoomlevel), lat2, lon2); - - setlocale(LC_NUMERIC, "C"); - - snprintf(cmd, sizeof(cmd), - "(echo \"%.6f %.6f\"; echo \"%.6f %.6f\") | " - "/usr/bin/cs2cs +proj=longlat +datum=WGS84 +to +init=%s -f %%.6f " - " > /tmp/tmpcs2cs ", lon1, lat1, lon2, lat2, srs); - vprintf("Running command: %s\n", cmd); - system_retcode = system(cmd); - - if (system_retcode) - g_printerr("cs2cs returned error code %d\n", - WEXITSTATUS(system_retcode)); - else if (!(in = g_fopen("/tmp/tmpcs2cs", "r"))) - g_printerr("Cannot open results of conversion\n"); - else if (5 != - fscanf(in, "%lf %lf %s %lf %lf", &lon1, &lat1, cmd, &lon2, &lat2)) { - g_printerr("Wrong conversion\n"); - fclose(in); - } else { - fclose(in); - ret = g_strdup_printf(uri, lon1, lat1, lon2, lat2); - } - - setlocale(LC_NUMERIC, ""); - - vprintf("%s(): return %s\n", __PRETTY_FUNCTION__, ret); - return ret; +return map_pixmap; } -/** - * Given the xyz coordinates of our map coordinate system, write the qrst - * quadtree coordinates to buffer. - */ -static void -map_convert_coords_to_quadtree_string(gint x, gint y, gint zoomlevel, - gchar * buffer, const gchar initial, - const gchar * const quadrant) +static GdkPixbuf * +map_tile_load(guint tilex, guint tiley, gint zoff, gboolean download) { - gchar *ptr = buffer; - gint n; - vprintf("%s()\n", __PRETTY_FUNCTION__); - - if (initial) - *ptr++ = initial; - - for (n = 16 - zoomlevel; n >= 0; n--) { - gint xbit = (x >> n) & 1; - gint ybit = (y >> n) & 1; - *ptr++ = quadrant[xbit + 2 * ybit]; +GdkPixbuf *pixbuf; +GError *error = NULL; +gchar buffer[BUFFER_SIZE]; +gchar key[BUFFER_SIZE]; +struct stat tstat; +gint se; + +g_snprintf(buffer, sizeof(buffer), "%s/%u/%u/%u.jpg", _curr_repo->cache_dir, _zoom + zoff, (tilex >> zoff), (tiley >> zoff)); +g_snprintf(key, sizeof(key), "%s/%u/%u/%u", _curr_repo->cache_dir, _zoom + zoff, (tilex >> zoff), (tiley >> zoff)); + +pixbuf=image_cache_get(map_ic, key, buffer); +if (!pixbuf) { + g_unlink(buffer); + + if (_auto_download && _curr_repo->type != REPOTYPE_NONE && !((_zoom + zoff - (_curr_repo->double_size ? 1 : 0)) % _curr_repo->dl_zoom_steps)) { + if (download) + map_initiate_download(tilex >> zoff, tiley >> zoff, _zoom + zoff, -INITIAL_DOWNLOAD_RETRIES); } - *ptr++ = '\0'; - vprintf("%s(): return\n", __PRETTY_FUNCTION__); + return NULL; } -/** - * Construct the URL that we should fetch, based on the current URI format. - * This method works differently depending on if a "%s" string is present in - * the URI format, since that would indicate a quadtree-based map coordinate - * system. - */ -static gchar *map_construct_url(guint tilex, guint tiley, guint zoom) -{ - vprintf("%s()\n", __PRETTY_FUNCTION__); - switch (_curr_repo->type) { - case REPOTYPE_XYZ: - return g_strdup_printf(_curr_repo->url, tilex, tiley, zoom); - - case REPOTYPE_XYZ_INV: - return g_strdup_printf(_curr_repo->url, 17 - zoom, tilex, - tiley); - - case REPOTYPE_QUAD_QRST: - { - gchar location[MAX_ZOOM + 2]; - map_convert_coords_to_quadtree_string(tilex, tiley, - zoom, location, - 't', "qrts"); - return g_strdup_printf(_curr_repo->url, location); - } - - case REPOTYPE_QUAD_ZERO: - { - /* This is a zero-based quadtree URI. */ - gchar location[MAX_ZOOM + 2]; - map_convert_coords_to_quadtree_string(tilex, tiley, - zoom, location, - '\0', "0123"); - return g_strdup_printf(_curr_repo->url, location); - } +g_object_ref(pixbuf); - case REPOTYPE_WMS: - return map_convert_wms_to_wms(tilex, tiley, zoom, - _curr_repo->url); +#if 0 +/* Check if we need to trim. */ +if (gdk_pixbuf_get_width(pixbuf) != TILE_SIZE_PIXELS || gdk_pixbuf_get_height(pixbuf) != TILE_SIZE_PIXELS) + pixbuf=pixbuf_trim(pixbuf); +#endif - default: - return NULL; +/* Check tile age, if file date is ower a week old, redownload if autodownload enabled */ +se=stat(buffer, &tstat); +if (se==0) { + time_t t; + t=time(NULL); + if (t-tstat.st_mtime>TILE_MAX_AGE) { + if (_auto_download && _curr_repo->type != REPOTYPE_NONE && !((_zoom + zoff - (_curr_repo->double_size ? 1 : 0)) % _curr_repo->dl_zoom_steps)) { + if (download) { + g_debug("Tile: %s is old, re-downloading\n", buffer); + map_initiate_download(tilex >> zoff, tiley >> zoff, _zoom + zoff, -INITIAL_DOWNLOAD_RETRIES); + image_cache_invalidate(map_ic, key); + } + } } - vprintf("%s(): ERROR\n", __PRETTY_FUNCTION__); - return ""; } -#ifdef WITH_OSSO -void con_check_connection(void) -{ -iap_connect(); -} -#else -void con_check_connection(void) -{ -/* NetworkManager support ? */ +return pixbuf; } -#endif -/** - * Initiate a download of the given xyz coordinates using the given buffer - * as the URL. If the map already exists on disk, or if we are already - * downloading the map, then this method does nothing. - */ -void map_initiate_download(guint tilex, guint tiley, guint zoom, gint retries) +gboolean +map_render_tile(guint tilex, guint tiley, guint destx, guint desty, gboolean fast_fail) { - ProgressUpdateInfo *pui; - vprintf("%s(%u, %u, %u, %d)\n", __PRETTY_FUNCTION__, tilex, tiley, zoom, - retries); - - con_check_connection(); - - pui = g_slice_new(ProgressUpdateInfo); - pui->tilex = tilex; - pui->tiley = tiley; - pui->zoom = zoom; - pui->priority = (abs((gint) tilex - unit2tile(_center.unitx)) - + abs((gint) tiley - unit2tile(_center.unity))); - if (!retries) - pui->priority = -pui->priority; /* "Negative" makes them lowest pri. */ - pui->retries = retries; - pui->repo = _curr_repo; - - if (g_tree_lookup(_pui_tree, pui) - || g_tree_lookup(_downloading_tree, pui)) { - /* Already downloading. */ - g_slice_free(ProgressUpdateInfo, pui); - return; - } - pui->src_str = NULL; - pui->dest_str = NULL; - pui->file = NULL; +GdkPixbuf *pixbuf=NULL; +gint zoff; - g_tree_insert(_pui_tree, pui, pui); -#ifdef WITH_OSSO - if (iap_is_connected() && !_curl_sid) -#endif - _curl_sid = g_timeout_add(100, (GSourceFunc) curl_download_timeout, NULL); +if (destx > buf_width_pixels || desty > buf_height_pixels) + return FALSE; - if (!_num_downloads++ && !_download_banner) - _download_banner = hildon_banner_show_progress(_window, NULL,_("Downloading maps")); +if (tilex > _world_size_tiles || tiley > _world_size_tiles) + return FALSE; - vprintf("%s(): return\n", __PRETTY_FUNCTION__); -} +g_debug("MAP RT: %u %u (%u) %u %u (%u, %u)", tilex, tiley, _world_size_tiles, destx, desty, buf_width_tiles, buf_height_tiles); -void -map_render_tile(guint tilex, guint tiley, guint destx, guint desty, - gboolean fast_fail) -{ - GdkPixbuf *pixbuf = NULL; - gchar buffer[BUFFER_SIZE]; - GError *error = NULL; - gint zoff; - - vprintf("%s(%u, %u, %u, %u)\n", __PRETTY_FUNCTION__, - tilex, tiley, destx, desty); - - if (tilex < _world_size_tiles && tiley < _world_size_tiles) { - /* The tile is possible. */ - for (zoff = (_curr_repo->double_size ? 1 : 0); - !pixbuf && (_zoom + zoff) <= MAX_ZOOM - && zoff <= TILE_SIZE_P2; zoff += 1) { - snprintf(buffer, sizeof(buffer), "%s/%u/%u/%u.jpg", - _curr_repo->cache_dir, _zoom + zoff, - (tilex >> zoff), (tiley >> zoff)); - - pixbuf = gdk_pixbuf_new_from_file(buffer, &error); - if (error || !pixbuf) { - /* Delete so we try again some other day. */ - g_unlink(buffer); - pixbuf = NULL; - error = NULL; - - /* Download, if we should. */ - if (_auto_download && _curr_repo->type != REPOTYPE_NONE && - !((_zoom + zoff - (_curr_repo->double_size ? 1 : 0)) % _curr_repo->dl_zoom_steps)) { - if (!fast_fail) - map_initiate_download(tilex >> zoff, - tiley >> zoff, - _zoom + zoff, - -INITIAL_DOWNLOAD_RETRIES); - fast_fail = TRUE; - } - } else { - /* Check if we need to trim. */ - if (gdk_pixbuf_get_width(pixbuf) != TILE_SIZE_PIXELS || gdk_pixbuf_get_height(pixbuf) != TILE_SIZE_PIXELS) - pixbuf = pixbuf_trim(pixbuf); - - /* Check if we need to blit. */ - if (zoff) { - map_pixbuf_scale_inplace(pixbuf, zoff, - (tilex - ((tilex >> zoff) << zoff)) << (TILE_SIZE_P2 - zoff), - (tiley - ((tiley >> zoff) << zoff)) << (TILE_SIZE_P2 - zoff)); - } - } - } - } - - if (pixbuf) { - gdk_draw_pixbuf(_map_pixmap, - _gc[COLORABLE_MARK], - pixbuf, 0, 0, destx, desty, - TILE_SIZE_PIXELS, TILE_SIZE_PIXELS, - GDK_RGB_DITHER_NONE, 0, 0); - g_object_unref(pixbuf); +/* The tile is possible. */ +for (zoff = (_curr_repo->double_size ? 1 : 0); !pixbuf && (_zoom + zoff) <= map_max_zoom && zoff <= TILE_SIZE_P2; zoff += 1) { + pixbuf=map_tile_load(tilex, tiley, zoff, !fast_fail); + if (!pixbuf) { + if (!fast_fail) + fast_fail=TRUE; } else { - gdk_draw_rectangle(_map_pixmap, _map_widget->style->black_gc, - TRUE, destx, desty, TILE_SIZE_PIXELS, TILE_SIZE_PIXELS); + /* Check if we need to blit. */ + if (zoff) { + map_pixbuf_scale_inplace(pixbuf, zoff, + (tilex - ((tilex >> zoff) << zoff)) << (TILE_SIZE_P2 - zoff), + (tiley - ((tiley >> zoff) << zoff)) << (TILE_SIZE_P2 - zoff)); + image_cache_invalidate_by_image(map_ic, pixbuf); + } } - - vprintf("%s(): return\n", __PRETTY_FUNCTION__); } -gboolean map_render_tile_idle(map_tile_rdata *mtr) -{ -map_render_tile(mtr->tilex, mtr->tiley, mtr->destx, mtr->desty, FALSE); -gtk_widget_queue_draw_area(_map_widget, mtr->destx, mtr->desty, TILE_SIZE_PIXELS, TILE_SIZE_PIXELS); - -g_slice_free(map_tile_rdata, mtr); -return FALSE; +if (pixbuf) { + gdk_draw_pixbuf(map_pixmap, _gc[COLORABLE_MARK], pixbuf, 0, 0, destx, desty, TILE_SIZE_PIXELS, TILE_SIZE_PIXELS, GDK_RGB_DITHER_NONE, 0, 0); + g_object_unref(pixbuf); + return TRUE; +} +gdk_draw_rectangle(map_pixmap, _map_widget->style->black_gc, TRUE, destx, desty, TILE_SIZE_PIXELS, TILE_SIZE_PIXELS); +return TRUE; } -gboolean map_download_idle_refresh(ProgressUpdateInfo * pui) +void +map_render_data(void) { - vprintf("%s(%p, %s)\n", __PRETTY_FUNCTION__, pui, pui->src_str); - - /* Test if download succeeded (only if retries != 0). */ - if (!pui->retries || g_file_test(pui->dest_str, G_FILE_TEST_EXISTS)) { - gint zoom_diff = pui->zoom - _zoom; - /* Only refresh at same or "lower" (more detailed) zoom level. */ - if (zoom_diff >= 0) { - /* If zoom has changed since we first put in the request for - * this tile, then we may have to update more than one tile. */ - guint tilex, tiley, tilex_end, tiley_end; - for (tilex = pui->tilex << zoom_diff, - tilex_end = tilex + (1 << zoom_diff); - tilex < tilex_end; tilex++) { - for (tiley = pui->tiley << zoom_diff, - tiley_end = tiley + (1 << zoom_diff); - tiley < tiley_end; tiley++) { - if ((tilex - _base_tilex) < BUF_WIDTH_TILES && (tiley - _base_tiley) < BUF_HEIGHT_TILES) { - map_render_tile(tilex, tiley, - ((tilex - _base_tilex) << TILE_SIZE_P2), - ((tiley - _base_tiley) << TILE_SIZE_P2), - TRUE); - MACRO_MAP_RENDER_DATA(); - gtk_widget_queue_draw_area - (_map_widget, - ((tilex - _base_tilex) << TILE_SIZE_P2) - _offsetx, - ((tiley - _base_tiley) << TILE_SIZE_P2) - _offsety, - TILE_SIZE_PIXELS, TILE_SIZE_PIXELS); - } - } - } - } - } - /* Else the download failed. Update retries and maybe try again. */ - else { - if (pui->retries > 0) - --pui->retries; - else if (pui->retries < 0) - ++pui->retries; - if (pui->retries) { - /* removal automatically calls progress_update_info_free(). */ - g_tree_steal(_downloading_tree, pui); - g_tree_insert(_pui_tree, pui, pui); -#ifdef WITH_OSSO - if (iap_is_connected() && !_curl_sid) -#endif - _curl_sid = g_timeout_add(100, - (GSourceFunc) - curl_download_timeout, - NULL); - /* Don't do anything else. */ - return FALSE; - } else { - /* No more retries left - something must be wrong. */ - MACRO_BANNER_SHOW_INFO(_window, - _("Error in download. Check internet connection" - " and/or Map Repository URL Format.")); - } - } +/* Don't update if dragging, too much lag */ +if (map_drag_id>0) + return; - /* removal automatically calls progress_update_info_free(). */ - g_tree_remove(_downloading_tree, pui); +if(_show_poi) + map_render_all_pois(buf_width_pixels, buf_height_pixels); - if (++_curr_download == _num_downloads) { -#ifdef WITH_HILDON - gtk_widget_destroy(_download_banner); - _download_banner = NULL; -#else - gtk_widget_hide(GTK_WIDGET(_progress_item)); -#endif - _num_downloads = _curr_download = 0; - } else - hildon_banner_set_fraction(HILDON_BANNER(_download_banner), - _curr_download / (double)_num_downloads); +if (_home.valid) + map_draw_position_icon(&_home, "home"); - vprintf("%s(): return\n", __PRETTY_FUNCTION__); - return FALSE; +if (_dest.valid) + map_draw_position_icon(&_dest, "destination"); + +if(_show_tracks>0) + map_render_paths(); } /** - * Force a redraw of the entire _map_pixmap, including fetching the + * Force a redraw of the entire map_pixmap, including fetching the * background maps from disk and redrawing the tracks on top of them. */ -void map_force_redraw() +void +map_force_redraw(void) { - guint new_x, new_y; - printf("%s()\n", __PRETTY_FUNCTION__); - - for (new_y = 0; new_y < BUF_HEIGHT_TILES; ++new_y) - for (new_x = 0; new_x < BUF_WIDTH_TILES; ++new_x) { - map_render_tile(_base_tilex + new_x, - _base_tiley + new_y, - new_x * TILE_SIZE_PIXELS, - new_y * TILE_SIZE_PIXELS, FALSE); - } - MACRO_MAP_RENDER_DATA(); - MACRO_QUEUE_DRAW_AREA(); +guint new_x, new_y; +#ifdef DEBUG +gulong tms; - vprintf("%s(): return\n", __PRETTY_FUNCTION__); +g_timer_start(map_timer); +#endif +for (new_y = 0; new_y < buf_height_tiles; ++new_y) + for (new_x = 0; new_x < buf_width_tiles; ++new_x) { + map_render_tile(_base_tilex + new_x, _base_tiley + new_y, + new_x * TILE_SIZE_PIXELS, new_y * TILE_SIZE_PIXELS, FALSE); + } +#ifdef DEBUG +g_timer_stop(map_timer); +g_debug("Full redraw: %f sec\n", g_timer_elapsed(map_timer, &tms)); +#endif + +map_render_data(); +MACRO_QUEUE_DRAW_AREA(); +} + +guint +map_get_zoom(void) +{ +return _zoom; } /** @@ -739,175 +550,172 @@ void map_force_redraw() * current zoom level, or if the new zoom is invalid * (not MIN_ZOOM <= new_zoom < MAX_ZOOM), then this method does nothing. */ -void map_set_zoom(guint new_zoom) +gboolean +map_set_zoom(guint new_zoom) { - printf("%s(%d)\n", __PRETTY_FUNCTION__, _zoom); - - /* Note that, since new_zoom is a guint and MIN_ZOOM is 0, this if - * condition also checks for new_zoom >= MIN_ZOOM. */ - if (new_zoom > (MAX_ZOOM - 1)) - return; - if (new_zoom == _zoom) - return; - - _zoom = new_zoom / _curr_repo->view_zoom_steps - * _curr_repo->view_zoom_steps; - _world_size_tiles = unit2tile(WORLD_SIZE_UNITS); - - /* If we're leading, update the center to reflect new zoom level. */ - MACRO_RECALC_CENTER(_center.unitx, _center.unity); +/* Note that, since new_zoom is a guint and MIN_ZOOM is 0, this if + * condition also checks for new_zoom >= MIN_ZOOM. */ +if (new_zoom > (map_max_zoom - 1)) + return FALSE; +if (new_zoom == _zoom) + return FALSE; - /* Update center bounds to reflect new zoom level. */ - _min_center.unitx = pixel2unit(grid2pixel(_screen_grids_halfwidth)); - _min_center.unity = pixel2unit(grid2pixel(_screen_grids_halfheight)); - _max_center.unitx = WORLD_SIZE_UNITS - grid2unit(_screen_grids_halfwidth) - 1; - _max_center.unity = WORLD_SIZE_UNITS - grid2unit(_screen_grids_halfheight) - 1; +_zoom = new_zoom / _curr_repo->view_zoom_steps * _curr_repo->view_zoom_steps; +_world_size_tiles = unit2tile(WORLD_SIZE_UNITS); - BOUND(_center.unitx, _min_center.unitx, _max_center.unitx); - BOUND(_center.unity, _min_center.unity, _max_center.unity); +/* If we're leading, update the center to reflect new zoom level. */ +MACRO_RECALC_CENTER(_gps->data, _center.unitx, _center.unity); - _base_tilex = grid2tile((gint) pixel2grid((gint) unit2pixel((gint) _center.unitx)) - - (gint) _screen_grids_halfwidth); - _base_tiley = grid2tile(pixel2grid(unit2pixel(_center.unity)) - - _screen_grids_halfheight); +/* Update center bounds to reflect new zoom level. */ +_min_center.unitx = pixel2unit(grid2pixel(_screen_grids_halfwidth)); +_min_center.unity = pixel2unit(grid2pixel(_screen_grids_halfheight)); +_max_center.unitx = WORLD_SIZE_UNITS - grid2unit(_screen_grids_halfwidth) - 1; +_max_center.unity = WORLD_SIZE_UNITS - grid2unit(_screen_grids_halfheight) - 1; - /* New zoom level, so we can't reuse the old buffer's pixels. */ +BOUND(_center.unitx, _min_center.unitx, _max_center.unitx); +BOUND(_center.unity, _min_center.unity, _max_center.unity); - /* Update state variables. */ - MACRO_RECALC_OFFSET(); - MACRO_RECALC_FOCUS_BASE(); - MACRO_RECALC_FOCUS_SIZE(); +_base_tilex = grid2tile((gint) pixel2grid((gint) unit2pixel((gint) _center.unitx)) - (gint) _screen_grids_halfwidth); +_base_tiley = grid2tile(pixel2grid(unit2pixel(_center.unity)) - _screen_grids_halfheight); - map_set_mark(); - map_force_redraw(); +/* New zoom level, so we can't reuse the old buffer's pixels. */ +/* Update state variables. */ +MACRO_RECALC_OFFSET(); +MACRO_RECALC_FOCUS_BASE(_center_ratio); +MACRO_RECALC_FOCUS_SIZE(_center_ratio); - vprintf("%s(): return\n", __PRETTY_FUNCTION__); +map_set_mark(&_gps->data); +map_force_redraw(); +return TRUE; } /** * Center the view on the given unitx/unity. */ -void map_center_unit(guint new_center_unitx, guint new_center_unity) +void +map_center_unit(guint new_center_unitx, guint new_center_unity) { - gint new_base_tilex, new_base_tiley; - guint new_x, new_y; - guint j, k, base_new_x, base_old_x, old_x, old_y, iox, ioy; - printf("%s(%d, %d)\n", __PRETTY_FUNCTION__, - new_center_unitx, new_center_unity); - - /* Assure that _center.unitx/y are bounded. */ - BOUND(new_center_unitx, _min_center.unitx, _max_center.unitx); - BOUND(new_center_unity, _min_center.unity, _max_center.unity); - - _center.unitx = new_center_unitx; - _center.unity = new_center_unity; - - new_base_tilex = grid2tile((gint) pixel2grid((gint)unit2pixel((gint) _center.unitx)) - - (gint)_screen_grids_halfwidth); - new_base_tiley = grid2tile(pixel2grid(unit2pixel(_center.unity)) - - _screen_grids_halfheight); - - /* Same zoom level, so it's likely that we can reuse some of the old - * buffer's pixels. */ - - if (new_base_tilex != _base_tilex || new_base_tiley != _base_tiley) { - /* If copying from old parts to new parts, we need to make sure we - * don't overwrite the old parts when copying, so set up new_x, - * new_y, old_x, old_y, iox, and ioy with that in mind. */ - if (new_base_tiley < _base_tiley) { - /* New is lower than old - start at bottom and go up. */ - new_y = BUF_HEIGHT_TILES - 1; - ioy = -1; - } else { - /* New is higher than old - start at top and go down. */ - new_y = 0; - ioy = 1; - } - if (new_base_tilex < _base_tilex) { - /* New is righter than old - start at right and go left. */ - base_new_x = BUF_WIDTH_TILES - 1; - iox = -1; - } else { - /* New is lefter than old - start at left and go right. */ - base_new_x = 0; - iox = 1; - } +gint new_base_tilex, new_base_tiley; +guint new_x, new_y; +guint j, k, base_new_x, base_old_x, old_x, old_y, iox, ioy; + +/* Assure that _center.unitx/y are bounded. */ +BOUND(new_center_unitx, _min_center.unitx, _max_center.unitx); +BOUND(new_center_unity, _min_center.unity, _max_center.unity); + +_center.unitx = new_center_unitx; +_center.unity = new_center_unity; + +new_base_tilex = grid2tile((gint) pixel2grid((gint)unit2pixel((gint) _center.unitx)) - (gint)_screen_grids_halfwidth); +new_base_tiley = grid2tile(pixel2grid(unit2pixel(_center.unity)) - _screen_grids_halfheight); + +/* Same zoom level, so it's likely that we can reuse some of the old + * buffer's pixels. */ + +if (new_base_tilex != _base_tilex || new_base_tiley != _base_tiley) { + /* If copying from old parts to new parts, we need to make sure we + * don't overwrite the old parts when copying, so set up new_x, + * new_y, old_x, old_y, iox, and ioy with that in mind. */ + if (new_base_tiley < _base_tiley) { + /* New is lower than old - start at bottom and go up. */ + new_y = buf_height_tiles - 1; + ioy = -1; + } else { + /* New is higher than old - start at top and go down. */ + new_y = 0; + ioy = 1; + } + if (new_base_tilex < _base_tilex) { + /* New is righter than old - start at right and go left. */ + base_new_x = buf_width_tiles - 1; + iox = -1; + } else { + /* New is lefter than old - start at left and go right. */ + base_new_x = 0; + iox = 1; + } - /* Iterate over the y tile values. */ - old_y = new_y + new_base_tiley - _base_tiley; - base_old_x = base_new_x + new_base_tilex - _base_tilex; - _base_tilex = new_base_tilex; - _base_tiley = new_base_tiley; - for (j = 0; j < BUF_HEIGHT_TILES; - ++j, new_y += ioy, old_y += ioy) { - new_x = base_new_x; - old_x = base_old_x; - /* Iterate over the x tile values. */ - for (k = 0; k < BUF_WIDTH_TILES; - ++k, new_x += iox, old_x += iox) { - /* Can we get this grid block from the old buffer?. */ - if (old_x >= 0 && old_x < BUF_WIDTH_TILES - && old_y >= 0 && old_y < BUF_HEIGHT_TILES) { - /* Copy from old buffer to new buffer. */ - gdk_draw_drawable(_map_pixmap, - _gc[COLORABLE_MARK], - _map_pixmap, - old_x * TILE_SIZE_PIXELS, - old_y * TILE_SIZE_PIXELS, - new_x * TILE_SIZE_PIXELS, - new_y * TILE_SIZE_PIXELS, - TILE_SIZE_PIXELS, - TILE_SIZE_PIXELS); - } else { -#if 0 - map_tile_rdata *mtr; - - mtr=g_slice_new(map_tile_rdata); - mtr->tilex=new_base_tilex + new_x; - mtr->tiley=new_base_tiley + new_y; - mtr->destx=new_x * TILE_SIZE_PIXELS; - mtr->desty=new_y * TILE_SIZE_PIXELS; - - gdk_draw_rectangle(_map_pixmap, _gc[COLORABLE_MARK_VELOCITY], - TRUE, mtr->destx, mtr->desty, TILE_SIZE_PIXELS, TILE_SIZE_PIXELS); - - g_idle_add_full(G_PRIORITY_HIGH_IDLE,(GSourceFunc)map_render_tile_idle, mtr,NULL); -#else - map_render_tile(new_base_tilex + new_x, - new_base_tiley + new_y, - new_x * TILE_SIZE_PIXELS, - new_y * TILE_SIZE_PIXELS, - FALSE); -#endif - } + /* Iterate over the y tile values. */ + old_y = new_y + new_base_tiley - _base_tiley; + base_old_x = base_new_x + new_base_tilex - _base_tilex; + _base_tilex = new_base_tilex; + _base_tiley = new_base_tiley; + + for (j = 0; j < buf_height_tiles; ++j, new_y += ioy, old_y += ioy) { + new_x = base_new_x; + old_x = base_old_x; + /* Iterate over the x tile values. */ + for (k = 0; k < buf_width_tiles; ++k, new_x += iox, old_x += iox) { + /* Can we get this grid block from the old buffer?. */ + if (old_x >= 0 && old_x < buf_width_tiles && old_y >= 0 && old_y < buf_height_tiles) { + /* Copy from old buffer to new buffer. */ + gdk_draw_drawable(map_pixmap, + _gc[COLORABLE_MARK], + map_pixmap, + old_x * TILE_SIZE_PIXELS, + old_y * TILE_SIZE_PIXELS, + new_x * TILE_SIZE_PIXELS, + new_y * TILE_SIZE_PIXELS, + TILE_SIZE_PIXELS, + TILE_SIZE_PIXELS); + } else { + map_render_tile(new_base_tilex + new_x, + new_base_tiley + new_y, + new_x * TILE_SIZE_PIXELS, + new_y * TILE_SIZE_PIXELS, + map_drag_id!=0 ? TRUE : FALSE); } } - MACRO_MAP_RENDER_DATA(); } + map_render_data(); +} - MACRO_RECALC_OFFSET(); - MACRO_RECALC_FOCUS_BASE(); - - map_set_mark(); - MACRO_QUEUE_DRAW_AREA(); +MACRO_RECALC_OFFSET(); +MACRO_RECALC_FOCUS_BASE(_center_ratio); - vprintf("%s(): return\n", __PRETTY_FUNCTION__); +map_set_mark(&_gps->data); +MACRO_QUEUE_DRAW_AREA(); } /** * Pan the view by the given number of units in the X and Y directions. */ -void map_pan(gint delta_unitx, gint delta_unity) +void +map_pan(gint delta_unitx, gint delta_unity) { - printf("%s(%d, %d)\n", __PRETTY_FUNCTION__, delta_unitx, delta_unity); +if (_center_mode > 0) + set_action_activate("autocenter_none", TRUE); - if (_center_mode > 0) - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM - (_menu_ac_none_item), TRUE); - map_center_unit(_center.unitx + delta_unitx, - _center.unity + delta_unity); +map_center_unit(_center.unitx + delta_unitx, _center.unity + delta_unity); +} + +/** + * Helper to center map on given lat/lon + */ +void +map_center_latlon(gdouble lat, gdouble lon) +{ +guint unitx, unity; + +latlon2unit(lat, lon, unitx, unity); +map_center_unit(unitx, unity); +} + +/** + * Helper to goto given point and update location + * + */ +gboolean +map_goto_position(Position *pos) +{ +if (pos->valid==FALSE) + return FALSE; - vprintf("%s(): return\n", __PRETTY_FUNCTION__); +_center_mode=CENTER_MANUAL; +map_center_latlon(pos->lat, pos->lon); +map_set_autozoom(FALSE, 0); +g_idle_add_full(G_PRIORITY_HIGH_IDLE,(GSourceFunc)map_update_location_from_center, NULL, NULL); +return TRUE; } /** @@ -916,411 +724,491 @@ void map_pan(gint delta_unitx, gint delta_unity) * drawing of the background map), then updates the mark, then queus the * draw area of the new mark. */ -void map_move_mark() +void +map_move_mark(void) { - printf("%s()\n", __PRETTY_FUNCTION__); - - /* Just queue the old and new draw areas. */ - gtk_widget_queue_draw_area(_map_widget, - _mark_minx<0 ? 0 : _mark_minx, - _mark_miny<0 ? 0 : _mark_miny, - _mark_width, _mark_height); - map_set_mark(); - gtk_widget_queue_draw_area(_map_widget, - _mark_minx<0 ? 0 : _mark_minx, - _mark_miny<0 ? 0 : _mark_miny, - _mark_width, _mark_height); - - vprintf("%s(): return\n", __PRETTY_FUNCTION__); +/* Just queue the old and new draw areas. */ +gtk_widget_queue_draw_area(_map_widget, + mark_minx<0 ? 0 : mark_minx, + mark_miny<0 ? 0 : mark_miny, + mark_width, mark_height); +map_set_mark(&_gps->data); +gtk_widget_queue_draw_area(_map_widget, + mark_minx<0 ? 0 : mark_minx, + mark_miny<0 ? 0 : mark_miny, + mark_width, mark_height); } gboolean -map_update_location_from_gps() +map_update_location_from_gps(Gps *gps) { -map_update_location(_pos.unitx, _pos.unity, FALSE); +g_assert(gps); +map_update_location(gps->data.lat, gps->data.lon, FALSE); return FALSE; } gboolean -map_update_location_from_center() +map_update_location_from_center(void) { +gdouble lat, lon; /* Force re-validation of place if user is clicking around */ map_loc.valid=FALSE; -map_update_location(_center.unitx, _center.unity, TRUE); +/* XXX: hmm, not the right place for this */ +#if 0 +if (_gps->fix==FIX_NOFIX) { + _gps->data.unitx=_center.unitx; + _gps->data.unity=_center.unity; + unit2latlon(_gps->data.unitx, _gps->data.unity, _gps->data.lat, _gps->data.lon); +} +#endif +unit2latlon(_center.unitx, _center.unity, lat, lon); +map_update_location(lat, lon, TRUE); return FALSE; } +void +map_draw_pixbuf_on_buffer(gint x, gint y, GdkPixbuf *p) +{ +if ((x < 0) || (y < 0)) + return; + +if ((x > buf_width_pixels) || (y > buf_height_pixels)) + return; + +gdk_draw_pixbuf(map_pixmap, _gc[COLORABLE_POI], + p, 0, 0, + x - gdk_pixbuf_get_width(p) / 2, + y - gdk_pixbuf_get_height(p) / 2, + -1, -1, GDK_RGB_DITHER_NONE, 0, 0); +} + /** - * Make sure the mark is up-to-date. This function triggers a panning of - * the view if the mark is appropriately close to the edge of the view. + * Draw given pixbuf on map, centered on x,y */ -void refresh_mark() +void +map_draw_pixbuf(guint unitx, guint unity, GdkPixbuf *p) { - printf("%s()\n", __PRETTY_FUNCTION__); +gint x,y; +x=unit2bufx(unitx); +y=unit2bufy(unity); - guint new_center_unitx; - guint new_center_unity; +map_draw_pixbuf_on_buffer(x, y, p); +} - MACRO_RECALC_CENTER(new_center_unitx, new_center_unity); +/** + * Draw an icon at given Position. + * + */ +static void +map_draw_position_icon(Position *pos, const gchar *icon) +{ +gint x, y; +guint ux, uy; +gchar buffer[128]; +GdkPixbuf *p; - if ((new_center_unitx - _focus.unitx) < _focus_unitwidth - && (new_center_unity - _focus.unity) < _focus_unitheight) - /* We're not changing the view - just move the mark. */ - map_move_mark(); - else - map_center_unit(new_center_unitx, new_center_unity); +latlon2unit(pos->lat, pos->lon, ux, uy); +x=unit2bufx(ux); +y=unit2bufy(uy); - /* Draw speed info */ - if (_speed_limit_on) - speed_limit(); +if ((x < 0) || (y < 0)) + return; - if (_center_mode>0) - g_idle_add((GSourceFunc)map_update_location_from_gps, NULL); +if ((x > buf_width_pixels) || (y > buf_height_pixels)) + return; - vprintf("%s(): return\n", __PRETTY_FUNCTION__); +g_snprintf(buffer, sizeof(buffer), "%s/pixmaps/mapper/%s.png", DATADIR, icon); +p=gdk_pixbuf_new_from_file(buffer, NULL); +if (!p) + return; + +map_draw_pixbuf_on_buffer(x, y, p); +g_object_unref(p); } /** - * Render a single track line to _map_pixmap. If either point on the line + * Make sure the mark is up-to-date. This function triggers a panning of + * the view if the mark is appropriately close to the edge of the view. + */ +void +map_refresh_mark(void) +{ +guint new_center_unitx; +guint new_center_unity; + +MACRO_RECALC_CENTER(_gps->data, new_center_unitx, new_center_unity); + +if ((new_center_unitx - _focus.unitx) < _focus_unitwidth && (new_center_unity - _focus.unity) < _focus_unitheight) + /* We're not changing the view - just move the mark. */ + map_move_mark(); +else + map_center_unit(new_center_unitx, new_center_unity); + +/* Draw speed info */ +if (_speed_on) + map_speed_draw(); + +if (_center_mode>0) + g_idle_add_full(G_PRIORITY_HIGH_IDLE,(GSourceFunc)map_update_location_from_gps, _gps, NULL); +} + +/** + * Render a single track line to map_pixmap. If either point on the line * is a break (defined as unity == 0), a circle is drawn at the other point. * IT IS AN ERROR FOR BOTH POINTS TO INDICATE A BREAK. */ void -map_render_segment(GdkGC * gc_norm, GdkGC * gc_alt, - guint unitx1, guint unity1, guint unitx2, guint unity2) +map_render_segment(GdkGC *gc_norm, GdkGC *gc_alt, guint unitx1, guint unity1, guint unitx2, guint unity2) { - vprintf("%s()\n", __PRETTY_FUNCTION__); - - if (!unity1) { - guint x2, y2; - x2 = unit2bufx(unitx2); - y2 = unit2bufy(unity2); - /* Make sure this circle will be visible. */ - if ((x2 < BUF_WIDTH_PIXELS) - && (y2 < BUF_HEIGHT_PIXELS)) - gdk_draw_arc(_map_pixmap, gc_alt, FALSE, /* FALSE: not filled. */ - x2 - _draw_width, y2 - _draw_width, 2 * _draw_width, 2 * _draw_width, 0, /* start at 0 degrees. */ - 360 * 64); - } else if (!unity2) { - guint x1, y1; - x1 = unit2bufx(unitx1); - y1 = unit2bufy(unity1); - /* Make sure this circle will be visible. */ - if ((x1 < BUF_WIDTH_PIXELS) - && ((unsigned)y1 < BUF_HEIGHT_PIXELS)) - gdk_draw_arc(_map_pixmap, gc_alt, FALSE, /* FALSE: not filled. */ - x1 - _draw_width, y1 - _draw_width, 2 * _draw_width, 2 * _draw_width, 0, /* start at 0 degrees. */ - 360 * 64); - } else { - gint x1, y1, x2, y2; - x1 = unit2bufx(unitx1); - y1 = unit2bufy(unity1); - x2 = unit2bufx(unitx2); - y2 = unit2bufy(unity2); - /* Make sure this line could possibly be visible. */ - if (!((x1 > BUF_WIDTH_PIXELS && x2 > BUF_WIDTH_PIXELS) - || (x1 < 0 && x2 < 0) - || (y1 > BUF_HEIGHT_PIXELS && y2 > BUF_HEIGHT_PIXELS) - || (y1 < 0 && y2 < 0))) - gdk_draw_line(_map_pixmap, gc_norm, x1, y1, x2, y2); +if (!unity1) { + guint x2, y2; + + x2 = unit2bufx(unitx2); + y2 = unit2bufy(unity2); + /* Make sure this circle will be visible. */ + if ((x2 < buf_width_pixels) && (y2 < buf_height_pixels)) + gdk_draw_arc(map_pixmap, gc_alt, FALSE, /* FALSE: not filled. */ + x2 - _draw_width, y2 - _draw_width, 2 * _draw_width, 2 * _draw_width, 0, /* start at 0 degrees. */ + 360 * 64); +} else if (!unity2) { + guint x1, y1; + + x1 = unit2bufx(unitx1); + y1 = unit2bufy(unity1); + /* Make sure this circle will be visible. */ + if ((x1 < buf_width_pixels) && ((unsigned)y1 < buf_height_pixels)) + gdk_draw_arc(map_pixmap, gc_alt, FALSE, /* FALSE: not filled. */ + x1 - _draw_width, y1 - _draw_width, 2 * _draw_width, 2 * _draw_width, 0, /* start at 0 degrees. */ + 360 * 64); +} else { + gint x1, y1, x2, y2; + + x1 = unit2bufx(unitx1); + y1 = unit2bufy(unity1); + x2 = unit2bufx(unitx2); + y2 = unit2bufy(unity2); + /* Make sure this line could possibly be visible. */ + if (!((x1 > buf_width_pixels && x2 > buf_width_pixels) + || (x1 < 0 && x2 < 0) + || (y1 > buf_height_pixels && y2 > buf_height_pixels) + || (y1 < 0 && y2 < 0))) + gdk_draw_line(map_pixmap, gc_norm, x1, y1, x2, y2); } +} - vprintf("%s(): return\n", __PRETTY_FUNCTION__); +void +map_render_waypoint(guint x1, guint y1, GdkGC *gc) +{ +if ((x1 > buf_width_pixels) || (y1 > buf_height_pixels)) + return; +gdk_draw_arc(map_pixmap, gc, FALSE, x1 - _draw_width, y1 - _draw_width, 2 * _draw_width, 2 * _draw_width, 0, 360 * 64); } /** - * Render all track data onto the _map_pixmap. Note that this does not + * Render all track data onto the map_pixmap. Note that this does not * clear the pixmap of previous track data (use map_force_redraw() for * that), and also note that this method does not queue any redraws, so it * is up to the caller to decide which part of the track really needs to be * redrawn. */ -void map_render_path(Path * path, GdkGC ** gc) +void +map_render_path(Path * path, GdkGC ** gc) { - Point *curr; - WayPoint *wcurr; - printf("%s()\n", __PRETTY_FUNCTION__); - - /* gc is a pointer to the first GC to use (for plain points). (gc + 1) - * is a pointer to the GC to use for waypoints, and (gc + 2) is a pointer - * to the GC to use for breaks. */ - - /* else there is a route to draw. */ - for (curr = path->head, wcurr = path->whead; curr++ != path->tail;) { - /* Draw the line from (curr - 1) to (curr). */ - map_render_segment(gc[0], gc[2], - curr[-1].unitx, curr[-1].unity, curr->unitx, - curr->unity); - - /* Now, check if curr is a waypoint. */ - if (wcurr && wcurr <= path->wtail && wcurr->point == curr) { - guint x1 = unit2bufx(wcurr->point->unitx); - guint y1 = unit2bufy(wcurr->point->unity); - if ((x1 < BUF_WIDTH_PIXELS) - && (y1 < BUF_HEIGHT_PIXELS)) { - gdk_draw_arc(_map_pixmap, gc[1], FALSE, /* FALSE: not filled. */ - x1 - _draw_width, y1 - _draw_width, 2 * _draw_width, 2 * _draw_width, 0, /* start at 0 degrees. */ - 360 * 64); - } - wcurr++; - } - } +Point *curr; +WayPoint *wcurr; - vprintf("%s(): return\n", __PRETTY_FUNCTION__); +/* gc is a pointer to the first GC to use (for plain points). (gc + 1) + * is a pointer to the GC to use for waypoints, and (gc + 2) is a pointer + * to the GC to use for breaks. */ + +/* else there is a route to draw. */ +for (curr = path->head, wcurr = path->whead; curr++ != path->tail;) { + /* Draw the line from (curr - 1) to (curr). */ + map_render_segment(gc[0], gc[2], curr[-1].unitx, curr[-1].unity, curr->unitx, curr->unity); + + /* Now, check if curr is a waypoint. */ + if (wcurr && wcurr <= path->wtail && wcurr->point == curr) { + guint x1 = unit2bufx(wcurr->point->unitx); + guint y1 = unit2bufy(wcurr->point->unity); + + map_render_waypoint(x1, y1, _gc[COLORABLE_TRACK_BREAK]); + wcurr++; + } +} } -void map_render_paths() +void +map_render_paths(void) { - printf("%s()\n", __PRETTY_FUNCTION__); - - if ((_show_tracks & ROUTES_MASK) && _route.head != _route.tail) { - map_render_path(&_route, _gc + COLORABLE_ROUTE); - - /* Now, draw the next waypoint on top of all other waypoints. */ - if (_next_way) { - guint x1 = unit2bufx(_next_way->point->unitx); - guint y1 = unit2bufy(_next_way->point->unity); - if ((x1 < BUF_WIDTH_PIXELS) - && (y1 < BUF_HEIGHT_PIXELS)) { - /* Draw the next waypoint as a break. */ - gdk_draw_arc(_map_pixmap, _gc[COLORABLE_ROUTE_BREAK], FALSE, /* FALSE: not filled. */ - x1 - _draw_width, y1 - _draw_width, 2 * _draw_width, 2 * _draw_width, 0, /* start at 0 degrees. */ - 360 * 64); - } +if ((_show_tracks & ROUTES_MASK) && _route->head != _route->tail) { + map_render_path(_route, _gc + COLORABLE_ROUTE); + + /* Now, draw the next waypoint on top of all other waypoints. */ + if (_next_way) { + guint x1 = unit2bufx(_next_way->point->unitx); + guint y1 = unit2bufy(_next_way->point->unity); + + if ((x1 < buf_width_pixels) && (y1 < buf_height_pixels)) { + /* Draw the next waypoint as a break. */ + gdk_draw_arc(map_pixmap, _gc[COLORABLE_ROUTE_BREAK], FALSE, /* FALSE: not filled. */ + x1 - _draw_width, y1 - _draw_width, 4 * _draw_width, 4 * _draw_width, 0, /* start at 0 degrees. */ + 360 * 64); } } - if (_show_tracks & TRACKS_MASK) - map_render_path(&_track, _gc + COLORABLE_TRACK); - - vprintf("%s(): return\n", __PRETTY_FUNCTION__); +} +if (_show_tracks & TRACKS_MASK) + map_render_path(_track, _gc + COLORABLE_TRACK); } -static gboolean map_follow_move(GtkWidget * widget, GdkEventMotion * event) +/** + * + * + */ +static gboolean +map_follow_move_cb(GtkWidget *widget, GdkEventMotion *event, gpointer data) { - gint xx, yy; - GdkModifierType state; - guint unitx, unity; - guint cx, cy; +GdkModifierType state; +gint xx, yy; +guint unitx, unity, nunitx, nunity; +guint cx, cy; - if (event->is_hint) { - gdk_window_get_pointer(event->window, &xx, &yy, &state); - state = event->state; - } else { - xx = event->x; - yy = event->y; - state = event->state; - } +if (!(event->state & GDK_BUTTON1_MASK)) { + map_drag_id=0; + return TRUE; +} - unitx = x2unit((gint) (xx - before[0])); - unity = y2unit((gint) (yy - before[1])); - cx = unit2x(_center.unitx); - cy = unit2y(_center.unity); +if (event->is_hint) { + gdk_window_get_pointer(event->window, &xx, &yy, &state); + state = event->state; +} else { + xx = event->x; + yy = event->y; + state = event->state; +} - map_center_unit(x2unit((gint) (cx - (xx - before[0]))), - y2unit((gint) (cy - (yy - before[1])))); +unitx = x2unit((gint) (xx - before[0])); +unity = y2unit((gint) (yy - before[1])); +cx = unit2x(_center.unitx); +cy = unit2y(_center.unity); - before[0] = xx; - before[1] = yy; - return FALSE; +nunitx=x2unit((gint) (cx - (xx - before[0]))); +nunity=y2unit((gint) (cy - (yy - before[1]))); + +map_center_unit(nunitx, nunity); + +map_dragged=TRUE; +g_debug("MAP PAN: %d %d %d %d (%d, %d)", cx, cy, xx, yy, nunitx, nunity); +before[0] = xx; +before[1] = yy; +return FALSE; } -gboolean map_key_zoom_timeout() +gboolean +map_key_zoom_timeout(void) { - printf("%s()\n", __PRETTY_FUNCTION__); - if (_key_zoom_new < _zoom) { - /* We're currently zooming in (_zoom is decreasing). */ - guint test = _key_zoom_new - _curr_repo->view_zoom_steps; - if (test < MAX_ZOOM) - /* We can zoom some more. Hurray! */ - _key_zoom_new = test; - else - /* We can't zoom anymore. Booooo! */ - return FALSE; - } else { - /* We're currently zooming out (_zoom is increasing). */ - guint test = _key_zoom_new + _curr_repo->view_zoom_steps; - if (test < MAX_ZOOM) - /* We can zoom some more. Hurray! */ - _key_zoom_new = test; - else - /* We can't zoom anymore. Booooo! */ - return FALSE; - } +if (_key_zoom_new < _zoom) { + /* We're currently zooming in (_zoom is decreasing). */ + guint test = _key_zoom_new - _curr_repo->view_zoom_steps; + if (test < map_max_zoom) + _key_zoom_new = test; + else + return FALSE; +} else { + /* We're currently zooming out (_zoom is increasing). */ + guint test = _key_zoom_new + _curr_repo->view_zoom_steps; + if (test < map_max_zoom) + _key_zoom_new = test; + else + return FALSE; +} - /* We can zoom more - tell them how much they're zooming. */ - { - gchar buffer[32]; - snprintf(buffer, sizeof(buffer), - "%s %d", _("Zoom to Level"), _key_zoom_new); - MACRO_BANNER_SHOW_INFO(_window, buffer); - } - vprintf("%s(): return\n", __PRETTY_FUNCTION__); - return TRUE; +return TRUE; } -void map_scale_draw(GdkEventExpose *event) +static void +map_information_text(guint x, guint y, GdkGC *gc, gchar *msg) { - gdk_rectangle_intersect(&event->area, &_scale_rect, &event->area); - - if (event->area.width && event->area.height) { - gdk_draw_rectangle(_map_widget->window, - _map_widget->style-> - bg_gc[GTK_WIDGET_STATE(_map_widget)], - TRUE, _scale_rect.x, _scale_rect.y, - _scale_rect.width, - _scale_rect.height); - gdk_draw_rectangle(_map_widget->window, - _map_widget->style-> - fg_gc[GTK_WIDGET_STATE(_map_widget)], - FALSE, _scale_rect.x, _scale_rect.y, - _scale_rect.width, - _scale_rect.height); - - /* Now calculate and draw the distance. */ - { - gchar buffer[16]; - gdouble distance; - gdouble lat1, lon1, lat2, lon2; - gint width; - - unit2latlon(_center.unitx - pixel2unit(SCALE_WIDTH / 2 - 4), - _center.unity, lat1, lon1); - unit2latlon(_center.unitx + pixel2unit(SCALE_WIDTH / 2 - 4), - _center.unity, lat2, lon2); - distance = calculate_distance(lat1, lon1, lat2, lon2) * UNITS_CONVERT[_units]; - - if (distance < 1.f) - snprintf(buffer, sizeof(buffer), - "%0.2f %s", distance, - UNITS_TEXT[_units]); - else if (distance < 10.f) - snprintf(buffer, sizeof(buffer), - "%0.1f %s", distance, - UNITS_TEXT[_units]); - else - snprintf(buffer, sizeof(buffer), - "%0.f %s", distance, - UNITS_TEXT[_units]); - - pango_layout_set_text(_scale_layout, buffer, -1); - pango_layout_get_pixel_size(_scale_layout, &width, NULL); - - /* Draw the layout itself. */ - gdk_draw_layout(_map_widget->window, - _map_widget->style-> - fg_gc[GTK_WIDGET_STATE - (_map_widget)], - _scale_rect.x + - (_scale_rect.width - width) / 2, - _scale_rect.y, _scale_layout); - - /* Draw little hashes on the ends. */ - gdk_draw_line(_map_widget->window, - _map_widget->style-> - fg_gc[GTK_WIDGET_STATE - (_map_widget)], - _scale_rect.x + 4, - _scale_rect.y + - _scale_rect.height / 2 - 4, - _scale_rect.x + 4, - _scale_rect.y + - _scale_rect.height / 2 + 4); - gdk_draw_line(_map_widget->window, - _map_widget->style-> - fg_gc[GTK_WIDGET_STATE - (_map_widget)], - _scale_rect.x + 4, - _scale_rect.y + - _scale_rect.height / 2, - _scale_rect.x + - (_scale_rect.width - width) / 2 - - 4, - _scale_rect.y + - _scale_rect.height / 2); - gdk_draw_line(_map_widget->window, - _map_widget->style-> - fg_gc[GTK_WIDGET_STATE - (_map_widget)], - _scale_rect.x + - _scale_rect.width - 4, - _scale_rect.y + - _scale_rect.height / 2 - 4, - _scale_rect.x + - _scale_rect.width - 4, - _scale_rect.y + - _scale_rect.height / 2 + 4); - gdk_draw_line(_map_widget->window, - _map_widget->style-> - fg_gc[GTK_WIDGET_STATE - (_map_widget)], - _scale_rect.x + - _scale_rect.width - 4, - _scale_rect.y + - _scale_rect.height / 2, - _scale_rect.x + - (_scale_rect.width + width) / 2 + - 4, - _scale_rect.y + - _scale_rect.height / 2); - } - } +guint width, height; + +pango_layout_set_text(speed_layout, msg, -1); +pango_layout_get_pixel_size(speed_layout, &width, &height); +gtk_widget_queue_draw_area(_map_widget, x - 5, y - 5, width * 3 + 15, height + 5); +gdk_window_process_all_updates(); +gdk_draw_layout(_map_widget->window, gc, x, y, speed_layout); } -gboolean map_cb_expose(GtkWidget * widget, GdkEventExpose * event) +static void +map_speed_draw(void) { - printf("%s(%d, %d, %d, %d)\n", __PRETTY_FUNCTION__, - event->area.x, event->area.y, - event->area.width, event->area.height); - - gdk_draw_drawable(GDK_DRAWABLE(_map_widget->window), - _gc[COLORABLE_MARK], - _map_pixmap, - event->area.x + _offsetx, event->area.y + _offsety, - event->area.x, event->area.y, - event->area.width, event->area.height); - map_draw_mark(); - - /* Draw scale, if necessary. */ - if (_show_scale) - map_scale_draw(event); - - vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__); - return TRUE; +GdkGC *gc; +gfloat cur_speed; +gchar *buffer; + +cur_speed = _gps->data.speed * UNITS_CONVERT[_units]; +gc=(cur_speed > _speed_limit) ? speed_gc1 : speed_gc2; +buffer = g_strdup_printf("%0.0f", cur_speed); +map_information_text(10, 10, gc, buffer); +g_free(buffer); } -int map_zoom(gint zdir) +static void +map_scale_draw(GdkEventExpose *event) { - gchar buffer[80]; - gint nzoom; +gchar buffer[16]; +gdouble distance; +gdouble lat1, lon1, lat2, lon2; +gint width; + +pango_layout_set_text(scale_layout, "0", -1); +pango_layout_get_pixel_size(scale_layout, NULL, &scale_rect.height); +scale_rect.y = _screen_height_pixels - scale_rect.height - 1; + +gdk_rectangle_intersect(&event->area, &scale_rect, &event->area); + +if (event->area.width && event->area.height) { + gdk_draw_rectangle(_map_widget->window, + _map_widget->style->bg_gc[GTK_WIDGET_STATE(_map_widget)], + TRUE, scale_rect.x, scale_rect.y, + scale_rect.width, + scale_rect.height); + gdk_draw_rectangle(_map_widget->window, + _map_widget->style->fg_gc[GTK_WIDGET_STATE(_map_widget)], + FALSE, scale_rect.x, scale_rect.y, + scale_rect.width, + scale_rect.height); + + /* Now calculate and draw the distance. */ + unit2latlon(_center.unitx - pixel2unit(SCALE_WIDTH / 2 - 4), _center.unity, lat1, lon1); + unit2latlon(_center.unitx + pixel2unit(SCALE_WIDTH / 2 - 4), _center.unity, lat2, lon2); + distance=calculate_distance(lat1, lon1, lat2, lon2) * UNITS_CONVERT[_units]; + + if (distance < 1.f) + g_snprintf(buffer, sizeof(buffer), "%0.2f %s", distance, UNITS_TEXT[_units]); + else if (distance < 10.f) + g_snprintf(buffer, sizeof(buffer), "%0.1f %s", distance, UNITS_TEXT[_units]); + else + g_snprintf(buffer, sizeof(buffer), "%0.f %s", distance, UNITS_TEXT[_units]); + + pango_layout_set_text(scale_layout, buffer, -1); + pango_layout_get_pixel_size(scale_layout, &width, NULL); - nzoom = _zoom + zdir; + /* Draw the layout itself. */ + gdk_draw_layout(_map_widget->window, + _map_widget->style->fg_gc[GTK_WIDGET_STATE(_map_widget)], + scale_rect.x + (scale_rect.width - width) / 2, + scale_rect.y, scale_layout); - if ((nzoom > 0) && (nzoom < MAX_ZOOM - 1)) { - snprintf(buffer, sizeof(buffer), "%s %d", - _("Zoom to Level"), nzoom); - MACRO_BANNER_SHOW_INFO(_window, buffer); - map_set_zoom(nzoom); + /* Draw little hashes on the ends. */ + gdk_draw_line(_map_widget->window, + _map_widget->style->fg_gc[GTK_WIDGET_STATE(_map_widget)], + scale_rect.x + 4, + scale_rect.y + scale_rect.height / 2 - 4, + scale_rect.x + 4, + scale_rect.y + scale_rect.height / 2 + 4); + gdk_draw_line(_map_widget->window, + _map_widget->style->fg_gc[GTK_WIDGET_STATE(_map_widget)], + scale_rect.x + 4, + scale_rect.y + scale_rect.height / 2, + scale_rect.x + (scale_rect.width - width) / 2 - 4, + scale_rect.y + scale_rect.height / 2); + gdk_draw_line(_map_widget->window, + _map_widget->style->fg_gc[GTK_WIDGET_STATE(_map_widget)], + scale_rect.x + scale_rect.width - 4, + scale_rect.y + scale_rect.height / 2 - 4, + scale_rect.x + scale_rect.width - 4, + scale_rect.y + scale_rect.height / 2 + 4); + gdk_draw_line(_map_widget->window, + _map_widget->style->fg_gc[GTK_WIDGET_STATE(_map_widget)], + scale_rect.x + scale_rect.width - 4, + scale_rect.y + scale_rect.height / 2, + scale_rect.x + (scale_rect.width + width) / 2 + 4, + scale_rect.y + scale_rect.height / 2); } +} + +static gboolean +map_cb_expose(GtkWidget *widget, GdkEventExpose *event) +{ +gdk_draw_drawable(GDK_DRAWABLE(_map_widget->window), + _gc[COLORABLE_MARK], + map_pixmap, + event->area.x + _offsetx, event->area.y + _offsety, + event->area.x, event->area.y, + event->area.width, event->area.height); +map_draw_mark(_gps); + +/* Draw scale, if necessary. */ +if (_show_scale) + map_scale_draw(event); + +#if 0 +if (_speed_on) + map_speed_draw(); +#endif - return nzoom; +return TRUE; +} + +int +map_zoom(gint zdir) +{ +gint nzoom; + +nzoom=_zoom+zdir; +if ((nzoom >= 0) && (nzoom < map_max_zoom - 1)) { + image_cache_clear(map_ic); + map_set_zoom(nzoom); +} +return nzoom; +} + +gboolean +map_zoom_in(void) +{ +map_zoom(-1); +return FALSE; +} + +gboolean +map_zoom_out(void) +{ +map_zoom(1); +return FALSE; } static gboolean -map_autozoomer() +map_autozoomer(void) { static gfloat z=5.0; static gint last=5; +gint b=0; gint iz; -if (_zoom_timeout_sid==0) +if (zoom_timeout_sid==0) return FALSE; -z=(z+_gps.speed+1)/5; +/* If location is known, use road type and speed for zoom setting */ +if (map_loc.valid && map_loc.street) { + switch (map_loc.street->type) { + case WAY_MOTORWAY: + case WAY_TRUNK: + b=2; + break; + case WAY_PRIMARY: + case WAY_SECONDARY: + b=1; + break; + default: + b=0; + break; + } +} + +z=(z+_gps->data.speed+1)/5; +z+=b; if (z>5) z=5.0; else if (z<1) z=1.0; iz=(gint)roundf(z); -#ifdef DEBUG -g_printf("Setting autozoom to: %f %d S:%f\n", z, iz, _gps.speed); -#endif +g_debug("Setting autozoom to: %f %d S:%f\n", z, iz, _gps->data.speed); if (iz>last) iz=last+1; else if (izdata.unitx=x2unit((gint) (x + 0.5)); +_gps->data.unity=y2unit((gint) (y + 0.5)); +unit2latlon(_gps->data.unitx, _gps->data.unity, _gps->data.lat, _gps->data.lon); +_gps->data.speed=20.f; +gps_data_integerize(&_gps->data); +_gps->data.time=time(NULL); +track_add(_track, &_gps->data); +map_refresh_mark(); } static void @@ -1373,15 +1262,16 @@ map_set_place_information(osm_way *s, osm_place *mp, osm_place *sp) gchar buffer[256]; if (!s && !mp && !sp) { - snprintf(buffer, sizeof(buffer), "Unknown location"); + g_snprintf(buffer, sizeof(buffer), _("Unknown location")); } else { /* oh, fun */ - snprintf(buffer, sizeof(buffer), "On %s%s%s%s%s%s%s%s%s", - s ? s->name ? s->name : _("unknown") : "?", + g_snprintf(buffer, sizeof(buffer), "%s%s%s%s%s%s%s%s%s%s", + s ? s->name ? s->name : "" : "", s ? s->ref ? ", " : "" : "", s ? s->ref ? s->ref : "" : "", - s ? s->int_ref ? ", " : "" : "", + s ? s->int_ref ? " (" : "" : "", s ? s->int_ref ? s->int_ref : "" : "", + s ? s->int_ref ? ") " : "" : "", (sp && sp->name) ? " in " : "", (sp && sp->name) ? sp->name : "", (mp && mp->name) ? " in " : "", @@ -1393,159 +1283,366 @@ gtk_label_set_label(GTK_LABEL(info_banner.location), buffer); static void map_update_destination(gdouble lat, gdouble lon) { +gdouble dh=0.0; +gdouble dt, cdist; +static gdouble prev_dt=99999.0; +static gboolean dest_reached=FALSE; +gchar buffer[64]; + if (_dest.valid) { - gchar buffer[32]; - gdouble dt=calculate_distance(lat, lon, _dest.lat, _dest.lon); - gdouble dh=calculate_course(lat, lon, _dest.lat, _dest.lon); - snprintf(buffer, sizeof(buffer), "%.02f %s (%0.02f)", dt * UNITS_CONVERT[_units], UNITS_TEXT[_units], dh); + dt=calculate_distance(lat, lon, _dest.lat, _dest.lon); + dh=calculate_course(lat, lon, _dest.lat, _dest.lon); + cdist=dt*UNITS_CONVERT[_units]; + + g_snprintf(buffer, sizeof(buffer), "%.02f %s (%0.02f)", cdist, UNITS_TEXT[_units], dh<0 ? 360+dh : dh); gtk_label_set_label(GTK_LABEL(info_banner.distance), buffer); + + if (dt<0.005 && dest_reached==FALSE) { + if (_center_mode>0) + announce_destination_reached(); + dest_reached=TRUE; + } else if (dt0 && _announce_destination==TRUE) + announce_distance_to_destination(cdist, UNITS_TEXT[_units], KM10KNOTS); + prev_dt=dt; + } else if (dt>prev_dt+KM10KNOTS/4) { + prev_dt=dt; + } + if (dt>0.05) { + dest_reached=FALSE; + } + g_debug("%f (Prev:%f)\n", prev_dt, dt); } else { + dest_reached=FALSE; + prev_dt=99999.0; gtk_label_set_label(GTK_LABEL(info_banner.distance), ""); } + +gtk_compass_set_dest_heading(_gps_compass, _dest.valid, (gfloat)dh); +gtk_compass_set_dest_heading(_tab_compass, _dest.valid, (gfloat)dh); + +if (_next_way && _next_way->point) { + gdouble wp_lat, wp_lon; + gfloat wc; + + unit2latlon(_next_way->point->unitx,_next_way->point->unity, wp_lat, wp_lon); + wc=calculate_course(lat, lon, wp_lat, wp_lon); + gtk_compass_set_way_heading(_gps_compass, TRUE, wc); + gtk_compass_set_way_heading(_tab_compass, TRUE, wc); +} else { + gtk_compass_set_way_heading(_gps_compass, FALSE, 0); + gtk_compass_set_way_heading(_tab_compass, FALSE, 0); +} + } +/** + * Query the OSM database for where we are. + * + * XXX: This is the wrong place for this function. + */ static void -map_update_location(gint x, gint y, gboolean force) +map_update_location(gdouble lat, gdouble lon, gboolean force) { gint ilat, ilon; -gdouble lat,lon; static gboolean inp=FALSE; /* We run the gtk mainloop in progress callback so we can be called again, we don't like that */ -if (inp==TRUE) +if (inp==TRUE) { + g_debug("LOC: Query in progress"); return; +} inp=TRUE; -unit2latlon(x, y, lat, lon); ilat=lat2mp_int(lat); ilon=lon2mp_int(lon); -if (_gps.fix>1 && !force) - osm_set_way_range_from_speed(_gps.speed); +if (_gps->data.fix>1 && !force) + osm_set_way_range_from_speed(_gps->data.speed); else - osm_set_way_range(OSM_RANGE_WAY/4); - -osm_progress_set_widget(_db, _progress_item); -_map_location_known=osm_get_location_data(ilat, ilon, &map_loc); -_map_location_dist=map_loc.street ? map_loc.street->dist : 900000.0; -if (map_loc.valid) - map_set_place_information(map_loc.street, map_loc.primary, map_loc.secondary); -else - map_set_place_information(NULL, NULL, NULL); -osm_progress_set_widget(_db, NULL); + osm_set_way_range(2800); map_update_destination(lat, lon); +if (osm_check_location(&map_loc, ilat, ilon)==FALSE) { + osm_progress_set_widget(_db, _progress_item); + osm_get_location_data(ilat, ilon, _gps->data.heading, &map_loc); + if (map_loc.valid) + map_set_place_information(map_loc.street, map_loc.primary, map_loc.secondary); + else + map_set_place_information(NULL, NULL, NULL); + osm_progress_set_widget(_db, NULL); +} else g_debug("IN PLACE"); + inp=FALSE; } -gboolean map_cb_scroll_event(GtkWidget * widget, GdkEventScroll * event) +/** + * Mouse scroller zoom in/out callback + */ +static gboolean +map_cb_scroll_event(GtkWidget * widget, GdkEventScroll * event) { +if (event->direction == GDK_SCROLL_UP) { + map_center_unit(x2unit((gint) (event->x + 0.5)), y2unit((gint) (event->y + 0.5))); + map_set_zoom(_zoom - 1); +} else if (event->direction == GDK_SCROLL_DOWN) { + map_center_unit(x2unit((gint) (event->x + 0.5)), y2unit((gint) (event->y + 0.5))); + map_set_zoom(_zoom + 1); +} +return FALSE; +} - if (event->direction == GDK_SCROLL_UP) { - map_center_unit(x2unit((gint) (event->x + 0.5)), - y2unit((gint) (event->y + 0.5))); - map_set_zoom(_zoom - 1); - } else if (event->direction == GDK_SCROLL_DOWN) { - map_center_unit(x2unit((gint) (event->x + 0.5)), - y2unit((gint) (event->y + 0.5))); - map_set_zoom(_zoom + 1); +/** + * Start map drag operation + */ +static void +map_drag_start(gint x,gint y) +{ +press[0] = x; +press[1] = y; +before[0] = press[0]; +before[1] = press[1]; +_center_mode=CENTER_MANUAL; +if (map_drag_id!=0) + g_signal_handler_disconnect(G_OBJECT(_map_widget), map_drag_id); +map_dragged=FALSE; +map_drag_id=g_signal_connect(G_OBJECT(_map_widget), "motion_notify_event", G_CALLBACK(map_follow_move_cb), NULL); +} + +/** + * Stop map drag operation + */ +static void +map_drag_stop(gint x, gint y) +{ +if (map_drag_id==0) + return; + +g_signal_handler_disconnect(G_OBJECT(_map_widget), map_drag_id); + +release[0]=x; +release[1]=y; +press[0]=0; +press[1]=0; +release[0]=0; +release[1]=0; +before[0]=0; +before[1]=0; +map_drag_id=0; +if (map_dragged==TRUE) + map_force_redraw(); +} + +/* Workaround hildon content menu problem */ +static gboolean +map_cb_show_poi_info_dialog(gpointer data) +{ +guint poi_id=GPOINTER_TO_INT(data); +if (poi_info_dialog(_window, poi_id)==FALSE) + g_printerr("Huh? Failed to display info dialog\n"); +return FALSE; +} + +static gboolean +map_cb_button_press(GtkWidget *widget, GdkEventButton *event) +{ +_cmenu_position_x = event->x + 0.5; +_cmenu_position_y = event->y + 0.5; + +switch (event->button) { +case 1: + if (event->type==GDK_2BUTTON_PRESS) { + map_center_unit(x2unit((gint) (event->x + 0.5)), y2unit((gint) (event->y + 0.5))); +#ifdef MAP_ZOOM_ON_DOUBLE_CLICK + map_set_zoom(_zoom-1); +#endif + map_data_needs_refresh=TRUE; + map_drag_stop(event->x, event->y); + return FALSE; + } + if (event->type==GDK_3BUTTON_PRESS) { + map_drag_stop(event->x, event->y); + return FALSE; } + map_drag_start(event->x, event->y); return FALSE; +break; +case 2: + /* */ +break; +case 3: +#ifndef WITH_HILDON + gtk_menu_popup(GTK_MENU(_menu_map), NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time()); +#endif +break; +} +/* Return FALSE to allow context menu to work. */ +return FALSE; } -gboolean map_cb_button_press(GtkWidget * widget, GdkEventButton * event) +static gboolean +map_pan_click_check(gint x, gint y) { - printf("%s()\n", __PRETTY_FUNCTION__); +gint pns=0, pew=0; - _cmenu_position_x = event->x + 0.5; - _cmenu_position_y = event->y + 0.5; +if (x(_screen_width_pixels-MAP_THUMB_MARGIN_X)) + pns=PAN_UNITS; - switch (event->button) { - case 1: - if (event->type == GDK_2BUTTON_PRESS) { - map_set_zoom(_zoom - 1); - return FALSE; - } - if (event->type == GDK_3BUTTON_PRESS) +if (y(_screen_height_pixels-MAP_THUMB_MARGIN_Y)) + pew=PAN_UNITS; + +if (pns!=0 || pew!=0) { + map_pan(pns, pew); + g_debug("MPAN: %d, %d", pns, pew); + return TRUE; +} +return FALSE; +} + +static gboolean +map_cb_button_release(GtkWidget *widget, GdkEventButton *event) +{ +gdouble lat, lon; +guint poi_id; +gint ux, uy; + +switch (event->button) { +case 1: + +#if defined(WITH_HILDON_NEW) + if (hildon_helper_event_button_is_finger(event)) { + g_debug("Thumb down"); + if (map_pan_click_check(event->x, event->y)) return FALSE; - break; - case 2: - press[0] = event->x; - press[1] = event->y; - before[0] = press[0]; - before[1] = press[1]; - - _id = g_signal_connect(G_OBJECT(_map_widget), - "motion_notify_event", - G_CALLBACK(map_follow_move), NULL); - break; - case 3: -#ifndef WITH_HILDON - gtk_menu_popup(GTK_MENU(_menu_map), NULL, NULL, NULL, NULL, - event->button, gtk_get_current_event_time()); -#endif - break; } +#endif + + switch (map_mode) { + case MAP_MODE_DRAW_TRACK: + map_draw_track(event->x, event->y); + break; + case MAP_MODE_DRAW_ROUTE: + map_draw_route(event->x, event->y); + break; + case MAP_MODE_SET_ROUTE_FROM: + case MAP_MODE_SET_ROUTE_POINT: + case MAP_MODE_SET_ROUTE_TO: + break; + default: + ux=x2unit(_cmenu_position_x); + uy=y2unit(_cmenu_position_y); - /* Return FALSE to allow context menu to work. */ - vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__); + unit2latlon(ux, uy, lat, lon); + if (map_poi_find_at_latlon(lat, lon, &poi_id)==TRUE) { + g_idle_add_full(G_PRIORITY_HIGH_IDLE,(GSourceFunc)map_cb_show_poi_info_dialog, GINT_TO_POINTER(poi_id), NULL); + } + if (map_data_needs_refresh==TRUE) { + map_data_needs_refresh=FALSE; + map_render_data(); + g_idle_add_full(G_PRIORITY_HIGH_IDLE,(GSourceFunc)map_update_location_from_center, NULL, NULL); + } + if (_center_mode>0) + set_action_activate("autocenter_none", TRUE); + map_drag_stop(event->x, event->y); + break; + } +break; +case 2: + if (map_pan_click_check(event->x, event->y)==FALSE) + map_set_zoom(_zoom-1); return FALSE; +break; +case 3: + /* */ +break; +} + +/* Return FALSE to avoid context menu (if it hasn't popped up already). */ +return FALSE; } -gboolean map_cb_button_release(GtkWidget * widget, GdkEventButton * event) +gboolean +map_dialog_goto_latlon(void) { - printf("%s()\n", __PRETTY_FUNCTION__); - - switch (event->button) { - case 1: - if (_center_mode > 0) - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(_menu_ac_none_item), TRUE); - - switch (_map_mode) { - case MAP_MODE_DRAW_TRACK: - map_draw_track(event->x, event->y); - break; - case MAP_MODE_DRAW_ROUTE: - map_draw_route(event->x, event->y); - break; - case MAP_MODE_SET_ROUTE_FROM: - case MAP_MODE_SET_ROUTE_POINT: - case MAP_MODE_SET_ROUTE_TO: - break; - } +GtkWidget *dialog; +GtkWidget *table; +GtkWidget *label; +GtkWidget *txt_lat; +GtkWidget *txt_lon; -#if 0 - ux = x2unit((gint) (event->x + 0.5)); - uy = y2unit((gint) (event->y + 0.5)); - map_update_location(ux, uy); -#else - g_idle_add((GSourceFunc)map_update_location_from_center, NULL); +dialog = gtk_dialog_new_with_buttons(_("Go to Lat/Lon"), + GTK_WINDOW(_window), + GTK_DIALOG_MODAL, GTK_STOCK_OK, + GTK_RESPONSE_ACCEPT, + GTK_STOCK_CANCEL, + GTK_RESPONSE_REJECT, NULL); + +gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), table = gtk_table_new(2, 3, FALSE), TRUE, TRUE, 0); + +gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(_("Latitude")),0, 1, 0, 1, GTK_FILL, 0, 2, 4); +gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f); + +gtk_table_attach(GTK_TABLE(table), txt_lat = gtk_entry_new(), 1, 2, 0, 1, GTK_FILL, 0, 2, 4); +gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); + +gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(_("Longitude")), 0, 1, 1, 2, GTK_FILL, 0, 2, 4); +gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f); + +gtk_table_attach(GTK_TABLE(table), txt_lon = gtk_entry_new(), 1, 2, 1, 2, GTK_FILL, 0, 2, 4); +gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); + +#if defined (WITH_DEVICE_770) && !defined(WITH_HILDON_NEW) +g_object_set(G_OBJECT(txt_lat), HILDON_INPUT_MODE_HINT, HILDON_INPUT_MODE_HINT_NUMERICSPECIAL, NULL); +g_object_set(G_OBJECT(txt_lon), HILDON_INPUT_MODE_HINT, HILDON_INPUT_MODE_HINT_NUMERICSPECIAL, NULL); #endif - map_center_unit(x2unit((gint) (event->x + 0.5)), - y2unit((gint) (event->y + 0.5))); - - break; - case 2: - release[0] = event->x; - release[1] = event->y; - - g_signal_handler_disconnect(G_OBJECT(_map_widget), _id); - - press[0] = 0; - press[1] = 0; - release[0] = 0; - release[1] = 0; - before[0] = 0; - before[1] = 0; - break; - case 3: - break; +/* Initialize with the current center position. */ +{ + gchar buffer[32]; + gdouble lat, lon; + unit2latlon(_center.unitx, _center.unity, lat, lon); + g_snprintf(buffer, sizeof(buffer), "%.06f", lat); + gtk_label_set_text(GTK_LABEL(txt_lat), buffer); + g_snprintf(buffer, sizeof(buffer), "%.06f", lon); + gtk_label_set_text(GTK_LABEL(txt_lon), buffer); +} + +gtk_widget_show_all(dialog); + +while (GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog))) { + const gchar *text; + gchar *error_check; + gdouble lat, lon; + guint unitx, unity; + + text = gtk_entry_get_text(GTK_ENTRY(txt_lat)); + lat = strtof(text, &error_check); + if (text == error_check || lat < -90.f || lat > 90.f) { + popup_error(dialog, _("Invalid Latitude")); + continue; } - /* Return FALSE to avoid context menu (if it hasn't popped up already). */ - vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__); - return FALSE; + text = gtk_entry_get_text(GTK_ENTRY(txt_lon)); + lon = strtof(text, &error_check); + if (text == error_check || lon < -180.f || lon > 180.f) { + popup_error(dialog, _("Invalid Longitude")); + continue; + } + + latlon2unit(lat, lon, unitx, unity); + if (_center_mode > 0) + set_action_activate("autocenter_none", TRUE); + + map_center_unit(unitx, unity); + break; } +gtk_widget_destroy(dialog); +return TRUE; +} +