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);
294 void maps_layer_register_map_source ( VikMapSource *map )
296 g_assert(map != NULL);
298 guint id = vik_map_source_get_uniq_id(map);
299 const char *label = vik_map_source_get_label(map);
300 g_assert(label != NULL);
302 int previous = map_uniq_id_to_index (id);
303 if (previous != NUM_MAP_TYPES)
305 _update_map_source (label, map, previous);
309 _add_map_source (id, label, map);
313 #define MAPS_LAYER_NTH_LABEL(n) (params_maptypes[n])
314 #define MAPS_LAYER_NTH_ID(n) (params_maptypes_ids[n])
315 #define MAPS_LAYER_NTH_TYPE(n) (VIK_MAP_SOURCE(g_list_nth_data(__map_types, (n))))
317 gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
319 return(vml->maptype);
322 gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
324 return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
327 /****************************************/
328 /******** CACHE DIR STUFF ***************/
329 /****************************************/
331 #define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
332 #define MAPS_CACHE_DIR maps_layer_default_dir()
336 #define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
337 #define LOCAL_MAPS_DIR "VIKING-MAPS"
338 #elif defined __APPLE__
340 #define GLOBAL_MAPS_DIR "/Library/cache/Viking/maps/"
341 #define LOCAL_MAPS_DIR "/Library/Application Support/Viking/viking-maps"
344 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
345 #define LOCAL_MAPS_DIR ".viking-maps"
348 gchar *maps_layer_default_dir ()
350 static gchar *defaultdir = NULL;
353 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
354 const gchar *mapdir = g_getenv("VIKING_MAPS");
356 defaultdir = g_strdup ( mapdir );
357 } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
358 defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
360 const gchar *home = g_get_home_dir();
361 if (!home || g_access(home, W_OK))
362 home = g_get_home_dir ();
364 defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
366 defaultdir = g_strdup ( LOCAL_MAPS_DIR );
368 if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
370 /* Add the separator at the end */
371 gchar *tmp = defaultdir;
372 defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
375 g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
380 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
382 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
384 g_mkdir ( vml->cache_dir, 0777 );
388 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
391 g_assert ( vml != NULL);
392 g_free ( vml->cache_dir );
393 vml->cache_dir = NULL;
395 if ( dir == NULL || dir[0] == '\0' )
397 if ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir") )
398 vml->cache_dir = g_strdup ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir")->s );
403 if ( dir[len-1] != G_DIR_SEPARATOR )
405 vml->cache_dir = g_malloc ( len+2 );
406 strncpy ( vml->cache_dir, dir, len );
407 vml->cache_dir[len] = G_DIR_SEPARATOR;
408 vml->cache_dir[len+1] = '\0';
411 vml->cache_dir = g_strdup ( dir );
413 maps_layer_mkdir_if_default_dir ( vml );
416 /****************************************/
417 /******** GOBJECT STUFF *****************/
418 /****************************************/
420 GType vik_maps_layer_get_type ()
422 static GType vml_type = 0;
426 static const GTypeInfo vml_info =
428 sizeof (VikMapsLayerClass),
429 NULL, /* base_init */
430 NULL, /* base_finalize */
431 NULL, /* class init */
432 NULL, /* class_finalize */
433 NULL, /* class_data */
434 sizeof (VikMapsLayer),
436 NULL /* instance init */
438 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
444 /****************************************/
445 /************** PARAMETERS **************/
446 /****************************************/
448 static guint map_index_to_uniq_id (guint8 index)
450 g_assert ( index < NUM_MAP_TYPES );
451 return vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(index));
454 static guint map_uniq_id_to_index ( guint uniq_id )
457 for ( i = 0; i < NUM_MAP_TYPES; i++ )
458 if ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(i)) == uniq_id )
460 return NUM_MAP_TYPES; /* no such thing */
463 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation )
465 // When loading from a file don't need the license reminder
466 if ( is_file_operation )
467 vml->license_notice_shown = TRUE;
471 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
472 case PARAM_MAPTYPE: {
473 gint maptype = map_uniq_id_to_index(data.u);
474 if ( maptype == NUM_MAP_TYPES ) g_warning(_("Unknown map type"));
475 else vml->maptype = maptype;
478 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
479 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
480 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
481 vml->mapzoom_id = data.u;
482 vml->xmapzoom = __mapzooms_x [data.u];
483 vml->ymapzoom = __mapzooms_y [data.u];
484 }else g_warning (_("Unknown Map Zoom")); break;
489 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation )
491 VikLayerParamData rv;
494 case PARAM_CACHE_DIR: rv.s = vml->cache_dir ? vml->cache_dir : ""; break;
495 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
496 case PARAM_ALPHA: rv.u = vml->alpha; break;
497 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
498 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
503 /****************************************/
504 /****** CREATING, COPYING, FREEING ******/
505 /****************************************/
507 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
510 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
511 vik_layer_init ( VIK_LAYER(vml), VIK_LAYER_MAPS );
512 idx = map_uniq_id_to_index(19); /* 19 is id for OSM MapQuest maps */
513 vml->maptype = (idx < NUM_MAP_TYPES) ? idx : 0;
516 vml->dl_tool_x = vml->dl_tool_y = -1;
517 maps_layer_set_cache_dir ( vml, NULL );
518 vml->autodownload = FALSE;
519 vml->last_center = NULL;
520 vml->last_xmpp = 0.0;
521 vml->last_ympp = 0.0;
523 vml->dl_right_click_menu = NULL;
524 vml->license_notice_shown = FALSE;
529 static void maps_layer_free ( VikMapsLayer *vml )
531 g_free ( vml->cache_dir );
532 vml->cache_dir = NULL;
533 if ( vml->dl_right_click_menu )
534 g_object_ref_sink ( G_OBJECT(vml->dl_right_click_menu) );
535 g_free(vml->last_center);
536 vml->last_center = NULL;
539 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
541 if (from_file != TRUE)
543 /* If this method is not called in file reading context
544 * it is called in GUI context.
545 * So, we can check if we have to inform the user about inconsistency */
546 VikViewportDrawMode vp_drawmode;
547 VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
548 VikMapSource *map = NULL;
550 vp_drawmode = vik_viewport_get_drawmode ( vp );
551 map = MAPS_LAYER_NTH_TYPE(vml->maptype);
552 if (vik_map_source_get_drawmode(map) != vp_drawmode) {
553 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vp, vik_map_source_get_drawmode(map));
554 gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
555 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_WIDGET(vp), msg );
559 if (vik_map_source_get_license (map) != NULL) {
560 if ( ! vml->license_notice_shown ) {
561 a_dialog_license (VIK_GTK_WINDOW_FROM_WIDGET(vp), vik_map_source_get_label (map),
562 vik_map_source_get_license (map), vik_map_source_get_license_url (map) );
563 vml->license_notice_shown = TRUE;
569 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml )
571 return vik_maps_layer_get_map_label ( vml );
574 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
576 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
579 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
581 VikMapsLayer *rv = maps_layer_new ( vvp );
582 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
586 /*********************/
587 /****** DRAWING ******/
588 /*********************/
590 static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
593 gint width, height, iii, jjj;
595 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
597 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
598 g_object_unref(G_OBJECT(pixbuf));
602 pixels = gdk_pixbuf_get_pixels(pixbuf);
603 width = gdk_pixbuf_get_width(pixbuf);
604 height = gdk_pixbuf_get_height(pixbuf);
606 /* r,g,b,a,r,g,b,a.... */
607 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
615 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
618 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
619 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_NEAREST);
620 g_object_unref ( G_OBJECT(pixbuf) );
624 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
629 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
630 mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
633 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
634 vml->cache_dir, mode,
635 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
636 if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
639 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
641 /* free the pixbuf on error */
644 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
645 g_warning ( _("Couldn't open image file: %s"), gx->message );
649 g_object_unref ( G_OBJECT(pixbuf) );
652 if ( vml->alpha < 255 )
653 pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
654 if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
655 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
657 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
658 mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
659 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
666 gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
668 const VikCoord *center = vik_viewport_get_center ( vvp );
670 if (vik_window_get_pan_move (VIK_WINDOW(VIK_GTK_WINDOW_FROM_WIDGET(GTK_WIDGET(vvp)))))
671 /* D'n'D pan in action: do not download */
674 if (vml->last_center == NULL) {
675 VikCoord *new_center = g_malloc(sizeof(VikCoord));
676 *new_center = *center;
677 vml->last_center = new_center;
678 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
679 vml->last_ympp = vik_viewport_get_ympp(vvp);
683 /* TODO: perhaps vik_coord_diff() */
684 if (vik_coord_equals(vml->last_center, center)
685 && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
686 && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
689 *(vml->last_center) = *center;
690 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
691 vml->last_ympp = vik_viewport_get_ympp(vvp);
695 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
698 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
699 gdouble yzoom = vik_viewport_get_ympp ( vvp );
700 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
701 gdouble existence_only = FALSE;
703 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
704 xshrinkfactor = vml->xmapzoom / xzoom;
705 yshrinkfactor = vml->ymapzoom / yzoom;
706 xzoom = vml->xmapzoom;
707 yzoom = vml->xmapzoom;
708 if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
709 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
710 if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR )
711 existence_only = TRUE;
713 g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
720 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
721 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
722 vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
726 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
727 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
728 gint mode = vik_map_source_get_uniq_id(map);
731 gint xx, yy, width, height;
734 guint max_path_len = strlen(vml->cache_dir) + 40;
735 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
737 if ( (!existence_only) && vml->autodownload && should_start_autodownload(vml, vvp)) {
738 g_debug("%s: Starting autodownload", __FUNCTION__);
739 if ( vik_map_source_supports_download_only_new (map) )
740 // Try to download newer tiles
741 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NEW );
743 // Download only missing tiles
744 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
747 if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
748 for ( x = xmin; x <= xmax; x++ ) {
749 for ( y = ymin; y <= ymax; y++ ) {
752 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
754 width = gdk_pixbuf_get_width ( pixbuf );
755 height = gdk_pixbuf_get_height ( pixbuf );
757 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
758 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
762 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
766 } else { /* tilesize is known, don't have to keep converting coords */
767 gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
768 gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
769 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
770 gint tilesize_x_ceil = ceil ( tilesize_x );
771 gint tilesize_y_ceil = ceil ( tilesize_y );
772 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
773 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
774 gdouble xx, yy; gint xx_tmp, yy_tmp;
775 gint base_yy, xend, yend;
777 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
778 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
780 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
781 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
782 xx = xx_tmp; yy = yy_tmp;
783 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
784 * eg if tile size 128, shrinkfactor 0.333 */
785 xx -= (tilesize_x/2);
786 base_yy = yy - (tilesize_y/2);
788 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
790 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
794 if ( existence_only ) {
795 g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE,
796 vml->cache_dir, mode,
797 ulm.scale, ulm.z, ulm.x, ulm.y );
798 if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
799 GdkGC *black_gc = GTK_WIDGET(vvp)->style->black_gc;
800 vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
804 for (scale_inc = 0; scale_inc < 4; scale_inc ++) {
805 /* try with correct then smaller zooms */
806 int scale_factor = 1 << scale_inc; /* 2^scale_inc */
808 ulm2.x = ulm.x / scale_factor;
809 ulm2.y = ulm.y / scale_factor;
810 ulm2.scale = ulm.scale + scale_inc;
811 pixbuf = get_pixbuf ( vml, mode, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
813 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
814 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
816 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);
818 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
823 /* retry with bigger zooms */
825 for (scale_dec = 1; scale_dec < 2; scale_dec ++) {
827 int scale_factor = 1 << scale_dec; /* 2^scale_dec */
829 ulm2.x = ulm.x * scale_factor;
830 ulm2.y = ulm.y * scale_factor;
831 ulm2.scale = ulm.scale - scale_dec;
832 for (pict_x = 0; pict_x < scale_factor; pict_x ++) {
833 for (pict_y = 0; pict_y < scale_factor; pict_y ++) {
834 MapCoord ulm3 = ulm2;
837 pixbuf = get_pixbuf ( vml, mode, &ulm3, path_buf, max_path_len, xshrinkfactor / scale_factor, yshrinkfactor / scale_factor );
841 gint dest_x = xx + pict_x * (tilesize_x_ceil / scale_factor);
842 gint dest_y = yy + pict_y * (tilesize_y_ceil / scale_factor);
843 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, dest_x, dest_y, tilesize_x_ceil / scale_factor, tilesize_y_ceil / scale_factor );
861 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
863 if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
868 gdouble level = vik_viewport_get_zoom ( vvp );
870 vik_viewport_get_min_max_lat_lon ( vvp, &bbox.south, &bbox.north, &bbox.west, &bbox.east );
871 vik_map_source_get_copyright ( MAPS_LAYER_NTH_TYPE(vml->maptype), bbox, level, vik_viewport_add_copyright, vvp );
874 const GdkPixbuf *logo = vik_map_source_get_logo ( MAPS_LAYER_NTH_TYPE(vml->maptype) );
875 vik_viewport_add_logo ( vvp, logo );
877 /* get corner coords */
878 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
879 /* UTM multi-zone stuff by Kit Transue */
880 gchar leftmost_zone, rightmost_zone, i;
881 leftmost_zone = vik_viewport_leftmost_zone( vvp );
882 rightmost_zone = vik_viewport_rightmost_zone( vvp );
883 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
884 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
885 maps_layer_draw_section ( vml, vvp, &ul, &br );
889 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
890 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
892 maps_layer_draw_section ( vml, vvp, &ul, &br );
897 /*************************/
898 /****** DOWNLOADING ******/
899 /*************************/
901 /* pass along data to thread, exists even if layer is deleted. */
911 gboolean refresh_display;
914 gboolean map_layer_alive;
918 static void mdi_free ( MapDownloadInfo *mdi )
920 g_mutex_free(mdi->mutex);
921 g_free ( mdi->cache_dir );
922 mdi->cache_dir = NULL;
923 g_free ( mdi->filename_buf );
924 mdi->filename_buf = NULL;
928 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
930 MapDownloadInfo *mdi = ptr;
931 g_mutex_lock(mdi->mutex);
932 mdi->map_layer_alive = FALSE;
933 g_mutex_unlock(mdi->mutex);
936 static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
938 void *handle = vik_map_source_download_handle_init(MAPS_LAYER_NTH_TYPE(mdi->maptype));
941 for ( x = mdi->x0; x <= mdi->xf; x++ )
943 for ( y = mdi->y0; y <= mdi->yf; y++ )
945 gboolean remove_mem_cache = FALSE;
946 gboolean need_download = FALSE;
947 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
948 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
949 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
952 int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
954 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
958 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
959 need_download = TRUE;
960 remove_mem_cache = TRUE;
962 } else { /* in case map file already exists */
963 switch (mdi->redownload) {
964 case REDOWNLOAD_NONE:
969 /* see if this one is bad or what */
971 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
972 if (gx || (!pixbuf)) {
973 g_remove ( mdi->filename_buf );
974 need_download = TRUE;
975 remove_mem_cache = TRUE;
979 g_object_unref ( pixbuf );
985 need_download = TRUE;
986 remove_mem_cache = TRUE;
990 /* FIXME: need a better way than to erase file in case of server/network problem */
991 g_remove ( mdi->filename_buf );
992 need_download = TRUE;
993 remove_mem_cache = TRUE;
996 case DOWNLOAD_OR_REFRESH:
997 remove_mem_cache = TRUE;
1001 g_warning ( "redownload state %d unknown\n", mdi->redownload);
1005 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
1007 if (need_download) {
1008 if ( vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf, handle))
1012 g_mutex_lock(mdi->mutex);
1013 if (remove_mem_cache)
1014 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 );
1015 if (mdi->refresh_display && mdi->map_layer_alive) {
1016 /* TODO: check if it's on visible area */
1017 vik_layer_emit_update ( VIK_LAYER(mdi->vml), TRUE ); // Yes update display from background
1019 g_mutex_unlock(mdi->mutex);
1020 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
1024 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1025 g_mutex_lock(mdi->mutex);
1026 if (mdi->map_layer_alive)
1027 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1028 g_mutex_unlock(mdi->mutex);
1032 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
1034 if ( mdi->mapcoord.x || mdi->mapcoord.y )
1036 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1037 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1038 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
1039 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
1041 g_remove ( mdi->filename_buf );
1046 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
1048 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1049 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1051 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1052 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm )
1053 && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
1055 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
1060 mdi->map_layer_alive = TRUE;
1061 mdi->mutex = g_mutex_new();
1062 mdi->refresh_display = TRUE;
1064 /* cache_dir and buffer for dest filename */
1065 mdi->cache_dir = g_strdup ( vml->cache_dir );
1066 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1067 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1068 mdi->maptype = vml->maptype;
1070 mdi->mapcoord = ulm;
1072 mdi->redownload = redownload;
1074 mdi->x0 = MIN(ulm.x, brm.x);
1075 mdi->xf = MAX(ulm.x, brm.x);
1076 mdi->y0 = MIN(ulm.y, brm.y);
1077 mdi->yf = MAX(ulm.y, brm.y);
1081 if ( mdi->redownload ) {
1082 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1084 /* calculate how many we need */
1085 for ( a = mdi->x0; a <= mdi->xf; a++ )
1087 for ( b = mdi->y0; b <= mdi->yf; b++ )
1089 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1090 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1092 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1098 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1100 if ( mdi->mapstoget )
1102 const gchar *tmp_str;
1107 if (redownload == REDOWNLOAD_BAD)
1108 tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
1110 tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
1114 tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
1116 tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
1118 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1119 /* launch the thread */
1120 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1121 tmp, /* description string */
1122 (vik_thr_func) map_download_thread, /* function to call within thread */
1123 mdi, /* pass along data */
1124 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1125 (vik_thr_free_func) mdi_cancel_cleanup,
1134 void maps_layer_download_section_without_redraw( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
1137 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1139 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
1140 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
1141 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
1145 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1150 mdi->map_layer_alive = TRUE;
1151 mdi->mutex = g_mutex_new();
1152 mdi->refresh_display = FALSE;
1154 mdi->cache_dir = g_strdup ( vml->cache_dir );
1155 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1156 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1157 mdi->maptype = vml->maptype;
1159 mdi->mapcoord = ulm;
1161 mdi->redownload = REDOWNLOAD_NONE;
1163 mdi->x0 = MIN(ulm.x, brm.x);
1164 mdi->xf = MAX(ulm.x, brm.x);
1165 mdi->y0 = MIN(ulm.y, brm.y);
1166 mdi->yf = MAX(ulm.y, brm.y);
1170 for (i = mdi->x0; i <= mdi->xf; i++) {
1171 for (j = mdi->y0; j <= mdi->yf; j++) {
1172 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1173 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1175 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1180 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1182 if (mdi->mapstoget) {
1185 fmt = ngettext("Downloading %d %s map...",
1186 "Downloading %d %s maps...",
1188 tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
1190 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1191 /* launch the thread */
1192 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1193 tmp, /* description string */
1194 (vik_thr_func) map_download_thread, /* function to call within thread */
1195 mdi, /* pass along data */
1196 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1197 (vik_thr_free_func) mdi_cancel_cleanup,
1205 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1207 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1210 static void maps_layer_redownload_all ( VikMapsLayer *vml )
1212 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1215 static void maps_layer_redownload_new ( VikMapsLayer *vml )
1217 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
1220 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1222 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1224 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1226 if ( event->button == 1 )
1229 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 );
1230 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 );
1231 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
1232 vml->dl_tool_x = vml->dl_tool_y = -1;
1237 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) );
1238 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) );
1240 vml->redownload_vvp = vvp;
1242 vml->dl_tool_x = vml->dl_tool_y = -1;
1244 if ( ! vml->dl_right_click_menu ) {
1246 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1248 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _Bad Map(s)") );
1249 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1250 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1252 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _New Map(s)") );
1253 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), vml );
1254 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1256 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _All Map(s)") );
1257 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1258 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1261 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1262 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1268 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1273 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1276 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1278 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1279 if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
1280 vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
1281 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1282 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1284 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1291 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1295 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1296 if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1297 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1298 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1300 gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1301 vml->cache_dir, __map_types[vml->maptype].uniq_id,
1302 mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1304 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1305 g_free ( filename_buf );
1306 vik_layer_emit_update ( VIK_LAYER(vml) );
1314 static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
1316 VikMapsLayer *vml = vml_vvp[0];
1317 VikViewport *vvp = vml_vvp[1];
1318 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
1320 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1321 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1326 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1327 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1329 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1330 if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
1331 vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
1332 vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
1333 start_download_thread ( vml, vvp, &ul, &br, redownload );
1334 else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
1335 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
1336 gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
1337 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1341 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
1345 static void maps_layer_download_missing_onscreen_maps ( gpointer vml_vvp[2] )
1347 download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1350 static void maps_layer_download_new_onscreen_maps ( gpointer vml_vvp[2] )
1352 download_onscreen_maps( vml_vvp, REDOWNLOAD_NEW);
1355 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1357 download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1360 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1362 static gpointer pass_along[2];
1364 pass_along[0] = vml;
1365 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1367 item = gtk_menu_item_new();
1368 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1369 gtk_widget_show ( item );
1371 /* Now with icons */
1372 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _Missing Onscreen Maps") );
1373 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
1374 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), pass_along );
1375 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1376 gtk_widget_show ( item );
1378 if ( vik_map_source_supports_download_only_new (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
1379 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _New Onscreen Maps") );
1380 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REDO, GTK_ICON_SIZE_MENU) );
1381 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), pass_along );
1382 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1383 gtk_widget_show ( item );
1386 item = gtk_image_menu_item_new_with_mnemonic ( _("Reload _All Onscreen Maps") );
1387 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
1388 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1389 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1390 gtk_widget_show ( item );