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 const gchar* maps_layer_tooltip ( VikMapsLayer *vml );
102 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len );
103 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
104 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation );
105 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation );
106 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp );
107 static VikMapsLayer *maps_layer_new ( VikViewport *vvp );
108 static void maps_layer_free ( VikMapsLayer *vml );
109 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
110 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
111 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp );
112 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir );
113 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload );
114 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp );
115 static guint map_uniq_id_to_index ( guint uniq_id );
118 static VikLayerParamScale params_scales[] = {
119 /* min, max, step, digits (decimal places) */
120 { 0, 255, 3, 0 }, /* alpha */
123 VikLayerParam maps_layer_params[] = {
124 { "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Map Type:"), VIK_LAYER_WIDGET_COMBOBOX, NULL, NULL },
125 { "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Maps Directory:"), VIK_LAYER_WIDGET_FOLDERENTRY },
126 { "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales },
127 { "autodownload", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload maps:"), VIK_LAYER_WIDGET_CHECKBUTTON },
128 { "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Zoom Level:"), VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms, NULL },
131 enum { PARAM_MAPTYPE=0, PARAM_CACHE_DIR, PARAM_ALPHA, PARAM_AUTODOWNLOAD, PARAM_MAPZOOM, NUM_PARAMS };
133 static VikToolInterface maps_tools[] = {
134 { N_("Maps Download"), (VikToolConstructorFunc) maps_layer_download_create, NULL, NULL, NULL,
135 (VikToolMouseFunc) maps_layer_download_click, NULL, (VikToolMouseFunc) maps_layer_download_release,
136 (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_mapdl_pixbuf },
139 VikLayerInterface vik_maps_layer_interface = {
141 &vikmapslayer_pixbuf,
144 sizeof(maps_tools) / sizeof(maps_tools[0]),
153 (VikLayerFuncCreate) maps_layer_new,
154 (VikLayerFuncRealize) NULL,
155 (VikLayerFuncPostRead) maps_layer_post_read,
156 (VikLayerFuncFree) maps_layer_free,
158 (VikLayerFuncProperties) NULL,
159 (VikLayerFuncDraw) maps_layer_draw,
160 (VikLayerFuncChangeCoordMode) NULL,
162 (VikLayerFuncSetMenuItemsSelection) NULL,
163 (VikLayerFuncGetMenuItemsSelection) NULL,
165 (VikLayerFuncAddMenuItems) maps_layer_add_menu_items,
166 (VikLayerFuncSublayerAddMenuItems) NULL,
168 (VikLayerFuncSublayerRenameRequest) NULL,
169 (VikLayerFuncSublayerToggleVisible) NULL,
170 (VikLayerFuncSublayerTooltip) NULL,
171 (VikLayerFuncLayerTooltip) maps_layer_tooltip,
173 (VikLayerFuncMarshall) maps_layer_marshall,
174 (VikLayerFuncUnmarshall) maps_layer_unmarshall,
176 (VikLayerFuncSetParam) maps_layer_set_param,
177 (VikLayerFuncGetParam) maps_layer_get_param,
179 (VikLayerFuncReadFileData) NULL,
180 (VikLayerFuncWriteFileData) NULL,
182 (VikLayerFuncDeleteItem) NULL,
183 (VikLayerFuncCutItem) NULL,
184 (VikLayerFuncCopyItem) NULL,
185 (VikLayerFuncPasteItem) NULL,
186 (VikLayerFuncFreeCopiedItem) NULL,
187 (VikLayerFuncDragDropRequest) NULL,
190 struct _VikMapsLayer {
196 gdouble xmapzoom, ymapzoom;
198 gboolean autodownload;
199 VikCoord *last_center;
203 gint dl_tool_x, dl_tool_y;
205 GtkMenu *dl_right_click_menu;
206 VikCoord redownload_ul, redownload_br; /* right click menu only */
207 VikViewport *redownload_vvp;
210 enum { REDOWNLOAD_NONE = 0, /* download only missing maps */
211 REDOWNLOAD_BAD, /* download missing and bad maps */
212 REDOWNLOAD_NEW, /* download missing maps that are newer on server only */
213 REDOWNLOAD_ALL, /* download all maps */
214 DOWNLOAD_OR_REFRESH }; /* download missing maps and refresh cache */
216 static VikLayerParam prefs[] = {
217 { VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Default maplayer directory:"), VIK_LAYER_WIDGET_FOLDERENTRY, NULL, NULL },
220 void maps_layer_init ()
222 VikLayerParamData tmp;
223 tmp.s = maps_layer_default_dir();
224 a_preferences_register(prefs, tmp, VIKING_PREFERENCES_GROUP_KEY);
227 /****************************************/
228 /******** MAPS LAYER TYPES **************/
229 /****************************************/
231 int _get_index_for_id ( guint id )
234 while (params_maptypes_ids[index] != 0)
236 if (params_maptypes_ids[index] == id)
243 void _add_map_source ( guint id, const char *label, VikMapSource *map )
247 len = g_strv_length (params_maptypes);
249 params_maptypes = g_realloc (params_maptypes, (len+2)*sizeof(gchar*));
250 params_maptypes[len] = g_strdup (label);
251 params_maptypes[len+1] = NULL;
254 params_maptypes_ids = g_realloc (params_maptypes_ids, (len+2)*sizeof(guint));
255 params_maptypes_ids[len] = id;
256 params_maptypes_ids[len+1] = 0;
258 /* We have to clone */
259 VikMapSource *clone = VIK_MAP_SOURCE(g_object_ref(map));
260 /* Register the clone in the list */
261 __map_types = g_list_append(__map_types, clone);
264 We have to ensure the mode LayerParam references the up-to-date
268 memcpy(&maps_layer_params[0].widget_data, ¶ms_maptypes, sizeof(gpointer));
269 memcpy(&maps_layer_params[0].extra_widget_data, ¶ms_maptypes_ids, sizeof(gpointer));
271 maps_layer_params[0].widget_data = params_maptypes;
272 maps_layer_params[0].extra_widget_data = params_maptypes_ids;
275 void _update_map_source ( const char *label, VikMapSource *map, int index )
277 GList *item = g_list_nth (__map_types, index);
278 g_object_unref (item->data);
279 item->data = g_object_ref (map);
280 /* Change previous data */
281 g_free (params_maptypes[index]);
282 params_maptypes[index] = g_strdup (label);
285 void maps_layer_register_map_source ( VikMapSource *map )
287 g_assert(map != NULL);
289 guint id = vik_map_source_get_uniq_id(map);
290 const char *label = vik_map_source_get_label(map);
291 g_assert(label != NULL);
293 int previous = map_uniq_id_to_index (id);
294 if (previous != NUM_MAP_TYPES)
296 _update_map_source (label, map, previous);
300 _add_map_source (id, label, map);
304 #define MAPS_LAYER_NTH_LABEL(n) (params_maptypes[n])
305 #define MAPS_LAYER_NTH_ID(n) (params_maptypes_ids[n])
306 #define MAPS_LAYER_NTH_TYPE(n) (VIK_MAP_SOURCE(g_list_nth_data(__map_types, (n))))
308 gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
310 return(vml->maptype);
313 gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
315 return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
318 /****************************************/
319 /******** CACHE DIR STUFF ***************/
320 /****************************************/
322 #define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
323 #define MAPS_CACHE_DIR maps_layer_default_dir()
327 #define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
328 #define LOCAL_MAPS_DIR "VIKING-MAPS"
331 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
332 #define LOCAL_MAPS_DIR ".viking-maps"
335 gchar *maps_layer_default_dir ()
337 static gchar *defaultdir = NULL;
340 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
341 const gchar *mapdir = g_getenv("VIKING_MAPS");
343 defaultdir = g_strdup ( mapdir );
344 } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
345 defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
347 const gchar *home = g_get_home_dir();
348 if (!home || g_access(home, W_OK))
349 home = g_get_home_dir ();
351 defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
353 defaultdir = g_strdup ( LOCAL_MAPS_DIR );
355 if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
357 /* Add the separator at the end */
358 gchar *tmp = defaultdir;
359 defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
362 g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
367 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
369 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
371 g_mkdir ( vml->cache_dir, 0777 );
375 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
378 g_assert ( vml != NULL);
379 g_free ( vml->cache_dir );
380 vml->cache_dir = NULL;
382 if ( dir == NULL || dir[0] == '\0' )
384 if ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir") )
385 vml->cache_dir = g_strdup ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir")->s );
390 if ( dir[len-1] != G_DIR_SEPARATOR )
392 vml->cache_dir = g_malloc ( len+2 );
393 strncpy ( vml->cache_dir, dir, len );
394 vml->cache_dir[len] = G_DIR_SEPARATOR;
395 vml->cache_dir[len+1] = '\0';
398 vml->cache_dir = g_strdup ( dir );
400 maps_layer_mkdir_if_default_dir ( vml );
403 /****************************************/
404 /******** GOBJECT STUFF *****************/
405 /****************************************/
407 GType vik_maps_layer_get_type ()
409 static GType vml_type = 0;
413 static const GTypeInfo vml_info =
415 sizeof (VikMapsLayerClass),
416 NULL, /* base_init */
417 NULL, /* base_finalize */
418 NULL, /* class init */
419 NULL, /* class_finalize */
420 NULL, /* class_data */
421 sizeof (VikMapsLayer),
423 NULL /* instance init */
425 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
431 /****************************************/
432 /************** PARAMETERS **************/
433 /****************************************/
435 static guint map_index_to_uniq_id (guint8 index)
437 g_assert ( index < NUM_MAP_TYPES );
438 return vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(index));
441 static guint map_uniq_id_to_index ( guint uniq_id )
444 for ( i = 0; i < NUM_MAP_TYPES; i++ )
445 if ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(i)) == uniq_id )
447 return NUM_MAP_TYPES; /* no such thing */
450 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation )
454 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
455 case PARAM_MAPTYPE: {
456 gint maptype = map_uniq_id_to_index(data.u);
457 if ( maptype == NUM_MAP_TYPES ) g_warning(_("Unknown map type"));
458 else vml->maptype = maptype;
461 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
462 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
463 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
464 vml->mapzoom_id = data.u;
465 vml->xmapzoom = __mapzooms_x [data.u];
466 vml->ymapzoom = __mapzooms_y [data.u];
467 }else g_warning (_("Unknown Map Zoom")); break;
472 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation )
474 VikLayerParamData rv;
477 case PARAM_CACHE_DIR: rv.s = vml->cache_dir ? vml->cache_dir : ""; break;
478 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
479 case PARAM_ALPHA: rv.u = vml->alpha; break;
480 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
481 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
486 /****************************************/
487 /****** CREATING, COPYING, FREEING ******/
488 /****************************************/
490 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
493 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
494 vik_layer_init ( VIK_LAYER(vml), VIK_LAYER_MAPS );
495 idx = map_uniq_id_to_index(13); /* 13 is id for OSM Mapnik maps */
496 vml->maptype = (idx < NUM_MAP_TYPES) ? idx : 0;
499 vml->dl_tool_x = vml->dl_tool_y = -1;
500 maps_layer_set_cache_dir ( vml, NULL );
501 vml->autodownload = FALSE;
502 vml->last_center = NULL;
503 vml->last_xmpp = 0.0;
504 vml->last_ympp = 0.0;
506 vml->dl_right_click_menu = NULL;
511 static void maps_layer_free ( VikMapsLayer *vml )
513 g_free ( vml->cache_dir );
514 vml->cache_dir = NULL;
515 if ( vml->dl_right_click_menu )
516 gtk_object_sink ( GTK_OBJECT(vml->dl_right_click_menu) );
517 g_free(vml->last_center);
518 vml->last_center = NULL;
521 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
523 if (from_file != TRUE)
525 /* If this method is not called in file reading context
526 * it is called in GUI context.
527 * So, we can check if we have to inform the user about inconsistency */
528 VikViewportDrawMode vp_drawmode;
529 VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
530 VikMapSource *map = NULL;
532 vp_drawmode = vik_viewport_get_drawmode ( VIK_VIEWPORT(vp) );
533 map = MAPS_LAYER_NTH_TYPE(vml->maptype);
534 if (vik_map_source_get_drawmode(map) != vp_drawmode) {
535 const gchar *drawmode_name = vik_viewport_get_drawmode_name (VIK_VIEWPORT(vp), vik_map_source_get_drawmode(map));
536 gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
537 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_WIDGET(vp), msg );
541 if (vik_map_source_get_license (map) != NULL) {
542 a_dialog_license (VIK_GTK_WINDOW_FROM_WIDGET(vp), vik_map_source_get_label (map),
543 vik_map_source_get_license (map), vik_map_source_get_license_url (map) );
548 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml )
550 return vik_maps_layer_get_map_label ( vml );
553 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
555 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
558 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
560 VikMapsLayer *rv = maps_layer_new ( vvp );
561 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
565 /*********************/
566 /****** DRAWING ******/
567 /*********************/
569 static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
572 gint width, height, iii, jjj;
574 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
576 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
577 g_object_unref(G_OBJECT(pixbuf));
581 pixels = gdk_pixbuf_get_pixels(pixbuf);
582 width = gdk_pixbuf_get_width(pixbuf);
583 height = gdk_pixbuf_get_height(pixbuf);
585 /* r,g,b,a,r,g,b,a.... */
586 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
594 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
597 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
598 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_NEAREST);
599 g_object_unref ( G_OBJECT(pixbuf) );
603 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
608 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
609 mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
612 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
613 vml->cache_dir, mode,
614 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
615 if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
618 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
620 /* free the pixbuf on error */
623 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
624 g_warning ( _("Couldn't open image file: %s"), gx->message );
628 g_object_unref ( G_OBJECT(pixbuf) );
631 if ( vml->alpha < 255 )
632 pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
633 if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
634 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
636 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
637 mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
638 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
645 gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
647 const VikCoord *center = vik_viewport_get_center ( vvp );
649 if (vik_window_get_pan_move (VIK_WINDOW(VIK_GTK_WINDOW_FROM_WIDGET(GTK_WIDGET(vvp)))))
650 /* D'n'D pan in action: do not download */
653 if (vml->last_center == NULL) {
654 VikCoord *new_center = g_malloc(sizeof(VikCoord));
655 *new_center = *center;
656 vml->last_center = new_center;
657 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
658 vml->last_ympp = vik_viewport_get_ympp(vvp);
662 /* TODO: perhaps vik_coord_diff() */
663 if (vik_coord_equals(vml->last_center, center)
664 && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
665 && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
668 *(vml->last_center) = *center;
669 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
670 vml->last_ympp = vik_viewport_get_ympp(vvp);
674 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
677 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
678 gdouble yzoom = vik_viewport_get_ympp ( vvp );
679 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
680 gdouble existence_only = FALSE;
682 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
683 xshrinkfactor = vml->xmapzoom / xzoom;
684 yshrinkfactor = vml->ymapzoom / yzoom;
685 xzoom = vml->xmapzoom;
686 yzoom = vml->xmapzoom;
687 if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
688 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
689 if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR )
690 existence_only = TRUE;
692 g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
699 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
700 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
701 vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
705 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
706 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
707 gint mode = vik_map_source_get_uniq_id(map);
710 gint xx, yy, width, height;
713 guint max_path_len = strlen(vml->cache_dir) + 40;
714 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
716 if ( (!existence_only) && vml->autodownload && should_start_autodownload(vml, vvp)) {
717 g_debug("%s: Starting autodownload", __FUNCTION__);
718 if ( vik_map_source_supports_download_only_new (map) )
719 // Try to download newer tiles
720 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NEW );
722 // Download only missing tiles
723 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
726 if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
727 for ( x = xmin; x <= xmax; x++ ) {
728 for ( y = ymin; y <= ymax; y++ ) {
731 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
733 width = gdk_pixbuf_get_width ( pixbuf );
734 height = gdk_pixbuf_get_height ( pixbuf );
736 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
737 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
741 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
745 } else { /* tilesize is known, don't have to keep converting coords */
746 gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
747 gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
748 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
749 gint tilesize_x_ceil = ceil ( tilesize_x );
750 gint tilesize_y_ceil = ceil ( tilesize_y );
751 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
752 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
753 gdouble xx, yy; gint xx_tmp, yy_tmp;
754 gint base_yy, xend, yend;
756 GdkGC *black_gc = GTK_WIDGET(vvp)->style->black_gc;
758 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
759 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
761 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
762 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
763 xx = xx_tmp; yy = yy_tmp;
764 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
765 * eg if tile size 128, shrinkfactor 0.333 */
766 xx -= (tilesize_x/2);
767 base_yy = yy - (tilesize_y/2);
769 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
771 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
775 if ( existence_only ) {
776 g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE,
777 vml->cache_dir, mode,
778 ulm.scale, ulm.z, ulm.x, ulm.y );
779 if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
780 vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
784 for (scale_inc = 0; scale_inc < 4; scale_inc ++) {
785 /* try with correct then smaller zooms */
786 int scale_factor = 1 << scale_inc; /* 2^scale_inc */
788 ulm2.x = ulm.x / scale_factor;
789 ulm2.y = ulm.y / scale_factor;
790 ulm2.scale = ulm.scale + scale_inc;
791 pixbuf = get_pixbuf ( vml, mode, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
793 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
794 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
796 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);
798 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
803 /* retry with bigger zooms */
805 for (scale_dec = 1; scale_dec < 2; scale_dec ++) {
807 int scale_factor = 1 << scale_dec; /* 2^scale_dec */
809 ulm2.x = ulm.x * scale_factor;
810 ulm2.y = ulm.y * scale_factor;
811 ulm2.scale = ulm.scale - scale_dec;
812 for (pict_x = 0; pict_x < scale_factor; pict_x ++) {
813 for (pict_y = 0; pict_y < scale_factor; pict_y ++) {
814 MapCoord ulm3 = ulm2;
817 pixbuf = get_pixbuf ( vml, mode, &ulm3, path_buf, max_path_len, xshrinkfactor / scale_factor, yshrinkfactor / scale_factor );
821 gint dest_x = xx + pict_x * (tilesize_x_ceil / scale_factor);
822 gint dest_y = yy + pict_y * (tilesize_y_ceil / scale_factor);
823 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, dest_x, dest_y, tilesize_x_ceil / scale_factor, tilesize_y_ceil / scale_factor );
841 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
843 if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
848 const gchar *copyright = vik_map_source_get_copyright ( MAPS_LAYER_NTH_TYPE(vml->maptype) );
849 vik_viewport_add_copyright ( vvp, copyright );
851 /* get corner coords */
852 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
853 /* UTM multi-zone stuff by Kit Transue */
854 gchar leftmost_zone, rightmost_zone, i;
855 leftmost_zone = vik_viewport_leftmost_zone( vvp );
856 rightmost_zone = vik_viewport_rightmost_zone( vvp );
857 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
858 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
859 maps_layer_draw_section ( vml, vvp, &ul, &br );
863 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
864 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
866 maps_layer_draw_section ( vml, vvp, &ul, &br );
871 /*************************/
872 /****** DOWNLOADING ******/
873 /*************************/
875 /* pass along data to thread, exists even if layer is deleted. */
885 gboolean refresh_display;
888 gboolean map_layer_alive;
892 static void mdi_free ( MapDownloadInfo *mdi )
894 g_mutex_free(mdi->mutex);
895 g_free ( mdi->cache_dir );
896 mdi->cache_dir = NULL;
897 g_free ( mdi->filename_buf );
898 mdi->filename_buf = NULL;
902 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
904 MapDownloadInfo *mdi = ptr;
905 g_mutex_lock(mdi->mutex);
906 mdi->map_layer_alive = FALSE;
907 g_mutex_unlock(mdi->mutex);
910 static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
912 void *handle = vik_map_source_download_handle_init(MAPS_LAYER_NTH_TYPE(mdi->maptype));
915 for ( x = mdi->x0; x <= mdi->xf; x++ )
917 for ( y = mdi->y0; y <= mdi->yf; y++ )
919 gboolean remove_mem_cache = FALSE;
920 gboolean need_download = FALSE;
921 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
922 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
923 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
926 int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
928 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
932 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
933 need_download = TRUE;
934 remove_mem_cache = TRUE;
936 } else { /* in case map file already exists */
937 switch (mdi->redownload) {
938 case REDOWNLOAD_NONE:
943 /* see if this one is bad or what */
945 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
946 if (gx || (!pixbuf)) {
947 g_remove ( mdi->filename_buf );
948 need_download = TRUE;
949 remove_mem_cache = TRUE;
953 g_object_unref ( pixbuf );
959 need_download = TRUE;
960 remove_mem_cache = TRUE;
964 /* FIXME: need a better way than to erase file in case of server/network problem */
965 g_remove ( mdi->filename_buf );
966 need_download = TRUE;
967 remove_mem_cache = TRUE;
970 case DOWNLOAD_OR_REFRESH:
971 remove_mem_cache = TRUE;
975 g_warning ( "redownload state %d unknown\n", mdi->redownload);
979 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
982 if ( vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf, handle))
987 g_mutex_lock(mdi->mutex);
988 if (remove_mem_cache)
989 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 );
990 if (mdi->refresh_display && mdi->map_layer_alive) {
991 /* TODO: check if it's on visible area */
992 vik_layer_emit_update ( VIK_LAYER(mdi->vml) );
994 g_mutex_unlock(mdi->mutex);
996 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
1000 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1001 g_mutex_lock(mdi->mutex);
1002 if (mdi->map_layer_alive)
1003 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1004 g_mutex_unlock(mdi->mutex);
1008 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
1010 if ( mdi->mapcoord.x || mdi->mapcoord.y )
1012 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1013 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1014 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
1015 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
1017 g_remove ( mdi->filename_buf );
1022 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
1024 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1025 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1027 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1028 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm )
1029 && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
1031 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
1036 mdi->map_layer_alive = TRUE;
1037 mdi->mutex = g_mutex_new();
1038 mdi->refresh_display = TRUE;
1040 /* cache_dir and buffer for dest filename */
1041 mdi->cache_dir = g_strdup ( vml->cache_dir );
1042 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1043 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1044 mdi->maptype = vml->maptype;
1046 mdi->mapcoord = ulm;
1048 mdi->redownload = redownload;
1050 mdi->x0 = MIN(ulm.x, brm.x);
1051 mdi->xf = MAX(ulm.x, brm.x);
1052 mdi->y0 = MIN(ulm.y, brm.y);
1053 mdi->yf = MAX(ulm.y, brm.y);
1057 if ( mdi->redownload ) {
1058 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1060 /* calculate how many we need */
1061 for ( a = mdi->x0; a <= mdi->xf; a++ )
1063 for ( b = mdi->y0; b <= mdi->yf; b++ )
1065 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1066 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1068 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1074 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1076 if ( mdi->mapstoget )
1078 const gchar *tmp_str;
1083 if (redownload == REDOWNLOAD_BAD)
1084 tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
1086 tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
1090 tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
1092 tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
1094 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1095 /* launch the thread */
1096 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1097 tmp, /* description string */
1098 (vik_thr_func) map_download_thread, /* function to call within thread */
1099 mdi, /* pass along data */
1100 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1101 (vik_thr_free_func) mdi_cancel_cleanup,
1110 void maps_layer_download_section_without_redraw( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
1113 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1115 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
1116 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
1117 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
1121 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1126 mdi->map_layer_alive = TRUE;
1127 mdi->mutex = g_mutex_new();
1128 mdi->refresh_display = FALSE;
1130 mdi->cache_dir = g_strdup ( vml->cache_dir );
1131 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1132 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1133 mdi->maptype = vml->maptype;
1135 mdi->mapcoord = ulm;
1137 mdi->redownload = REDOWNLOAD_NONE;
1139 mdi->x0 = MIN(ulm.x, brm.x);
1140 mdi->xf = MAX(ulm.x, brm.x);
1141 mdi->y0 = MIN(ulm.y, brm.y);
1142 mdi->yf = MAX(ulm.y, brm.y);
1146 for (i = mdi->x0; i <= mdi->xf; i++) {
1147 for (j = mdi->y0; j <= mdi->yf; j++) {
1148 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1149 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1151 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1156 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1158 if (mdi->mapstoget) {
1161 fmt = ngettext("Downloading %d %s map...",
1162 "Downloading %d %s maps...",
1164 tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
1166 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1167 /* launch the thread */
1168 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1169 tmp, /* description string */
1170 (vik_thr_func) map_download_thread, /* function to call within thread */
1171 mdi, /* pass along data */
1172 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1173 (vik_thr_free_func) mdi_cancel_cleanup,
1181 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1183 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1186 static void maps_layer_redownload_all ( VikMapsLayer *vml )
1188 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1191 static void maps_layer_redownload_new ( VikMapsLayer *vml )
1193 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
1196 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1198 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1200 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1202 if ( event->button == 1 )
1205 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 );
1206 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 );
1207 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
1208 vml->dl_tool_x = vml->dl_tool_y = -1;
1213 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) );
1214 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) );
1216 vml->redownload_vvp = vvp;
1218 vml->dl_tool_x = vml->dl_tool_y = -1;
1220 if ( ! vml->dl_right_click_menu ) {
1222 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1224 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _Bad Map(s)") );
1225 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1226 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1228 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _New Map(s)") );
1229 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), vml );
1230 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1232 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _All Map(s)") );
1233 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1234 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1237 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1238 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1244 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1249 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1252 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1254 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1255 if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
1256 vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
1257 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1258 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1260 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1267 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1271 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1272 if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1273 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1274 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1276 gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1277 vml->cache_dir, __map_types[vml->maptype].uniq_id,
1278 mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1280 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1281 g_free ( filename_buf );
1282 vik_layer_emit_update ( VIK_LAYER(vml) );
1290 static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
1292 VikMapsLayer *vml = vml_vvp[0];
1293 VikViewport *vvp = vml_vvp[1];
1294 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
1296 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1297 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1302 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1303 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1305 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1306 if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
1307 vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
1308 vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
1309 start_download_thread ( vml, vvp, &ul, &br, redownload );
1310 else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
1311 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
1312 gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
1313 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1317 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
1321 static void maps_layer_download_missing_onscreen_maps ( gpointer vml_vvp[2] )
1323 download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1326 static void maps_layer_download_new_onscreen_maps ( gpointer vml_vvp[2] )
1328 download_onscreen_maps( vml_vvp, REDOWNLOAD_NEW);
1331 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1333 download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1336 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1338 static gpointer pass_along[2];
1340 pass_along[0] = vml;
1341 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1343 item = gtk_menu_item_new();
1344 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1345 gtk_widget_show ( item );
1347 item = gtk_menu_item_new_with_mnemonic ( _("Download _Missing Onscreen Maps") );
1348 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), pass_along );
1349 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1350 gtk_widget_show ( item );
1352 if ( vik_map_source_supports_download_only_new (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
1353 item = gtk_menu_item_new_with_mnemonic ( _("Download _New Onscreen Maps") );
1354 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), pass_along );
1355 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1356 gtk_widget_show ( item );
1359 /* TODO Add GTK_STOCK_REFRESH icon */
1360 item = gtk_menu_item_new_with_mnemonic ( _("Reload _All Onscreen Maps") );
1361 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1362 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1363 gtk_widget_show ( item );