From 51653348bccfed999f45c15197db720d8af6b89f Mon Sep 17 00:00:00 2001 From: Kaj-Michael Lang Date: Mon, 5 May 2008 18:09:13 +0300 Subject: [PATCH] Map widget starts to work --- src/gtkmap.c | 249 ++++++++++++++++++++++++++++-------------- src/gtkmap.h | 14 +-- src/map-widget-test.c | 20 +++- 3 files changed, 190 insertions(+), 93 deletions(-) diff --git a/src/gtkmap.c b/src/gtkmap.c index 3c3afde..3fc3948 100644 --- a/src/gtkmap.c +++ b/src/gtkmap.c @@ -17,6 +17,8 @@ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "config.h" + #include #include #include @@ -42,6 +44,9 @@ #define BUF_WIDTH_PIXELS (1024) #define BUF_HEIGHT_PIXELS (768) +/* Filename buffer */ +#define BUFFER_SIZE (2048) + #define SCALE_WIDTH (256) #define MAP_CACHE_DEFAULT (64) @@ -201,7 +206,7 @@ struct _GtkMapPriv /* #define GTK_MAP_WORLD_SIZE_UNITS(max_zoom) (2 << (max_zoom + GTK_MAP_TILE_SIZE_P2)) */ -#define GTK_MAP_WORLD_SIZE_UNITS (1<<31) +#define GTK_MAP_WORLD_SIZE_UNITS (2<<26) #define WORLD_SIZE_UNITS GTK_MAP_WORLD_SIZE_UNITS /* Pans are done two "grids" at a time, or 64 pixels. */ @@ -267,7 +272,6 @@ object_class->get_property = gtk_map_get_property; widget_class->size_request = gtk_map_size_request; widget_class->expose_event = gtk_map_expose; -/* widget_class->configure_event = gtk_map_configure; */ widget_class->realize = gtk_map_realize; widget_class->size_allocate = gtk_map_size_allocate; @@ -338,10 +342,6 @@ GtkMapPriv *priv; g_debug("GTKMAP: %s", __PRETTY_FUNCTION__); priv=GTK_MAP_GET_PRIVATE(map); -#ifdef WITH_CAIRO -priv->ct=gdk_cairo_create(GTK_WIDGET(map)->window); -#endif - priv->base_tilex=-5; priv->base_tiley=-5; @@ -368,49 +368,11 @@ priv->show_markers=TRUE; priv->show_location=TRUE; priv->gl=FALSE; - -#ifdef WITH_GL -priv->gl_config=gdk_gl_config_new_by_mode(GDK_GL_MODE_RGB | GDK_GL_MODE_DEPTH); -if (priv->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, priv->gl_config, NULL, TRUE, GDK_GL_RGBA_TYPE); - priv->gl=TRUE; -} -#endif - priv->buffer=NULL; - -gtk_widget_set_extension_events(GTK_WIDGET(map), GDK_EXTENSION_EVENTS_ALL); - -gtk_widget_add_events(GTK_WIDGET(map), GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - | GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK); - -#if 0 -g_signal_connect(G_OBJECT(map), "button_press_event", G_CALLBACK(gtk_map_cb_button_press), NULL); -#endif - -} - -static gboolean -gtk_map_configure(GtkWidget *widget, GdkEventConfigure *event) -{ -GtkMap *map; -GtkMapPriv *priv; - -g_return_val_if_fail(GTK_IS_MAP(widget), TRUE); -map=GTK_MAP(widget); -priv=GTK_MAP_GET_PRIVATE(map); - -g_debug("GTKMAP: %s", __PRETTY_FUNCTION__); - -return TRUE; } - static void -gtk_map_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +gtk_map_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GtkMap *map; g_return_if_fail(GTK_IS_MAP(object)); @@ -426,6 +388,7 @@ static void gtk_map_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GtkMap *map; + g_return_if_fail(GTK_IS_MAP(object)); map=GTK_MAP(object); switch (prop_id) { @@ -446,12 +409,19 @@ static void gtk_map_finalize(GObject *object) { GtkMap *map; +GtkMapPriv *priv; g_return_if_fail(GTK_IS_MAP(object)); map=GTK_MAP(object); +priv=GTK_MAP_GET_PRIVATE(map); g_debug("GTKMAP: %s", __PRETTY_FUNCTION__); +#ifdef WITH_CAIRO +if (priv->ct) + cairo_destroy(priv->ct); +#endif + if (GTK_WIDGET(object)->parent && GTK_WIDGET_MAPPED(object)) { gtk_widget_unmap(GTK_WIDGET(object)); } @@ -513,6 +483,7 @@ if (GTK_WIDGET_REALIZED(widget)) gdk_window_move_resize(widget->window, allocation->x, allocation->y, allocation->width, allocation->height); gtk_map_update_size(widget, allocation->width, allocation->height); +gtk_map_refresh(widget); } static void @@ -584,7 +555,7 @@ attributes.width=widget->allocation.width; attributes.height=widget->allocation.height; attributes.wclass=GDK_INPUT_OUTPUT; -attributes.event_mask=gtk_widget_get_events(widget) | GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK; +attributes.event_mask=gtk_widget_get_events(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; attributes_mask=GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; attributes.visual=gtk_widget_get_visual(widget); @@ -597,6 +568,19 @@ gdk_window_set_user_data(widget->window, widget); widget->style=gtk_style_attach(widget->style, widget->window); gtk_style_set_background(widget->style, widget->window, GTK_STATE_NORMAL); +gtk_widget_set_extension_events(widget, GDK_EXTENSION_EVENTS_ALL); + +#ifdef WITH_GL +priv->gl_config=gdk_gl_config_new_by_mode(GDK_GL_MODE_RGB | GDK_GL_MODE_DEPTH); +if (priv->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(widget->window, priv->gl_config, NULL, TRUE, GDK_GL_RGBA_TYPE); + priv->gl=TRUE; +} +#endif + priv->scale_context=gtk_widget_get_pango_context(widget); priv->scale_layout=pango_layout_new(priv->scale_context); priv->scale_font=pango_font_description_new(); @@ -623,6 +607,30 @@ priv->speed_font=pango_font_description_new(); pango_font_description_set_size(priv->speed_font, 48 * PANGO_SCALE); pango_layout_set_font_description(priv->speed_layout, priv->speed_font); pango_layout_set_alignment(priv->speed_layout, PANGO_ALIGN_LEFT); + +#if 0 +g_signal_connect(G_OBJECT(widget), "button_press_event", G_CALLBACK(gtk_map_press_cb), NULL); +#endif + +} + +static void +draw (GtkWidget *clock, cairo_t *cr) +{ + double x, y; + double radius; + int i; + + x = clock->allocation.x + clock->allocation.width / 2; + y = clock->allocation.y + clock->allocation.height / 2; + radius = MIN (clock->allocation.width / 2, clock->allocation.height / 2) - 5; + + /* clock back */ + cairo_arc (cr, x, y, radius, 0, 2 * M_PI); + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_fill_preserve (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_stroke (cr); } static gboolean @@ -637,6 +645,10 @@ g_return_val_if_fail(event != NULL, FALSE); map=GTK_MAP(widget); priv=GTK_MAP_GET_PRIVATE(map); +#ifdef WITH_CAIRO +priv->ct=gdk_cairo_create(widget->window); +#endif + g_debug("GTKMAP: expose (%d, %d)-(%d, %d)", event->area.x, event->area.y, event->area.width, event->area.height); if (priv->buffer) @@ -660,6 +672,11 @@ if (priv->show_location) if (priv->show_scale) gtk_map_scale_draw(widget, event); +#ifdef WITH_CAIRO +cairo_destroy(priv->ct); +priv->ct=NULL; +#endif + return TRUE; } @@ -677,32 +694,32 @@ g_debug("GTKMAP: %s", __PRETTY_FUNCTION__); if (!gdk_rectangle_intersect(&event->area, &priv->mark_rect, NULL)) return; +return; + #ifdef WITH_CAIRO -cairo_arc(priv->ct, priv->mark_x1, priv->marky1, priv->draw_width*2, 0, 2 * M_PI); +cairo_save(priv->ct); +cairo_arc(priv->ct, priv->mark_x1, priv->mark_y1, priv->draw_width*2, 0, 2 * M_PI); cairo_set_source_rgb(priv->ct, 1, 1, 1); cairo_fill_preserve(priv->ct); -cairo_set_source_rgb(priv->ct, 0, 0, 0); +cairo_set_source_rgba(priv->ct, 0.2, 0.2, 0.8, 0.7); if (priv->show_velvec) { cairo_save(priv->ct); cairo_set_line_width(priv->ct, priv->draw_width); - cairo_move_to(priv->ct, priv->mark_x1, priv->marky1); - cairo_line_to(priv->ct, priv->mark_x2, priv->marky2); + cairo_move_to(priv->ct, priv->mark_x1, priv->mark_y1); + cairo_line_to(priv->ct, priv->mark_x2, priv->mark_y2); cairo_restore(priv->ct); } +cairo_restore(priv->ct); cairo_stroke(priv->ct); #else -gdk_draw_arc(widget->window, - priv->gc_mark, - FALSE, +gdk_draw_arc(widget->window, priv->gc_mark, FALSE, priv->mark_x1 - priv->draw_width, priv->mark_y1 - priv->draw_width, - 2 * priv->draw_width, - 2 * priv->draw_width, + 2 * priv->draw_width, 2 * priv->draw_width, 0, 360 * 64); if (priv->show_velvec) - gdk_draw_line(widget->window, - priv->gc_velvec, + gdk_draw_line(widget->window, priv->gc_velvec, priv->mark_x1, priv->mark_y1, priv->mark_x2, priv->mark_y2); #endif @@ -751,14 +768,6 @@ priv->scale_rect.y = priv->screen_height_pixels - priv->scale_rect.height - 1; if (!gdk_rectangle_intersect(&event->area, &priv->scale_rect, NULL)) return; -gdk_draw_rectangle(widget->window, widget->style->bg_gc[GTK_WIDGET_STATE(widget)], - TRUE, priv->scale_rect.x, priv->scale_rect.y, - priv->scale_rect.width, priv->scale_rect.height); - -gdk_draw_rectangle(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], - FALSE, priv->scale_rect.x, priv->scale_rect.y, - priv->scale_rect.width, priv->scale_rect.height); - /* Now calculate and draw the distance. */ unit2latlon(priv->center.unitx - pixel2unit(SCALE_WIDTH / 2 - 4), priv->center.unity, lat1, lon1); unit2latlon(priv->center.unitx + pixel2unit(SCALE_WIDTH / 2 - 4), priv->center.unity, lat2, lon2); @@ -773,6 +782,19 @@ else g_debug("SCALE: %s", buffer); +#ifdef WITH_CAIRO +cairo_rectangle(priv->ct, priv->scale_rect.x, priv->scale_rect.y, priv->scale_rect.width, priv->scale_rect.height); +cairo_set_source_rgba(priv->ct, 1, 1, 1, 0.8); +cairo_fill_preserve(priv->ct); +cairo_set_source_rgb(priv->ct, 0, 0, 0); +cairo_stroke(priv->ct); +#else +gdk_draw_rectangle(widget->window, widget->style->bg_gc[GTK_WIDGET_STATE(widget)], + TRUE, priv->scale_rect.x, priv->scale_rect.y, priv->scale_rect.width, priv->scale_rect.height); +gdk_draw_rectangle(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], + FALSE, priv->scale_rect.x, priv->scale_rect.y, priv->scale_rect.width, priv->scale_rect.height); +#endif + pango_layout_set_text(priv->scale_layout, buffer, -1); pango_layout_get_pixel_size(priv->scale_layout, &width, NULL); @@ -783,26 +805,22 @@ gdk_draw_layout(widget->window, priv->scale_rect.y, priv->scale_layout); /* Draw little hashes on the ends. */ -gdk_draw_line(widget->window, - widget->style->fg_gc[GTK_WIDGET_STATE(widget)], +gdk_draw_line(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], priv->scale_rect.x + 4, priv->scale_rect.y + priv->scale_rect.height / 2 - 4, priv->scale_rect.x + 4, priv->scale_rect.y + priv->scale_rect.height / 2 + 4); -gdk_draw_line(widget->window, - widget->style->fg_gc[GTK_WIDGET_STATE(widget)], +gdk_draw_line(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], priv->scale_rect.x + 4, priv->scale_rect.y + priv->scale_rect.height / 2, priv->scale_rect.x + (priv->scale_rect.width - width) / 2 - 4, priv->scale_rect.y + priv->scale_rect.height / 2); -gdk_draw_line(widget->window, - widget->style->fg_gc[GTK_WIDGET_STATE(widget)], +gdk_draw_line(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], priv->scale_rect.x + priv->scale_rect.width - 4, priv->scale_rect.y + priv->scale_rect.height / 2 - 4, priv->scale_rect.x + priv->scale_rect.width - 4, priv->scale_rect.y + priv->scale_rect.height / 2 + 4); -gdk_draw_line(widget->window, - widget->style->fg_gc[GTK_WIDGET_STATE(widget)], +gdk_draw_line(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], priv->scale_rect.x + priv->scale_rect.width - 4, priv->scale_rect.y + priv->scale_rect.height / 2, priv->scale_rect.x + (priv->scale_rect.width + width) / 2 + 4, @@ -919,14 +937,75 @@ gtk_map_tile_load(GtkWidget *widget, guint tilex, guint tiley, gint zoff, gboole { GtkMap *map; GtkMapPriv *priv; +GdkPixbuf *pixbuf; +GError *error = NULL; +gchar buffer[BUFFER_SIZE]; +gchar key[BUFFER_SIZE]; +struct stat tstat; +gint se; g_return_val_if_fail(GTK_IS_MAP(widget), FALSE); map=GTK_MAP(widget); priv=GTK_MAP_GET_PRIVATE(map); -g_debug("LOAD: %u, %u @ (%d+%d)", tilex, tiley, priv->zoom, zoff); +g_snprintf(buffer, sizeof(buffer), "%s/%u/%u/%u.jpg", priv->curr_repo->cache_dir, priv->zoom + zoff, (tilex >> zoff), (tiley >> zoff)); +g_snprintf(key, sizeof(key), "%s/%u/%u/%u", priv->curr_repo->cache_dir, priv->zoom + zoff, (tilex >> zoff), (tiley >> zoff)); + +g_debug("LOAD: %u, %u @ (%d+%d): %s", tilex, tiley, priv->zoom, zoff, buffer); + +pixbuf=image_cache_get(priv->icache, key, buffer); +if (!pixbuf) { +#if 0 + 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); + } +#endif + return NULL; +} + +g_object_ref(pixbuf); + +#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 + +#if 0 +/* 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); + } + } + } +} +#endif -return NULL; +return pixbuf; +} + +void +gtk_map_set_tile_repository(GtkWidget *widget, RepoData *rd) +{ +GtkMap *map; +GtkMapPriv *priv; + +g_return_if_fail(GTK_IS_MAP(widget)); +map=GTK_MAP(widget); +priv=GTK_MAP_GET_PRIVATE(map); + +priv->curr_repo=rd; } static gboolean @@ -1075,8 +1154,7 @@ if (new_base_tilex != priv->base_tilex || new_base_tiley != priv->base_tiley) { gtk_map_recalc_offset(priv); gtk_map_recalc_focus_base(priv); - -gtk_map_refresh(map); +gtk_map_refresh(widget); } void @@ -1089,13 +1167,24 @@ g_return_if_fail(GTK_IS_MAP(widget)); map=GTK_MAP(widget); priv=GTK_MAP_GET_PRIVATE(map); -gtk_map_set_center(widget, priv->center.unitx + delta_x, priv->center.unity + delta_y); +gtk_map_set_center(widget, priv->center.unitx + delta_x*GTK_MAP_PAN_UNITS, priv->center.unity + delta_y*GTK_MAP_PAN_UNITS); } -void +static void gtk_map_refresh(GtkWidget *widget) { +GtkMap *map; +GtkMapPriv *priv; +guint x, y; + g_return_if_fail(GTK_IS_MAP(widget)); +map=GTK_MAP(widget); +priv=GTK_MAP_GET_PRIVATE(map); + +for (y = 0; y < priv->buf_height_tiles; ++y) + for (x = 0; x < priv->buf_width_tiles; ++x) + gtk_map_render_tile(map, priv->base_tilex + x, priv->base_tiley + y, x * GTK_MAP_TILE_SIZE_PIXELS, y * GTK_MAP_TILE_SIZE_PIXELS, FALSE); + gtk_widget_queue_draw_area(widget, 0, 0, widget->allocation.width, widget->allocation.height); } @@ -1159,7 +1248,7 @@ gtk_map_recalc_offset(priv); gtk_map_recalc_focus_base(priv); gtk_map_recalc_focus_size(priv); -gtk_map_refresh(GTK_WIDGET(map)); +gtk_map_refresh(widget); return TRUE; } diff --git a/src/gtkmap.h b/src/gtkmap.h index faf252c..47985b4 100644 --- a/src/gtkmap.h +++ b/src/gtkmap.h @@ -22,6 +22,7 @@ #include #include "path.h" +#include "map-tile-repo.h" typedef enum { CENTER_WAS_LATLON = -2, @@ -41,11 +42,7 @@ typedef struct _GtkMapClass GtkMapClass; struct _GtkMap { GtkDrawingArea map; - - guint width, height; guint size; - guint xoffset, yoffset; - gfloat heading; gfloat speed; }; @@ -58,14 +55,15 @@ G_BEGIN_DECLS GType gtk_map_get_type(void); GtkWidget* gtk_map_new(void); -void gtk_map_refresh(GtkWidget *widget); +void gtk_map_refresh(GtkWidget *map); + +void gtk_map_set_tile_repository(GtkWidget *map, RepoData *rd); gboolean gtk_map_key_zoom_timeout(GtkWidget *map); +void gtk_map_render_path(GtkWidget *map, Path *path, GdkGC ** gc); -void gtk_map_render_path(Path *path, GdkGC ** gc); -void gtk_map_pan(GtkWidget *map, gint delta_unitx, gint delta_unity); -void gtk_map_move_mark(GtkWidget *map); void gtk_map_set_mark(GtkWidget *map); +void gtk_map_move_mark(GtkWidget *map); void gtk_map_render_data(GtkWidget *map); void gtk_map_render_waypoint(GtkWidget *map, guint x1, guint y1, GdkGC *gc); diff --git a/src/map-widget-test.c b/src/map-widget-test.c index 0706796..37a1f45 100644 --- a/src/map-widget-test.c +++ b/src/map-widget-test.c @@ -1,6 +1,10 @@ #include #include + #include "gtkmap.h" +#include "map-tile-repo.h" + +#define TESTREPO "/home/milang/MyDocs/.documents/Maps/OpenStreet" GtkWidget *map; @@ -14,28 +18,28 @@ return TRUE; static gboolean map_pan_up(GtkWidget *widget, gpointer data) { -gtk_map_pan(map, -1, 0); +gtk_map_pan(map, 0, -1); return TRUE; } static gboolean map_pan_down(GtkWidget *widget, gpointer data) { -gtk_map_pan(map, 1, 0); +gtk_map_pan(map, 0, 1); return TRUE; } static gboolean map_pan_left(GtkWidget *widget, gpointer data) { -gtk_map_pan(map, 0, -1); +gtk_map_pan(map, -1, 0); return TRUE; } static gboolean map_pan_right(GtkWidget *widget, gpointer data) { -gtk_map_pan(map, 0, 1); +gtk_map_pan(map, 1, 0); return TRUE; } @@ -44,9 +48,14 @@ main (int argc, char **args) { GtkDialog *dialog; GtkWidget *hbox, *zoomer, *btn_left, *btn_right, *btn_up, *btn_down, *vbox; +RepoData *rd; gtk_init (&argc, &args); - + +rd=map_tile_repo_new(); +rd->view_zoom_steps=1; +rd->cache_dir=TESTREPO; + dialog=GTK_DIALOG(gtk_dialog_new ()); gtk_window_set_title(GTK_WINDOW(dialog), "Map test"); gtk_dialog_add_button (dialog, "Close", GTK_RESPONSE_CLOSE); @@ -55,6 +64,7 @@ hbox=gtk_hbox_new(FALSE, 3); vbox=gtk_vbox_new(FALSE, 3); map=gtk_map_new(); +gtk_map_set_tile_repository(map, rd); gtk_box_pack_start(GTK_BOX(hbox), map, TRUE, TRUE, 0); zoomer=gtk_vscale_new_with_range(0,17,1); -- 2.39.5