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", "0.5", "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, 0.5, 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, 0.5, 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 { { "MapsDownload", "vik-icon-Maps Download", N_("_Maps Download"), NULL, N_("Maps Download"), 0 },
135 (VikToolConstructorFunc) maps_layer_download_create,
139 (VikToolMouseFunc) maps_layer_download_click,
141 (VikToolMouseFunc) maps_layer_download_release,
144 GDK_CURSOR_IS_PIXMAP, &cursor_mapdl_pixbuf },
147 VikLayerInterface vik_maps_layer_interface = {
151 &vikmapslayer_pixbuf,
154 sizeof(maps_tools) / sizeof(maps_tools[0]),
163 (VikLayerFuncCreate) maps_layer_new,
164 (VikLayerFuncRealize) NULL,
165 (VikLayerFuncPostRead) maps_layer_post_read,
166 (VikLayerFuncFree) maps_layer_free,
168 (VikLayerFuncProperties) NULL,
169 (VikLayerFuncDraw) maps_layer_draw,
170 (VikLayerFuncChangeCoordMode) NULL,
172 (VikLayerFuncSetMenuItemsSelection) NULL,
173 (VikLayerFuncGetMenuItemsSelection) NULL,
175 (VikLayerFuncAddMenuItems) maps_layer_add_menu_items,
176 (VikLayerFuncSublayerAddMenuItems) NULL,
178 (VikLayerFuncSublayerRenameRequest) NULL,
179 (VikLayerFuncSublayerToggleVisible) NULL,
180 (VikLayerFuncSublayerTooltip) NULL,
181 (VikLayerFuncLayerTooltip) maps_layer_tooltip,
182 (VikLayerFuncLayerSelected) NULL,
184 (VikLayerFuncMarshall) maps_layer_marshall,
185 (VikLayerFuncUnmarshall) maps_layer_unmarshall,
187 (VikLayerFuncSetParam) maps_layer_set_param,
188 (VikLayerFuncGetParam) maps_layer_get_param,
190 (VikLayerFuncReadFileData) NULL,
191 (VikLayerFuncWriteFileData) NULL,
193 (VikLayerFuncDeleteItem) NULL,
194 (VikLayerFuncCutItem) NULL,
195 (VikLayerFuncCopyItem) NULL,
196 (VikLayerFuncPasteItem) NULL,
197 (VikLayerFuncFreeCopiedItem) NULL,
198 (VikLayerFuncDragDropRequest) NULL,
200 (VikLayerFuncSelectClick) NULL,
201 (VikLayerFuncSelectMove) NULL,
202 (VikLayerFuncSelectRelease) NULL,
203 (VikLayerFuncSelectedViewportMenu) NULL,
206 struct _VikMapsLayer {
212 gdouble xmapzoom, ymapzoom;
214 gboolean autodownload;
215 VikCoord *last_center;
219 gint dl_tool_x, dl_tool_y;
221 GtkMenu *dl_right_click_menu;
222 VikCoord redownload_ul, redownload_br; /* right click menu only */
223 VikViewport *redownload_vvp;
225 gboolean license_notice_shown; // FALSE for new maps only, otherwise
226 // TRUE for saved maps & other layer changes as we don't need to show it again
229 enum { REDOWNLOAD_NONE = 0, /* download only missing maps */
230 REDOWNLOAD_BAD, /* download missing and bad maps */
231 REDOWNLOAD_NEW, /* download missing maps that are newer on server only */
232 REDOWNLOAD_ALL, /* download all maps */
233 DOWNLOAD_OR_REFRESH }; /* download missing maps and refresh cache */
235 static VikLayerParam prefs[] = {
236 { VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Default maplayer directory:"), VIK_LAYER_WIDGET_FOLDERENTRY, NULL, NULL },
239 void maps_layer_init ()
241 VikLayerParamData tmp;
242 tmp.s = maps_layer_default_dir();
243 a_preferences_register(prefs, tmp, VIKING_PREFERENCES_GROUP_KEY);
246 /****************************************/
247 /******** MAPS LAYER TYPES **************/
248 /****************************************/
250 int _get_index_for_id ( guint id )
253 while (params_maptypes_ids[index] != 0)
255 if (params_maptypes_ids[index] == id)
262 void _add_map_source ( guint id, const char *label, VikMapSource *map )
266 len = g_strv_length (params_maptypes);
268 params_maptypes = g_realloc (params_maptypes, (len+2)*sizeof(gchar*));
269 params_maptypes[len] = g_strdup (label);
270 params_maptypes[len+1] = NULL;
273 params_maptypes_ids = g_realloc (params_maptypes_ids, (len+2)*sizeof(guint));
274 params_maptypes_ids[len] = id;
275 params_maptypes_ids[len+1] = 0;
277 /* We have to clone */
278 VikMapSource *clone = VIK_MAP_SOURCE(g_object_ref(map));
279 /* Register the clone in the list */
280 __map_types = g_list_append(__map_types, clone);
283 We have to ensure the mode LayerParam references the up-to-date
287 memcpy(&maps_layer_params[0].widget_data, ¶ms_maptypes, sizeof(gpointer));
288 memcpy(&maps_layer_params[0].extra_widget_data, ¶ms_maptypes_ids, sizeof(gpointer));
290 maps_layer_params[0].widget_data = params_maptypes;
291 maps_layer_params[0].extra_widget_data = params_maptypes_ids;
294 void _update_map_source ( const char *label, VikMapSource *map, int index )
296 GList *item = g_list_nth (__map_types, index);
297 g_object_unref (item->data);
298 item->data = g_object_ref (map);
299 /* Change previous data */
300 g_free (params_maptypes[index]);
301 params_maptypes[index] = g_strdup (label);
305 * maps_layer_register_map_source:
306 * @map: the new VikMapSource
308 * Register a new VikMapSource.
309 * Override existing one (equality of id).
311 void maps_layer_register_map_source ( VikMapSource *map )
313 g_assert(map != NULL);
315 guint id = vik_map_source_get_uniq_id(map);
316 const char *label = vik_map_source_get_label(map);
317 g_assert(label != NULL);
319 int previous = map_uniq_id_to_index (id);
320 if (previous != NUM_MAP_TYPES)
322 _update_map_source (label, map, previous);
326 _add_map_source (id, label, map);
330 #define MAPS_LAYER_NTH_LABEL(n) (params_maptypes[n])
331 #define MAPS_LAYER_NTH_ID(n) (params_maptypes_ids[n])
332 #define MAPS_LAYER_NTH_TYPE(n) (VIK_MAP_SOURCE(g_list_nth_data(__map_types, (n))))
334 gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
336 return(vml->maptype);
339 gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
341 return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
344 /****************************************/
345 /******** CACHE DIR STUFF ***************/
346 /****************************************/
348 #define DIRECTDIRACCESS "%s%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d%s"
349 #define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
350 #define MAPS_CACHE_DIR maps_layer_default_dir()
354 #define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
355 #define LOCAL_MAPS_DIR "VIKING-MAPS"
356 #elif defined __APPLE__
358 #define GLOBAL_MAPS_DIR "/Library/cache/Viking/maps/"
359 #define LOCAL_MAPS_DIR "/Library/Application Support/Viking/viking-maps"
362 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
363 #define LOCAL_MAPS_DIR ".viking-maps"
366 gchar *maps_layer_default_dir ()
368 static gchar *defaultdir = NULL;
371 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
372 const gchar *mapdir = g_getenv("VIKING_MAPS");
374 defaultdir = g_strdup ( mapdir );
375 } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
376 defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
378 const gchar *home = g_get_home_dir();
379 if (!home || g_access(home, W_OK))
380 home = g_get_home_dir ();
382 defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
384 defaultdir = g_strdup ( LOCAL_MAPS_DIR );
386 if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
388 /* Add the separator at the end */
389 gchar *tmp = defaultdir;
390 defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
393 g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
398 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
400 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
402 g_mkdir ( vml->cache_dir, 0777 );
406 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
409 g_assert ( vml != NULL);
410 g_free ( vml->cache_dir );
411 vml->cache_dir = NULL;
413 if ( dir == NULL || dir[0] == '\0' )
415 if ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir") )
416 vml->cache_dir = g_strdup ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir")->s );
421 if ( dir[len-1] != G_DIR_SEPARATOR )
423 vml->cache_dir = g_malloc ( len+2 );
424 strncpy ( vml->cache_dir, dir, len );
425 vml->cache_dir[len] = G_DIR_SEPARATOR;
426 vml->cache_dir[len+1] = '\0';
429 vml->cache_dir = g_strdup ( dir );
431 maps_layer_mkdir_if_default_dir ( vml );
434 /****************************************/
435 /******** GOBJECT STUFF *****************/
436 /****************************************/
438 GType vik_maps_layer_get_type ()
440 static GType vml_type = 0;
444 static const GTypeInfo vml_info =
446 sizeof (VikMapsLayerClass),
447 NULL, /* base_init */
448 NULL, /* base_finalize */
449 NULL, /* class init */
450 NULL, /* class_finalize */
451 NULL, /* class_data */
452 sizeof (VikMapsLayer),
454 NULL /* instance init */
456 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
462 /****************************************/
463 /************** PARAMETERS **************/
464 /****************************************/
466 static guint map_index_to_uniq_id (guint8 index)
468 g_assert ( index < NUM_MAP_TYPES );
469 return vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(index));
472 static guint map_uniq_id_to_index ( guint uniq_id )
475 for ( i = 0; i < NUM_MAP_TYPES; i++ )
476 if ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(i)) == uniq_id )
478 return NUM_MAP_TYPES; /* no such thing */
481 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation )
483 // When loading from a file don't need the license reminder
484 if ( is_file_operation )
485 vml->license_notice_shown = TRUE;
489 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
490 case PARAM_MAPTYPE: {
491 gint maptype = map_uniq_id_to_index(data.u);
492 if ( maptype == NUM_MAP_TYPES ) g_warning(_("Unknown map type"));
493 else vml->maptype = maptype;
496 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
497 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
498 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
499 vml->mapzoom_id = data.u;
500 vml->xmapzoom = __mapzooms_x [data.u];
501 vml->ymapzoom = __mapzooms_y [data.u];
502 }else g_warning (_("Unknown Map Zoom")); break;
507 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation )
509 VikLayerParamData rv;
512 case PARAM_CACHE_DIR: rv.s = vml->cache_dir ? vml->cache_dir : ""; break;
513 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
514 case PARAM_ALPHA: rv.u = vml->alpha; break;
515 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
516 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
521 /****************************************/
522 /****** CREATING, COPYING, FREEING ******/
523 /****************************************/
525 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
528 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
529 vik_layer_init ( VIK_LAYER(vml), VIK_LAYER_MAPS );
530 idx = map_uniq_id_to_index(19); /* 19 is id for OSM MapQuest maps */
531 vml->maptype = (idx < NUM_MAP_TYPES) ? idx : 0;
532 vml->maptype = (idx < NUM_MAP_TYPES) ? idx : 0;
535 vml->dl_tool_x = vml->dl_tool_y = -1;
536 maps_layer_set_cache_dir ( vml, NULL );
537 vml->autodownload = FALSE;
538 vml->last_center = NULL;
539 vml->last_xmpp = 0.0;
540 vml->last_ympp = 0.0;
542 vml->dl_right_click_menu = NULL;
543 vml->license_notice_shown = FALSE;
548 static void maps_layer_free ( VikMapsLayer *vml )
550 g_free ( vml->cache_dir );
551 vml->cache_dir = NULL;
552 if ( vml->dl_right_click_menu )
553 g_object_ref_sink ( G_OBJECT(vml->dl_right_click_menu) );
554 g_free(vml->last_center);
555 vml->last_center = NULL;
558 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
560 if (from_file != TRUE)
562 /* If this method is not called in file reading context
563 * it is called in GUI context.
564 * So, we can check if we have to inform the user about inconsistency */
565 VikViewportDrawMode vp_drawmode;
566 VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
567 VikMapSource *map = NULL;
569 vp_drawmode = vik_viewport_get_drawmode ( vp );
570 map = MAPS_LAYER_NTH_TYPE(vml->maptype);
571 if (vik_map_source_get_drawmode(map) != vp_drawmode) {
572 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vp, vik_map_source_get_drawmode(map));
573 gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
574 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_WIDGET(vp), msg );
578 if (vik_map_source_get_license (map) != NULL) {
579 if ( ! vml->license_notice_shown ) {
580 a_dialog_license (VIK_GTK_WINDOW_FROM_WIDGET(vp), vik_map_source_get_label (map),
581 vik_map_source_get_license (map), vik_map_source_get_license_url (map) );
582 vml->license_notice_shown = TRUE;
588 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml )
590 return vik_maps_layer_get_map_label ( vml );
593 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
595 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
598 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
600 VikMapsLayer *rv = maps_layer_new ( vvp );
601 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
605 /*********************/
606 /****** DRAWING ******/
607 /*********************/
609 static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
612 gint width, height, iii, jjj;
614 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
616 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
617 g_object_unref(G_OBJECT(pixbuf));
621 pixels = gdk_pixbuf_get_pixels(pixbuf);
622 width = gdk_pixbuf_get_width(pixbuf);
623 height = gdk_pixbuf_get_height(pixbuf);
625 /* r,g,b,a,r,g,b,a.... */
626 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
634 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
637 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
638 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_NEAREST);
639 g_object_unref ( G_OBJECT(pixbuf) );
643 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
648 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
649 mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
652 if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
653 g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS,
654 vml->cache_dir, (17 - mapcoord->scale), mapcoord->x, mapcoord->y, ".png" );
656 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
657 vml->cache_dir, mode,
658 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
660 if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
663 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
665 /* free the pixbuf on error */
668 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
669 g_warning ( _("Couldn't open image file: %s"), gx->message );
673 g_object_unref ( G_OBJECT(pixbuf) );
676 if ( vml->alpha < 255 )
677 pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
678 if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
679 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
681 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
682 mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
683 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
690 gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
692 const VikCoord *center = vik_viewport_get_center ( vvp );
694 if (vik_window_get_pan_move (VIK_WINDOW(VIK_GTK_WINDOW_FROM_WIDGET(GTK_WIDGET(vvp)))))
695 /* D'n'D pan in action: do not download */
698 if (vml->last_center == NULL) {
699 VikCoord *new_center = g_malloc(sizeof(VikCoord));
700 *new_center = *center;
701 vml->last_center = new_center;
702 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
703 vml->last_ympp = vik_viewport_get_ympp(vvp);
707 /* TODO: perhaps vik_coord_diff() */
708 if (vik_coord_equals(vml->last_center, center)
709 && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
710 && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
713 *(vml->last_center) = *center;
714 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
715 vml->last_ympp = vik_viewport_get_ympp(vvp);
719 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
722 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
723 gdouble yzoom = vik_viewport_get_ympp ( vvp );
724 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
725 gboolean existence_only = FALSE;
727 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
728 xshrinkfactor = vml->xmapzoom / xzoom;
729 yshrinkfactor = vml->ymapzoom / yzoom;
730 xzoom = vml->xmapzoom;
731 yzoom = vml->xmapzoom;
732 if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
733 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
734 if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR )
735 existence_only = TRUE;
737 g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
744 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
745 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
746 vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
750 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
751 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
752 gint mode = vik_map_source_get_uniq_id(map);
755 gint xx, yy, width, height;
758 guint max_path_len = strlen(vml->cache_dir) + 40;
759 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
761 if ( (!existence_only) && vml->autodownload && should_start_autodownload(vml, vvp)) {
762 g_debug("%s: Starting autodownload", __FUNCTION__);
763 if ( vik_map_source_supports_download_only_new (map) )
764 // Try to download newer tiles
765 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NEW );
767 // Download only missing tiles
768 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
771 if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
772 for ( x = xmin; x <= xmax; x++ ) {
773 for ( y = ymin; y <= ymax; y++ ) {
776 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
778 width = gdk_pixbuf_get_width ( pixbuf );
779 height = gdk_pixbuf_get_height ( pixbuf );
781 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
782 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
786 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
790 } else { /* tilesize is known, don't have to keep converting coords */
791 gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
792 gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
793 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
794 gint tilesize_x_ceil = ceil ( tilesize_x );
795 gint tilesize_y_ceil = ceil ( tilesize_y );
796 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
797 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
798 gdouble xx, yy; gint xx_tmp, yy_tmp;
799 gint base_yy, xend, yend;
801 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
802 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
804 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
805 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
806 xx = xx_tmp; yy = yy_tmp;
807 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
808 * eg if tile size 128, shrinkfactor 0.333 */
809 xx -= (tilesize_x/2);
810 base_yy = yy - (tilesize_y/2);
812 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
814 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
818 if ( existence_only ) {
819 if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
820 g_snprintf ( path_buf, max_path_len, DIRECTDIRACCESS,
821 vml->cache_dir, (17 - ulm.scale), ulm.x, ulm.y, ".png" );
823 g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE,
824 vml->cache_dir, mode,
825 ulm.scale, ulm.z, ulm.x, ulm.y );
826 if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
827 GdkGC *black_gc = GTK_WIDGET(vvp)->style->black_gc;
828 vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
832 for (scale_inc = 0; scale_inc < 4; scale_inc ++) {
833 /* try with correct then smaller zooms */
834 int scale_factor = 1 << scale_inc; /* 2^scale_inc */
836 ulm2.x = ulm.x / scale_factor;
837 ulm2.y = ulm.y / scale_factor;
838 ulm2.scale = ulm.scale + scale_inc;
839 pixbuf = get_pixbuf ( vml, mode, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
841 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
842 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
844 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);
846 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
851 /* retry with bigger zooms */
853 for (scale_dec = 1; scale_dec < 2; scale_dec ++) {
855 int scale_factor = 1 << scale_dec; /* 2^scale_dec */
857 ulm2.x = ulm.x * scale_factor;
858 ulm2.y = ulm.y * scale_factor;
859 ulm2.scale = ulm.scale - scale_dec;
860 for (pict_x = 0; pict_x < scale_factor; pict_x ++) {
861 for (pict_y = 0; pict_y < scale_factor; pict_y ++) {
862 MapCoord ulm3 = ulm2;
865 pixbuf = get_pixbuf ( vml, mode, &ulm3, path_buf, max_path_len, xshrinkfactor / scale_factor, yshrinkfactor / scale_factor );
869 gint dest_x = xx + pict_x * (tilesize_x_ceil / scale_factor);
870 gint dest_y = yy + pict_y * (tilesize_y_ceil / scale_factor);
871 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, dest_x, dest_y, tilesize_x_ceil / scale_factor, tilesize_y_ceil / scale_factor );
889 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
891 if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
896 gdouble level = vik_viewport_get_zoom ( vvp );
898 vik_viewport_get_min_max_lat_lon ( vvp, &bbox.south, &bbox.north, &bbox.west, &bbox.east );
899 vik_map_source_get_copyright ( MAPS_LAYER_NTH_TYPE(vml->maptype), bbox, level, vik_viewport_add_copyright, vvp );
902 const GdkPixbuf *logo = vik_map_source_get_logo ( MAPS_LAYER_NTH_TYPE(vml->maptype) );
903 vik_viewport_add_logo ( vvp, logo );
905 /* get corner coords */
906 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
907 /* UTM multi-zone stuff by Kit Transue */
908 gchar leftmost_zone, rightmost_zone, i;
909 leftmost_zone = vik_viewport_leftmost_zone( vvp );
910 rightmost_zone = vik_viewport_rightmost_zone( vvp );
911 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
912 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
913 maps_layer_draw_section ( vml, vvp, &ul, &br );
917 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
918 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
920 maps_layer_draw_section ( vml, vvp, &ul, &br );
925 /*************************/
926 /****** DOWNLOADING ******/
927 /*************************/
929 /* pass along data to thread, exists even if layer is deleted. */
939 gboolean refresh_display;
942 gboolean map_layer_alive;
946 static void mdi_free ( MapDownloadInfo *mdi )
948 g_mutex_free(mdi->mutex);
949 g_free ( mdi->cache_dir );
950 mdi->cache_dir = NULL;
951 g_free ( mdi->filename_buf );
952 mdi->filename_buf = NULL;
956 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
958 MapDownloadInfo *mdi = ptr;
959 g_mutex_lock(mdi->mutex);
960 mdi->map_layer_alive = FALSE;
961 g_mutex_unlock(mdi->mutex);
964 static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
966 void *handle = vik_map_source_download_handle_init(MAPS_LAYER_NTH_TYPE(mdi->maptype));
969 for ( x = mdi->x0; x <= mdi->xf; x++ )
971 for ( y = mdi->y0; y <= mdi->yf; y++ )
973 gboolean remove_mem_cache = FALSE;
974 gboolean need_download = FALSE;
975 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
976 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
977 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
980 int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
982 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
986 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
987 need_download = TRUE;
988 remove_mem_cache = TRUE;
990 } else { /* in case map file already exists */
991 switch (mdi->redownload) {
992 case REDOWNLOAD_NONE:
997 /* see if this one is bad or what */
999 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
1000 if (gx || (!pixbuf)) {
1001 g_remove ( mdi->filename_buf );
1002 need_download = TRUE;
1003 remove_mem_cache = TRUE;
1004 g_error_free ( gx );
1007 g_object_unref ( pixbuf );
1012 case REDOWNLOAD_NEW:
1013 need_download = TRUE;
1014 remove_mem_cache = TRUE;
1017 case REDOWNLOAD_ALL:
1018 /* FIXME: need a better way than to erase file in case of server/network problem */
1019 g_remove ( mdi->filename_buf );
1020 need_download = TRUE;
1021 remove_mem_cache = TRUE;
1024 case DOWNLOAD_OR_REFRESH:
1025 remove_mem_cache = TRUE;
1029 g_warning ( "redownload state %d unknown\n", mdi->redownload);
1033 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
1035 if (need_download) {
1036 if ( vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf, handle))
1040 g_mutex_lock(mdi->mutex);
1041 if (remove_mem_cache)
1042 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 );
1043 if (mdi->refresh_display && mdi->map_layer_alive) {
1044 /* TODO: check if it's on visible area */
1045 vik_layer_emit_update ( VIK_LAYER(mdi->vml), TRUE ); // Yes update display from background
1047 g_mutex_unlock(mdi->mutex);
1048 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
1052 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1053 g_mutex_lock(mdi->mutex);
1054 if (mdi->map_layer_alive)
1055 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1056 g_mutex_unlock(mdi->mutex);
1060 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
1062 if ( mdi->mapcoord.x || mdi->mapcoord.y )
1064 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1065 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1066 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
1067 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
1069 g_remove ( mdi->filename_buf );
1074 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
1076 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1077 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1079 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1081 // Don't ever attempt download on direct access
1082 if ( vik_map_source_is_direct_file_access ( map ) )
1085 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm )
1086 && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
1088 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
1093 mdi->map_layer_alive = TRUE;
1094 mdi->mutex = g_mutex_new();
1095 mdi->refresh_display = TRUE;
1097 /* cache_dir and buffer for dest filename */
1098 mdi->cache_dir = g_strdup ( vml->cache_dir );
1099 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1100 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1101 mdi->maptype = vml->maptype;
1103 mdi->mapcoord = ulm;
1105 mdi->redownload = redownload;
1107 mdi->x0 = MIN(ulm.x, brm.x);
1108 mdi->xf = MAX(ulm.x, brm.x);
1109 mdi->y0 = MIN(ulm.y, brm.y);
1110 mdi->yf = MAX(ulm.y, brm.y);
1114 if ( mdi->redownload ) {
1115 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1117 /* calculate how many we need */
1118 for ( a = mdi->x0; a <= mdi->xf; a++ )
1120 for ( b = mdi->y0; b <= mdi->yf; b++ )
1122 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1123 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1125 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1131 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1133 if ( mdi->mapstoget )
1135 const gchar *tmp_str;
1140 if (redownload == REDOWNLOAD_BAD)
1141 tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
1143 tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
1147 tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
1149 tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
1151 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1152 /* launch the thread */
1153 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1154 tmp, /* description string */
1155 (vik_thr_func) map_download_thread, /* function to call within thread */
1156 mdi, /* pass along data */
1157 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1158 (vik_thr_free_func) mdi_cancel_cleanup,
1167 void maps_layer_download_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
1170 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1172 // Don't ever attempt download on direct access
1173 if ( vik_map_source_is_direct_file_access ( map ) )
1176 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
1177 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
1178 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
1182 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1187 mdi->map_layer_alive = TRUE;
1188 mdi->mutex = g_mutex_new();
1189 mdi->refresh_display = TRUE;
1191 mdi->cache_dir = g_strdup ( vml->cache_dir );
1192 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1193 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1194 mdi->maptype = vml->maptype;
1196 mdi->mapcoord = ulm;
1198 mdi->redownload = REDOWNLOAD_NONE;
1200 mdi->x0 = MIN(ulm.x, brm.x);
1201 mdi->xf = MAX(ulm.x, brm.x);
1202 mdi->y0 = MIN(ulm.y, brm.y);
1203 mdi->yf = MAX(ulm.y, brm.y);
1207 for (i = mdi->x0; i <= mdi->xf; i++) {
1208 for (j = mdi->y0; j <= mdi->yf; j++) {
1209 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1210 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1212 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1217 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1219 if (mdi->mapstoget) {
1222 fmt = ngettext("Downloading %d %s map...",
1223 "Downloading %d %s maps...",
1225 tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
1227 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1228 /* launch the thread */
1229 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1230 tmp, /* description string */
1231 (vik_thr_func) map_download_thread, /* function to call within thread */
1232 mdi, /* pass along data */
1233 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1234 (vik_thr_free_func) mdi_cancel_cleanup,
1242 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1244 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1247 static void maps_layer_redownload_all ( VikMapsLayer *vml )
1249 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1252 static void maps_layer_redownload_new ( VikMapsLayer *vml )
1254 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
1257 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1259 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1261 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1263 if ( event->button == 1 )
1266 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 );
1267 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 );
1268 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
1269 vml->dl_tool_x = vml->dl_tool_y = -1;
1274 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) );
1275 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) );
1277 vml->redownload_vvp = vvp;
1279 vml->dl_tool_x = vml->dl_tool_y = -1;
1281 if ( ! vml->dl_right_click_menu ) {
1283 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1285 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _Bad Map(s)") );
1286 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1287 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1289 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _New Map(s)") );
1290 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), vml );
1291 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1293 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _All Map(s)") );
1294 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1295 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1298 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1299 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1305 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1310 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1313 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1315 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1316 if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
1317 vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
1318 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1319 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1321 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1328 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1332 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1333 if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1334 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1335 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1337 gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1338 vml->cache_dir, __map_types[vml->maptype].uniq_id,
1339 mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1341 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1342 g_free ( filename_buf );
1343 vik_layer_emit_update ( VIK_LAYER(vml) );
1351 static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
1353 VikMapsLayer *vml = vml_vvp[0];
1354 VikViewport *vvp = vml_vvp[1];
1355 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
1357 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1358 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1363 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1364 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1366 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1367 if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
1368 vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
1369 vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
1370 start_download_thread ( vml, vvp, &ul, &br, redownload );
1371 else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
1372 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
1373 gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
1374 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1378 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
1382 static void maps_layer_download_missing_onscreen_maps ( gpointer vml_vvp[2] )
1384 download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1387 static void maps_layer_download_new_onscreen_maps ( gpointer vml_vvp[2] )
1389 download_onscreen_maps( vml_vvp, REDOWNLOAD_NEW);
1392 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1394 download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1397 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1399 static gpointer pass_along[2];
1401 pass_along[0] = vml;
1402 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1404 item = gtk_menu_item_new();
1405 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1406 gtk_widget_show ( item );
1408 /* Now with icons */
1409 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _Missing Onscreen Maps") );
1410 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
1411 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), pass_along );
1412 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1413 gtk_widget_show ( item );
1415 if ( vik_map_source_supports_download_only_new (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
1416 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _New Onscreen Maps") );
1417 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REDO, GTK_ICON_SIZE_MENU) );
1418 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), pass_along );
1419 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1420 gtk_widget_show ( item );
1423 item = gtk_image_menu_item_new_with_mnemonic ( _("Reload _All Onscreen Maps") );
1424 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
1425 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1426 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1427 gtk_widget_show ( item );
1431 * Enable downloading maps of the current screen area either 'new' or 'everything'
1433 void vik_maps_layer_download ( VikMapsLayer *vml, VikViewport *vvp, gboolean only_new )
1438 static gpointer pass_along[2];
1439 pass_along[0] = vml;
1440 pass_along[1] = vvp;
1443 // Get only new maps
1444 maps_layer_download_new_onscreen_maps ( pass_along );
1446 // Redownload everything
1447 maps_layer_redownload_all_onscreen_maps ( pass_along );