2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
4 * Copyright (C) 2005, Evan Battaglia <viking@greentorch.org>
5 * Copyright (C) 2010, Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
6 * UTM multi-zone stuff by Kit Transue <notlostyet@didactek.com>
7 * Dynamic map type by Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #define MAX_SHRINKFACTOR 8.0000001 /* zoom 1 viewing 8-tiles */
30 #define MIN_SHRINKFACTOR 0.0312499 /* zoom 32 viewing 1-tiles */
32 #define REAL_MIN_SHRINKFACTOR 0.0039062499 /* if shrinkfactor is between MAX and REAL_MAX, will only check for existence */
35 #include <gdk-pixbuf/gdk-pixdata.h>
37 #include <glib/gstdio.h>
38 #include <glib/gi18n.h>
51 #include "viktreeview.h"
52 #include "vikviewport.h"
54 #include "vikmapslayer.h"
61 /* only for dialog.h -- ugh */
62 #include "vikwaypoint.h"
64 #include "preferences.h"
66 #include "vikstatus.h"
67 #include "background.h"
69 #include "vikaggregatelayer.h"
70 #include "viklayerspanel.h"
73 #include "terraserver.h"
75 #include "icons/icons.h"
77 /****** MAP TYPES ******/
79 static GList *__map_types = NULL;
81 #define NUM_MAP_TYPES g_list_length(__map_types)
83 /* List of label for each map type */
84 static gchar **params_maptypes = NULL;
86 /* Corresponding IDS. (Cf. field uniq_id in VikMapsLayer struct) */
87 static guint *params_maptypes_ids = NULL;
89 /******** MAPZOOMS *********/
91 static gchar *params_mapzooms[] = { N_("Use Viking Zoom Level"), "0.25", "0.5", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", "USGS 10k", "USGS 24k", "USGS 25k", "USGS 50k", "USGS 100k", "USGS 200k", "USGS 250k", NULL };
92 static gdouble __mapzooms_x[] = { 0.0, 0.25, 0.5, 1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0, 512.0, 1024.0, 1.016, 2.4384, 2.54, 5.08, 10.16, 20.32, 25.4 };
93 static gdouble __mapzooms_y[] = { 0.0, 0.25, 0.5, 1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0, 512.0, 1024.0, 1.016, 2.4384, 2.54, 5.08, 10.16, 20.32, 25.4 };
95 #define NUM_MAPZOOMS (sizeof(params_mapzooms)/sizeof(params_mapzooms[0]) - 1)
97 /**************************/
100 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file);
101 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml );
102 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len );
103 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
104 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation );
105 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation );
106 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp );
107 static VikMapsLayer *maps_layer_new ( VikViewport *vvp );
108 static void maps_layer_free ( VikMapsLayer *vml );
109 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
110 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
111 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp );
112 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir );
113 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload );
114 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp );
115 static guint map_uniq_id_to_index ( guint uniq_id );
118 static VikLayerParamScale params_scales[] = {
119 /* min, max, step, digits (decimal places) */
120 { 0, 255, 3, 0 }, /* alpha */
123 VikLayerParam maps_layer_params[] = {
124 { "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Map Type:"), VIK_LAYER_WIDGET_COMBOBOX, NULL, NULL },
125 { "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Maps Directory:"), VIK_LAYER_WIDGET_FOLDERENTRY },
126 { "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales },
127 { "autodownload", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload maps:"), VIK_LAYER_WIDGET_CHECKBUTTON },
128 { "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Zoom Level:"), VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms, NULL },
131 enum { PARAM_MAPTYPE=0, PARAM_CACHE_DIR, PARAM_ALPHA, PARAM_AUTODOWNLOAD, PARAM_MAPZOOM, NUM_PARAMS };
133 static VikToolInterface maps_tools[] = {
134 { { "MapsDownload", "vik-icon-Maps Download", N_("_Maps Download"), NULL, N_("Maps Download"), 0 },
135 (VikToolConstructorFunc) maps_layer_download_create, NULL, NULL, NULL,
136 (VikToolMouseFunc) maps_layer_download_click, NULL, (VikToolMouseFunc) maps_layer_download_release,
137 (VikToolKeyFunc) NULL,
139 GDK_CURSOR_IS_PIXMAP, &cursor_mapdl_pixbuf },
142 VikLayerInterface vik_maps_layer_interface = {
145 &vikmapslayer_pixbuf,
148 sizeof(maps_tools) / sizeof(maps_tools[0]),
157 (VikLayerFuncCreate) maps_layer_new,
158 (VikLayerFuncRealize) NULL,
159 (VikLayerFuncPostRead) maps_layer_post_read,
160 (VikLayerFuncFree) maps_layer_free,
162 (VikLayerFuncProperties) NULL,
163 (VikLayerFuncDraw) maps_layer_draw,
164 (VikLayerFuncChangeCoordMode) NULL,
166 (VikLayerFuncSetMenuItemsSelection) NULL,
167 (VikLayerFuncGetMenuItemsSelection) NULL,
169 (VikLayerFuncAddMenuItems) maps_layer_add_menu_items,
170 (VikLayerFuncSublayerAddMenuItems) NULL,
172 (VikLayerFuncSublayerRenameRequest) NULL,
173 (VikLayerFuncSublayerToggleVisible) NULL,
174 (VikLayerFuncSublayerTooltip) NULL,
175 (VikLayerFuncLayerTooltip) maps_layer_tooltip,
176 (VikLayerFuncLayerSelected) NULL,
178 (VikLayerFuncMarshall) maps_layer_marshall,
179 (VikLayerFuncUnmarshall) maps_layer_unmarshall,
181 (VikLayerFuncSetParam) maps_layer_set_param,
182 (VikLayerFuncGetParam) maps_layer_get_param,
184 (VikLayerFuncReadFileData) NULL,
185 (VikLayerFuncWriteFileData) NULL,
187 (VikLayerFuncDeleteItem) NULL,
188 (VikLayerFuncCutItem) NULL,
189 (VikLayerFuncCopyItem) NULL,
190 (VikLayerFuncPasteItem) NULL,
191 (VikLayerFuncFreeCopiedItem) NULL,
192 (VikLayerFuncDragDropRequest) NULL,
194 (VikLayerFuncSelectClick) NULL,
195 (VikLayerFuncSelectMove) NULL,
196 (VikLayerFuncSelectRelease) NULL,
197 (VikLayerFuncSelectedViewportMenu) NULL,
200 struct _VikMapsLayer {
206 gdouble xmapzoom, ymapzoom;
208 gboolean autodownload;
209 VikCoord *last_center;
213 gint dl_tool_x, dl_tool_y;
215 GtkMenu *dl_right_click_menu;
216 VikCoord redownload_ul, redownload_br; /* right click menu only */
217 VikViewport *redownload_vvp;
219 gboolean license_notice_shown; // FALSE for new maps only, otherwise
220 // TRUE for saved maps & other layer changes as we don't need to show it again
223 enum { REDOWNLOAD_NONE = 0, /* download only missing maps */
224 REDOWNLOAD_BAD, /* download missing and bad maps */
225 REDOWNLOAD_NEW, /* download missing maps that are newer on server only */
226 REDOWNLOAD_ALL, /* download all maps */
227 DOWNLOAD_OR_REFRESH }; /* download missing maps and refresh cache */
229 static VikLayerParam prefs[] = {
230 { VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Default maplayer directory:"), VIK_LAYER_WIDGET_FOLDERENTRY, NULL, NULL },
233 void maps_layer_init ()
235 VikLayerParamData tmp;
236 tmp.s = maps_layer_default_dir();
237 a_preferences_register(prefs, tmp, VIKING_PREFERENCES_GROUP_KEY);
240 /****************************************/
241 /******** MAPS LAYER TYPES **************/
242 /****************************************/
244 int _get_index_for_id ( guint id )
247 while (params_maptypes_ids[index] != 0)
249 if (params_maptypes_ids[index] == id)
256 void _add_map_source ( guint id, const char *label, VikMapSource *map )
260 len = g_strv_length (params_maptypes);
262 params_maptypes = g_realloc (params_maptypes, (len+2)*sizeof(gchar*));
263 params_maptypes[len] = g_strdup (label);
264 params_maptypes[len+1] = NULL;
267 params_maptypes_ids = g_realloc (params_maptypes_ids, (len+2)*sizeof(guint));
268 params_maptypes_ids[len] = id;
269 params_maptypes_ids[len+1] = 0;
271 /* We have to clone */
272 VikMapSource *clone = VIK_MAP_SOURCE(g_object_ref(map));
273 /* Register the clone in the list */
274 __map_types = g_list_append(__map_types, clone);
277 We have to ensure the mode LayerParam references the up-to-date
281 memcpy(&maps_layer_params[0].widget_data, ¶ms_maptypes, sizeof(gpointer));
282 memcpy(&maps_layer_params[0].extra_widget_data, ¶ms_maptypes_ids, sizeof(gpointer));
284 maps_layer_params[0].widget_data = params_maptypes;
285 maps_layer_params[0].extra_widget_data = params_maptypes_ids;
288 void _update_map_source ( const char *label, VikMapSource *map, int index )
290 GList *item = g_list_nth (__map_types, index);
291 g_object_unref (item->data);
292 item->data = g_object_ref (map);
293 /* Change previous data */
294 g_free (params_maptypes[index]);
295 params_maptypes[index] = g_strdup (label);
299 * maps_layer_register_map_source:
300 * @map: the new VikMapSource
302 * Register a new VikMapSource.
303 * Override existing one (equality of id).
305 void maps_layer_register_map_source ( VikMapSource *map )
307 g_assert(map != NULL);
309 guint id = vik_map_source_get_uniq_id(map);
310 const char *label = vik_map_source_get_label(map);
311 g_assert(label != NULL);
313 int previous = map_uniq_id_to_index (id);
314 if (previous != NUM_MAP_TYPES)
316 _update_map_source (label, map, previous);
320 _add_map_source (id, label, map);
324 #define MAPS_LAYER_NTH_LABEL(n) (params_maptypes[n])
325 #define MAPS_LAYER_NTH_ID(n) (params_maptypes_ids[n])
326 #define MAPS_LAYER_NTH_TYPE(n) (VIK_MAP_SOURCE(g_list_nth_data(__map_types, (n))))
328 gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
330 return(vml->maptype);
333 gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
335 return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
338 /****************************************/
339 /******** CACHE DIR STUFF ***************/
340 /****************************************/
342 #define DIRECTDIRACCESS "%s%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d%s"
343 #define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
344 #define MAPS_CACHE_DIR maps_layer_default_dir()
348 #define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
349 #define LOCAL_MAPS_DIR "VIKING-MAPS"
350 #elif defined __APPLE__
352 #define GLOBAL_MAPS_DIR "/Library/cache/Viking/maps/"
353 #define LOCAL_MAPS_DIR "/Library/Application Support/Viking/viking-maps"
356 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
357 #define LOCAL_MAPS_DIR ".viking-maps"
360 gchar *maps_layer_default_dir ()
362 static gchar *defaultdir = NULL;
365 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
366 const gchar *mapdir = g_getenv("VIKING_MAPS");
368 defaultdir = g_strdup ( mapdir );
369 } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
370 defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
372 const gchar *home = g_get_home_dir();
373 if (!home || g_access(home, W_OK))
374 home = g_get_home_dir ();
376 defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
378 defaultdir = g_strdup ( LOCAL_MAPS_DIR );
380 if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
382 /* Add the separator at the end */
383 gchar *tmp = defaultdir;
384 defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
387 g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
392 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
394 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
396 g_mkdir ( vml->cache_dir, 0777 );
400 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
403 g_assert ( vml != NULL);
404 g_free ( vml->cache_dir );
405 vml->cache_dir = NULL;
407 if ( dir == NULL || dir[0] == '\0' )
409 if ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir") )
410 vml->cache_dir = g_strdup ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir")->s );
415 if ( dir[len-1] != G_DIR_SEPARATOR )
417 vml->cache_dir = g_malloc ( len+2 );
418 strncpy ( vml->cache_dir, dir, len );
419 vml->cache_dir[len] = G_DIR_SEPARATOR;
420 vml->cache_dir[len+1] = '\0';
423 vml->cache_dir = g_strdup ( dir );
425 maps_layer_mkdir_if_default_dir ( vml );
428 /****************************************/
429 /******** GOBJECT STUFF *****************/
430 /****************************************/
432 GType vik_maps_layer_get_type ()
434 static GType vml_type = 0;
438 static const GTypeInfo vml_info =
440 sizeof (VikMapsLayerClass),
441 NULL, /* base_init */
442 NULL, /* base_finalize */
443 NULL, /* class init */
444 NULL, /* class_finalize */
445 NULL, /* class_data */
446 sizeof (VikMapsLayer),
448 NULL /* instance init */
450 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
456 /****************************************/
457 /************** PARAMETERS **************/
458 /****************************************/
460 static guint map_index_to_uniq_id (guint8 index)
462 g_assert ( index < NUM_MAP_TYPES );
463 return vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(index));
466 static guint map_uniq_id_to_index ( guint uniq_id )
469 for ( i = 0; i < NUM_MAP_TYPES; i++ )
470 if ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(i)) == uniq_id )
472 return NUM_MAP_TYPES; /* no such thing */
475 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation )
477 // When loading from a file don't need the license reminder
478 if ( is_file_operation )
479 vml->license_notice_shown = TRUE;
483 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
484 case PARAM_MAPTYPE: {
485 gint maptype = map_uniq_id_to_index(data.u);
486 if ( maptype == NUM_MAP_TYPES ) g_warning(_("Unknown map type"));
487 else vml->maptype = maptype;
490 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
491 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
492 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
493 vml->mapzoom_id = data.u;
494 vml->xmapzoom = __mapzooms_x [data.u];
495 vml->ymapzoom = __mapzooms_y [data.u];
496 }else g_warning (_("Unknown Map Zoom")); break;
501 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation )
503 VikLayerParamData rv;
506 case PARAM_CACHE_DIR: rv.s = vml->cache_dir ? vml->cache_dir : ""; break;
507 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
508 case PARAM_ALPHA: rv.u = vml->alpha; break;
509 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
510 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
515 /****************************************/
516 /****** CREATING, COPYING, FREEING ******/
517 /****************************************/
519 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
522 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
523 vik_layer_init ( VIK_LAYER(vml), VIK_LAYER_MAPS );
524 idx = map_uniq_id_to_index(19); /* 19 is id for OSM MapQuest maps */
525 vml->maptype = (idx < NUM_MAP_TYPES) ? idx : 0;
526 vml->maptype = (idx < NUM_MAP_TYPES) ? idx : 0;
529 vml->dl_tool_x = vml->dl_tool_y = -1;
530 maps_layer_set_cache_dir ( vml, NULL );
531 vml->autodownload = FALSE;
532 vml->last_center = NULL;
533 vml->last_xmpp = 0.0;
534 vml->last_ympp = 0.0;
536 vml->dl_right_click_menu = NULL;
537 vml->license_notice_shown = FALSE;
542 static void maps_layer_free ( VikMapsLayer *vml )
544 g_free ( vml->cache_dir );
545 vml->cache_dir = NULL;
546 if ( vml->dl_right_click_menu )
547 g_object_ref_sink ( G_OBJECT(vml->dl_right_click_menu) );
548 g_free(vml->last_center);
549 vml->last_center = NULL;
552 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
554 if (from_file != TRUE)
556 /* If this method is not called in file reading context
557 * it is called in GUI context.
558 * So, we can check if we have to inform the user about inconsistency */
559 VikViewportDrawMode vp_drawmode;
560 VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
561 VikMapSource *map = NULL;
563 vp_drawmode = vik_viewport_get_drawmode ( vp );
564 map = MAPS_LAYER_NTH_TYPE(vml->maptype);
565 if (vik_map_source_get_drawmode(map) != vp_drawmode) {
566 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vp, vik_map_source_get_drawmode(map));
567 gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
568 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_WIDGET(vp), msg );
572 if (vik_map_source_get_license (map) != NULL) {
573 if ( ! vml->license_notice_shown ) {
574 a_dialog_license (VIK_GTK_WINDOW_FROM_WIDGET(vp), vik_map_source_get_label (map),
575 vik_map_source_get_license (map), vik_map_source_get_license_url (map) );
576 vml->license_notice_shown = TRUE;
582 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml )
584 return vik_maps_layer_get_map_label ( vml );
587 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
589 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
592 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
594 VikMapsLayer *rv = maps_layer_new ( vvp );
595 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
599 /*********************/
600 /****** DRAWING ******/
601 /*********************/
603 static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
606 gint width, height, iii, jjj;
608 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
610 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
611 g_object_unref(G_OBJECT(pixbuf));
615 pixels = gdk_pixbuf_get_pixels(pixbuf);
616 width = gdk_pixbuf_get_width(pixbuf);
617 height = gdk_pixbuf_get_height(pixbuf);
619 /* r,g,b,a,r,g,b,a.... */
620 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
628 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
631 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
632 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_NEAREST);
633 g_object_unref ( G_OBJECT(pixbuf) );
637 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
642 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
643 mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
646 if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
647 g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS,
648 vml->cache_dir, (17 - mapcoord->scale), mapcoord->x, mapcoord->y, ".png" );
650 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
651 vml->cache_dir, mode,
652 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
654 if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
657 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
659 /* free the pixbuf on error */
662 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
663 g_warning ( _("Couldn't open image file: %s"), gx->message );
667 g_object_unref ( G_OBJECT(pixbuf) );
670 if ( vml->alpha < 255 )
671 pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
672 if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
673 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
675 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
676 mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
677 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
684 gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
686 const VikCoord *center = vik_viewport_get_center ( vvp );
688 if (vik_window_get_pan_move (VIK_WINDOW(VIK_GTK_WINDOW_FROM_WIDGET(GTK_WIDGET(vvp)))))
689 /* D'n'D pan in action: do not download */
692 if (vml->last_center == NULL) {
693 VikCoord *new_center = g_malloc(sizeof(VikCoord));
694 *new_center = *center;
695 vml->last_center = new_center;
696 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
697 vml->last_ympp = vik_viewport_get_ympp(vvp);
701 /* TODO: perhaps vik_coord_diff() */
702 if (vik_coord_equals(vml->last_center, center)
703 && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
704 && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
707 *(vml->last_center) = *center;
708 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
709 vml->last_ympp = vik_viewport_get_ympp(vvp);
713 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
716 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
717 gdouble yzoom = vik_viewport_get_ympp ( vvp );
718 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
719 gboolean existence_only = FALSE;
721 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
722 xshrinkfactor = vml->xmapzoom / xzoom;
723 yshrinkfactor = vml->ymapzoom / yzoom;
724 xzoom = vml->xmapzoom;
725 yzoom = vml->xmapzoom;
726 if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
727 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
728 if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR )
729 existence_only = TRUE;
731 g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
738 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
739 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
740 vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
744 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
745 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
746 gint mode = vik_map_source_get_uniq_id(map);
749 gint xx, yy, width, height;
752 guint max_path_len = strlen(vml->cache_dir) + 40;
753 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
755 if ( (!existence_only) && vml->autodownload && should_start_autodownload(vml, vvp)) {
756 g_debug("%s: Starting autodownload", __FUNCTION__);
757 if ( vik_map_source_supports_download_only_new (map) )
758 // Try to download newer tiles
759 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NEW );
761 // Download only missing tiles
762 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
765 if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
766 for ( x = xmin; x <= xmax; x++ ) {
767 for ( y = ymin; y <= ymax; y++ ) {
770 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
772 width = gdk_pixbuf_get_width ( pixbuf );
773 height = gdk_pixbuf_get_height ( pixbuf );
775 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
776 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
780 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
784 } else { /* tilesize is known, don't have to keep converting coords */
785 gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
786 gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
787 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
788 gint tilesize_x_ceil = ceil ( tilesize_x );
789 gint tilesize_y_ceil = ceil ( tilesize_y );
790 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
791 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
792 gdouble xx, yy; gint xx_tmp, yy_tmp;
793 gint base_yy, xend, yend;
795 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
796 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
798 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
799 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
800 xx = xx_tmp; yy = yy_tmp;
801 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
802 * eg if tile size 128, shrinkfactor 0.333 */
803 xx -= (tilesize_x/2);
804 base_yy = yy - (tilesize_y/2);
806 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
808 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
812 if ( existence_only ) {
813 if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
814 g_snprintf ( path_buf, max_path_len, DIRECTDIRACCESS,
815 vml->cache_dir, (17 - ulm.scale), ulm.x, ulm.y, ".png" );
817 g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE,
818 vml->cache_dir, mode,
819 ulm.scale, ulm.z, ulm.x, ulm.y );
820 if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
821 GdkGC *black_gc = GTK_WIDGET(vvp)->style->black_gc;
822 vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
826 for (scale_inc = 0; scale_inc < 4; scale_inc ++) {
827 /* try with correct then smaller zooms */
828 int scale_factor = 1 << scale_inc; /* 2^scale_inc */
830 ulm2.x = ulm.x / scale_factor;
831 ulm2.y = ulm.y / scale_factor;
832 ulm2.scale = ulm.scale + scale_inc;
833 pixbuf = get_pixbuf ( vml, mode, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
835 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
836 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
838 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);
840 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
845 /* retry with bigger zooms */
847 for (scale_dec = 1; scale_dec < 2; scale_dec ++) {
849 int scale_factor = 1 << scale_dec; /* 2^scale_dec */
851 ulm2.x = ulm.x * scale_factor;
852 ulm2.y = ulm.y * scale_factor;
853 ulm2.scale = ulm.scale - scale_dec;
854 for (pict_x = 0; pict_x < scale_factor; pict_x ++) {
855 for (pict_y = 0; pict_y < scale_factor; pict_y ++) {
856 MapCoord ulm3 = ulm2;
859 pixbuf = get_pixbuf ( vml, mode, &ulm3, path_buf, max_path_len, xshrinkfactor / scale_factor, yshrinkfactor / scale_factor );
863 gint dest_x = xx + pict_x * (tilesize_x_ceil / scale_factor);
864 gint dest_y = yy + pict_y * (tilesize_y_ceil / scale_factor);
865 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, dest_x, dest_y, tilesize_x_ceil / scale_factor, tilesize_y_ceil / scale_factor );
883 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
885 if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
890 gdouble level = vik_viewport_get_zoom ( vvp );
892 vik_viewport_get_min_max_lat_lon ( vvp, &bbox.south, &bbox.north, &bbox.west, &bbox.east );
893 vik_map_source_get_copyright ( MAPS_LAYER_NTH_TYPE(vml->maptype), bbox, level, vik_viewport_add_copyright, vvp );
896 const GdkPixbuf *logo = vik_map_source_get_logo ( MAPS_LAYER_NTH_TYPE(vml->maptype) );
897 vik_viewport_add_logo ( vvp, logo );
899 /* get corner coords */
900 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
901 /* UTM multi-zone stuff by Kit Transue */
902 gchar leftmost_zone, rightmost_zone, i;
903 leftmost_zone = vik_viewport_leftmost_zone( vvp );
904 rightmost_zone = vik_viewport_rightmost_zone( vvp );
905 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
906 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
907 maps_layer_draw_section ( vml, vvp, &ul, &br );
911 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
912 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
914 maps_layer_draw_section ( vml, vvp, &ul, &br );
919 /*************************/
920 /****** DOWNLOADING ******/
921 /*************************/
923 /* pass along data to thread, exists even if layer is deleted. */
933 gboolean refresh_display;
936 gboolean map_layer_alive;
940 static void mdi_free ( MapDownloadInfo *mdi )
942 g_mutex_free(mdi->mutex);
943 g_free ( mdi->cache_dir );
944 mdi->cache_dir = NULL;
945 g_free ( mdi->filename_buf );
946 mdi->filename_buf = NULL;
950 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
952 MapDownloadInfo *mdi = ptr;
953 g_mutex_lock(mdi->mutex);
954 mdi->map_layer_alive = FALSE;
955 g_mutex_unlock(mdi->mutex);
958 static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
960 void *handle = vik_map_source_download_handle_init(MAPS_LAYER_NTH_TYPE(mdi->maptype));
963 for ( x = mdi->x0; x <= mdi->xf; x++ )
965 for ( y = mdi->y0; y <= mdi->yf; y++ )
967 gboolean remove_mem_cache = FALSE;
968 gboolean need_download = FALSE;
969 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
970 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
971 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
974 int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
976 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
980 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
981 need_download = TRUE;
982 remove_mem_cache = TRUE;
984 } else { /* in case map file already exists */
985 switch (mdi->redownload) {
986 case REDOWNLOAD_NONE:
991 /* see if this one is bad or what */
993 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
994 if (gx || (!pixbuf)) {
995 g_remove ( mdi->filename_buf );
996 need_download = TRUE;
997 remove_mem_cache = TRUE;
1001 g_object_unref ( pixbuf );
1006 case REDOWNLOAD_NEW:
1007 need_download = TRUE;
1008 remove_mem_cache = TRUE;
1011 case REDOWNLOAD_ALL:
1012 /* FIXME: need a better way than to erase file in case of server/network problem */
1013 g_remove ( mdi->filename_buf );
1014 need_download = TRUE;
1015 remove_mem_cache = TRUE;
1018 case DOWNLOAD_OR_REFRESH:
1019 remove_mem_cache = TRUE;
1023 g_warning ( "redownload state %d unknown\n", mdi->redownload);
1027 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
1029 if (need_download) {
1030 if ( vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf, handle))
1034 g_mutex_lock(mdi->mutex);
1035 if (remove_mem_cache)
1036 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 );
1037 if (mdi->refresh_display && mdi->map_layer_alive) {
1038 /* TODO: check if it's on visible area */
1039 vik_layer_emit_update ( VIK_LAYER(mdi->vml), TRUE ); // Yes update display from background
1041 g_mutex_unlock(mdi->mutex);
1042 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
1046 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1047 g_mutex_lock(mdi->mutex);
1048 if (mdi->map_layer_alive)
1049 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1050 g_mutex_unlock(mdi->mutex);
1054 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
1056 if ( mdi->mapcoord.x || mdi->mapcoord.y )
1058 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1059 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1060 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
1061 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
1063 g_remove ( mdi->filename_buf );
1068 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
1070 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1071 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1073 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1075 // Don't ever attempt download on direct access
1076 if ( vik_map_source_is_direct_file_access ( map ) )
1079 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm )
1080 && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
1082 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
1087 mdi->map_layer_alive = TRUE;
1088 mdi->mutex = g_mutex_new();
1089 mdi->refresh_display = TRUE;
1091 /* cache_dir and buffer for dest filename */
1092 mdi->cache_dir = g_strdup ( vml->cache_dir );
1093 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1094 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1095 mdi->maptype = vml->maptype;
1097 mdi->mapcoord = ulm;
1099 mdi->redownload = redownload;
1101 mdi->x0 = MIN(ulm.x, brm.x);
1102 mdi->xf = MAX(ulm.x, brm.x);
1103 mdi->y0 = MIN(ulm.y, brm.y);
1104 mdi->yf = MAX(ulm.y, brm.y);
1108 if ( mdi->redownload ) {
1109 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1111 /* calculate how many we need */
1112 for ( a = mdi->x0; a <= mdi->xf; a++ )
1114 for ( b = mdi->y0; b <= mdi->yf; b++ )
1116 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1117 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1119 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1125 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1127 if ( mdi->mapstoget )
1129 const gchar *tmp_str;
1134 if (redownload == REDOWNLOAD_BAD)
1135 tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
1137 tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
1141 tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
1143 tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
1145 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1146 /* launch the thread */
1147 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1148 tmp, /* description string */
1149 (vik_thr_func) map_download_thread, /* function to call within thread */
1150 mdi, /* pass along data */
1151 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1152 (vik_thr_free_func) mdi_cancel_cleanup,
1161 void maps_layer_download_section_without_redraw( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
1164 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1166 // Don't ever attempt download on direct access
1167 if ( vik_map_source_is_direct_file_access ( map ) )
1170 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
1171 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
1172 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
1176 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1181 mdi->map_layer_alive = TRUE;
1182 mdi->mutex = g_mutex_new();
1183 mdi->refresh_display = FALSE;
1185 mdi->cache_dir = g_strdup ( vml->cache_dir );
1186 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1187 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1188 mdi->maptype = vml->maptype;
1190 mdi->mapcoord = ulm;
1192 mdi->redownload = REDOWNLOAD_NONE;
1194 mdi->x0 = MIN(ulm.x, brm.x);
1195 mdi->xf = MAX(ulm.x, brm.x);
1196 mdi->y0 = MIN(ulm.y, brm.y);
1197 mdi->yf = MAX(ulm.y, brm.y);
1201 for (i = mdi->x0; i <= mdi->xf; i++) {
1202 for (j = mdi->y0; j <= mdi->yf; j++) {
1203 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1204 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1206 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1211 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1213 if (mdi->mapstoget) {
1216 fmt = ngettext("Downloading %d %s map...",
1217 "Downloading %d %s maps...",
1219 tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
1221 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1222 /* launch the thread */
1223 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1224 tmp, /* description string */
1225 (vik_thr_func) map_download_thread, /* function to call within thread */
1226 mdi, /* pass along data */
1227 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1228 (vik_thr_free_func) mdi_cancel_cleanup,
1236 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1238 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1241 static void maps_layer_redownload_all ( VikMapsLayer *vml )
1243 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1246 static void maps_layer_redownload_new ( VikMapsLayer *vml )
1248 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
1251 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1253 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1255 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1257 if ( event->button == 1 )
1260 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 );
1261 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 );
1262 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
1263 vml->dl_tool_x = vml->dl_tool_y = -1;
1268 vik_viewport_screen_to_coord ( vvp, MAX(0, MIN(event->x, vml->dl_tool_x)), MAX(0, MIN(event->y, vml->dl_tool_y)), &(vml->redownload_ul) );
1269 vik_viewport_screen_to_coord ( vvp, MIN(vik_viewport_get_width(vvp), MAX(event->x, vml->dl_tool_x)), MIN(vik_viewport_get_height(vvp), MAX ( event->y, vml->dl_tool_y ) ), &(vml->redownload_br) );
1271 vml->redownload_vvp = vvp;
1273 vml->dl_tool_x = vml->dl_tool_y = -1;
1275 if ( ! vml->dl_right_click_menu ) {
1277 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1279 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _Bad Map(s)") );
1280 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1281 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1283 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _New Map(s)") );
1284 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), vml );
1285 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1287 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _All Map(s)") );
1288 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1289 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1292 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1293 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1299 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1304 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1307 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1309 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1310 if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
1311 vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
1312 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1313 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1315 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1322 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1326 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1327 if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1328 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1329 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1331 gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1332 vml->cache_dir, __map_types[vml->maptype].uniq_id,
1333 mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1335 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1336 g_free ( filename_buf );
1337 vik_layer_emit_update ( VIK_LAYER(vml) );
1345 static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
1347 VikMapsLayer *vml = vml_vvp[0];
1348 VikViewport *vvp = vml_vvp[1];
1349 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
1351 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1352 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1357 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1358 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1360 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1361 if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
1362 vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
1363 vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
1364 start_download_thread ( vml, vvp, &ul, &br, redownload );
1365 else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
1366 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
1367 gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
1368 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1372 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
1376 static void maps_layer_download_missing_onscreen_maps ( gpointer vml_vvp[2] )
1378 download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1381 static void maps_layer_download_new_onscreen_maps ( gpointer vml_vvp[2] )
1383 download_onscreen_maps( vml_vvp, REDOWNLOAD_NEW);
1386 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1388 download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1391 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1393 static gpointer pass_along[2];
1395 pass_along[0] = vml;
1396 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1398 item = gtk_menu_item_new();
1399 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1400 gtk_widget_show ( item );
1402 /* Now with icons */
1403 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _Missing Onscreen Maps") );
1404 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
1405 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), pass_along );
1406 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1407 gtk_widget_show ( item );
1409 if ( vik_map_source_supports_download_only_new (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
1410 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _New Onscreen Maps") );
1411 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REDO, GTK_ICON_SIZE_MENU) );
1412 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), pass_along );
1413 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1414 gtk_widget_show ( item );
1417 item = gtk_image_menu_item_new_with_mnemonic ( _("Reload _All Onscreen Maps") );
1418 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
1419 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1420 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1421 gtk_widget_show ( item );