2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
4 * Copyright (C) 2005, Evan Battaglia <viking@greentorch.org>
5 * Copyright (C) 2010, Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
6 * UTM multi-zone stuff by Kit Transue <notlostyet@didactek.com>
7 * Dynamic map type by Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #define MAX_SHRINKFACTOR 8.0000001 /* zoom 1 viewing 8-tiles */
30 #define MIN_SHRINKFACTOR 0.0312499 /* zoom 32 viewing 1-tiles */
32 #define REAL_MIN_SHRINKFACTOR 0.0039062499 /* if shrinkfactor is between MAX and REAL_MAX, will only check for existence */
35 #include <gdk-pixbuf/gdk-pixdata.h>
37 #include <glib/gstdio.h>
38 #include <glib/gi18n.h>
51 #include "viktreeview.h"
52 #include "vikviewport.h"
54 #include "vikmapslayer.h"
61 /* only for dialog.h -- ugh */
62 #include "vikwaypoint.h"
64 #include "preferences.h"
66 #include "vikstatus.h"
67 #include "background.h"
69 #include "vikaggregatelayer.h"
70 #include "viklayerspanel.h"
73 #include "terraserver.h"
75 #include "icons/icons.h"
77 /****** MAP TYPES ******/
79 static GList *__map_types = NULL;
81 #define NUM_MAP_TYPES g_list_length(__map_types)
83 /* List of label for each map type */
84 static gchar **params_maptypes = NULL;
86 /* Corresponding IDS. (Cf. field uniq_id in VikMapsLayer struct) */
87 static guint *params_maptypes_ids = NULL;
89 /******** MAPZOOMS *********/
91 static gchar *params_mapzooms[] = { N_("Use Viking Zoom Level"), "0.25", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", "USGS 10k", "USGS 24k", "USGS 25k", "USGS 50k", "USGS 100k", "USGS 200k", "USGS 250k", NULL };
92 static gdouble __mapzooms_x[] = { 0.0, 0.25, 1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0, 512.0, 1024.0, 1.016, 2.4384, 2.54, 5.08, 10.16, 20.32, 25.4 };
93 static gdouble __mapzooms_y[] = { 0.0, 0.25, 1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0, 512.0, 1024.0, 1.016, 2.4384, 2.54, 5.08, 10.16, 20.32, 25.4 };
95 #define NUM_MAPZOOMS (sizeof(params_mapzooms)/sizeof(params_mapzooms[0]) - 1)
97 /**************************/
100 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file);
101 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len );
102 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
103 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation );
104 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation );
105 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp );
106 static VikMapsLayer *maps_layer_new ( VikViewport *vvp );
107 static void maps_layer_free ( VikMapsLayer *vml );
108 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
109 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
110 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp );
111 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir );
112 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload );
113 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp );
114 static guint map_uniq_id_to_index ( guint uniq_id );
117 static VikLayerParamScale params_scales[] = {
118 /* min, max, step, digits (decimal places) */
119 { 0, 255, 3, 0 }, /* alpha */
122 VikLayerParam maps_layer_params[] = {
123 { "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Map Type:"), VIK_LAYER_WIDGET_COMBOBOX, NULL, NULL },
124 { "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Maps Directory:"), VIK_LAYER_WIDGET_FOLDERENTRY },
125 { "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales },
126 { "autodownload", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload maps:"), VIK_LAYER_WIDGET_CHECKBUTTON },
127 { "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Zoom Level:"), VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms, NULL },
130 enum { PARAM_MAPTYPE=0, PARAM_CACHE_DIR, PARAM_ALPHA, PARAM_AUTODOWNLOAD, PARAM_MAPZOOM, NUM_PARAMS };
132 static VikToolInterface maps_tools[] = {
133 { N_("Maps Download"), (VikToolConstructorFunc) maps_layer_download_create, NULL, NULL, NULL,
134 (VikToolMouseFunc) maps_layer_download_click, NULL, (VikToolMouseFunc) maps_layer_download_release,
135 (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_mapdl_pixbuf },
138 VikLayerInterface vik_maps_layer_interface = {
140 &vikmapslayer_pixbuf,
143 sizeof(maps_tools) / sizeof(maps_tools[0]),
152 (VikLayerFuncCreate) maps_layer_new,
153 (VikLayerFuncRealize) NULL,
154 (VikLayerFuncPostRead) maps_layer_post_read,
155 (VikLayerFuncFree) maps_layer_free,
157 (VikLayerFuncProperties) NULL,
158 (VikLayerFuncDraw) maps_layer_draw,
159 (VikLayerFuncChangeCoordMode) NULL,
161 (VikLayerFuncSetMenuItemsSelection) NULL,
162 (VikLayerFuncGetMenuItemsSelection) NULL,
164 (VikLayerFuncAddMenuItems) maps_layer_add_menu_items,
165 (VikLayerFuncSublayerAddMenuItems) NULL,
167 (VikLayerFuncSublayerRenameRequest) NULL,
168 (VikLayerFuncSublayerToggleVisible) NULL,
170 (VikLayerFuncMarshall) maps_layer_marshall,
171 (VikLayerFuncUnmarshall) maps_layer_unmarshall,
173 (VikLayerFuncSetParam) maps_layer_set_param,
174 (VikLayerFuncGetParam) maps_layer_get_param,
176 (VikLayerFuncReadFileData) NULL,
177 (VikLayerFuncWriteFileData) NULL,
179 (VikLayerFuncDeleteItem) NULL,
180 (VikLayerFuncCopyItem) NULL,
181 (VikLayerFuncPasteItem) NULL,
182 (VikLayerFuncFreeCopiedItem) NULL,
183 (VikLayerFuncDragDropRequest) NULL,
186 struct _VikMapsLayer {
192 gdouble xmapzoom, ymapzoom;
194 gboolean autodownload;
195 VikCoord *last_center;
199 gint dl_tool_x, dl_tool_y;
201 GtkMenu *dl_right_click_menu;
202 VikCoord redownload_ul, redownload_br; /* right click menu only */
203 VikViewport *redownload_vvp;
206 enum { REDOWNLOAD_NONE = 0, /* download only missing maps */
207 REDOWNLOAD_BAD, /* download missing and bad maps */
208 REDOWNLOAD_NEW, /* download missing maps that are newer on server only */
209 REDOWNLOAD_ALL, /* download all maps */
210 DOWNLOAD_OR_REFRESH }; /* download missing maps and refresh cache */
212 static VikLayerParam prefs[] = {
213 { VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Default maplayer directory:"), VIK_LAYER_WIDGET_FOLDERENTRY, NULL, NULL },
216 void maps_layer_init ()
218 VikLayerParamData tmp;
219 tmp.s = maps_layer_default_dir();
220 a_preferences_register(prefs, tmp, VIKING_PREFERENCES_GROUP_KEY);
223 /****************************************/
224 /******** MAPS LAYER TYPES **************/
225 /****************************************/
227 int _get_index_for_id ( guint id )
230 while (params_maptypes_ids[index] != 0)
232 if (params_maptypes_ids[index] == id)
239 void _add_map_source ( guint id, const char *label, VikMapSource *map )
243 len = g_strv_length (params_maptypes);
245 params_maptypes = g_realloc (params_maptypes, (len+2)*sizeof(gchar*));
246 params_maptypes[len] = g_strdup (label);
247 params_maptypes[len+1] = NULL;
250 params_maptypes_ids = g_realloc (params_maptypes_ids, (len+2)*sizeof(guint));
251 params_maptypes_ids[len] = id;
252 params_maptypes_ids[len+1] = 0;
254 /* We have to clone */
255 VikMapSource *clone = VIK_MAP_SOURCE(g_object_ref(map));
256 /* Register the clone in the list */
257 __map_types = g_list_append(__map_types, clone);
260 We have to ensure the mode LayerParam references the up-to-date
264 memcpy(&maps_layer_params[0].widget_data, ¶ms_maptypes, sizeof(gpointer));
265 memcpy(&maps_layer_params[0].extra_widget_data, ¶ms_maptypes_ids, sizeof(gpointer));
267 maps_layer_params[0].widget_data = params_maptypes;
268 maps_layer_params[0].extra_widget_data = params_maptypes_ids;
271 void _update_map_source ( const char *label, VikMapSource *map, int index )
273 GList *item = g_list_nth (__map_types, index);
274 g_object_unref (item->data);
275 item->data = g_object_ref (map);
276 /* Change previous data */
277 g_free (params_maptypes[index]);
278 params_maptypes[index] = g_strdup (label);
281 void maps_layer_register_map_source ( VikMapSource *map )
283 g_assert(map != NULL);
285 guint id = vik_map_source_get_uniq_id(map);
286 const char *label = vik_map_source_get_label(map);
287 g_assert(label != NULL);
289 int previous = map_uniq_id_to_index (id);
290 if (previous != NUM_MAP_TYPES)
292 _update_map_source (label, map, previous);
296 _add_map_source (id, label, map);
300 #define MAPS_LAYER_NTH_LABEL(n) (params_maptypes[n])
301 #define MAPS_LAYER_NTH_ID(n) (params_maptypes_ids[n])
302 #define MAPS_LAYER_NTH_TYPE(n) (VIK_MAP_SOURCE(g_list_nth_data(__map_types, (n))))
304 gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
306 return(vml->maptype);
309 gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
311 return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
314 /****************************************/
315 /******** CACHE DIR STUFF ***************/
316 /****************************************/
318 #define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
319 #define MAPS_CACHE_DIR maps_layer_default_dir()
323 #define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
324 #define LOCAL_MAPS_DIR "VIKING-MAPS"
327 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
328 #define LOCAL_MAPS_DIR ".viking-maps"
331 gchar *maps_layer_default_dir ()
333 static gchar *defaultdir = NULL;
336 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
337 const gchar *mapdir = g_getenv("VIKING_MAPS");
339 defaultdir = g_strdup ( mapdir );
340 } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
341 defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
343 const gchar *home = g_get_home_dir();
344 if (!home || g_access(home, W_OK))
345 home = g_get_home_dir ();
347 defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
349 defaultdir = g_strdup ( LOCAL_MAPS_DIR );
351 if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
353 /* Add the separator at the end */
354 gchar *tmp = defaultdir;
355 defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
358 g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
363 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
365 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
367 g_mkdir ( vml->cache_dir, 0777 );
371 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
374 g_assert ( vml != NULL);
375 g_free ( vml->cache_dir );
376 vml->cache_dir = NULL;
378 if ( dir == NULL || dir[0] == '\0' )
380 if ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir") )
381 vml->cache_dir = g_strdup ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir")->s );
386 if ( dir[len-1] != G_DIR_SEPARATOR )
388 vml->cache_dir = g_malloc ( len+2 );
389 strncpy ( vml->cache_dir, dir, len );
390 vml->cache_dir[len] = G_DIR_SEPARATOR;
391 vml->cache_dir[len+1] = '\0';
394 vml->cache_dir = g_strdup ( dir );
396 maps_layer_mkdir_if_default_dir ( vml );
399 /****************************************/
400 /******** GOBJECT STUFF *****************/
401 /****************************************/
403 GType vik_maps_layer_get_type ()
405 static GType vml_type = 0;
409 static const GTypeInfo vml_info =
411 sizeof (VikMapsLayerClass),
412 NULL, /* base_init */
413 NULL, /* base_finalize */
414 NULL, /* class init */
415 NULL, /* class_finalize */
416 NULL, /* class_data */
417 sizeof (VikMapsLayer),
419 NULL /* instance init */
421 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
427 /****************************************/
428 /************** PARAMETERS **************/
429 /****************************************/
431 static guint map_index_to_uniq_id (guint8 index)
433 g_assert ( index < NUM_MAP_TYPES );
434 return vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(index));
437 static guint map_uniq_id_to_index ( guint uniq_id )
440 for ( i = 0; i < NUM_MAP_TYPES; i++ )
441 if ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(i)) == uniq_id )
443 return NUM_MAP_TYPES; /* no such thing */
446 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation )
450 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
451 case PARAM_MAPTYPE: {
452 gint maptype = map_uniq_id_to_index(data.u);
453 if ( maptype == NUM_MAP_TYPES ) g_warning(_("Unknown map type"));
454 else vml->maptype = maptype;
457 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
458 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
459 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
460 vml->mapzoom_id = data.u;
461 vml->xmapzoom = __mapzooms_x [data.u];
462 vml->ymapzoom = __mapzooms_y [data.u];
463 }else g_warning (_("Unknown Map Zoom")); break;
468 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation )
470 VikLayerParamData rv;
473 case PARAM_CACHE_DIR: rv.s = vml->cache_dir ? vml->cache_dir : ""; break;
474 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
475 case PARAM_ALPHA: rv.u = vml->alpha; break;
476 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
477 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
482 /****************************************/
483 /****** CREATING, COPYING, FREEING ******/
484 /****************************************/
486 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
489 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
490 vik_layer_init ( VIK_LAYER(vml), VIK_LAYER_MAPS );
491 idx = map_uniq_id_to_index(13); /* 13 is id for OSM Mapnik maps */
492 vml->maptype = (idx < NUM_MAP_TYPES) ? idx : 0;
495 vml->dl_tool_x = vml->dl_tool_y = -1;
496 maps_layer_set_cache_dir ( vml, NULL );
497 vml->autodownload = FALSE;
498 vml->last_center = NULL;
499 vml->last_xmpp = 0.0;
500 vml->last_ympp = 0.0;
502 vml->dl_right_click_menu = NULL;
507 static void maps_layer_free ( VikMapsLayer *vml )
509 g_free ( vml->cache_dir );
510 vml->cache_dir = NULL;
511 if ( vml->dl_right_click_menu )
512 gtk_object_sink ( GTK_OBJECT(vml->dl_right_click_menu) );
513 g_free(vml->last_center);
514 vml->last_center = NULL;
517 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
519 if (from_file != TRUE)
521 /* If this method is not called in file reading context
522 * it is called in GUI context.
523 * So, we can check if we have to inform the user about inconsistency */
524 VikViewportDrawMode vp_drawmode;
525 VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
526 VikMapSource *map = NULL;
528 vp_drawmode = vik_viewport_get_drawmode ( VIK_VIEWPORT(vp) );
529 map = MAPS_LAYER_NTH_TYPE(vml->maptype);
530 if (vik_map_source_get_drawmode(map) != vp_drawmode) {
531 const gchar *drawmode_name = vik_viewport_get_drawmode_name (VIK_VIEWPORT(vp), vik_map_source_get_drawmode(map));
532 gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
533 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_WIDGET(vp), msg );
537 if (vik_map_source_get_license (map) != NULL) {
538 a_dialog_license (VIK_GTK_WINDOW_FROM_WIDGET(vp), vik_map_source_get_label (map),
539 vik_map_source_get_license (map), vik_map_source_get_license_url (map) );
544 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
546 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
549 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
551 VikMapsLayer *rv = maps_layer_new ( vvp );
552 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
556 /*********************/
557 /****** DRAWING ******/
558 /*********************/
560 static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
563 gint width, height, iii, jjj;
565 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
567 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
568 g_object_unref(G_OBJECT(pixbuf));
572 pixels = gdk_pixbuf_get_pixels(pixbuf);
573 width = gdk_pixbuf_get_width(pixbuf);
574 height = gdk_pixbuf_get_height(pixbuf);
576 /* r,g,b,a,r,g,b,a.... */
577 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
585 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
588 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
589 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_NEAREST);
590 g_object_unref ( G_OBJECT(pixbuf) );
594 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
599 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
600 mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
603 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
604 vml->cache_dir, mode,
605 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
606 if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
609 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
611 /* free the pixbuf on error */
614 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
615 g_warning ( _("Couldn't open image file: %s"), gx->message );
619 g_object_unref ( G_OBJECT(pixbuf) );
622 if ( vml->alpha < 255 )
623 pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
624 if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
625 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
627 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
628 mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
629 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
636 gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
638 const VikCoord *center = vik_viewport_get_center ( vvp );
640 if (vik_window_get_pan_move (VIK_WINDOW(VIK_GTK_WINDOW_FROM_WIDGET(GTK_WIDGET(vvp)))))
641 /* D'n'D pan in action: do not download */
644 if (vml->last_center == NULL) {
645 VikCoord *new_center = g_malloc(sizeof(VikCoord));
646 *new_center = *center;
647 vml->last_center = new_center;
648 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
649 vml->last_ympp = vik_viewport_get_ympp(vvp);
653 /* TODO: perhaps vik_coord_diff() */
654 if (vik_coord_equals(vml->last_center, center)
655 && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
656 && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
659 *(vml->last_center) = *center;
660 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
661 vml->last_ympp = vik_viewport_get_ympp(vvp);
665 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
668 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
669 gdouble yzoom = vik_viewport_get_ympp ( vvp );
670 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
671 gdouble existence_only = FALSE;
673 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
674 xshrinkfactor = vml->xmapzoom / xzoom;
675 yshrinkfactor = vml->ymapzoom / yzoom;
676 xzoom = vml->xmapzoom;
677 yzoom = vml->xmapzoom;
678 if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
679 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
680 if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR )
681 existence_only = TRUE;
683 g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
690 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
691 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
692 vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
696 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
697 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
698 gint mode = vik_map_source_get_uniq_id(map);
701 gint xx, yy, width, height;
704 guint max_path_len = strlen(vml->cache_dir) + 40;
705 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
707 if ( (!existence_only) && vml->autodownload && should_start_autodownload(vml, vvp)) {
708 g_debug("%s: Starting autodownload", __FUNCTION__);
709 if ( vik_map_source_supports_download_only_new (map) )
710 // Try to download newer tiles
711 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NEW );
713 // Download only missing tiles
714 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
717 if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
718 for ( x = xmin; x <= xmax; x++ ) {
719 for ( y = ymin; y <= ymax; y++ ) {
722 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
724 width = gdk_pixbuf_get_width ( pixbuf );
725 height = gdk_pixbuf_get_height ( pixbuf );
727 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
728 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
732 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
736 } else { /* tilesize is known, don't have to keep converting coords */
737 gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
738 gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
739 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
740 gint tilesize_x_ceil = ceil ( tilesize_x );
741 gint tilesize_y_ceil = ceil ( tilesize_y );
742 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
743 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
744 gdouble xx, yy; gint xx_tmp, yy_tmp;
745 gint base_yy, xend, yend;
747 GdkGC *black_gc = GTK_WIDGET(vvp)->style->black_gc;
749 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
750 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
752 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
753 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
754 xx = xx_tmp; yy = yy_tmp;
755 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
756 * eg if tile size 128, shrinkfactor 0.333 */
757 xx -= (tilesize_x/2);
758 base_yy = yy - (tilesize_y/2);
760 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
762 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
766 if ( existence_only ) {
767 g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE,
768 vml->cache_dir, mode,
769 ulm.scale, ulm.z, ulm.x, ulm.y );
770 if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
771 vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
775 for (scale_inc = 0; scale_inc < 4; scale_inc ++) {
776 /* try with correct then smaller zooms */
777 int scale_factor = 1 << scale_inc; /* 2^scale_inc */
779 ulm2.x = ulm.x / scale_factor;
780 ulm2.y = ulm.y / scale_factor;
781 ulm2.scale = ulm.scale + scale_inc;
782 pixbuf = get_pixbuf ( vml, mode, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
784 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
785 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
787 printf("maps_layer_draw_section - x=%d, y=%d, z=%d, src_x=%d, src_y=%d, xx=%d, yy=%d - %x\n", ulm.x, ulm.y, ulm.scale, src_x, src_y, (int)xx, (int)yy, vvp);
789 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
794 /* retry with bigger zooms */
796 for (scale_dec = 1; scale_dec < 2; scale_dec ++) {
798 int scale_factor = 1 << scale_dec; /* 2^scale_dec */
800 ulm2.x = ulm.x * scale_factor;
801 ulm2.y = ulm.y * scale_factor;
802 ulm2.scale = ulm.scale - scale_dec;
803 for (pict_x = 0; pict_x < scale_factor; pict_x ++) {
804 for (pict_y = 0; pict_y < scale_factor; pict_y ++) {
805 MapCoord ulm3 = ulm2;
808 pixbuf = get_pixbuf ( vml, mode, &ulm3, path_buf, max_path_len, xshrinkfactor / scale_factor, yshrinkfactor / scale_factor );
812 gint dest_x = xx + pict_x * (tilesize_x_ceil / scale_factor);
813 gint dest_y = yy + pict_y * (tilesize_y_ceil / scale_factor);
814 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, dest_x, dest_y, tilesize_x_ceil / scale_factor, tilesize_y_ceil / scale_factor );
832 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
834 if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
839 const gchar *copyright = vik_map_source_get_copyright ( MAPS_LAYER_NTH_TYPE(vml->maptype) );
840 vik_viewport_add_copyright ( vvp, copyright );
842 /* get corner coords */
843 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
844 /* UTM multi-zone stuff by Kit Transue */
845 gchar leftmost_zone, rightmost_zone, i;
846 leftmost_zone = vik_viewport_leftmost_zone( vvp );
847 rightmost_zone = vik_viewport_rightmost_zone( vvp );
848 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
849 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
850 maps_layer_draw_section ( vml, vvp, &ul, &br );
854 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
855 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
857 maps_layer_draw_section ( vml, vvp, &ul, &br );
862 /*************************/
863 /****** DOWNLOADING ******/
864 /*************************/
866 /* pass along data to thread, exists even if layer is deleted. */
876 gboolean refresh_display;
879 gboolean map_layer_alive;
883 static void mdi_free ( MapDownloadInfo *mdi )
885 g_mutex_free(mdi->mutex);
886 g_free ( mdi->cache_dir );
887 mdi->cache_dir = NULL;
888 g_free ( mdi->filename_buf );
889 mdi->filename_buf = NULL;
893 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
895 MapDownloadInfo *mdi = ptr;
896 g_mutex_lock(mdi->mutex);
897 mdi->map_layer_alive = FALSE;
898 g_mutex_unlock(mdi->mutex);
901 static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
903 void *handle = vik_map_source_download_handle_init(MAPS_LAYER_NTH_TYPE(mdi->maptype));
906 for ( x = mdi->x0; x <= mdi->xf; x++ )
908 for ( y = mdi->y0; y <= mdi->yf; y++ )
910 gboolean remove_mem_cache = FALSE;
911 gboolean need_download = FALSE;
912 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
913 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
914 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
917 int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
919 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
923 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
924 need_download = TRUE;
925 remove_mem_cache = TRUE;
927 } else { /* in case map file already exists */
928 switch (mdi->redownload) {
929 case REDOWNLOAD_NONE:
934 /* see if this one is bad or what */
936 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
937 if (gx || (!pixbuf)) {
938 g_remove ( mdi->filename_buf );
939 need_download = TRUE;
940 remove_mem_cache = TRUE;
944 g_object_unref ( pixbuf );
950 need_download = TRUE;
951 remove_mem_cache = TRUE;
955 /* FIXME: need a better way than to erase file in case of server/network problem */
956 g_remove ( mdi->filename_buf );
957 need_download = TRUE;
958 remove_mem_cache = TRUE;
961 case DOWNLOAD_OR_REFRESH:
962 remove_mem_cache = TRUE;
966 g_warning ( "redownload state %d unknown\n", mdi->redownload);
970 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
973 if ( vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf, handle))
978 g_mutex_lock(mdi->mutex);
979 if (remove_mem_cache)
980 a_mapcache_remove_all_shrinkfactors ( x, y, mdi->mapcoord.z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)), mdi->mapcoord.scale );
981 if (mdi->refresh_display && mdi->map_layer_alive) {
982 /* TODO: check if it's on visible area */
983 vik_layer_emit_update ( VIK_LAYER(mdi->vml) );
985 g_mutex_unlock(mdi->mutex);
987 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
991 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
992 g_mutex_lock(mdi->mutex);
993 if (mdi->map_layer_alive)
994 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
995 g_mutex_unlock(mdi->mutex);
999 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
1001 if ( mdi->mapcoord.x || mdi->mapcoord.y )
1003 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1004 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1005 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
1006 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
1008 g_remove ( mdi->filename_buf );
1013 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
1015 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1016 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1018 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1019 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm )
1020 && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
1022 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
1027 mdi->map_layer_alive = TRUE;
1028 mdi->mutex = g_mutex_new();
1029 mdi->refresh_display = TRUE;
1031 /* cache_dir and buffer for dest filename */
1032 mdi->cache_dir = g_strdup ( vml->cache_dir );
1033 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1034 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1035 mdi->maptype = vml->maptype;
1037 mdi->mapcoord = ulm;
1039 mdi->redownload = redownload;
1041 mdi->x0 = MIN(ulm.x, brm.x);
1042 mdi->xf = MAX(ulm.x, brm.x);
1043 mdi->y0 = MIN(ulm.y, brm.y);
1044 mdi->yf = MAX(ulm.y, brm.y);
1048 if ( mdi->redownload ) {
1049 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1051 /* calculate how many we need */
1052 for ( a = mdi->x0; a <= mdi->xf; a++ )
1054 for ( b = mdi->y0; b <= mdi->yf; b++ )
1056 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1057 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1059 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1065 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1067 if ( mdi->mapstoget )
1069 const gchar *tmp_str;
1074 if (redownload == REDOWNLOAD_BAD)
1075 tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
1077 tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
1081 tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
1083 tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
1085 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1086 /* launch the thread */
1087 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1088 tmp, /* description string */
1089 (vik_thr_func) map_download_thread, /* function to call within thread */
1090 mdi, /* pass along data */
1091 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1092 (vik_thr_free_func) mdi_cancel_cleanup,
1101 void maps_layer_download_section_without_redraw( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
1104 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1106 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
1107 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
1108 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
1112 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1117 mdi->map_layer_alive = TRUE;
1118 mdi->mutex = g_mutex_new();
1119 mdi->refresh_display = FALSE;
1121 mdi->cache_dir = g_strdup ( vml->cache_dir );
1122 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1123 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1124 mdi->maptype = vml->maptype;
1126 mdi->mapcoord = ulm;
1128 mdi->redownload = REDOWNLOAD_NONE;
1130 mdi->x0 = MIN(ulm.x, brm.x);
1131 mdi->xf = MAX(ulm.x, brm.x);
1132 mdi->y0 = MIN(ulm.y, brm.y);
1133 mdi->yf = MAX(ulm.y, brm.y);
1137 for (i = mdi->x0; i <= mdi->xf; i++) {
1138 for (j = mdi->y0; j <= mdi->yf; j++) {
1139 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1140 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1142 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1147 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1149 if (mdi->mapstoget) {
1152 fmt = ngettext("Downloading %d %s map...",
1153 "Downloading %d %s maps...",
1155 tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
1157 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1158 /* launch the thread */
1159 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1160 tmp, /* description string */
1161 (vik_thr_func) map_download_thread, /* function to call within thread */
1162 mdi, /* pass along data */
1163 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1164 (vik_thr_free_func) mdi_cancel_cleanup,
1172 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1174 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1177 static void maps_layer_redownload_all ( VikMapsLayer *vml )
1179 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1182 static void maps_layer_redownload_new ( VikMapsLayer *vml )
1184 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
1187 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1189 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1191 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1193 if ( event->button == 1 )
1196 vik_viewport_screen_to_coord ( vvp, MAX(0, MIN(event->x, vml->dl_tool_x)), MAX(0, MIN(event->y, vml->dl_tool_y)), &ul );
1197 vik_viewport_screen_to_coord ( vvp, MIN(vik_viewport_get_width(vvp), MAX(event->x, vml->dl_tool_x)), MIN(vik_viewport_get_height(vvp), MAX ( event->y, vml->dl_tool_y ) ), &br );
1198 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
1199 vml->dl_tool_x = vml->dl_tool_y = -1;
1204 vik_viewport_screen_to_coord ( vvp, MAX(0, MIN(event->x, vml->dl_tool_x)), MAX(0, MIN(event->y, vml->dl_tool_y)), &(vml->redownload_ul) );
1205 vik_viewport_screen_to_coord ( vvp, MIN(vik_viewport_get_width(vvp), MAX(event->x, vml->dl_tool_x)), MIN(vik_viewport_get_height(vvp), MAX ( event->y, vml->dl_tool_y ) ), &(vml->redownload_br) );
1207 vml->redownload_vvp = vvp;
1209 vml->dl_tool_x = vml->dl_tool_y = -1;
1211 if ( ! vml->dl_right_click_menu ) {
1213 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1215 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _Bad Map(s)") );
1216 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1217 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1219 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _New Map(s)") );
1220 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), vml );
1221 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1223 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _All Map(s)") );
1224 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1225 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1228 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1229 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1235 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1240 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1243 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1245 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1246 if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
1247 vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
1248 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1249 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1251 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1258 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1262 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1263 if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1264 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1265 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1267 gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1268 vml->cache_dir, __map_types[vml->maptype].uniq_id,
1269 mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1271 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1272 g_free ( filename_buf );
1273 vik_layer_emit_update ( VIK_LAYER(vml) );
1281 static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
1283 VikMapsLayer *vml = vml_vvp[0];
1284 VikViewport *vvp = vml_vvp[1];
1285 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
1287 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1288 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1293 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1294 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1296 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1297 if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
1298 vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
1299 vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
1300 start_download_thread ( vml, vvp, &ul, &br, redownload );
1301 else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
1302 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
1303 gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
1304 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1308 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
1312 static void maps_layer_download_missing_onscreen_maps ( gpointer vml_vvp[2] )
1314 download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1317 static void maps_layer_download_new_onscreen_maps ( gpointer vml_vvp[2] )
1319 download_onscreen_maps( vml_vvp, REDOWNLOAD_NEW);
1322 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1324 download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1327 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1329 static gpointer pass_along[2];
1331 pass_along[0] = vml;
1332 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1334 item = gtk_menu_item_new();
1335 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1336 gtk_widget_show ( item );
1338 item = gtk_menu_item_new_with_mnemonic ( _("Download _Missing Onscreen Maps") );
1339 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), pass_along );
1340 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1341 gtk_widget_show ( item );
1343 if ( vik_map_source_supports_download_only_new (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
1344 item = gtk_menu_item_new_with_mnemonic ( _("Download _New Onscreen Maps") );
1345 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), pass_along );
1346 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1347 gtk_widget_show ( item );
1350 /* TODO Add GTK_STOCK_REFRESH icon */
1351 item = gtk_menu_item_new_with_mnemonic ( _("Reload _All Onscreen Maps") );
1352 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1353 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1354 gtk_widget_show ( item );