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,
169 (VikLayerFuncSublayerTooltip) NULL,
170 (VikLayerFuncLayerTooltip) NULL,
172 (VikLayerFuncMarshall) maps_layer_marshall,
173 (VikLayerFuncUnmarshall) maps_layer_unmarshall,
175 (VikLayerFuncSetParam) maps_layer_set_param,
176 (VikLayerFuncGetParam) maps_layer_get_param,
178 (VikLayerFuncReadFileData) NULL,
179 (VikLayerFuncWriteFileData) NULL,
181 (VikLayerFuncDeleteItem) NULL,
182 (VikLayerFuncCopyItem) NULL,
183 (VikLayerFuncPasteItem) NULL,
184 (VikLayerFuncFreeCopiedItem) NULL,
185 (VikLayerFuncDragDropRequest) NULL,
188 struct _VikMapsLayer {
194 gdouble xmapzoom, ymapzoom;
196 gboolean autodownload;
197 VikCoord *last_center;
201 gint dl_tool_x, dl_tool_y;
203 GtkMenu *dl_right_click_menu;
204 VikCoord redownload_ul, redownload_br; /* right click menu only */
205 VikViewport *redownload_vvp;
208 enum { REDOWNLOAD_NONE = 0, /* download only missing maps */
209 REDOWNLOAD_BAD, /* download missing and bad maps */
210 REDOWNLOAD_NEW, /* download missing maps that are newer on server only */
211 REDOWNLOAD_ALL, /* download all maps */
212 DOWNLOAD_OR_REFRESH }; /* download missing maps and refresh cache */
214 static VikLayerParam prefs[] = {
215 { VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Default maplayer directory:"), VIK_LAYER_WIDGET_FOLDERENTRY, NULL, NULL },
218 void maps_layer_init ()
220 VikLayerParamData tmp;
221 tmp.s = maps_layer_default_dir();
222 a_preferences_register(prefs, tmp, VIKING_PREFERENCES_GROUP_KEY);
225 /****************************************/
226 /******** MAPS LAYER TYPES **************/
227 /****************************************/
229 int _get_index_for_id ( guint id )
232 while (params_maptypes_ids[index] != 0)
234 if (params_maptypes_ids[index] == id)
241 void _add_map_source ( guint id, const char *label, VikMapSource *map )
245 len = g_strv_length (params_maptypes);
247 params_maptypes = g_realloc (params_maptypes, (len+2)*sizeof(gchar*));
248 params_maptypes[len] = g_strdup (label);
249 params_maptypes[len+1] = NULL;
252 params_maptypes_ids = g_realloc (params_maptypes_ids, (len+2)*sizeof(guint));
253 params_maptypes_ids[len] = id;
254 params_maptypes_ids[len+1] = 0;
256 /* We have to clone */
257 VikMapSource *clone = VIK_MAP_SOURCE(g_object_ref(map));
258 /* Register the clone in the list */
259 __map_types = g_list_append(__map_types, clone);
262 We have to ensure the mode LayerParam references the up-to-date
266 memcpy(&maps_layer_params[0].widget_data, ¶ms_maptypes, sizeof(gpointer));
267 memcpy(&maps_layer_params[0].extra_widget_data, ¶ms_maptypes_ids, sizeof(gpointer));
269 maps_layer_params[0].widget_data = params_maptypes;
270 maps_layer_params[0].extra_widget_data = params_maptypes_ids;
273 void _update_map_source ( const char *label, VikMapSource *map, int index )
275 GList *item = g_list_nth (__map_types, index);
276 g_object_unref (item->data);
277 item->data = g_object_ref (map);
278 /* Change previous data */
279 g_free (params_maptypes[index]);
280 params_maptypes[index] = g_strdup (label);
283 void maps_layer_register_map_source ( VikMapSource *map )
285 g_assert(map != NULL);
287 guint id = vik_map_source_get_uniq_id(map);
288 const char *label = vik_map_source_get_label(map);
289 g_assert(label != NULL);
291 int previous = map_uniq_id_to_index (id);
292 if (previous != NUM_MAP_TYPES)
294 _update_map_source (label, map, previous);
298 _add_map_source (id, label, map);
302 #define MAPS_LAYER_NTH_LABEL(n) (params_maptypes[n])
303 #define MAPS_LAYER_NTH_ID(n) (params_maptypes_ids[n])
304 #define MAPS_LAYER_NTH_TYPE(n) (VIK_MAP_SOURCE(g_list_nth_data(__map_types, (n))))
306 gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
308 return(vml->maptype);
311 gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
313 return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
316 /****************************************/
317 /******** CACHE DIR STUFF ***************/
318 /****************************************/
320 #define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
321 #define MAPS_CACHE_DIR maps_layer_default_dir()
325 #define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
326 #define LOCAL_MAPS_DIR "VIKING-MAPS"
329 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
330 #define LOCAL_MAPS_DIR ".viking-maps"
333 gchar *maps_layer_default_dir ()
335 static gchar *defaultdir = NULL;
338 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
339 const gchar *mapdir = g_getenv("VIKING_MAPS");
341 defaultdir = g_strdup ( mapdir );
342 } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
343 defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
345 const gchar *home = g_get_home_dir();
346 if (!home || g_access(home, W_OK))
347 home = g_get_home_dir ();
349 defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
351 defaultdir = g_strdup ( LOCAL_MAPS_DIR );
353 if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
355 /* Add the separator at the end */
356 gchar *tmp = defaultdir;
357 defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
360 g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
365 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
367 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
369 g_mkdir ( vml->cache_dir, 0777 );
373 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
376 g_assert ( vml != NULL);
377 g_free ( vml->cache_dir );
378 vml->cache_dir = NULL;
380 if ( dir == NULL || dir[0] == '\0' )
382 if ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir") )
383 vml->cache_dir = g_strdup ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir")->s );
388 if ( dir[len-1] != G_DIR_SEPARATOR )
390 vml->cache_dir = g_malloc ( len+2 );
391 strncpy ( vml->cache_dir, dir, len );
392 vml->cache_dir[len] = G_DIR_SEPARATOR;
393 vml->cache_dir[len+1] = '\0';
396 vml->cache_dir = g_strdup ( dir );
398 maps_layer_mkdir_if_default_dir ( vml );
401 /****************************************/
402 /******** GOBJECT STUFF *****************/
403 /****************************************/
405 GType vik_maps_layer_get_type ()
407 static GType vml_type = 0;
411 static const GTypeInfo vml_info =
413 sizeof (VikMapsLayerClass),
414 NULL, /* base_init */
415 NULL, /* base_finalize */
416 NULL, /* class init */
417 NULL, /* class_finalize */
418 NULL, /* class_data */
419 sizeof (VikMapsLayer),
421 NULL /* instance init */
423 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
429 /****************************************/
430 /************** PARAMETERS **************/
431 /****************************************/
433 static guint map_index_to_uniq_id (guint8 index)
435 g_assert ( index < NUM_MAP_TYPES );
436 return vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(index));
439 static guint map_uniq_id_to_index ( guint uniq_id )
442 for ( i = 0; i < NUM_MAP_TYPES; i++ )
443 if ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(i)) == uniq_id )
445 return NUM_MAP_TYPES; /* no such thing */
448 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation )
452 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
453 case PARAM_MAPTYPE: {
454 gint maptype = map_uniq_id_to_index(data.u);
455 if ( maptype == NUM_MAP_TYPES ) g_warning(_("Unknown map type"));
456 else vml->maptype = maptype;
459 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
460 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
461 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
462 vml->mapzoom_id = data.u;
463 vml->xmapzoom = __mapzooms_x [data.u];
464 vml->ymapzoom = __mapzooms_y [data.u];
465 }else g_warning (_("Unknown Map Zoom")); break;
470 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation )
472 VikLayerParamData rv;
475 case PARAM_CACHE_DIR: rv.s = vml->cache_dir ? vml->cache_dir : ""; break;
476 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
477 case PARAM_ALPHA: rv.u = vml->alpha; break;
478 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
479 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
484 /****************************************/
485 /****** CREATING, COPYING, FREEING ******/
486 /****************************************/
488 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
491 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
492 vik_layer_init ( VIK_LAYER(vml), VIK_LAYER_MAPS );
493 idx = map_uniq_id_to_index(13); /* 13 is id for OSM Mapnik maps */
494 vml->maptype = (idx < NUM_MAP_TYPES) ? idx : 0;
497 vml->dl_tool_x = vml->dl_tool_y = -1;
498 maps_layer_set_cache_dir ( vml, NULL );
499 vml->autodownload = FALSE;
500 vml->last_center = NULL;
501 vml->last_xmpp = 0.0;
502 vml->last_ympp = 0.0;
504 vml->dl_right_click_menu = NULL;
509 static void maps_layer_free ( VikMapsLayer *vml )
511 g_free ( vml->cache_dir );
512 vml->cache_dir = NULL;
513 if ( vml->dl_right_click_menu )
514 gtk_object_sink ( GTK_OBJECT(vml->dl_right_click_menu) );
515 g_free(vml->last_center);
516 vml->last_center = NULL;
519 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
521 if (from_file != TRUE)
523 /* If this method is not called in file reading context
524 * it is called in GUI context.
525 * So, we can check if we have to inform the user about inconsistency */
526 VikViewportDrawMode vp_drawmode;
527 VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
528 VikMapSource *map = NULL;
530 vp_drawmode = vik_viewport_get_drawmode ( VIK_VIEWPORT(vp) );
531 map = MAPS_LAYER_NTH_TYPE(vml->maptype);
532 if (vik_map_source_get_drawmode(map) != vp_drawmode) {
533 const gchar *drawmode_name = vik_viewport_get_drawmode_name (VIK_VIEWPORT(vp), vik_map_source_get_drawmode(map));
534 gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
535 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_WIDGET(vp), msg );
539 if (vik_map_source_get_license (map) != NULL) {
540 a_dialog_license (VIK_GTK_WINDOW_FROM_WIDGET(vp), vik_map_source_get_label (map),
541 vik_map_source_get_license (map), vik_map_source_get_license_url (map) );
546 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
548 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
551 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
553 VikMapsLayer *rv = maps_layer_new ( vvp );
554 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
558 /*********************/
559 /****** DRAWING ******/
560 /*********************/
562 static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
565 gint width, height, iii, jjj;
567 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
569 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
570 g_object_unref(G_OBJECT(pixbuf));
574 pixels = gdk_pixbuf_get_pixels(pixbuf);
575 width = gdk_pixbuf_get_width(pixbuf);
576 height = gdk_pixbuf_get_height(pixbuf);
578 /* r,g,b,a,r,g,b,a.... */
579 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
587 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
590 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
591 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_NEAREST);
592 g_object_unref ( G_OBJECT(pixbuf) );
596 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
601 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
602 mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
605 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
606 vml->cache_dir, mode,
607 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
608 if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
611 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
613 /* free the pixbuf on error */
616 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
617 g_warning ( _("Couldn't open image file: %s"), gx->message );
621 g_object_unref ( G_OBJECT(pixbuf) );
624 if ( vml->alpha < 255 )
625 pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
626 if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
627 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
629 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
630 mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
631 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
638 gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
640 const VikCoord *center = vik_viewport_get_center ( vvp );
642 if (vik_window_get_pan_move (VIK_WINDOW(VIK_GTK_WINDOW_FROM_WIDGET(GTK_WIDGET(vvp)))))
643 /* D'n'D pan in action: do not download */
646 if (vml->last_center == NULL) {
647 VikCoord *new_center = g_malloc(sizeof(VikCoord));
648 *new_center = *center;
649 vml->last_center = new_center;
650 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
651 vml->last_ympp = vik_viewport_get_ympp(vvp);
655 /* TODO: perhaps vik_coord_diff() */
656 if (vik_coord_equals(vml->last_center, center)
657 && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
658 && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
661 *(vml->last_center) = *center;
662 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
663 vml->last_ympp = vik_viewport_get_ympp(vvp);
667 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
670 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
671 gdouble yzoom = vik_viewport_get_ympp ( vvp );
672 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
673 gdouble existence_only = FALSE;
675 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
676 xshrinkfactor = vml->xmapzoom / xzoom;
677 yshrinkfactor = vml->ymapzoom / yzoom;
678 xzoom = vml->xmapzoom;
679 yzoom = vml->xmapzoom;
680 if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
681 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
682 if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR )
683 existence_only = TRUE;
685 g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
692 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
693 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
694 vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
698 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
699 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
700 gint mode = vik_map_source_get_uniq_id(map);
703 gint xx, yy, width, height;
706 guint max_path_len = strlen(vml->cache_dir) + 40;
707 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
709 if ( (!existence_only) && vml->autodownload && should_start_autodownload(vml, vvp)) {
710 g_debug("%s: Starting autodownload", __FUNCTION__);
711 if ( vik_map_source_supports_download_only_new (map) )
712 // Try to download newer tiles
713 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NEW );
715 // Download only missing tiles
716 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
719 if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
720 for ( x = xmin; x <= xmax; x++ ) {
721 for ( y = ymin; y <= ymax; y++ ) {
724 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
726 width = gdk_pixbuf_get_width ( pixbuf );
727 height = gdk_pixbuf_get_height ( pixbuf );
729 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
730 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
734 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
738 } else { /* tilesize is known, don't have to keep converting coords */
739 gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
740 gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
741 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
742 gint tilesize_x_ceil = ceil ( tilesize_x );
743 gint tilesize_y_ceil = ceil ( tilesize_y );
744 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
745 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
746 gdouble xx, yy; gint xx_tmp, yy_tmp;
747 gint base_yy, xend, yend;
749 GdkGC *black_gc = GTK_WIDGET(vvp)->style->black_gc;
751 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
752 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
754 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
755 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
756 xx = xx_tmp; yy = yy_tmp;
757 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
758 * eg if tile size 128, shrinkfactor 0.333 */
759 xx -= (tilesize_x/2);
760 base_yy = yy - (tilesize_y/2);
762 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
764 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
768 if ( existence_only ) {
769 g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE,
770 vml->cache_dir, mode,
771 ulm.scale, ulm.z, ulm.x, ulm.y );
772 if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
773 vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
777 for (scale_inc = 0; scale_inc < 4; scale_inc ++) {
778 /* try with correct then smaller zooms */
779 int scale_factor = 1 << scale_inc; /* 2^scale_inc */
781 ulm2.x = ulm.x / scale_factor;
782 ulm2.y = ulm.y / scale_factor;
783 ulm2.scale = ulm.scale + scale_inc;
784 pixbuf = get_pixbuf ( vml, mode, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
786 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
787 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
789 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);
791 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
796 /* retry with bigger zooms */
798 for (scale_dec = 1; scale_dec < 2; scale_dec ++) {
800 int scale_factor = 1 << scale_dec; /* 2^scale_dec */
802 ulm2.x = ulm.x * scale_factor;
803 ulm2.y = ulm.y * scale_factor;
804 ulm2.scale = ulm.scale - scale_dec;
805 for (pict_x = 0; pict_x < scale_factor; pict_x ++) {
806 for (pict_y = 0; pict_y < scale_factor; pict_y ++) {
807 MapCoord ulm3 = ulm2;
810 pixbuf = get_pixbuf ( vml, mode, &ulm3, path_buf, max_path_len, xshrinkfactor / scale_factor, yshrinkfactor / scale_factor );
814 gint dest_x = xx + pict_x * (tilesize_x_ceil / scale_factor);
815 gint dest_y = yy + pict_y * (tilesize_y_ceil / scale_factor);
816 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, dest_x, dest_y, tilesize_x_ceil / scale_factor, tilesize_y_ceil / scale_factor );
834 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
836 if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
841 const gchar *copyright = vik_map_source_get_copyright ( MAPS_LAYER_NTH_TYPE(vml->maptype) );
842 vik_viewport_add_copyright ( vvp, copyright );
844 /* get corner coords */
845 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
846 /* UTM multi-zone stuff by Kit Transue */
847 gchar leftmost_zone, rightmost_zone, i;
848 leftmost_zone = vik_viewport_leftmost_zone( vvp );
849 rightmost_zone = vik_viewport_rightmost_zone( vvp );
850 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
851 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
852 maps_layer_draw_section ( vml, vvp, &ul, &br );
856 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
857 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
859 maps_layer_draw_section ( vml, vvp, &ul, &br );
864 /*************************/
865 /****** DOWNLOADING ******/
866 /*************************/
868 /* pass along data to thread, exists even if layer is deleted. */
878 gboolean refresh_display;
881 gboolean map_layer_alive;
885 static void mdi_free ( MapDownloadInfo *mdi )
887 g_mutex_free(mdi->mutex);
888 g_free ( mdi->cache_dir );
889 mdi->cache_dir = NULL;
890 g_free ( mdi->filename_buf );
891 mdi->filename_buf = NULL;
895 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
897 MapDownloadInfo *mdi = ptr;
898 g_mutex_lock(mdi->mutex);
899 mdi->map_layer_alive = FALSE;
900 g_mutex_unlock(mdi->mutex);
903 static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
905 void *handle = vik_map_source_download_handle_init(MAPS_LAYER_NTH_TYPE(mdi->maptype));
908 for ( x = mdi->x0; x <= mdi->xf; x++ )
910 for ( y = mdi->y0; y <= mdi->yf; y++ )
912 gboolean remove_mem_cache = FALSE;
913 gboolean need_download = FALSE;
914 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
915 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
916 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
919 int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
921 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
925 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
926 need_download = TRUE;
927 remove_mem_cache = TRUE;
929 } else { /* in case map file already exists */
930 switch (mdi->redownload) {
931 case REDOWNLOAD_NONE:
936 /* see if this one is bad or what */
938 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
939 if (gx || (!pixbuf)) {
940 g_remove ( mdi->filename_buf );
941 need_download = TRUE;
942 remove_mem_cache = TRUE;
946 g_object_unref ( pixbuf );
952 need_download = TRUE;
953 remove_mem_cache = TRUE;
957 /* FIXME: need a better way than to erase file in case of server/network problem */
958 g_remove ( mdi->filename_buf );
959 need_download = TRUE;
960 remove_mem_cache = TRUE;
963 case DOWNLOAD_OR_REFRESH:
964 remove_mem_cache = TRUE;
968 g_warning ( "redownload state %d unknown\n", mdi->redownload);
972 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
975 if ( vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf, handle))
980 g_mutex_lock(mdi->mutex);
981 if (remove_mem_cache)
982 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 );
983 if (mdi->refresh_display && mdi->map_layer_alive) {
984 /* TODO: check if it's on visible area */
985 vik_layer_emit_update ( VIK_LAYER(mdi->vml) );
987 g_mutex_unlock(mdi->mutex);
989 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
993 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
994 g_mutex_lock(mdi->mutex);
995 if (mdi->map_layer_alive)
996 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
997 g_mutex_unlock(mdi->mutex);
1001 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
1003 if ( mdi->mapcoord.x || mdi->mapcoord.y )
1005 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1006 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1007 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
1008 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
1010 g_remove ( mdi->filename_buf );
1015 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
1017 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1018 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1020 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1021 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm )
1022 && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
1024 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
1029 mdi->map_layer_alive = TRUE;
1030 mdi->mutex = g_mutex_new();
1031 mdi->refresh_display = TRUE;
1033 /* cache_dir and buffer for dest filename */
1034 mdi->cache_dir = g_strdup ( vml->cache_dir );
1035 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1036 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1037 mdi->maptype = vml->maptype;
1039 mdi->mapcoord = ulm;
1041 mdi->redownload = redownload;
1043 mdi->x0 = MIN(ulm.x, brm.x);
1044 mdi->xf = MAX(ulm.x, brm.x);
1045 mdi->y0 = MIN(ulm.y, brm.y);
1046 mdi->yf = MAX(ulm.y, brm.y);
1050 if ( mdi->redownload ) {
1051 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1053 /* calculate how many we need */
1054 for ( a = mdi->x0; a <= mdi->xf; a++ )
1056 for ( b = mdi->y0; b <= mdi->yf; b++ )
1058 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1059 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1061 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1067 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1069 if ( mdi->mapstoget )
1071 const gchar *tmp_str;
1076 if (redownload == REDOWNLOAD_BAD)
1077 tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
1079 tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
1083 tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
1085 tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
1087 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1088 /* launch the thread */
1089 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1090 tmp, /* description string */
1091 (vik_thr_func) map_download_thread, /* function to call within thread */
1092 mdi, /* pass along data */
1093 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1094 (vik_thr_free_func) mdi_cancel_cleanup,
1103 void maps_layer_download_section_without_redraw( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
1106 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1108 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
1109 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
1110 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
1114 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1119 mdi->map_layer_alive = TRUE;
1120 mdi->mutex = g_mutex_new();
1121 mdi->refresh_display = FALSE;
1123 mdi->cache_dir = g_strdup ( vml->cache_dir );
1124 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1125 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1126 mdi->maptype = vml->maptype;
1128 mdi->mapcoord = ulm;
1130 mdi->redownload = REDOWNLOAD_NONE;
1132 mdi->x0 = MIN(ulm.x, brm.x);
1133 mdi->xf = MAX(ulm.x, brm.x);
1134 mdi->y0 = MIN(ulm.y, brm.y);
1135 mdi->yf = MAX(ulm.y, brm.y);
1139 for (i = mdi->x0; i <= mdi->xf; i++) {
1140 for (j = mdi->y0; j <= mdi->yf; j++) {
1141 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1142 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1144 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1149 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1151 if (mdi->mapstoget) {
1154 fmt = ngettext("Downloading %d %s map...",
1155 "Downloading %d %s maps...",
1157 tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
1159 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1160 /* launch the thread */
1161 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1162 tmp, /* description string */
1163 (vik_thr_func) map_download_thread, /* function to call within thread */
1164 mdi, /* pass along data */
1165 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1166 (vik_thr_free_func) mdi_cancel_cleanup,
1174 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1176 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1179 static void maps_layer_redownload_all ( VikMapsLayer *vml )
1181 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1184 static void maps_layer_redownload_new ( VikMapsLayer *vml )
1186 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
1189 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1191 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1193 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1195 if ( event->button == 1 )
1198 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 );
1199 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 );
1200 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
1201 vml->dl_tool_x = vml->dl_tool_y = -1;
1206 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) );
1207 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) );
1209 vml->redownload_vvp = vvp;
1211 vml->dl_tool_x = vml->dl_tool_y = -1;
1213 if ( ! vml->dl_right_click_menu ) {
1215 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1217 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _Bad Map(s)") );
1218 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1219 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1221 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _New Map(s)") );
1222 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), vml );
1223 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1225 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _All Map(s)") );
1226 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1227 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1230 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1231 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1237 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1242 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1245 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1247 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1248 if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
1249 vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
1250 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1251 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1253 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1260 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1264 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1265 if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1266 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1267 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1269 gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1270 vml->cache_dir, __map_types[vml->maptype].uniq_id,
1271 mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1273 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1274 g_free ( filename_buf );
1275 vik_layer_emit_update ( VIK_LAYER(vml) );
1283 static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
1285 VikMapsLayer *vml = vml_vvp[0];
1286 VikViewport *vvp = vml_vvp[1];
1287 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
1289 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1290 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1295 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1296 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1298 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1299 if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
1300 vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
1301 vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
1302 start_download_thread ( vml, vvp, &ul, &br, redownload );
1303 else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
1304 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
1305 gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
1306 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1310 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
1314 static void maps_layer_download_missing_onscreen_maps ( gpointer vml_vvp[2] )
1316 download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1319 static void maps_layer_download_new_onscreen_maps ( gpointer vml_vvp[2] )
1321 download_onscreen_maps( vml_vvp, REDOWNLOAD_NEW);
1324 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1326 download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1329 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1331 static gpointer pass_along[2];
1333 pass_along[0] = vml;
1334 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1336 item = gtk_menu_item_new();
1337 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1338 gtk_widget_show ( item );
1340 item = gtk_menu_item_new_with_mnemonic ( _("Download _Missing Onscreen Maps") );
1341 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), pass_along );
1342 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1343 gtk_widget_show ( item );
1345 if ( vik_map_source_supports_download_only_new (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
1346 item = gtk_menu_item_new_with_mnemonic ( _("Download _New Onscreen Maps") );
1347 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), pass_along );
1348 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1349 gtk_widget_show ( item );
1352 /* TODO Add GTK_STOCK_REFRESH icon */
1353 item = gtk_menu_item_new_with_mnemonic ( _("Reload _All Onscreen Maps") );
1354 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1355 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1356 gtk_widget_show ( item );