2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
4 * Copyright (C) 2005, Evan Battaglia <viking@greentorch.org>
5 * Copyright (C) 2010, Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
6 * UTM multi-zone stuff by Kit Transue <notlostyet@didactek.com>
7 * Dynamic map type by Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #define MAX_SHRINKFACTOR 8.0000001 /* zoom 1 viewing 8-tiles */
30 #define MIN_SHRINKFACTOR 0.0312499 /* zoom 32 viewing 1-tiles */
32 #define REAL_MIN_SHRINKFACTOR 0.0039062499 /* if shrinkfactor is between MAX and REAL_MAX, will only check for existence */
35 #include <gdk-pixbuf/gdk-pixdata.h>
37 #include <glib/gstdio.h>
38 #include <glib/gi18n.h>
51 #include "viktreeview.h"
52 #include "vikviewport.h"
54 #include "vikmapslayer.h"
61 /* only for dialog.h -- ugh */
62 #include "vikwaypoint.h"
64 #include "preferences.h"
66 #include "vikstatus.h"
67 #include "background.h"
69 #include "vikaggregatelayer.h"
70 #include "viklayerspanel.h"
73 #include "terraserver.h"
75 #include "icons/icons.h"
77 /****** MAP TYPES ******/
79 static GList *__map_types = NULL;
81 #define NUM_MAP_TYPES g_list_length(__map_types)
83 /* List of label for each map type */
84 static gchar **params_maptypes = NULL;
86 /* Corresponding IDS. (Cf. field uniq_id in VikMapsLayer struct) */
87 static guint *params_maptypes_ids = NULL;
89 /******** MAPZOOMS *********/
91 static gchar *params_mapzooms[] = { N_("Use Viking Zoom Level"), "0.25", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", "USGS 10k", "USGS 24k", "USGS 25k", "USGS 50k", "USGS 100k", "USGS 200k", "USGS 250k", NULL };
92 static gdouble __mapzooms_x[] = { 0.0, 0.25, 1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0, 512.0, 1024.0, 1.016, 2.4384, 2.54, 5.08, 10.16, 20.32, 25.4 };
93 static gdouble __mapzooms_y[] = { 0.0, 0.25, 1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0, 512.0, 1024.0, 1.016, 2.4384, 2.54, 5.08, 10.16, 20.32, 25.4 };
95 #define NUM_MAPZOOMS (sizeof(params_mapzooms)/sizeof(params_mapzooms[0]) - 1)
97 /**************************/
100 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file);
101 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml );
102 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len );
103 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
104 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation );
105 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation );
106 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp );
107 static VikMapsLayer *maps_layer_new ( VikViewport *vvp );
108 static void maps_layer_free ( VikMapsLayer *vml );
109 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
110 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
111 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp );
112 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir );
113 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload );
114 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp );
115 static guint map_uniq_id_to_index ( guint uniq_id );
118 static VikLayerParamScale params_scales[] = {
119 /* min, max, step, digits (decimal places) */
120 { 0, 255, 3, 0 }, /* alpha */
123 VikLayerParam maps_layer_params[] = {
124 { "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Map Type:"), VIK_LAYER_WIDGET_COMBOBOX, NULL, NULL },
125 { "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Maps Directory:"), VIK_LAYER_WIDGET_FOLDERENTRY },
126 { "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales },
127 { "autodownload", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload maps:"), VIK_LAYER_WIDGET_CHECKBUTTON },
128 { "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Zoom Level:"), VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms, NULL },
131 enum { PARAM_MAPTYPE=0, PARAM_CACHE_DIR, PARAM_ALPHA, PARAM_AUTODOWNLOAD, PARAM_MAPZOOM, NUM_PARAMS };
133 static VikToolInterface maps_tools[] = {
134 { N_("Maps Download"), (VikToolConstructorFunc) maps_layer_download_create, NULL, NULL, NULL,
135 (VikToolMouseFunc) maps_layer_download_click, NULL, (VikToolMouseFunc) maps_layer_download_release,
136 (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_mapdl_pixbuf },
139 VikLayerInterface vik_maps_layer_interface = {
141 &vikmapslayer_pixbuf,
144 sizeof(maps_tools) / sizeof(maps_tools[0]),
153 (VikLayerFuncCreate) maps_layer_new,
154 (VikLayerFuncRealize) NULL,
155 (VikLayerFuncPostRead) maps_layer_post_read,
156 (VikLayerFuncFree) maps_layer_free,
158 (VikLayerFuncProperties) NULL,
159 (VikLayerFuncDraw) maps_layer_draw,
160 (VikLayerFuncChangeCoordMode) NULL,
162 (VikLayerFuncSetMenuItemsSelection) NULL,
163 (VikLayerFuncGetMenuItemsSelection) NULL,
165 (VikLayerFuncAddMenuItems) maps_layer_add_menu_items,
166 (VikLayerFuncSublayerAddMenuItems) NULL,
168 (VikLayerFuncSublayerRenameRequest) NULL,
169 (VikLayerFuncSublayerToggleVisible) NULL,
170 (VikLayerFuncSublayerTooltip) NULL,
171 (VikLayerFuncLayerTooltip) maps_layer_tooltip,
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"
340 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
341 #define LOCAL_MAPS_DIR ".viking-maps"
344 gchar *maps_layer_default_dir ()
346 static gchar *defaultdir = NULL;
349 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
350 const gchar *mapdir = g_getenv("VIKING_MAPS");
352 defaultdir = g_strdup ( mapdir );
353 } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
354 defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
356 const gchar *home = g_get_home_dir();
357 if (!home || g_access(home, W_OK))
358 home = g_get_home_dir ();
360 defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
362 defaultdir = g_strdup ( LOCAL_MAPS_DIR );
364 if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
366 /* Add the separator at the end */
367 gchar *tmp = defaultdir;
368 defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
371 g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
376 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
378 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
380 g_mkdir ( vml->cache_dir, 0777 );
384 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
387 g_assert ( vml != NULL);
388 g_free ( vml->cache_dir );
389 vml->cache_dir = NULL;
391 if ( dir == NULL || dir[0] == '\0' )
393 if ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir") )
394 vml->cache_dir = g_strdup ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir")->s );
399 if ( dir[len-1] != G_DIR_SEPARATOR )
401 vml->cache_dir = g_malloc ( len+2 );
402 strncpy ( vml->cache_dir, dir, len );
403 vml->cache_dir[len] = G_DIR_SEPARATOR;
404 vml->cache_dir[len+1] = '\0';
407 vml->cache_dir = g_strdup ( dir );
409 maps_layer_mkdir_if_default_dir ( vml );
412 /****************************************/
413 /******** GOBJECT STUFF *****************/
414 /****************************************/
416 GType vik_maps_layer_get_type ()
418 static GType vml_type = 0;
422 static const GTypeInfo vml_info =
424 sizeof (VikMapsLayerClass),
425 NULL, /* base_init */
426 NULL, /* base_finalize */
427 NULL, /* class init */
428 NULL, /* class_finalize */
429 NULL, /* class_data */
430 sizeof (VikMapsLayer),
432 NULL /* instance init */
434 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
440 /****************************************/
441 /************** PARAMETERS **************/
442 /****************************************/
444 static guint map_index_to_uniq_id (guint8 index)
446 g_assert ( index < NUM_MAP_TYPES );
447 return vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(index));
450 static guint map_uniq_id_to_index ( guint uniq_id )
453 for ( i = 0; i < NUM_MAP_TYPES; i++ )
454 if ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(i)) == uniq_id )
456 return NUM_MAP_TYPES; /* no such thing */
459 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation )
461 // When loading from a file don't need the license reminder
462 if ( is_file_operation )
463 vml->license_notice_shown = TRUE;
467 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
468 case PARAM_MAPTYPE: {
469 gint maptype = map_uniq_id_to_index(data.u);
470 if ( maptype == NUM_MAP_TYPES ) g_warning(_("Unknown map type"));
471 else vml->maptype = maptype;
474 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
475 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
476 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
477 vml->mapzoom_id = data.u;
478 vml->xmapzoom = __mapzooms_x [data.u];
479 vml->ymapzoom = __mapzooms_y [data.u];
480 }else g_warning (_("Unknown Map Zoom")); break;
485 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation )
487 VikLayerParamData rv;
490 case PARAM_CACHE_DIR: rv.s = vml->cache_dir ? vml->cache_dir : ""; break;
491 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
492 case PARAM_ALPHA: rv.u = vml->alpha; break;
493 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
494 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
499 /****************************************/
500 /****** CREATING, COPYING, FREEING ******/
501 /****************************************/
503 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
506 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
507 vik_layer_init ( VIK_LAYER(vml), VIK_LAYER_MAPS );
508 idx = map_uniq_id_to_index(13); /* 13 is id for OSM Mapnik maps */
509 vml->maptype = (idx < NUM_MAP_TYPES) ? idx : 0;
512 vml->dl_tool_x = vml->dl_tool_y = -1;
513 maps_layer_set_cache_dir ( vml, NULL );
514 vml->autodownload = FALSE;
515 vml->last_center = NULL;
516 vml->last_xmpp = 0.0;
517 vml->last_ympp = 0.0;
519 vml->dl_right_click_menu = NULL;
520 vml->license_notice_shown = FALSE;
525 static void maps_layer_free ( VikMapsLayer *vml )
527 g_free ( vml->cache_dir );
528 vml->cache_dir = NULL;
529 if ( vml->dl_right_click_menu )
530 g_object_ref_sink ( G_OBJECT(vml->dl_right_click_menu) );
531 g_free(vml->last_center);
532 vml->last_center = NULL;
535 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
537 if (from_file != TRUE)
539 /* If this method is not called in file reading context
540 * it is called in GUI context.
541 * So, we can check if we have to inform the user about inconsistency */
542 VikViewportDrawMode vp_drawmode;
543 VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
544 VikMapSource *map = NULL;
546 vp_drawmode = vik_viewport_get_drawmode ( vp );
547 map = MAPS_LAYER_NTH_TYPE(vml->maptype);
548 if (vik_map_source_get_drawmode(map) != vp_drawmode) {
549 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vp, vik_map_source_get_drawmode(map));
550 gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
551 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_WIDGET(vp), msg );
555 if (vik_map_source_get_license (map) != NULL) {
556 if ( ! vml->license_notice_shown ) {
557 a_dialog_license (VIK_GTK_WINDOW_FROM_WIDGET(vp), vik_map_source_get_label (map),
558 vik_map_source_get_license (map), vik_map_source_get_license_url (map) );
559 vml->license_notice_shown = TRUE;
565 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml )
567 return vik_maps_layer_get_map_label ( vml );
570 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
572 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
575 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
577 VikMapsLayer *rv = maps_layer_new ( vvp );
578 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
582 /*********************/
583 /****** DRAWING ******/
584 /*********************/
586 static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
589 gint width, height, iii, jjj;
591 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
593 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
594 g_object_unref(G_OBJECT(pixbuf));
598 pixels = gdk_pixbuf_get_pixels(pixbuf);
599 width = gdk_pixbuf_get_width(pixbuf);
600 height = gdk_pixbuf_get_height(pixbuf);
602 /* r,g,b,a,r,g,b,a.... */
603 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
611 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
614 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
615 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_NEAREST);
616 g_object_unref ( G_OBJECT(pixbuf) );
620 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
625 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
626 mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
629 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
630 vml->cache_dir, mode,
631 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
632 if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
635 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
637 /* free the pixbuf on error */
640 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
641 g_warning ( _("Couldn't open image file: %s"), gx->message );
645 g_object_unref ( G_OBJECT(pixbuf) );
648 if ( vml->alpha < 255 )
649 pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
650 if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
651 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
653 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
654 mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
655 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
662 gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
664 const VikCoord *center = vik_viewport_get_center ( vvp );
666 if (vik_window_get_pan_move (VIK_WINDOW(VIK_GTK_WINDOW_FROM_WIDGET(GTK_WIDGET(vvp)))))
667 /* D'n'D pan in action: do not download */
670 if (vml->last_center == NULL) {
671 VikCoord *new_center = g_malloc(sizeof(VikCoord));
672 *new_center = *center;
673 vml->last_center = new_center;
674 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
675 vml->last_ympp = vik_viewport_get_ympp(vvp);
679 /* TODO: perhaps vik_coord_diff() */
680 if (vik_coord_equals(vml->last_center, center)
681 && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
682 && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
685 *(vml->last_center) = *center;
686 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
687 vml->last_ympp = vik_viewport_get_ympp(vvp);
691 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
694 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
695 gdouble yzoom = vik_viewport_get_ympp ( vvp );
696 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
697 gdouble existence_only = FALSE;
699 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
700 xshrinkfactor = vml->xmapzoom / xzoom;
701 yshrinkfactor = vml->ymapzoom / yzoom;
702 xzoom = vml->xmapzoom;
703 yzoom = vml->xmapzoom;
704 if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
705 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
706 if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR )
707 existence_only = TRUE;
709 g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
716 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
717 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
718 vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
722 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
723 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
724 gint mode = vik_map_source_get_uniq_id(map);
727 gint xx, yy, width, height;
730 guint max_path_len = strlen(vml->cache_dir) + 40;
731 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
733 if ( (!existence_only) && vml->autodownload && should_start_autodownload(vml, vvp)) {
734 g_debug("%s: Starting autodownload", __FUNCTION__);
735 if ( vik_map_source_supports_download_only_new (map) )
736 // Try to download newer tiles
737 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NEW );
739 // Download only missing tiles
740 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
743 if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
744 for ( x = xmin; x <= xmax; x++ ) {
745 for ( y = ymin; y <= ymax; y++ ) {
748 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
750 width = gdk_pixbuf_get_width ( pixbuf );
751 height = gdk_pixbuf_get_height ( pixbuf );
753 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
754 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
758 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
762 } else { /* tilesize is known, don't have to keep converting coords */
763 gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
764 gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
765 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
766 gint tilesize_x_ceil = ceil ( tilesize_x );
767 gint tilesize_y_ceil = ceil ( tilesize_y );
768 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
769 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
770 gdouble xx, yy; gint xx_tmp, yy_tmp;
771 gint base_yy, xend, yend;
773 GdkGC *black_gc = GTK_WIDGET(vvp)->style->black_gc;
775 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
776 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
778 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
779 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
780 xx = xx_tmp; yy = yy_tmp;
781 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
782 * eg if tile size 128, shrinkfactor 0.333 */
783 xx -= (tilesize_x/2);
784 base_yy = yy - (tilesize_y/2);
786 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
788 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
792 if ( existence_only ) {
793 g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE,
794 vml->cache_dir, mode,
795 ulm.scale, ulm.z, ulm.x, ulm.y );
796 if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
797 vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
801 for (scale_inc = 0; scale_inc < 4; scale_inc ++) {
802 /* try with correct then smaller zooms */
803 int scale_factor = 1 << scale_inc; /* 2^scale_inc */
805 ulm2.x = ulm.x / scale_factor;
806 ulm2.y = ulm.y / scale_factor;
807 ulm2.scale = ulm.scale + scale_inc;
808 pixbuf = get_pixbuf ( vml, mode, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
810 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
811 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
813 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);
815 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
820 /* retry with bigger zooms */
822 for (scale_dec = 1; scale_dec < 2; scale_dec ++) {
824 int scale_factor = 1 << scale_dec; /* 2^scale_dec */
826 ulm2.x = ulm.x * scale_factor;
827 ulm2.y = ulm.y * scale_factor;
828 ulm2.scale = ulm.scale - scale_dec;
829 for (pict_x = 0; pict_x < scale_factor; pict_x ++) {
830 for (pict_y = 0; pict_y < scale_factor; pict_y ++) {
831 MapCoord ulm3 = ulm2;
834 pixbuf = get_pixbuf ( vml, mode, &ulm3, path_buf, max_path_len, xshrinkfactor / scale_factor, yshrinkfactor / scale_factor );
838 gint dest_x = xx + pict_x * (tilesize_x_ceil / scale_factor);
839 gint dest_y = yy + pict_y * (tilesize_y_ceil / scale_factor);
840 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, dest_x, dest_y, tilesize_x_ceil / scale_factor, tilesize_y_ceil / scale_factor );
858 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
860 if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
865 gdouble level = vik_viewport_get_zoom ( vvp );
867 vik_viewport_get_min_max_lat_lon ( vvp, &bbox.south, &bbox.north, &bbox.west, &bbox.east );
868 vik_map_source_get_copyright ( MAPS_LAYER_NTH_TYPE(vml->maptype), bbox, level, vik_viewport_add_copyright, vvp );
871 const GdkPixbuf *logo = vik_map_source_get_logo ( MAPS_LAYER_NTH_TYPE(vml->maptype) );
872 vik_viewport_add_logo ( vvp, logo );
874 /* get corner coords */
875 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
876 /* UTM multi-zone stuff by Kit Transue */
877 gchar leftmost_zone, rightmost_zone, i;
878 leftmost_zone = vik_viewport_leftmost_zone( vvp );
879 rightmost_zone = vik_viewport_rightmost_zone( vvp );
880 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
881 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
882 maps_layer_draw_section ( vml, vvp, &ul, &br );
886 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
887 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
889 maps_layer_draw_section ( vml, vvp, &ul, &br );
894 /*************************/
895 /****** DOWNLOADING ******/
896 /*************************/
898 /* pass along data to thread, exists even if layer is deleted. */
908 gboolean refresh_display;
911 gboolean map_layer_alive;
915 static void mdi_free ( MapDownloadInfo *mdi )
917 g_mutex_free(mdi->mutex);
918 g_free ( mdi->cache_dir );
919 mdi->cache_dir = NULL;
920 g_free ( mdi->filename_buf );
921 mdi->filename_buf = NULL;
925 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
927 MapDownloadInfo *mdi = ptr;
928 g_mutex_lock(mdi->mutex);
929 mdi->map_layer_alive = FALSE;
930 g_mutex_unlock(mdi->mutex);
933 static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
935 void *handle = vik_map_source_download_handle_init(MAPS_LAYER_NTH_TYPE(mdi->maptype));
938 for ( x = mdi->x0; x <= mdi->xf; x++ )
940 for ( y = mdi->y0; y <= mdi->yf; y++ )
942 gboolean remove_mem_cache = FALSE;
943 gboolean need_download = FALSE;
944 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
945 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
946 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
949 int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
951 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
955 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
956 need_download = TRUE;
957 remove_mem_cache = TRUE;
959 } else { /* in case map file already exists */
960 switch (mdi->redownload) {
961 case REDOWNLOAD_NONE:
966 /* see if this one is bad or what */
968 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
969 if (gx || (!pixbuf)) {
970 g_remove ( mdi->filename_buf );
971 need_download = TRUE;
972 remove_mem_cache = TRUE;
976 g_object_unref ( pixbuf );
982 need_download = TRUE;
983 remove_mem_cache = TRUE;
987 /* FIXME: need a better way than to erase file in case of server/network problem */
988 g_remove ( mdi->filename_buf );
989 need_download = TRUE;
990 remove_mem_cache = TRUE;
993 case DOWNLOAD_OR_REFRESH:
994 remove_mem_cache = TRUE;
998 g_warning ( "redownload state %d unknown\n", mdi->redownload);
1002 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
1004 if (need_download) {
1005 if ( vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf, handle))
1009 gdk_threads_enter();
1010 g_mutex_lock(mdi->mutex);
1011 if (remove_mem_cache)
1012 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 );
1013 if (mdi->refresh_display && mdi->map_layer_alive) {
1014 /* TODO: check if it's on visible area */
1015 vik_layer_emit_update ( VIK_LAYER(mdi->vml) );
1017 g_mutex_unlock(mdi->mutex);
1018 gdk_threads_leave();
1019 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
1023 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1024 g_mutex_lock(mdi->mutex);
1025 if (mdi->map_layer_alive)
1026 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1027 g_mutex_unlock(mdi->mutex);
1031 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
1033 if ( mdi->mapcoord.x || mdi->mapcoord.y )
1035 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1036 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1037 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
1038 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
1040 g_remove ( mdi->filename_buf );
1045 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
1047 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1048 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1050 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1051 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm )
1052 && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
1054 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
1059 mdi->map_layer_alive = TRUE;
1060 mdi->mutex = g_mutex_new();
1061 mdi->refresh_display = TRUE;
1063 /* cache_dir and buffer for dest filename */
1064 mdi->cache_dir = g_strdup ( vml->cache_dir );
1065 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1066 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1067 mdi->maptype = vml->maptype;
1069 mdi->mapcoord = ulm;
1071 mdi->redownload = redownload;
1073 mdi->x0 = MIN(ulm.x, brm.x);
1074 mdi->xf = MAX(ulm.x, brm.x);
1075 mdi->y0 = MIN(ulm.y, brm.y);
1076 mdi->yf = MAX(ulm.y, brm.y);
1080 if ( mdi->redownload ) {
1081 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1083 /* calculate how many we need */
1084 for ( a = mdi->x0; a <= mdi->xf; a++ )
1086 for ( b = mdi->y0; b <= mdi->yf; b++ )
1088 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1089 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1091 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1097 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1099 if ( mdi->mapstoget )
1101 const gchar *tmp_str;
1106 if (redownload == REDOWNLOAD_BAD)
1107 tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
1109 tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
1113 tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
1115 tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
1117 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1118 /* launch the thread */
1119 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1120 tmp, /* description string */
1121 (vik_thr_func) map_download_thread, /* function to call within thread */
1122 mdi, /* pass along data */
1123 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1124 (vik_thr_free_func) mdi_cancel_cleanup,
1133 void maps_layer_download_section_without_redraw( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
1136 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1138 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
1139 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
1140 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
1144 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1149 mdi->map_layer_alive = TRUE;
1150 mdi->mutex = g_mutex_new();
1151 mdi->refresh_display = FALSE;
1153 mdi->cache_dir = g_strdup ( vml->cache_dir );
1154 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1155 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1156 mdi->maptype = vml->maptype;
1158 mdi->mapcoord = ulm;
1160 mdi->redownload = REDOWNLOAD_NONE;
1162 mdi->x0 = MIN(ulm.x, brm.x);
1163 mdi->xf = MAX(ulm.x, brm.x);
1164 mdi->y0 = MIN(ulm.y, brm.y);
1165 mdi->yf = MAX(ulm.y, brm.y);
1169 for (i = mdi->x0; i <= mdi->xf; i++) {
1170 for (j = mdi->y0; j <= mdi->yf; j++) {
1171 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1172 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1174 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1179 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1181 if (mdi->mapstoget) {
1184 fmt = ngettext("Downloading %d %s map...",
1185 "Downloading %d %s maps...",
1187 tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
1189 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1190 /* launch the thread */
1191 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1192 tmp, /* description string */
1193 (vik_thr_func) map_download_thread, /* function to call within thread */
1194 mdi, /* pass along data */
1195 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1196 (vik_thr_free_func) mdi_cancel_cleanup,
1204 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1206 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1209 static void maps_layer_redownload_all ( VikMapsLayer *vml )
1211 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1214 static void maps_layer_redownload_new ( VikMapsLayer *vml )
1216 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
1219 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1221 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1223 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1225 if ( event->button == 1 )
1228 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 );
1229 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 );
1230 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
1231 vml->dl_tool_x = vml->dl_tool_y = -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)), &(vml->redownload_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 ) ), &(vml->redownload_br) );
1239 vml->redownload_vvp = vvp;
1241 vml->dl_tool_x = vml->dl_tool_y = -1;
1243 if ( ! vml->dl_right_click_menu ) {
1245 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1247 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _Bad Map(s)") );
1248 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1249 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1251 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _New Map(s)") );
1252 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), vml );
1253 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1255 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _All Map(s)") );
1256 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1257 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1260 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1261 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1267 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1272 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1275 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1277 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1278 if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
1279 vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
1280 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1281 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1283 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1290 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1294 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1295 if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1296 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1297 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1299 gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1300 vml->cache_dir, __map_types[vml->maptype].uniq_id,
1301 mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1303 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1304 g_free ( filename_buf );
1305 vik_layer_emit_update ( VIK_LAYER(vml) );
1313 static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
1315 VikMapsLayer *vml = vml_vvp[0];
1316 VikViewport *vvp = vml_vvp[1];
1317 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
1319 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1320 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1325 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1326 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1328 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1329 if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
1330 vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
1331 vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
1332 start_download_thread ( vml, vvp, &ul, &br, redownload );
1333 else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
1334 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
1335 gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
1336 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1340 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
1344 static void maps_layer_download_missing_onscreen_maps ( gpointer vml_vvp[2] )
1346 download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1349 static void maps_layer_download_new_onscreen_maps ( gpointer vml_vvp[2] )
1351 download_onscreen_maps( vml_vvp, REDOWNLOAD_NEW);
1354 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1356 download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1359 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1361 static gpointer pass_along[2];
1363 pass_along[0] = vml;
1364 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1366 item = gtk_menu_item_new();
1367 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1368 gtk_widget_show ( item );
1370 /* Now with icons */
1371 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _Missing Onscreen Maps") );
1372 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
1373 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), pass_along );
1374 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1375 gtk_widget_show ( item );
1377 if ( vik_map_source_supports_download_only_new (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
1378 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _New Onscreen Maps") );
1379 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REDO, GTK_ICON_SIZE_MENU) );
1380 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), pass_along );
1381 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1382 gtk_widget_show ( item );
1385 item = gtk_image_menu_item_new_with_mnemonic ( _("Reload _All Onscreen Maps") );
1386 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
1387 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1388 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1389 gtk_widget_show ( item );