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 { 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,
172 (VikLayerFuncLayerSelected) NULL,
174 (VikLayerFuncMarshall) maps_layer_marshall,
175 (VikLayerFuncUnmarshall) maps_layer_unmarshall,
177 (VikLayerFuncSetParam) maps_layer_set_param,
178 (VikLayerFuncGetParam) maps_layer_get_param,
180 (VikLayerFuncReadFileData) NULL,
181 (VikLayerFuncWriteFileData) NULL,
183 (VikLayerFuncDeleteItem) NULL,
184 (VikLayerFuncCutItem) NULL,
185 (VikLayerFuncCopyItem) NULL,
186 (VikLayerFuncPasteItem) NULL,
187 (VikLayerFuncFreeCopiedItem) NULL,
188 (VikLayerFuncDragDropRequest) NULL,
190 (VikLayerFuncSelectClick) NULL,
191 (VikLayerFuncSelectMove) NULL,
192 (VikLayerFuncSelectRelease) NULL,
193 (VikLayerFuncSelectedViewportMenu) NULL,
196 struct _VikMapsLayer {
202 gdouble xmapzoom, ymapzoom;
204 gboolean autodownload;
205 VikCoord *last_center;
209 gint dl_tool_x, dl_tool_y;
211 GtkMenu *dl_right_click_menu;
212 VikCoord redownload_ul, redownload_br; /* right click menu only */
213 VikViewport *redownload_vvp;
215 gboolean license_notice_shown; // FALSE for new maps only, otherwise
216 // TRUE for saved maps & other layer changes as we don't need to show it again
219 enum { REDOWNLOAD_NONE = 0, /* download only missing maps */
220 REDOWNLOAD_BAD, /* download missing and bad maps */
221 REDOWNLOAD_NEW, /* download missing maps that are newer on server only */
222 REDOWNLOAD_ALL, /* download all maps */
223 DOWNLOAD_OR_REFRESH }; /* download missing maps and refresh cache */
225 static VikLayerParam prefs[] = {
226 { VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Default maplayer directory:"), VIK_LAYER_WIDGET_FOLDERENTRY, NULL, NULL },
229 void maps_layer_init ()
231 VikLayerParamData tmp;
232 tmp.s = maps_layer_default_dir();
233 a_preferences_register(prefs, tmp, VIKING_PREFERENCES_GROUP_KEY);
236 /****************************************/
237 /******** MAPS LAYER TYPES **************/
238 /****************************************/
240 int _get_index_for_id ( guint id )
243 while (params_maptypes_ids[index] != 0)
245 if (params_maptypes_ids[index] == id)
252 void _add_map_source ( guint id, const char *label, VikMapSource *map )
256 len = g_strv_length (params_maptypes);
258 params_maptypes = g_realloc (params_maptypes, (len+2)*sizeof(gchar*));
259 params_maptypes[len] = g_strdup (label);
260 params_maptypes[len+1] = NULL;
263 params_maptypes_ids = g_realloc (params_maptypes_ids, (len+2)*sizeof(guint));
264 params_maptypes_ids[len] = id;
265 params_maptypes_ids[len+1] = 0;
267 /* We have to clone */
268 VikMapSource *clone = VIK_MAP_SOURCE(g_object_ref(map));
269 /* Register the clone in the list */
270 __map_types = g_list_append(__map_types, clone);
273 We have to ensure the mode LayerParam references the up-to-date
277 memcpy(&maps_layer_params[0].widget_data, ¶ms_maptypes, sizeof(gpointer));
278 memcpy(&maps_layer_params[0].extra_widget_data, ¶ms_maptypes_ids, sizeof(gpointer));
280 maps_layer_params[0].widget_data = params_maptypes;
281 maps_layer_params[0].extra_widget_data = params_maptypes_ids;
284 void _update_map_source ( const char *label, VikMapSource *map, int index )
286 GList *item = g_list_nth (__map_types, index);
287 g_object_unref (item->data);
288 item->data = g_object_ref (map);
289 /* Change previous data */
290 g_free (params_maptypes[index]);
291 params_maptypes[index] = g_strdup (label);
295 * maps_layer_register_map_source:
296 * @map: the new VikMapSource
298 * Register a new VikMapSource.
299 * Override existing one (equality of id).
301 void maps_layer_register_map_source ( VikMapSource *map )
303 g_assert(map != NULL);
305 guint id = vik_map_source_get_uniq_id(map);
306 const char *label = vik_map_source_get_label(map);
307 g_assert(label != NULL);
309 int previous = map_uniq_id_to_index (id);
310 if (previous != NUM_MAP_TYPES)
312 _update_map_source (label, map, previous);
316 _add_map_source (id, label, map);
320 #define MAPS_LAYER_NTH_LABEL(n) (params_maptypes[n])
321 #define MAPS_LAYER_NTH_ID(n) (params_maptypes_ids[n])
322 #define MAPS_LAYER_NTH_TYPE(n) (VIK_MAP_SOURCE(g_list_nth_data(__map_types, (n))))
324 gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
326 return(vml->maptype);
329 gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
331 return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
334 /****************************************/
335 /******** CACHE DIR STUFF ***************/
336 /****************************************/
338 #define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
339 #define MAPS_CACHE_DIR maps_layer_default_dir()
343 #define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
344 #define LOCAL_MAPS_DIR "VIKING-MAPS"
345 #elif defined __APPLE__
347 #define GLOBAL_MAPS_DIR "/Library/cache/Viking/maps/"
348 #define LOCAL_MAPS_DIR "/Library/Application Support/Viking/viking-maps"
351 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
352 #define LOCAL_MAPS_DIR ".viking-maps"
355 gchar *maps_layer_default_dir ()
357 static gchar *defaultdir = NULL;
360 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
361 const gchar *mapdir = g_getenv("VIKING_MAPS");
363 defaultdir = g_strdup ( mapdir );
364 } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
365 defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
367 const gchar *home = g_get_home_dir();
368 if (!home || g_access(home, W_OK))
369 home = g_get_home_dir ();
371 defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
373 defaultdir = g_strdup ( LOCAL_MAPS_DIR );
375 if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
377 /* Add the separator at the end */
378 gchar *tmp = defaultdir;
379 defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
382 g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
387 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
389 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
391 g_mkdir ( vml->cache_dir, 0777 );
395 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
398 g_assert ( vml != NULL);
399 g_free ( vml->cache_dir );
400 vml->cache_dir = NULL;
402 if ( dir == NULL || dir[0] == '\0' )
404 if ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir") )
405 vml->cache_dir = g_strdup ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir")->s );
410 if ( dir[len-1] != G_DIR_SEPARATOR )
412 vml->cache_dir = g_malloc ( len+2 );
413 strncpy ( vml->cache_dir, dir, len );
414 vml->cache_dir[len] = G_DIR_SEPARATOR;
415 vml->cache_dir[len+1] = '\0';
418 vml->cache_dir = g_strdup ( dir );
420 maps_layer_mkdir_if_default_dir ( vml );
423 /****************************************/
424 /******** GOBJECT STUFF *****************/
425 /****************************************/
427 GType vik_maps_layer_get_type ()
429 static GType vml_type = 0;
433 static const GTypeInfo vml_info =
435 sizeof (VikMapsLayerClass),
436 NULL, /* base_init */
437 NULL, /* base_finalize */
438 NULL, /* class init */
439 NULL, /* class_finalize */
440 NULL, /* class_data */
441 sizeof (VikMapsLayer),
443 NULL /* instance init */
445 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
451 /****************************************/
452 /************** PARAMETERS **************/
453 /****************************************/
455 static guint map_index_to_uniq_id (guint8 index)
457 g_assert ( index < NUM_MAP_TYPES );
458 return vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(index));
461 static guint map_uniq_id_to_index ( guint uniq_id )
464 for ( i = 0; i < NUM_MAP_TYPES; i++ )
465 if ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(i)) == uniq_id )
467 return NUM_MAP_TYPES; /* no such thing */
470 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation )
472 // When loading from a file don't need the license reminder
473 if ( is_file_operation )
474 vml->license_notice_shown = TRUE;
478 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
479 case PARAM_MAPTYPE: {
480 gint maptype = map_uniq_id_to_index(data.u);
481 if ( maptype == NUM_MAP_TYPES ) g_warning(_("Unknown map type"));
482 else vml->maptype = maptype;
485 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
486 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
487 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
488 vml->mapzoom_id = data.u;
489 vml->xmapzoom = __mapzooms_x [data.u];
490 vml->ymapzoom = __mapzooms_y [data.u];
491 }else g_warning (_("Unknown Map Zoom")); break;
496 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation )
498 VikLayerParamData rv;
501 case PARAM_CACHE_DIR: rv.s = vml->cache_dir ? vml->cache_dir : ""; break;
502 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
503 case PARAM_ALPHA: rv.u = vml->alpha; break;
504 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
505 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
510 /****************************************/
511 /****** CREATING, COPYING, FREEING ******/
512 /****************************************/
514 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
517 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
518 vik_layer_init ( VIK_LAYER(vml), VIK_LAYER_MAPS );
519 idx = map_uniq_id_to_index(19); /* 19 is id for OSM MapQuest maps */
520 vml->maptype = (idx < NUM_MAP_TYPES) ? idx : 0;
523 vml->dl_tool_x = vml->dl_tool_y = -1;
524 maps_layer_set_cache_dir ( vml, NULL );
525 vml->autodownload = FALSE;
526 vml->last_center = NULL;
527 vml->last_xmpp = 0.0;
528 vml->last_ympp = 0.0;
530 vml->dl_right_click_menu = NULL;
531 vml->license_notice_shown = FALSE;
536 static void maps_layer_free ( VikMapsLayer *vml )
538 g_free ( vml->cache_dir );
539 vml->cache_dir = NULL;
540 if ( vml->dl_right_click_menu )
541 g_object_ref_sink ( G_OBJECT(vml->dl_right_click_menu) );
542 g_free(vml->last_center);
543 vml->last_center = NULL;
546 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
548 if (from_file != TRUE)
550 /* If this method is not called in file reading context
551 * it is called in GUI context.
552 * So, we can check if we have to inform the user about inconsistency */
553 VikViewportDrawMode vp_drawmode;
554 VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
555 VikMapSource *map = NULL;
557 vp_drawmode = vik_viewport_get_drawmode ( vp );
558 map = MAPS_LAYER_NTH_TYPE(vml->maptype);
559 if (vik_map_source_get_drawmode(map) != vp_drawmode) {
560 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vp, vik_map_source_get_drawmode(map));
561 gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
562 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_WIDGET(vp), msg );
566 if (vik_map_source_get_license (map) != NULL) {
567 if ( ! vml->license_notice_shown ) {
568 a_dialog_license (VIK_GTK_WINDOW_FROM_WIDGET(vp), vik_map_source_get_label (map),
569 vik_map_source_get_license (map), vik_map_source_get_license_url (map) );
570 vml->license_notice_shown = TRUE;
576 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml )
578 return vik_maps_layer_get_map_label ( vml );
581 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
583 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
586 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
588 VikMapsLayer *rv = maps_layer_new ( vvp );
589 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
593 /*********************/
594 /****** DRAWING ******/
595 /*********************/
597 static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
600 gint width, height, iii, jjj;
602 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
604 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
605 g_object_unref(G_OBJECT(pixbuf));
609 pixels = gdk_pixbuf_get_pixels(pixbuf);
610 width = gdk_pixbuf_get_width(pixbuf);
611 height = gdk_pixbuf_get_height(pixbuf);
613 /* r,g,b,a,r,g,b,a.... */
614 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
622 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
625 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
626 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_NEAREST);
627 g_object_unref ( G_OBJECT(pixbuf) );
631 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
636 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
637 mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
640 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
641 vml->cache_dir, mode,
642 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
643 if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
646 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
648 /* free the pixbuf on error */
651 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
652 g_warning ( _("Couldn't open image file: %s"), gx->message );
656 g_object_unref ( G_OBJECT(pixbuf) );
659 if ( vml->alpha < 255 )
660 pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
661 if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
662 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
664 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
665 mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
666 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
673 gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
675 const VikCoord *center = vik_viewport_get_center ( vvp );
677 if (vik_window_get_pan_move (VIK_WINDOW(VIK_GTK_WINDOW_FROM_WIDGET(GTK_WIDGET(vvp)))))
678 /* D'n'D pan in action: do not download */
681 if (vml->last_center == NULL) {
682 VikCoord *new_center = g_malloc(sizeof(VikCoord));
683 *new_center = *center;
684 vml->last_center = new_center;
685 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
686 vml->last_ympp = vik_viewport_get_ympp(vvp);
690 /* TODO: perhaps vik_coord_diff() */
691 if (vik_coord_equals(vml->last_center, center)
692 && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
693 && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
696 *(vml->last_center) = *center;
697 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
698 vml->last_ympp = vik_viewport_get_ympp(vvp);
702 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
705 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
706 gdouble yzoom = vik_viewport_get_ympp ( vvp );
707 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
708 gdouble existence_only = FALSE;
710 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
711 xshrinkfactor = vml->xmapzoom / xzoom;
712 yshrinkfactor = vml->ymapzoom / yzoom;
713 xzoom = vml->xmapzoom;
714 yzoom = vml->xmapzoom;
715 if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
716 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
717 if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR )
718 existence_only = TRUE;
720 g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
727 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
728 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
729 vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
733 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
734 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
735 gint mode = vik_map_source_get_uniq_id(map);
738 gint xx, yy, width, height;
741 guint max_path_len = strlen(vml->cache_dir) + 40;
742 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
744 if ( (!existence_only) && vml->autodownload && should_start_autodownload(vml, vvp)) {
745 g_debug("%s: Starting autodownload", __FUNCTION__);
746 if ( vik_map_source_supports_download_only_new (map) )
747 // Try to download newer tiles
748 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NEW );
750 // Download only missing tiles
751 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
754 if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
755 for ( x = xmin; x <= xmax; x++ ) {
756 for ( y = ymin; y <= ymax; y++ ) {
759 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
761 width = gdk_pixbuf_get_width ( pixbuf );
762 height = gdk_pixbuf_get_height ( pixbuf );
764 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
765 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
769 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
773 } else { /* tilesize is known, don't have to keep converting coords */
774 gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
775 gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
776 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
777 gint tilesize_x_ceil = ceil ( tilesize_x );
778 gint tilesize_y_ceil = ceil ( tilesize_y );
779 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
780 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
781 gdouble xx, yy; gint xx_tmp, yy_tmp;
782 gint base_yy, xend, yend;
784 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
785 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
787 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
788 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
789 xx = xx_tmp; yy = yy_tmp;
790 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
791 * eg if tile size 128, shrinkfactor 0.333 */
792 xx -= (tilesize_x/2);
793 base_yy = yy - (tilesize_y/2);
795 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
797 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
801 if ( existence_only ) {
802 g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE,
803 vml->cache_dir, mode,
804 ulm.scale, ulm.z, ulm.x, ulm.y );
805 if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
806 GdkGC *black_gc = GTK_WIDGET(vvp)->style->black_gc;
807 vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
811 for (scale_inc = 0; scale_inc < 4; scale_inc ++) {
812 /* try with correct then smaller zooms */
813 int scale_factor = 1 << scale_inc; /* 2^scale_inc */
815 ulm2.x = ulm.x / scale_factor;
816 ulm2.y = ulm.y / scale_factor;
817 ulm2.scale = ulm.scale + scale_inc;
818 pixbuf = get_pixbuf ( vml, mode, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
820 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
821 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
823 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);
825 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
830 /* retry with bigger zooms */
832 for (scale_dec = 1; scale_dec < 2; scale_dec ++) {
834 int scale_factor = 1 << scale_dec; /* 2^scale_dec */
836 ulm2.x = ulm.x * scale_factor;
837 ulm2.y = ulm.y * scale_factor;
838 ulm2.scale = ulm.scale - scale_dec;
839 for (pict_x = 0; pict_x < scale_factor; pict_x ++) {
840 for (pict_y = 0; pict_y < scale_factor; pict_y ++) {
841 MapCoord ulm3 = ulm2;
844 pixbuf = get_pixbuf ( vml, mode, &ulm3, path_buf, max_path_len, xshrinkfactor / scale_factor, yshrinkfactor / scale_factor );
848 gint dest_x = xx + pict_x * (tilesize_x_ceil / scale_factor);
849 gint dest_y = yy + pict_y * (tilesize_y_ceil / scale_factor);
850 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, dest_x, dest_y, tilesize_x_ceil / scale_factor, tilesize_y_ceil / scale_factor );
868 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
870 if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
875 gdouble level = vik_viewport_get_zoom ( vvp );
877 vik_viewport_get_min_max_lat_lon ( vvp, &bbox.south, &bbox.north, &bbox.west, &bbox.east );
878 vik_map_source_get_copyright ( MAPS_LAYER_NTH_TYPE(vml->maptype), bbox, level, vik_viewport_add_copyright, vvp );
881 const GdkPixbuf *logo = vik_map_source_get_logo ( MAPS_LAYER_NTH_TYPE(vml->maptype) );
882 vik_viewport_add_logo ( vvp, logo );
884 /* get corner coords */
885 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
886 /* UTM multi-zone stuff by Kit Transue */
887 gchar leftmost_zone, rightmost_zone, i;
888 leftmost_zone = vik_viewport_leftmost_zone( vvp );
889 rightmost_zone = vik_viewport_rightmost_zone( vvp );
890 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
891 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
892 maps_layer_draw_section ( vml, vvp, &ul, &br );
896 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
897 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
899 maps_layer_draw_section ( vml, vvp, &ul, &br );
904 /*************************/
905 /****** DOWNLOADING ******/
906 /*************************/
908 /* pass along data to thread, exists even if layer is deleted. */
918 gboolean refresh_display;
921 gboolean map_layer_alive;
925 static void mdi_free ( MapDownloadInfo *mdi )
927 g_mutex_free(mdi->mutex);
928 g_free ( mdi->cache_dir );
929 mdi->cache_dir = NULL;
930 g_free ( mdi->filename_buf );
931 mdi->filename_buf = NULL;
935 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
937 MapDownloadInfo *mdi = ptr;
938 g_mutex_lock(mdi->mutex);
939 mdi->map_layer_alive = FALSE;
940 g_mutex_unlock(mdi->mutex);
943 static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
945 void *handle = vik_map_source_download_handle_init(MAPS_LAYER_NTH_TYPE(mdi->maptype));
948 for ( x = mdi->x0; x <= mdi->xf; x++ )
950 for ( y = mdi->y0; y <= mdi->yf; y++ )
952 gboolean remove_mem_cache = FALSE;
953 gboolean need_download = FALSE;
954 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
955 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
956 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
959 int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
961 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
965 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
966 need_download = TRUE;
967 remove_mem_cache = TRUE;
969 } else { /* in case map file already exists */
970 switch (mdi->redownload) {
971 case REDOWNLOAD_NONE:
976 /* see if this one is bad or what */
978 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
979 if (gx || (!pixbuf)) {
980 g_remove ( mdi->filename_buf );
981 need_download = TRUE;
982 remove_mem_cache = TRUE;
986 g_object_unref ( pixbuf );
992 need_download = TRUE;
993 remove_mem_cache = TRUE;
997 /* FIXME: need a better way than to erase file in case of server/network problem */
998 g_remove ( mdi->filename_buf );
999 need_download = TRUE;
1000 remove_mem_cache = TRUE;
1003 case DOWNLOAD_OR_REFRESH:
1004 remove_mem_cache = TRUE;
1008 g_warning ( "redownload state %d unknown\n", mdi->redownload);
1012 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
1014 if (need_download) {
1015 if ( vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf, handle))
1019 g_mutex_lock(mdi->mutex);
1020 if (remove_mem_cache)
1021 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 );
1022 if (mdi->refresh_display && mdi->map_layer_alive) {
1023 /* TODO: check if it's on visible area */
1024 vik_layer_emit_update ( VIK_LAYER(mdi->vml), TRUE ); // Yes update display from background
1026 g_mutex_unlock(mdi->mutex);
1027 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
1031 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1032 g_mutex_lock(mdi->mutex);
1033 if (mdi->map_layer_alive)
1034 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1035 g_mutex_unlock(mdi->mutex);
1039 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
1041 if ( mdi->mapcoord.x || mdi->mapcoord.y )
1043 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1044 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1045 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
1046 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
1048 g_remove ( mdi->filename_buf );
1053 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
1055 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1056 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1058 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1059 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm )
1060 && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
1062 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
1067 mdi->map_layer_alive = TRUE;
1068 mdi->mutex = g_mutex_new();
1069 mdi->refresh_display = TRUE;
1071 /* cache_dir and buffer for dest filename */
1072 mdi->cache_dir = g_strdup ( vml->cache_dir );
1073 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1074 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1075 mdi->maptype = vml->maptype;
1077 mdi->mapcoord = ulm;
1079 mdi->redownload = redownload;
1081 mdi->x0 = MIN(ulm.x, brm.x);
1082 mdi->xf = MAX(ulm.x, brm.x);
1083 mdi->y0 = MIN(ulm.y, brm.y);
1084 mdi->yf = MAX(ulm.y, brm.y);
1088 if ( mdi->redownload ) {
1089 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1091 /* calculate how many we need */
1092 for ( a = mdi->x0; a <= mdi->xf; a++ )
1094 for ( b = mdi->y0; b <= mdi->yf; b++ )
1096 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1097 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1099 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1105 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1107 if ( mdi->mapstoget )
1109 const gchar *tmp_str;
1114 if (redownload == REDOWNLOAD_BAD)
1115 tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
1117 tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
1121 tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
1123 tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
1125 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1126 /* launch the thread */
1127 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1128 tmp, /* description string */
1129 (vik_thr_func) map_download_thread, /* function to call within thread */
1130 mdi, /* pass along data */
1131 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1132 (vik_thr_free_func) mdi_cancel_cleanup,
1141 void maps_layer_download_section_without_redraw( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
1144 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1146 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
1147 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
1148 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
1152 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1157 mdi->map_layer_alive = TRUE;
1158 mdi->mutex = g_mutex_new();
1159 mdi->refresh_display = FALSE;
1161 mdi->cache_dir = g_strdup ( vml->cache_dir );
1162 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1163 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1164 mdi->maptype = vml->maptype;
1166 mdi->mapcoord = ulm;
1168 mdi->redownload = REDOWNLOAD_NONE;
1170 mdi->x0 = MIN(ulm.x, brm.x);
1171 mdi->xf = MAX(ulm.x, brm.x);
1172 mdi->y0 = MIN(ulm.y, brm.y);
1173 mdi->yf = MAX(ulm.y, brm.y);
1177 for (i = mdi->x0; i <= mdi->xf; i++) {
1178 for (j = mdi->y0; j <= mdi->yf; j++) {
1179 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1180 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1182 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1187 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1189 if (mdi->mapstoget) {
1192 fmt = ngettext("Downloading %d %s map...",
1193 "Downloading %d %s maps...",
1195 tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
1197 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1198 /* launch the thread */
1199 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1200 tmp, /* description string */
1201 (vik_thr_func) map_download_thread, /* function to call within thread */
1202 mdi, /* pass along data */
1203 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1204 (vik_thr_free_func) mdi_cancel_cleanup,
1212 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1214 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1217 static void maps_layer_redownload_all ( VikMapsLayer *vml )
1219 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1222 static void maps_layer_redownload_new ( VikMapsLayer *vml )
1224 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
1227 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1229 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1231 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1233 if ( event->button == 1 )
1236 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 );
1237 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 );
1238 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
1239 vml->dl_tool_x = vml->dl_tool_y = -1;
1244 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) );
1245 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) );
1247 vml->redownload_vvp = vvp;
1249 vml->dl_tool_x = vml->dl_tool_y = -1;
1251 if ( ! vml->dl_right_click_menu ) {
1253 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1255 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _Bad Map(s)") );
1256 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1257 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1259 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _New Map(s)") );
1260 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), vml );
1261 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1263 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _All Map(s)") );
1264 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1265 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1268 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1269 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1275 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1280 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1283 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1285 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1286 if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
1287 vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
1288 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1289 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1291 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1298 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1302 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1303 if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1304 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1305 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1307 gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1308 vml->cache_dir, __map_types[vml->maptype].uniq_id,
1309 mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1311 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1312 g_free ( filename_buf );
1313 vik_layer_emit_update ( VIK_LAYER(vml) );
1321 static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
1323 VikMapsLayer *vml = vml_vvp[0];
1324 VikViewport *vvp = vml_vvp[1];
1325 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
1327 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1328 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1333 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1334 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1336 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1337 if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
1338 vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
1339 vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
1340 start_download_thread ( vml, vvp, &ul, &br, redownload );
1341 else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
1342 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
1343 gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
1344 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1348 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
1352 static void maps_layer_download_missing_onscreen_maps ( gpointer vml_vvp[2] )
1354 download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1357 static void maps_layer_download_new_onscreen_maps ( gpointer vml_vvp[2] )
1359 download_onscreen_maps( vml_vvp, REDOWNLOAD_NEW);
1362 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1364 download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1367 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1369 static gpointer pass_along[2];
1371 pass_along[0] = vml;
1372 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1374 item = gtk_menu_item_new();
1375 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1376 gtk_widget_show ( item );
1378 /* Now with icons */
1379 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _Missing Onscreen Maps") );
1380 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
1381 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), pass_along );
1382 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1383 gtk_widget_show ( item );
1385 if ( vik_map_source_supports_download_only_new (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
1386 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _New Onscreen Maps") );
1387 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REDO, GTK_ICON_SIZE_MENU) );
1388 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), pass_along );
1389 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1390 gtk_widget_show ( item );
1393 item = gtk_image_menu_item_new_with_mnemonic ( _("Reload _All Onscreen Maps") );
1394 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
1395 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1396 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1397 gtk_widget_show ( item );