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, NULL },
125 { "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Maps Directory:"), VIK_LAYER_WIDGET_FOLDERENTRY, NULL, NULL, NULL },
126 { "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales, NULL,
127 N_("Control the Alpha value for transparency effects") },
128 { "autodownload", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload maps:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL },
129 { "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Zoom Level:"), VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms, NULL,
130 N_("Determines the method of displaying map tiles for the current zoom level. 'Viking Zoom Level' uses the best matching level, otherwise setting a fixed value will always use map tiles of the specified value regardless of the actual zoom level.") },
133 enum { PARAM_MAPTYPE=0, PARAM_CACHE_DIR, PARAM_ALPHA, PARAM_AUTODOWNLOAD, PARAM_MAPZOOM, NUM_PARAMS };
135 static VikToolInterface maps_tools[] = {
136 { { "MapsDownload", "vik-icon-Maps Download", N_("_Maps Download"), NULL, N_("Maps Download"), 0 },
137 (VikToolConstructorFunc) maps_layer_download_create,
141 (VikToolMouseFunc) maps_layer_download_click,
143 (VikToolMouseFunc) maps_layer_download_release,
146 GDK_CURSOR_IS_PIXMAP, &cursor_mapdl_pixbuf },
149 VikLayerInterface vik_maps_layer_interface = {
153 &vikmapslayer_pixbuf,
156 sizeof(maps_tools) / sizeof(maps_tools[0]),
165 (VikLayerFuncCreate) maps_layer_new,
166 (VikLayerFuncRealize) NULL,
167 (VikLayerFuncPostRead) maps_layer_post_read,
168 (VikLayerFuncFree) maps_layer_free,
170 (VikLayerFuncProperties) NULL,
171 (VikLayerFuncDraw) maps_layer_draw,
172 (VikLayerFuncChangeCoordMode) NULL,
174 (VikLayerFuncSetMenuItemsSelection) NULL,
175 (VikLayerFuncGetMenuItemsSelection) NULL,
177 (VikLayerFuncAddMenuItems) maps_layer_add_menu_items,
178 (VikLayerFuncSublayerAddMenuItems) NULL,
180 (VikLayerFuncSublayerRenameRequest) NULL,
181 (VikLayerFuncSublayerToggleVisible) NULL,
182 (VikLayerFuncSublayerTooltip) NULL,
183 (VikLayerFuncLayerTooltip) maps_layer_tooltip,
184 (VikLayerFuncLayerSelected) NULL,
186 (VikLayerFuncMarshall) maps_layer_marshall,
187 (VikLayerFuncUnmarshall) maps_layer_unmarshall,
189 (VikLayerFuncSetParam) maps_layer_set_param,
190 (VikLayerFuncGetParam) maps_layer_get_param,
192 (VikLayerFuncReadFileData) NULL,
193 (VikLayerFuncWriteFileData) NULL,
195 (VikLayerFuncDeleteItem) NULL,
196 (VikLayerFuncCutItem) NULL,
197 (VikLayerFuncCopyItem) NULL,
198 (VikLayerFuncPasteItem) NULL,
199 (VikLayerFuncFreeCopiedItem) NULL,
200 (VikLayerFuncDragDropRequest) NULL,
202 (VikLayerFuncSelectClick) NULL,
203 (VikLayerFuncSelectMove) NULL,
204 (VikLayerFuncSelectRelease) NULL,
205 (VikLayerFuncSelectedViewportMenu) NULL,
208 struct _VikMapsLayer {
214 gdouble xmapzoom, ymapzoom;
216 gboolean autodownload;
217 VikCoord *last_center;
221 gint dl_tool_x, dl_tool_y;
223 GtkMenu *dl_right_click_menu;
224 VikCoord redownload_ul, redownload_br; /* right click menu only */
225 VikViewport *redownload_vvp;
227 gboolean license_notice_shown; // FALSE for new maps only, otherwise
228 // TRUE for saved maps & other layer changes as we don't need to show it again
231 enum { REDOWNLOAD_NONE = 0, /* download only missing maps */
232 REDOWNLOAD_BAD, /* download missing and bad maps */
233 REDOWNLOAD_NEW, /* download missing maps that are newer on server only */
234 REDOWNLOAD_ALL, /* download all maps */
235 DOWNLOAD_OR_REFRESH }; /* download missing maps and refresh cache */
237 static VikLayerParam prefs[] = {
238 { VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Default maplayer directory:"), VIK_LAYER_WIDGET_FOLDERENTRY, NULL, NULL, N_("Choose a directory to store cached Map tiles for this layer") },
241 void maps_layer_init ()
243 VikLayerParamData tmp;
244 tmp.s = maps_layer_default_dir();
245 a_preferences_register(prefs, tmp, VIKING_PREFERENCES_GROUP_KEY);
248 /****************************************/
249 /******** MAPS LAYER TYPES **************/
250 /****************************************/
252 int _get_index_for_id ( guint id )
255 while (params_maptypes_ids[index] != 0)
257 if (params_maptypes_ids[index] == id)
264 void _add_map_source ( guint id, const char *label, VikMapSource *map )
268 len = g_strv_length (params_maptypes);
270 params_maptypes = g_realloc (params_maptypes, (len+2)*sizeof(gchar*));
271 params_maptypes[len] = g_strdup (label);
272 params_maptypes[len+1] = NULL;
275 params_maptypes_ids = g_realloc (params_maptypes_ids, (len+2)*sizeof(guint));
276 params_maptypes_ids[len] = id;
277 params_maptypes_ids[len+1] = 0;
279 /* We have to clone */
280 VikMapSource *clone = VIK_MAP_SOURCE(g_object_ref(map));
281 /* Register the clone in the list */
282 __map_types = g_list_append(__map_types, clone);
285 We have to ensure the mode LayerParam references the up-to-date
289 memcpy(&maps_layer_params[0].widget_data, ¶ms_maptypes, sizeof(gpointer));
290 memcpy(&maps_layer_params[0].extra_widget_data, ¶ms_maptypes_ids, sizeof(gpointer));
292 maps_layer_params[0].widget_data = params_maptypes;
293 maps_layer_params[0].extra_widget_data = params_maptypes_ids;
296 void _update_map_source ( const char *label, VikMapSource *map, int index )
298 GList *item = g_list_nth (__map_types, index);
299 g_object_unref (item->data);
300 item->data = g_object_ref (map);
301 /* Change previous data */
302 g_free (params_maptypes[index]);
303 params_maptypes[index] = g_strdup (label);
307 * maps_layer_register_map_source:
308 * @map: the new VikMapSource
310 * Register a new VikMapSource.
311 * Override existing one (equality of id).
313 void maps_layer_register_map_source ( VikMapSource *map )
315 g_assert(map != NULL);
317 guint id = vik_map_source_get_uniq_id(map);
318 const char *label = vik_map_source_get_label(map);
319 g_assert(label != NULL);
321 int previous = map_uniq_id_to_index (id);
322 if (previous != NUM_MAP_TYPES)
324 _update_map_source (label, map, previous);
328 _add_map_source (id, label, map);
332 #define MAPS_LAYER_NTH_LABEL(n) (params_maptypes[n])
333 #define MAPS_LAYER_NTH_ID(n) (params_maptypes_ids[n])
334 #define MAPS_LAYER_NTH_TYPE(n) (VIK_MAP_SOURCE(g_list_nth_data(__map_types, (n))))
336 gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
338 return(vml->maptype);
341 gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
343 return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
346 /****************************************/
347 /******** CACHE DIR STUFF ***************/
348 /****************************************/
350 #define DIRECTDIRACCESS "%s%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d%s"
351 #define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
352 #define MAPS_CACHE_DIR maps_layer_default_dir()
356 #define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
357 #define LOCAL_MAPS_DIR "VIKING-MAPS"
358 #elif defined __APPLE__
360 #define GLOBAL_MAPS_DIR "/Library/cache/Viking/maps/"
361 #define LOCAL_MAPS_DIR "/Library/Application Support/Viking/viking-maps"
364 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
365 #define LOCAL_MAPS_DIR ".viking-maps"
368 gchar *maps_layer_default_dir ()
370 static gchar *defaultdir = NULL;
373 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
374 const gchar *mapdir = g_getenv("VIKING_MAPS");
376 defaultdir = g_strdup ( mapdir );
377 } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
378 defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
380 const gchar *home = g_get_home_dir();
381 if (!home || g_access(home, W_OK))
382 home = g_get_home_dir ();
384 defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
386 defaultdir = g_strdup ( LOCAL_MAPS_DIR );
388 if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
390 /* Add the separator at the end */
391 gchar *tmp = defaultdir;
392 defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
395 g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
400 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
402 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
404 g_mkdir ( vml->cache_dir, 0777 );
408 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
411 g_assert ( vml != NULL);
412 g_free ( vml->cache_dir );
413 vml->cache_dir = NULL;
415 if ( dir == NULL || dir[0] == '\0' )
417 if ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir") )
418 vml->cache_dir = g_strdup ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir")->s );
423 if ( dir[len-1] != G_DIR_SEPARATOR )
425 vml->cache_dir = g_malloc ( len+2 );
426 strncpy ( vml->cache_dir, dir, len );
427 vml->cache_dir[len] = G_DIR_SEPARATOR;
428 vml->cache_dir[len+1] = '\0';
431 vml->cache_dir = g_strdup ( dir );
433 maps_layer_mkdir_if_default_dir ( vml );
436 /****************************************/
437 /******** GOBJECT STUFF *****************/
438 /****************************************/
440 GType vik_maps_layer_get_type ()
442 static GType vml_type = 0;
446 static const GTypeInfo vml_info =
448 sizeof (VikMapsLayerClass),
449 NULL, /* base_init */
450 NULL, /* base_finalize */
451 NULL, /* class init */
452 NULL, /* class_finalize */
453 NULL, /* class_data */
454 sizeof (VikMapsLayer),
456 NULL /* instance init */
458 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
464 /****************************************/
465 /************** PARAMETERS **************/
466 /****************************************/
468 static guint map_index_to_uniq_id (guint8 index)
470 g_assert ( index < NUM_MAP_TYPES );
471 return vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(index));
474 static guint map_uniq_id_to_index ( guint uniq_id )
477 for ( i = 0; i < NUM_MAP_TYPES; i++ )
478 if ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(i)) == uniq_id )
480 return NUM_MAP_TYPES; /* no such thing */
483 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation )
485 // When loading from a file don't need the license reminder
486 if ( is_file_operation )
487 vml->license_notice_shown = TRUE;
491 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
492 case PARAM_MAPTYPE: {
493 gint maptype = map_uniq_id_to_index(data.u);
494 if ( maptype == NUM_MAP_TYPES ) g_warning(_("Unknown map type"));
495 else vml->maptype = maptype;
498 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
499 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
500 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
501 vml->mapzoom_id = data.u;
502 vml->xmapzoom = __mapzooms_x [data.u];
503 vml->ymapzoom = __mapzooms_y [data.u];
504 }else g_warning (_("Unknown Map Zoom")); break;
509 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation )
511 VikLayerParamData rv;
514 case PARAM_CACHE_DIR: rv.s = vml->cache_dir ? vml->cache_dir : ""; break;
515 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
516 case PARAM_ALPHA: rv.u = vml->alpha; break;
517 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
518 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
523 /****************************************/
524 /****** CREATING, COPYING, FREEING ******/
525 /****************************************/
527 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
530 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
531 vik_layer_set_type ( VIK_LAYER(vml), VIK_LAYER_MAPS );
532 idx = map_uniq_id_to_index(19); /* 19 is id for OSM MapQuest maps */
533 vml->maptype = (idx < NUM_MAP_TYPES) ? idx : 0;
534 vml->maptype = (idx < NUM_MAP_TYPES) ? idx : 0;
537 vml->dl_tool_x = vml->dl_tool_y = -1;
538 maps_layer_set_cache_dir ( vml, NULL );
539 vml->autodownload = FALSE;
540 vml->last_center = NULL;
541 vml->last_xmpp = 0.0;
542 vml->last_ympp = 0.0;
544 vml->dl_right_click_menu = NULL;
545 vml->license_notice_shown = FALSE;
550 static void maps_layer_free ( VikMapsLayer *vml )
552 g_free ( vml->cache_dir );
553 vml->cache_dir = NULL;
554 if ( vml->dl_right_click_menu )
555 g_object_ref_sink ( G_OBJECT(vml->dl_right_click_menu) );
556 g_free(vml->last_center);
557 vml->last_center = NULL;
560 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
562 if (from_file != TRUE)
564 /* If this method is not called in file reading context
565 * it is called in GUI context.
566 * So, we can check if we have to inform the user about inconsistency */
567 VikViewportDrawMode vp_drawmode;
568 VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
569 VikMapSource *map = NULL;
571 vp_drawmode = vik_viewport_get_drawmode ( vp );
572 map = MAPS_LAYER_NTH_TYPE(vml->maptype);
573 if (vik_map_source_get_drawmode(map) != vp_drawmode) {
574 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vp, vik_map_source_get_drawmode(map));
575 gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
576 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_WIDGET(vp), msg );
580 if (vik_map_source_get_license (map) != NULL) {
581 if ( ! vml->license_notice_shown ) {
582 a_dialog_license (VIK_GTK_WINDOW_FROM_WIDGET(vp), vik_map_source_get_label (map),
583 vik_map_source_get_license (map), vik_map_source_get_license_url (map) );
584 vml->license_notice_shown = TRUE;
590 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml )
592 return vik_maps_layer_get_map_label ( vml );
595 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
597 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
600 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
602 VikMapsLayer *rv = maps_layer_new ( vvp );
603 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
607 /*********************/
608 /****** DRAWING ******/
609 /*********************/
611 static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
614 gint width, height, iii, jjj;
616 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
618 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
619 g_object_unref(G_OBJECT(pixbuf));
623 pixels = gdk_pixbuf_get_pixels(pixbuf);
624 width = gdk_pixbuf_get_width(pixbuf);
625 height = gdk_pixbuf_get_height(pixbuf);
627 /* r,g,b,a,r,g,b,a.... */
628 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
636 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
639 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
640 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_NEAREST);
641 g_object_unref ( G_OBJECT(pixbuf) );
645 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
650 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
651 mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
654 if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
655 g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS,
656 vml->cache_dir, (17 - mapcoord->scale), mapcoord->x, mapcoord->y, ".png" );
658 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
659 vml->cache_dir, mode,
660 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
662 if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
665 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
667 /* free the pixbuf on error */
670 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
671 g_warning ( _("Couldn't open image file: %s"), gx->message );
675 g_object_unref ( G_OBJECT(pixbuf) );
678 if ( vml->alpha < 255 )
679 pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
680 if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
681 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
683 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
684 mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
685 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
692 gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
694 const VikCoord *center = vik_viewport_get_center ( vvp );
696 if (vik_window_get_pan_move (VIK_WINDOW(VIK_GTK_WINDOW_FROM_WIDGET(GTK_WIDGET(vvp)))))
697 /* D'n'D pan in action: do not download */
700 if (vml->last_center == NULL) {
701 VikCoord *new_center = g_malloc(sizeof(VikCoord));
702 *new_center = *center;
703 vml->last_center = new_center;
704 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
705 vml->last_ympp = vik_viewport_get_ympp(vvp);
709 /* TODO: perhaps vik_coord_diff() */
710 if (vik_coord_equals(vml->last_center, center)
711 && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
712 && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
715 *(vml->last_center) = *center;
716 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
717 vml->last_ympp = vik_viewport_get_ympp(vvp);
721 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
724 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
725 gdouble yzoom = vik_viewport_get_ympp ( vvp );
726 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
727 gboolean existence_only = FALSE;
729 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
730 xshrinkfactor = vml->xmapzoom / xzoom;
731 yshrinkfactor = vml->ymapzoom / yzoom;
732 xzoom = vml->xmapzoom;
733 yzoom = vml->xmapzoom;
734 if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
735 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
736 if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR )
737 existence_only = TRUE;
739 g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
746 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
747 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
748 vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
752 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
753 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
754 gint mode = vik_map_source_get_uniq_id(map);
757 gint xx, yy, width, height;
760 guint max_path_len = strlen(vml->cache_dir) + 40;
761 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
763 if ( (!existence_only) && vml->autodownload && should_start_autodownload(vml, vvp)) {
764 g_debug("%s: Starting autodownload", __FUNCTION__);
765 if ( vik_map_source_supports_download_only_new (map) )
766 // Try to download newer tiles
767 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NEW );
769 // Download only missing tiles
770 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
773 if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
774 for ( x = xmin; x <= xmax; x++ ) {
775 for ( y = ymin; y <= ymax; y++ ) {
778 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
780 width = gdk_pixbuf_get_width ( pixbuf );
781 height = gdk_pixbuf_get_height ( pixbuf );
783 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
784 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
788 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
792 } else { /* tilesize is known, don't have to keep converting coords */
793 gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
794 gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
795 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
796 gint tilesize_x_ceil = ceil ( tilesize_x );
797 gint tilesize_y_ceil = ceil ( tilesize_y );
798 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
799 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
800 gdouble xx, yy; gint xx_tmp, yy_tmp;
801 gint base_yy, xend, yend;
803 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
804 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
806 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
807 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
808 xx = xx_tmp; yy = yy_tmp;
809 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
810 * eg if tile size 128, shrinkfactor 0.333 */
811 xx -= (tilesize_x/2);
812 base_yy = yy - (tilesize_y/2);
814 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
816 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
820 if ( existence_only ) {
821 if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
822 g_snprintf ( path_buf, max_path_len, DIRECTDIRACCESS,
823 vml->cache_dir, (17 - ulm.scale), ulm.x, ulm.y, ".png" );
825 g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE,
826 vml->cache_dir, mode,
827 ulm.scale, ulm.z, ulm.x, ulm.y );
828 if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
829 GdkGC *black_gc = GTK_WIDGET(vvp)->style->black_gc;
830 vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
834 for (scale_inc = 0; scale_inc < 4; scale_inc ++) {
835 /* try with correct then smaller zooms */
836 int scale_factor = 1 << scale_inc; /* 2^scale_inc */
838 ulm2.x = ulm.x / scale_factor;
839 ulm2.y = ulm.y / scale_factor;
840 ulm2.scale = ulm.scale + scale_inc;
841 pixbuf = get_pixbuf ( vml, mode, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
843 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
844 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
846 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);
848 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
853 /* retry with bigger zooms */
855 for (scale_dec = 1; scale_dec < 2; scale_dec ++) {
857 int scale_factor = 1 << scale_dec; /* 2^scale_dec */
859 ulm2.x = ulm.x * scale_factor;
860 ulm2.y = ulm.y * scale_factor;
861 ulm2.scale = ulm.scale - scale_dec;
862 for (pict_x = 0; pict_x < scale_factor; pict_x ++) {
863 for (pict_y = 0; pict_y < scale_factor; pict_y ++) {
864 MapCoord ulm3 = ulm2;
867 pixbuf = get_pixbuf ( vml, mode, &ulm3, path_buf, max_path_len, xshrinkfactor / scale_factor, yshrinkfactor / scale_factor );
871 gint dest_x = xx + pict_x * (tilesize_x_ceil / scale_factor);
872 gint dest_y = yy + pict_y * (tilesize_y_ceil / scale_factor);
873 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, dest_x, dest_y, tilesize_x_ceil / scale_factor, tilesize_y_ceil / scale_factor );
891 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
893 if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
898 gdouble level = vik_viewport_get_zoom ( vvp );
900 vik_viewport_get_min_max_lat_lon ( vvp, &bbox.south, &bbox.north, &bbox.west, &bbox.east );
901 vik_map_source_get_copyright ( MAPS_LAYER_NTH_TYPE(vml->maptype), bbox, level, vik_viewport_add_copyright, vvp );
904 const GdkPixbuf *logo = vik_map_source_get_logo ( MAPS_LAYER_NTH_TYPE(vml->maptype) );
905 vik_viewport_add_logo ( vvp, logo );
907 /* get corner coords */
908 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
909 /* UTM multi-zone stuff by Kit Transue */
910 gchar leftmost_zone, rightmost_zone, i;
911 leftmost_zone = vik_viewport_leftmost_zone( vvp );
912 rightmost_zone = vik_viewport_rightmost_zone( vvp );
913 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
914 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
915 maps_layer_draw_section ( vml, vvp, &ul, &br );
919 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
920 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
922 maps_layer_draw_section ( vml, vvp, &ul, &br );
927 /*************************/
928 /****** DOWNLOADING ******/
929 /*************************/
931 /* pass along data to thread, exists even if layer is deleted. */
941 gboolean refresh_display;
944 gboolean map_layer_alive;
948 static void mdi_free ( MapDownloadInfo *mdi )
950 g_mutex_free(mdi->mutex);
951 g_free ( mdi->cache_dir );
952 mdi->cache_dir = NULL;
953 g_free ( mdi->filename_buf );
954 mdi->filename_buf = NULL;
958 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
960 MapDownloadInfo *mdi = ptr;
961 g_mutex_lock(mdi->mutex);
962 mdi->map_layer_alive = FALSE;
963 g_mutex_unlock(mdi->mutex);
966 static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
968 void *handle = vik_map_source_download_handle_init(MAPS_LAYER_NTH_TYPE(mdi->maptype));
971 for ( x = mdi->x0; x <= mdi->xf; x++ )
973 for ( y = mdi->y0; y <= mdi->yf; y++ )
975 gboolean remove_mem_cache = FALSE;
976 gboolean need_download = FALSE;
977 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
978 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
979 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
982 int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
984 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
988 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
989 need_download = TRUE;
990 remove_mem_cache = TRUE;
992 } else { /* in case map file already exists */
993 switch (mdi->redownload) {
994 case REDOWNLOAD_NONE:
999 /* see if this one is bad or what */
1001 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
1002 if (gx || (!pixbuf)) {
1003 g_remove ( mdi->filename_buf );
1004 need_download = TRUE;
1005 remove_mem_cache = TRUE;
1006 g_error_free ( gx );
1009 g_object_unref ( pixbuf );
1014 case REDOWNLOAD_NEW:
1015 need_download = TRUE;
1016 remove_mem_cache = TRUE;
1019 case REDOWNLOAD_ALL:
1020 /* FIXME: need a better way than to erase file in case of server/network problem */
1021 g_remove ( mdi->filename_buf );
1022 need_download = TRUE;
1023 remove_mem_cache = TRUE;
1026 case DOWNLOAD_OR_REFRESH:
1027 remove_mem_cache = TRUE;
1031 g_warning ( "redownload state %d unknown\n", mdi->redownload);
1035 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
1037 if (need_download) {
1038 if ( vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf, handle))
1042 g_mutex_lock(mdi->mutex);
1043 if (remove_mem_cache)
1044 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 );
1045 if (mdi->refresh_display && mdi->map_layer_alive) {
1046 /* TODO: check if it's on visible area */
1047 vik_layer_emit_update ( VIK_LAYER(mdi->vml) ); // NB update display from background
1049 g_mutex_unlock(mdi->mutex);
1050 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
1054 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1055 g_mutex_lock(mdi->mutex);
1056 if (mdi->map_layer_alive)
1057 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1058 g_mutex_unlock(mdi->mutex);
1062 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
1064 if ( mdi->mapcoord.x || mdi->mapcoord.y )
1066 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1067 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1068 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
1069 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
1071 g_remove ( mdi->filename_buf );
1076 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
1078 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1079 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1081 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1083 // Don't ever attempt download on direct access
1084 if ( vik_map_source_is_direct_file_access ( map ) )
1087 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm )
1088 && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
1090 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
1095 mdi->map_layer_alive = TRUE;
1096 mdi->mutex = g_mutex_new();
1097 mdi->refresh_display = TRUE;
1099 /* cache_dir and buffer for dest filename */
1100 mdi->cache_dir = g_strdup ( vml->cache_dir );
1101 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1102 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1103 mdi->maptype = vml->maptype;
1105 mdi->mapcoord = ulm;
1107 mdi->redownload = redownload;
1109 mdi->x0 = MIN(ulm.x, brm.x);
1110 mdi->xf = MAX(ulm.x, brm.x);
1111 mdi->y0 = MIN(ulm.y, brm.y);
1112 mdi->yf = MAX(ulm.y, brm.y);
1116 if ( mdi->redownload ) {
1117 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1119 /* calculate how many we need */
1120 for ( a = mdi->x0; a <= mdi->xf; a++ )
1122 for ( b = mdi->y0; b <= mdi->yf; b++ )
1124 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1125 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1127 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1133 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1135 if ( mdi->mapstoget )
1137 const gchar *tmp_str;
1142 if (redownload == REDOWNLOAD_BAD)
1143 tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
1145 tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
1149 tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
1151 tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
1153 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1154 /* launch the thread */
1155 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1156 tmp, /* description string */
1157 (vik_thr_func) map_download_thread, /* function to call within thread */
1158 mdi, /* pass along data */
1159 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1160 (vik_thr_free_func) mdi_cancel_cleanup,
1169 void maps_layer_download_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
1172 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1174 // Don't ever attempt download on direct access
1175 if ( vik_map_source_is_direct_file_access ( map ) )
1178 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
1179 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
1180 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
1184 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1189 mdi->map_layer_alive = TRUE;
1190 mdi->mutex = g_mutex_new();
1191 mdi->refresh_display = TRUE;
1193 mdi->cache_dir = g_strdup ( vml->cache_dir );
1194 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1195 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1196 mdi->maptype = vml->maptype;
1198 mdi->mapcoord = ulm;
1200 mdi->redownload = REDOWNLOAD_NONE;
1202 mdi->x0 = MIN(ulm.x, brm.x);
1203 mdi->xf = MAX(ulm.x, brm.x);
1204 mdi->y0 = MIN(ulm.y, brm.y);
1205 mdi->yf = MAX(ulm.y, brm.y);
1209 for (i = mdi->x0; i <= mdi->xf; i++) {
1210 for (j = mdi->y0; j <= mdi->yf; j++) {
1211 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1212 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1214 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1219 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1221 if (mdi->mapstoget) {
1224 fmt = ngettext("Downloading %d %s map...",
1225 "Downloading %d %s maps...",
1227 tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
1229 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1230 /* launch the thread */
1231 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1232 tmp, /* description string */
1233 (vik_thr_func) map_download_thread, /* function to call within thread */
1234 mdi, /* pass along data */
1235 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1236 (vik_thr_free_func) mdi_cancel_cleanup,
1244 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1246 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1249 static void maps_layer_redownload_all ( VikMapsLayer *vml )
1251 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1254 static void maps_layer_redownload_new ( VikMapsLayer *vml )
1256 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
1259 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1261 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1263 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1265 if ( event->button == 1 )
1268 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 );
1269 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 );
1270 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
1271 vml->dl_tool_x = vml->dl_tool_y = -1;
1276 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) );
1277 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) );
1279 vml->redownload_vvp = vvp;
1281 vml->dl_tool_x = vml->dl_tool_y = -1;
1283 if ( ! vml->dl_right_click_menu ) {
1285 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1287 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _Bad Map(s)") );
1288 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1289 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1291 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _New Map(s)") );
1292 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), vml );
1293 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1295 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _All Map(s)") );
1296 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1297 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1300 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1301 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1307 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1312 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1315 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1317 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1318 if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
1319 vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
1320 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1321 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1323 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1330 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1334 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1335 if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1336 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1337 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1339 gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1340 vml->cache_dir, __map_types[vml->maptype].uniq_id,
1341 mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1343 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1344 g_free ( filename_buf );
1345 vik_layer_emit_update ( VIK_LAYER(vml) );
1353 static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
1355 VikMapsLayer *vml = vml_vvp[0];
1356 VikViewport *vvp = vml_vvp[1];
1357 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
1359 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1360 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1365 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1366 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1368 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1369 if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
1370 vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
1371 vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
1372 start_download_thread ( vml, vvp, &ul, &br, redownload );
1373 else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
1374 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
1375 gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
1376 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1380 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
1384 static void maps_layer_download_missing_onscreen_maps ( gpointer vml_vvp[2] )
1386 download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1389 static void maps_layer_download_new_onscreen_maps ( gpointer vml_vvp[2] )
1391 download_onscreen_maps( vml_vvp, REDOWNLOAD_NEW);
1394 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1396 download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1399 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1401 static gpointer pass_along[2];
1403 pass_along[0] = vml;
1404 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1406 item = gtk_menu_item_new();
1407 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1408 gtk_widget_show ( item );
1410 /* Now with icons */
1411 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _Missing Onscreen Maps") );
1412 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
1413 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), pass_along );
1414 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1415 gtk_widget_show ( item );
1417 if ( vik_map_source_supports_download_only_new (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
1418 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _New Onscreen Maps") );
1419 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REDO, GTK_ICON_SIZE_MENU) );
1420 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), pass_along );
1421 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1422 gtk_widget_show ( item );
1425 item = gtk_image_menu_item_new_with_mnemonic ( _("Reload _All Onscreen Maps") );
1426 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
1427 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1428 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1429 gtk_widget_show ( item );
1433 * Enable downloading maps of the current screen area either 'new' or 'everything'
1435 void vik_maps_layer_download ( VikMapsLayer *vml, VikViewport *vvp, gboolean only_new )
1440 static gpointer pass_along[2];
1441 pass_along[0] = vml;
1442 pass_along[1] = vvp;
1445 // Get only new maps
1446 maps_layer_download_new_onscreen_maps ( pass_along );
1448 // Redownload everything
1449 maps_layer_redownload_all_onscreen_maps ( pass_along );