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, GDK_CURSOR_IS_PIXMAP, &cursor_mapdl_pixbuf },
140 VikLayerInterface vik_maps_layer_interface = {
143 &vikmapslayer_pixbuf,
146 sizeof(maps_tools) / sizeof(maps_tools[0]),
155 (VikLayerFuncCreate) maps_layer_new,
156 (VikLayerFuncRealize) NULL,
157 (VikLayerFuncPostRead) maps_layer_post_read,
158 (VikLayerFuncFree) maps_layer_free,
160 (VikLayerFuncProperties) NULL,
161 (VikLayerFuncDraw) maps_layer_draw,
162 (VikLayerFuncChangeCoordMode) NULL,
164 (VikLayerFuncSetMenuItemsSelection) NULL,
165 (VikLayerFuncGetMenuItemsSelection) NULL,
167 (VikLayerFuncAddMenuItems) maps_layer_add_menu_items,
168 (VikLayerFuncSublayerAddMenuItems) NULL,
170 (VikLayerFuncSublayerRenameRequest) NULL,
171 (VikLayerFuncSublayerToggleVisible) NULL,
172 (VikLayerFuncSublayerTooltip) NULL,
173 (VikLayerFuncLayerTooltip) maps_layer_tooltip,
174 (VikLayerFuncLayerSelected) NULL,
176 (VikLayerFuncMarshall) maps_layer_marshall,
177 (VikLayerFuncUnmarshall) maps_layer_unmarshall,
179 (VikLayerFuncSetParam) maps_layer_set_param,
180 (VikLayerFuncGetParam) maps_layer_get_param,
182 (VikLayerFuncReadFileData) NULL,
183 (VikLayerFuncWriteFileData) NULL,
185 (VikLayerFuncDeleteItem) NULL,
186 (VikLayerFuncCutItem) NULL,
187 (VikLayerFuncCopyItem) NULL,
188 (VikLayerFuncPasteItem) NULL,
189 (VikLayerFuncFreeCopiedItem) NULL,
190 (VikLayerFuncDragDropRequest) NULL,
192 (VikLayerFuncSelectClick) NULL,
193 (VikLayerFuncSelectMove) NULL,
194 (VikLayerFuncSelectRelease) NULL,
195 (VikLayerFuncSelectedViewportMenu) NULL,
198 struct _VikMapsLayer {
204 gdouble xmapzoom, ymapzoom;
206 gboolean autodownload;
207 VikCoord *last_center;
211 gint dl_tool_x, dl_tool_y;
213 GtkMenu *dl_right_click_menu;
214 VikCoord redownload_ul, redownload_br; /* right click menu only */
215 VikViewport *redownload_vvp;
217 gboolean license_notice_shown; // FALSE for new maps only, otherwise
218 // TRUE for saved maps & other layer changes as we don't need to show it again
221 enum { REDOWNLOAD_NONE = 0, /* download only missing maps */
222 REDOWNLOAD_BAD, /* download missing and bad maps */
223 REDOWNLOAD_NEW, /* download missing maps that are newer on server only */
224 REDOWNLOAD_ALL, /* download all maps */
225 DOWNLOAD_OR_REFRESH }; /* download missing maps and refresh cache */
227 static VikLayerParam prefs[] = {
228 { VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Default maplayer directory:"), VIK_LAYER_WIDGET_FOLDERENTRY, NULL, NULL },
231 void maps_layer_init ()
233 VikLayerParamData tmp;
234 tmp.s = maps_layer_default_dir();
235 a_preferences_register(prefs, tmp, VIKING_PREFERENCES_GROUP_KEY);
238 /****************************************/
239 /******** MAPS LAYER TYPES **************/
240 /****************************************/
242 int _get_index_for_id ( guint id )
245 while (params_maptypes_ids[index] != 0)
247 if (params_maptypes_ids[index] == id)
254 void _add_map_source ( guint id, const char *label, VikMapSource *map )
258 len = g_strv_length (params_maptypes);
260 params_maptypes = g_realloc (params_maptypes, (len+2)*sizeof(gchar*));
261 params_maptypes[len] = g_strdup (label);
262 params_maptypes[len+1] = NULL;
265 params_maptypes_ids = g_realloc (params_maptypes_ids, (len+2)*sizeof(guint));
266 params_maptypes_ids[len] = id;
267 params_maptypes_ids[len+1] = 0;
269 /* We have to clone */
270 VikMapSource *clone = VIK_MAP_SOURCE(g_object_ref(map));
271 /* Register the clone in the list */
272 __map_types = g_list_append(__map_types, clone);
275 We have to ensure the mode LayerParam references the up-to-date
279 memcpy(&maps_layer_params[0].widget_data, ¶ms_maptypes, sizeof(gpointer));
280 memcpy(&maps_layer_params[0].extra_widget_data, ¶ms_maptypes_ids, sizeof(gpointer));
282 maps_layer_params[0].widget_data = params_maptypes;
283 maps_layer_params[0].extra_widget_data = params_maptypes_ids;
286 void _update_map_source ( const char *label, VikMapSource *map, int index )
288 GList *item = g_list_nth (__map_types, index);
289 g_object_unref (item->data);
290 item->data = g_object_ref (map);
291 /* Change previous data */
292 g_free (params_maptypes[index]);
293 params_maptypes[index] = g_strdup (label);
297 * maps_layer_register_map_source:
298 * @map: the new VikMapSource
300 * Register a new VikMapSource.
301 * Override existing one (equality of id).
303 void maps_layer_register_map_source ( VikMapSource *map )
305 g_assert(map != NULL);
307 guint id = vik_map_source_get_uniq_id(map);
308 const char *label = vik_map_source_get_label(map);
309 g_assert(label != NULL);
311 int previous = map_uniq_id_to_index (id);
312 if (previous != NUM_MAP_TYPES)
314 _update_map_source (label, map, previous);
318 _add_map_source (id, label, map);
322 #define MAPS_LAYER_NTH_LABEL(n) (params_maptypes[n])
323 #define MAPS_LAYER_NTH_ID(n) (params_maptypes_ids[n])
324 #define MAPS_LAYER_NTH_TYPE(n) (VIK_MAP_SOURCE(g_list_nth_data(__map_types, (n))))
326 gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
328 return(vml->maptype);
331 gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
333 return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
336 /****************************************/
337 /******** CACHE DIR STUFF ***************/
338 /****************************************/
340 #define DIRECTDIRACCESS "%s%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d%s"
341 #define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
342 #define MAPS_CACHE_DIR maps_layer_default_dir()
346 #define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
347 #define LOCAL_MAPS_DIR "VIKING-MAPS"
348 #elif defined __APPLE__
350 #define GLOBAL_MAPS_DIR "/Library/cache/Viking/maps/"
351 #define LOCAL_MAPS_DIR "/Library/Application Support/Viking/viking-maps"
354 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
355 #define LOCAL_MAPS_DIR ".viking-maps"
358 gchar *maps_layer_default_dir ()
360 static gchar *defaultdir = NULL;
363 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
364 const gchar *mapdir = g_getenv("VIKING_MAPS");
366 defaultdir = g_strdup ( mapdir );
367 } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
368 defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
370 const gchar *home = g_get_home_dir();
371 if (!home || g_access(home, W_OK))
372 home = g_get_home_dir ();
374 defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
376 defaultdir = g_strdup ( LOCAL_MAPS_DIR );
378 if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
380 /* Add the separator at the end */
381 gchar *tmp = defaultdir;
382 defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
385 g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
390 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
392 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
394 g_mkdir ( vml->cache_dir, 0777 );
398 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
401 g_assert ( vml != NULL);
402 g_free ( vml->cache_dir );
403 vml->cache_dir = NULL;
405 if ( dir == NULL || dir[0] == '\0' )
407 if ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir") )
408 vml->cache_dir = g_strdup ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir")->s );
413 if ( dir[len-1] != G_DIR_SEPARATOR )
415 vml->cache_dir = g_malloc ( len+2 );
416 strncpy ( vml->cache_dir, dir, len );
417 vml->cache_dir[len] = G_DIR_SEPARATOR;
418 vml->cache_dir[len+1] = '\0';
421 vml->cache_dir = g_strdup ( dir );
423 maps_layer_mkdir_if_default_dir ( vml );
426 /****************************************/
427 /******** GOBJECT STUFF *****************/
428 /****************************************/
430 GType vik_maps_layer_get_type ()
432 static GType vml_type = 0;
436 static const GTypeInfo vml_info =
438 sizeof (VikMapsLayerClass),
439 NULL, /* base_init */
440 NULL, /* base_finalize */
441 NULL, /* class init */
442 NULL, /* class_finalize */
443 NULL, /* class_data */
444 sizeof (VikMapsLayer),
446 NULL /* instance init */
448 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
454 /****************************************/
455 /************** PARAMETERS **************/
456 /****************************************/
458 static guint map_index_to_uniq_id (guint8 index)
460 g_assert ( index < NUM_MAP_TYPES );
461 return vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(index));
464 static guint map_uniq_id_to_index ( guint uniq_id )
467 for ( i = 0; i < NUM_MAP_TYPES; i++ )
468 if ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(i)) == uniq_id )
470 return NUM_MAP_TYPES; /* no such thing */
473 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation )
475 // When loading from a file don't need the license reminder
476 if ( is_file_operation )
477 vml->license_notice_shown = TRUE;
481 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
482 case PARAM_MAPTYPE: {
483 gint maptype = map_uniq_id_to_index(data.u);
484 if ( maptype == NUM_MAP_TYPES ) g_warning(_("Unknown map type"));
485 else vml->maptype = maptype;
488 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
489 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
490 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
491 vml->mapzoom_id = data.u;
492 vml->xmapzoom = __mapzooms_x [data.u];
493 vml->ymapzoom = __mapzooms_y [data.u];
494 }else g_warning (_("Unknown Map Zoom")); break;
499 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation )
501 VikLayerParamData rv;
504 case PARAM_CACHE_DIR: rv.s = vml->cache_dir ? vml->cache_dir : ""; break;
505 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
506 case PARAM_ALPHA: rv.u = vml->alpha; break;
507 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
508 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
513 /****************************************/
514 /****** CREATING, COPYING, FREEING ******/
515 /****************************************/
517 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
520 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
521 vik_layer_init ( VIK_LAYER(vml), VIK_LAYER_MAPS );
522 idx = map_uniq_id_to_index(19); /* 19 is id for OSM MapQuest maps */
523 vml->maptype = (idx < NUM_MAP_TYPES) ? idx : 0;
524 vml->maptype = (idx < NUM_MAP_TYPES) ? idx : 0;
527 vml->dl_tool_x = vml->dl_tool_y = -1;
528 maps_layer_set_cache_dir ( vml, NULL );
529 vml->autodownload = FALSE;
530 vml->last_center = NULL;
531 vml->last_xmpp = 0.0;
532 vml->last_ympp = 0.0;
534 vml->dl_right_click_menu = NULL;
535 vml->license_notice_shown = FALSE;
540 static void maps_layer_free ( VikMapsLayer *vml )
542 g_free ( vml->cache_dir );
543 vml->cache_dir = NULL;
544 if ( vml->dl_right_click_menu )
545 g_object_ref_sink ( G_OBJECT(vml->dl_right_click_menu) );
546 g_free(vml->last_center);
547 vml->last_center = NULL;
550 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
552 if (from_file != TRUE)
554 /* If this method is not called in file reading context
555 * it is called in GUI context.
556 * So, we can check if we have to inform the user about inconsistency */
557 VikViewportDrawMode vp_drawmode;
558 VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
559 VikMapSource *map = NULL;
561 vp_drawmode = vik_viewport_get_drawmode ( vp );
562 map = MAPS_LAYER_NTH_TYPE(vml->maptype);
563 if (vik_map_source_get_drawmode(map) != vp_drawmode) {
564 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vp, vik_map_source_get_drawmode(map));
565 gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
566 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_WIDGET(vp), msg );
570 if (vik_map_source_get_license (map) != NULL) {
571 if ( ! vml->license_notice_shown ) {
572 a_dialog_license (VIK_GTK_WINDOW_FROM_WIDGET(vp), vik_map_source_get_label (map),
573 vik_map_source_get_license (map), vik_map_source_get_license_url (map) );
574 vml->license_notice_shown = TRUE;
580 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml )
582 return vik_maps_layer_get_map_label ( vml );
585 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
587 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
590 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
592 VikMapsLayer *rv = maps_layer_new ( vvp );
593 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
597 /*********************/
598 /****** DRAWING ******/
599 /*********************/
601 static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
604 gint width, height, iii, jjj;
606 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
608 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
609 g_object_unref(G_OBJECT(pixbuf));
613 pixels = gdk_pixbuf_get_pixels(pixbuf);
614 width = gdk_pixbuf_get_width(pixbuf);
615 height = gdk_pixbuf_get_height(pixbuf);
617 /* r,g,b,a,r,g,b,a.... */
618 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
626 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
629 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
630 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_NEAREST);
631 g_object_unref ( G_OBJECT(pixbuf) );
635 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
640 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
641 mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
644 if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
645 g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS,
646 vml->cache_dir, (17 - mapcoord->scale), mapcoord->x, mapcoord->y, ".png" );
648 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
649 vml->cache_dir, mode,
650 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
652 if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
655 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
657 /* free the pixbuf on error */
660 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
661 g_warning ( _("Couldn't open image file: %s"), gx->message );
665 g_object_unref ( G_OBJECT(pixbuf) );
668 if ( vml->alpha < 255 )
669 pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
670 if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
671 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
673 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
674 mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
675 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
682 gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
684 const VikCoord *center = vik_viewport_get_center ( vvp );
686 if (vik_window_get_pan_move (VIK_WINDOW(VIK_GTK_WINDOW_FROM_WIDGET(GTK_WIDGET(vvp)))))
687 /* D'n'D pan in action: do not download */
690 if (vml->last_center == NULL) {
691 VikCoord *new_center = g_malloc(sizeof(VikCoord));
692 *new_center = *center;
693 vml->last_center = new_center;
694 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
695 vml->last_ympp = vik_viewport_get_ympp(vvp);
699 /* TODO: perhaps vik_coord_diff() */
700 if (vik_coord_equals(vml->last_center, center)
701 && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
702 && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
705 *(vml->last_center) = *center;
706 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
707 vml->last_ympp = vik_viewport_get_ympp(vvp);
711 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
714 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
715 gdouble yzoom = vik_viewport_get_ympp ( vvp );
716 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
717 gboolean existence_only = FALSE;
719 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
720 xshrinkfactor = vml->xmapzoom / xzoom;
721 yshrinkfactor = vml->ymapzoom / yzoom;
722 xzoom = vml->xmapzoom;
723 yzoom = vml->xmapzoom;
724 if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
725 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
726 if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR )
727 existence_only = TRUE;
729 g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
736 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
737 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
738 vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
742 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
743 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
744 gint mode = vik_map_source_get_uniq_id(map);
747 gint xx, yy, width, height;
750 guint max_path_len = strlen(vml->cache_dir) + 40;
751 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
753 if ( (!existence_only) && vml->autodownload && should_start_autodownload(vml, vvp)) {
754 g_debug("%s: Starting autodownload", __FUNCTION__);
755 if ( vik_map_source_supports_download_only_new (map) )
756 // Try to download newer tiles
757 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NEW );
759 // Download only missing tiles
760 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
763 if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
764 for ( x = xmin; x <= xmax; x++ ) {
765 for ( y = ymin; y <= ymax; y++ ) {
768 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
770 width = gdk_pixbuf_get_width ( pixbuf );
771 height = gdk_pixbuf_get_height ( pixbuf );
773 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
774 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
778 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
782 } else { /* tilesize is known, don't have to keep converting coords */
783 gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
784 gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
785 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
786 gint tilesize_x_ceil = ceil ( tilesize_x );
787 gint tilesize_y_ceil = ceil ( tilesize_y );
788 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
789 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
790 gdouble xx, yy; gint xx_tmp, yy_tmp;
791 gint base_yy, xend, yend;
793 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
794 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
796 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
797 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
798 xx = xx_tmp; yy = yy_tmp;
799 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
800 * eg if tile size 128, shrinkfactor 0.333 */
801 xx -= (tilesize_x/2);
802 base_yy = yy - (tilesize_y/2);
804 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
806 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
810 if ( existence_only ) {
811 if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
812 g_snprintf ( path_buf, max_path_len, DIRECTDIRACCESS,
813 vml->cache_dir, (17 - ulm.scale), ulm.x, ulm.y, ".png" );
815 g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE,
816 vml->cache_dir, mode,
817 ulm.scale, ulm.z, ulm.x, ulm.y );
818 if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
819 GdkGC *black_gc = GTK_WIDGET(vvp)->style->black_gc;
820 vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
824 for (scale_inc = 0; scale_inc < 4; scale_inc ++) {
825 /* try with correct then smaller zooms */
826 int scale_factor = 1 << scale_inc; /* 2^scale_inc */
828 ulm2.x = ulm.x / scale_factor;
829 ulm2.y = ulm.y / scale_factor;
830 ulm2.scale = ulm.scale + scale_inc;
831 pixbuf = get_pixbuf ( vml, mode, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
833 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
834 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
836 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);
838 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
843 /* retry with bigger zooms */
845 for (scale_dec = 1; scale_dec < 2; scale_dec ++) {
847 int scale_factor = 1 << scale_dec; /* 2^scale_dec */
849 ulm2.x = ulm.x * scale_factor;
850 ulm2.y = ulm.y * scale_factor;
851 ulm2.scale = ulm.scale - scale_dec;
852 for (pict_x = 0; pict_x < scale_factor; pict_x ++) {
853 for (pict_y = 0; pict_y < scale_factor; pict_y ++) {
854 MapCoord ulm3 = ulm2;
857 pixbuf = get_pixbuf ( vml, mode, &ulm3, path_buf, max_path_len, xshrinkfactor / scale_factor, yshrinkfactor / scale_factor );
861 gint dest_x = xx + pict_x * (tilesize_x_ceil / scale_factor);
862 gint dest_y = yy + pict_y * (tilesize_y_ceil / scale_factor);
863 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, dest_x, dest_y, tilesize_x_ceil / scale_factor, tilesize_y_ceil / scale_factor );
881 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
883 if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
888 gdouble level = vik_viewport_get_zoom ( vvp );
890 vik_viewport_get_min_max_lat_lon ( vvp, &bbox.south, &bbox.north, &bbox.west, &bbox.east );
891 vik_map_source_get_copyright ( MAPS_LAYER_NTH_TYPE(vml->maptype), bbox, level, vik_viewport_add_copyright, vvp );
894 const GdkPixbuf *logo = vik_map_source_get_logo ( MAPS_LAYER_NTH_TYPE(vml->maptype) );
895 vik_viewport_add_logo ( vvp, logo );
897 /* get corner coords */
898 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
899 /* UTM multi-zone stuff by Kit Transue */
900 gchar leftmost_zone, rightmost_zone, i;
901 leftmost_zone = vik_viewport_leftmost_zone( vvp );
902 rightmost_zone = vik_viewport_rightmost_zone( vvp );
903 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
904 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
905 maps_layer_draw_section ( vml, vvp, &ul, &br );
909 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
910 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
912 maps_layer_draw_section ( vml, vvp, &ul, &br );
917 /*************************/
918 /****** DOWNLOADING ******/
919 /*************************/
921 /* pass along data to thread, exists even if layer is deleted. */
931 gboolean refresh_display;
934 gboolean map_layer_alive;
938 static void mdi_free ( MapDownloadInfo *mdi )
940 g_mutex_free(mdi->mutex);
941 g_free ( mdi->cache_dir );
942 mdi->cache_dir = NULL;
943 g_free ( mdi->filename_buf );
944 mdi->filename_buf = NULL;
948 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
950 MapDownloadInfo *mdi = ptr;
951 g_mutex_lock(mdi->mutex);
952 mdi->map_layer_alive = FALSE;
953 g_mutex_unlock(mdi->mutex);
956 static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
958 void *handle = vik_map_source_download_handle_init(MAPS_LAYER_NTH_TYPE(mdi->maptype));
961 for ( x = mdi->x0; x <= mdi->xf; x++ )
963 for ( y = mdi->y0; y <= mdi->yf; y++ )
965 gboolean remove_mem_cache = FALSE;
966 gboolean need_download = FALSE;
967 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
968 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
969 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
972 int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
974 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
978 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
979 need_download = TRUE;
980 remove_mem_cache = TRUE;
982 } else { /* in case map file already exists */
983 switch (mdi->redownload) {
984 case REDOWNLOAD_NONE:
989 /* see if this one is bad or what */
991 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
992 if (gx || (!pixbuf)) {
993 g_remove ( mdi->filename_buf );
994 need_download = TRUE;
995 remove_mem_cache = TRUE;
999 g_object_unref ( pixbuf );
1004 case REDOWNLOAD_NEW:
1005 need_download = TRUE;
1006 remove_mem_cache = TRUE;
1009 case REDOWNLOAD_ALL:
1010 /* FIXME: need a better way than to erase file in case of server/network problem */
1011 g_remove ( mdi->filename_buf );
1012 need_download = TRUE;
1013 remove_mem_cache = TRUE;
1016 case DOWNLOAD_OR_REFRESH:
1017 remove_mem_cache = TRUE;
1021 g_warning ( "redownload state %d unknown\n", mdi->redownload);
1025 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
1027 if (need_download) {
1028 if ( vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf, handle))
1032 g_mutex_lock(mdi->mutex);
1033 if (remove_mem_cache)
1034 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 );
1035 if (mdi->refresh_display && mdi->map_layer_alive) {
1036 /* TODO: check if it's on visible area */
1037 vik_layer_emit_update ( VIK_LAYER(mdi->vml), TRUE ); // Yes update display from background
1039 g_mutex_unlock(mdi->mutex);
1040 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
1044 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1045 g_mutex_lock(mdi->mutex);
1046 if (mdi->map_layer_alive)
1047 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1048 g_mutex_unlock(mdi->mutex);
1052 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
1054 if ( mdi->mapcoord.x || mdi->mapcoord.y )
1056 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1057 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1058 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
1059 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
1061 g_remove ( mdi->filename_buf );
1066 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
1068 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1069 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1071 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1073 // Don't ever attempt download on direct access
1074 if ( vik_map_source_is_direct_file_access ( map ) )
1077 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm )
1078 && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
1080 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
1085 mdi->map_layer_alive = TRUE;
1086 mdi->mutex = g_mutex_new();
1087 mdi->refresh_display = TRUE;
1089 /* cache_dir and buffer for dest filename */
1090 mdi->cache_dir = g_strdup ( vml->cache_dir );
1091 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1092 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1093 mdi->maptype = vml->maptype;
1095 mdi->mapcoord = ulm;
1097 mdi->redownload = redownload;
1099 mdi->x0 = MIN(ulm.x, brm.x);
1100 mdi->xf = MAX(ulm.x, brm.x);
1101 mdi->y0 = MIN(ulm.y, brm.y);
1102 mdi->yf = MAX(ulm.y, brm.y);
1106 if ( mdi->redownload ) {
1107 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1109 /* calculate how many we need */
1110 for ( a = mdi->x0; a <= mdi->xf; a++ )
1112 for ( b = mdi->y0; b <= mdi->yf; b++ )
1114 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1115 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1117 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1123 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1125 if ( mdi->mapstoget )
1127 const gchar *tmp_str;
1132 if (redownload == REDOWNLOAD_BAD)
1133 tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
1135 tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
1139 tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
1141 tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
1143 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1144 /* launch the thread */
1145 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1146 tmp, /* description string */
1147 (vik_thr_func) map_download_thread, /* function to call within thread */
1148 mdi, /* pass along data */
1149 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1150 (vik_thr_free_func) mdi_cancel_cleanup,
1159 void maps_layer_download_section_without_redraw( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
1162 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1164 // Don't ever attempt download on direct access
1165 if ( vik_map_source_is_direct_file_access ( map ) )
1168 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
1169 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
1170 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
1174 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1179 mdi->map_layer_alive = TRUE;
1180 mdi->mutex = g_mutex_new();
1181 mdi->refresh_display = FALSE;
1183 mdi->cache_dir = g_strdup ( vml->cache_dir );
1184 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1185 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1186 mdi->maptype = vml->maptype;
1188 mdi->mapcoord = ulm;
1190 mdi->redownload = REDOWNLOAD_NONE;
1192 mdi->x0 = MIN(ulm.x, brm.x);
1193 mdi->xf = MAX(ulm.x, brm.x);
1194 mdi->y0 = MIN(ulm.y, brm.y);
1195 mdi->yf = MAX(ulm.y, brm.y);
1199 for (i = mdi->x0; i <= mdi->xf; i++) {
1200 for (j = mdi->y0; j <= mdi->yf; j++) {
1201 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1202 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1204 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1209 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1211 if (mdi->mapstoget) {
1214 fmt = ngettext("Downloading %d %s map...",
1215 "Downloading %d %s maps...",
1217 tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
1219 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1220 /* launch the thread */
1221 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1222 tmp, /* description string */
1223 (vik_thr_func) map_download_thread, /* function to call within thread */
1224 mdi, /* pass along data */
1225 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1226 (vik_thr_free_func) mdi_cancel_cleanup,
1234 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1236 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1239 static void maps_layer_redownload_all ( VikMapsLayer *vml )
1241 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1244 static void maps_layer_redownload_new ( VikMapsLayer *vml )
1246 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
1249 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1251 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1253 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1255 if ( event->button == 1 )
1258 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 );
1259 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 );
1260 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
1261 vml->dl_tool_x = vml->dl_tool_y = -1;
1266 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) );
1267 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) );
1269 vml->redownload_vvp = vvp;
1271 vml->dl_tool_x = vml->dl_tool_y = -1;
1273 if ( ! vml->dl_right_click_menu ) {
1275 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1277 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _Bad Map(s)") );
1278 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1279 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1281 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _New Map(s)") );
1282 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), vml );
1283 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1285 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _All Map(s)") );
1286 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1287 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1290 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1291 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1297 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1302 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1305 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1307 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1308 if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
1309 vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
1310 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1311 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1313 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1320 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1324 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1325 if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1326 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1327 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1329 gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1330 vml->cache_dir, __map_types[vml->maptype].uniq_id,
1331 mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1333 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1334 g_free ( filename_buf );
1335 vik_layer_emit_update ( VIK_LAYER(vml) );
1343 static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
1345 VikMapsLayer *vml = vml_vvp[0];
1346 VikViewport *vvp = vml_vvp[1];
1347 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
1349 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1350 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1355 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1356 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1358 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1359 if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
1360 vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
1361 vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
1362 start_download_thread ( vml, vvp, &ul, &br, redownload );
1363 else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
1364 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
1365 gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
1366 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1370 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
1374 static void maps_layer_download_missing_onscreen_maps ( gpointer vml_vvp[2] )
1376 download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1379 static void maps_layer_download_new_onscreen_maps ( gpointer vml_vvp[2] )
1381 download_onscreen_maps( vml_vvp, REDOWNLOAD_NEW);
1384 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1386 download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1389 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1391 static gpointer pass_along[2];
1393 pass_along[0] = vml;
1394 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1396 item = gtk_menu_item_new();
1397 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1398 gtk_widget_show ( item );
1400 /* Now with icons */
1401 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _Missing Onscreen Maps") );
1402 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
1403 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), pass_along );
1404 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1405 gtk_widget_show ( item );
1407 if ( vik_map_source_supports_download_only_new (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
1408 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _New Onscreen Maps") );
1409 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REDO, GTK_ICON_SIZE_MENU) );
1410 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), pass_along );
1411 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1412 gtk_widget_show ( item );
1415 item = gtk_image_menu_item_new_with_mnemonic ( _("Reload _All Onscreen Maps") );
1416 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
1417 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1418 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1419 gtk_widget_show ( item );