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,
173 (VikLayerFuncMarshall) maps_layer_marshall,
174 (VikLayerFuncUnmarshall) maps_layer_unmarshall,
176 (VikLayerFuncSetParam) maps_layer_set_param,
177 (VikLayerFuncGetParam) maps_layer_get_param,
179 (VikLayerFuncReadFileData) NULL,
180 (VikLayerFuncWriteFileData) NULL,
182 (VikLayerFuncDeleteItem) NULL,
183 (VikLayerFuncCutItem) NULL,
184 (VikLayerFuncCopyItem) NULL,
185 (VikLayerFuncPasteItem) NULL,
186 (VikLayerFuncFreeCopiedItem) NULL,
187 (VikLayerFuncDragDropRequest) NULL,
190 struct _VikMapsLayer {
196 gdouble xmapzoom, ymapzoom;
198 gboolean autodownload;
199 VikCoord *last_center;
203 gint dl_tool_x, dl_tool_y;
205 GtkMenu *dl_right_click_menu;
206 VikCoord redownload_ul, redownload_br; /* right click menu only */
207 VikViewport *redownload_vvp;
209 gboolean license_notice_shown; // FALSE for new maps only, otherwise
210 // TRUE for saved maps & other layer changes as we don't need to show it again
213 enum { REDOWNLOAD_NONE = 0, /* download only missing maps */
214 REDOWNLOAD_BAD, /* download missing and bad maps */
215 REDOWNLOAD_NEW, /* download missing maps that are newer on server only */
216 REDOWNLOAD_ALL, /* download all maps */
217 DOWNLOAD_OR_REFRESH }; /* download missing maps and refresh cache */
219 static VikLayerParam prefs[] = {
220 { VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Default maplayer directory:"), VIK_LAYER_WIDGET_FOLDERENTRY, NULL, NULL },
223 void maps_layer_init ()
225 VikLayerParamData tmp;
226 tmp.s = maps_layer_default_dir();
227 a_preferences_register(prefs, tmp, VIKING_PREFERENCES_GROUP_KEY);
230 /****************************************/
231 /******** MAPS LAYER TYPES **************/
232 /****************************************/
234 int _get_index_for_id ( guint id )
237 while (params_maptypes_ids[index] != 0)
239 if (params_maptypes_ids[index] == id)
246 void _add_map_source ( guint id, const char *label, VikMapSource *map )
250 len = g_strv_length (params_maptypes);
252 params_maptypes = g_realloc (params_maptypes, (len+2)*sizeof(gchar*));
253 params_maptypes[len] = g_strdup (label);
254 params_maptypes[len+1] = NULL;
257 params_maptypes_ids = g_realloc (params_maptypes_ids, (len+2)*sizeof(guint));
258 params_maptypes_ids[len] = id;
259 params_maptypes_ids[len+1] = 0;
261 /* We have to clone */
262 VikMapSource *clone = VIK_MAP_SOURCE(g_object_ref(map));
263 /* Register the clone in the list */
264 __map_types = g_list_append(__map_types, clone);
267 We have to ensure the mode LayerParam references the up-to-date
271 memcpy(&maps_layer_params[0].widget_data, ¶ms_maptypes, sizeof(gpointer));
272 memcpy(&maps_layer_params[0].extra_widget_data, ¶ms_maptypes_ids, sizeof(gpointer));
274 maps_layer_params[0].widget_data = params_maptypes;
275 maps_layer_params[0].extra_widget_data = params_maptypes_ids;
278 void _update_map_source ( const char *label, VikMapSource *map, int index )
280 GList *item = g_list_nth (__map_types, index);
281 g_object_unref (item->data);
282 item->data = g_object_ref (map);
283 /* Change previous data */
284 g_free (params_maptypes[index]);
285 params_maptypes[index] = g_strdup (label);
288 void maps_layer_register_map_source ( VikMapSource *map )
290 g_assert(map != NULL);
292 guint id = vik_map_source_get_uniq_id(map);
293 const char *label = vik_map_source_get_label(map);
294 g_assert(label != NULL);
296 int previous = map_uniq_id_to_index (id);
297 if (previous != NUM_MAP_TYPES)
299 _update_map_source (label, map, previous);
303 _add_map_source (id, label, map);
307 #define MAPS_LAYER_NTH_LABEL(n) (params_maptypes[n])
308 #define MAPS_LAYER_NTH_ID(n) (params_maptypes_ids[n])
309 #define MAPS_LAYER_NTH_TYPE(n) (VIK_MAP_SOURCE(g_list_nth_data(__map_types, (n))))
311 gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
313 return(vml->maptype);
316 gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
318 return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
321 /****************************************/
322 /******** CACHE DIR STUFF ***************/
323 /****************************************/
325 #define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
326 #define MAPS_CACHE_DIR maps_layer_default_dir()
330 #define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
331 #define LOCAL_MAPS_DIR "VIKING-MAPS"
334 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
335 #define LOCAL_MAPS_DIR ".viking-maps"
338 gchar *maps_layer_default_dir ()
340 static gchar *defaultdir = NULL;
343 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
344 const gchar *mapdir = g_getenv("VIKING_MAPS");
346 defaultdir = g_strdup ( mapdir );
347 } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
348 defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
350 const gchar *home = g_get_home_dir();
351 if (!home || g_access(home, W_OK))
352 home = g_get_home_dir ();
354 defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
356 defaultdir = g_strdup ( LOCAL_MAPS_DIR );
358 if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
360 /* Add the separator at the end */
361 gchar *tmp = defaultdir;
362 defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
365 g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
370 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
372 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
374 g_mkdir ( vml->cache_dir, 0777 );
378 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
381 g_assert ( vml != NULL);
382 g_free ( vml->cache_dir );
383 vml->cache_dir = NULL;
385 if ( dir == NULL || dir[0] == '\0' )
387 if ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir") )
388 vml->cache_dir = g_strdup ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir")->s );
393 if ( dir[len-1] != G_DIR_SEPARATOR )
395 vml->cache_dir = g_malloc ( len+2 );
396 strncpy ( vml->cache_dir, dir, len );
397 vml->cache_dir[len] = G_DIR_SEPARATOR;
398 vml->cache_dir[len+1] = '\0';
401 vml->cache_dir = g_strdup ( dir );
403 maps_layer_mkdir_if_default_dir ( vml );
406 /****************************************/
407 /******** GOBJECT STUFF *****************/
408 /****************************************/
410 GType vik_maps_layer_get_type ()
412 static GType vml_type = 0;
416 static const GTypeInfo vml_info =
418 sizeof (VikMapsLayerClass),
419 NULL, /* base_init */
420 NULL, /* base_finalize */
421 NULL, /* class init */
422 NULL, /* class_finalize */
423 NULL, /* class_data */
424 sizeof (VikMapsLayer),
426 NULL /* instance init */
428 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
434 /****************************************/
435 /************** PARAMETERS **************/
436 /****************************************/
438 static guint map_index_to_uniq_id (guint8 index)
440 g_assert ( index < NUM_MAP_TYPES );
441 return vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(index));
444 static guint map_uniq_id_to_index ( guint uniq_id )
447 for ( i = 0; i < NUM_MAP_TYPES; i++ )
448 if ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(i)) == uniq_id )
450 return NUM_MAP_TYPES; /* no such thing */
453 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation )
455 // When loading from a file don't need the license reminder
456 if ( is_file_operation )
457 vml->license_notice_shown = TRUE;
461 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
462 case PARAM_MAPTYPE: {
463 gint maptype = map_uniq_id_to_index(data.u);
464 if ( maptype == NUM_MAP_TYPES ) g_warning(_("Unknown map type"));
465 else vml->maptype = maptype;
468 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
469 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
470 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
471 vml->mapzoom_id = data.u;
472 vml->xmapzoom = __mapzooms_x [data.u];
473 vml->ymapzoom = __mapzooms_y [data.u];
474 }else g_warning (_("Unknown Map Zoom")); break;
479 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation )
481 VikLayerParamData rv;
484 case PARAM_CACHE_DIR: rv.s = vml->cache_dir ? vml->cache_dir : ""; break;
485 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
486 case PARAM_ALPHA: rv.u = vml->alpha; break;
487 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
488 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
493 /****************************************/
494 /****** CREATING, COPYING, FREEING ******/
495 /****************************************/
497 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
500 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
501 vik_layer_init ( VIK_LAYER(vml), VIK_LAYER_MAPS );
502 idx = map_uniq_id_to_index(13); /* 13 is id for OSM Mapnik maps */
503 vml->maptype = (idx < NUM_MAP_TYPES) ? idx : 0;
506 vml->dl_tool_x = vml->dl_tool_y = -1;
507 maps_layer_set_cache_dir ( vml, NULL );
508 vml->autodownload = FALSE;
509 vml->last_center = NULL;
510 vml->last_xmpp = 0.0;
511 vml->last_ympp = 0.0;
513 vml->dl_right_click_menu = NULL;
514 vml->license_notice_shown = FALSE;
519 static void maps_layer_free ( VikMapsLayer *vml )
521 g_free ( vml->cache_dir );
522 vml->cache_dir = NULL;
523 if ( vml->dl_right_click_menu )
524 gtk_object_sink ( GTK_OBJECT(vml->dl_right_click_menu) );
525 g_free(vml->last_center);
526 vml->last_center = NULL;
529 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
531 if (from_file != TRUE)
533 /* If this method is not called in file reading context
534 * it is called in GUI context.
535 * So, we can check if we have to inform the user about inconsistency */
536 VikViewportDrawMode vp_drawmode;
537 VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
538 VikMapSource *map = NULL;
540 vp_drawmode = vik_viewport_get_drawmode ( vp );
541 map = MAPS_LAYER_NTH_TYPE(vml->maptype);
542 if (vik_map_source_get_drawmode(map) != vp_drawmode) {
543 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vp, vik_map_source_get_drawmode(map));
544 gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
545 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_WIDGET(vp), msg );
549 if (vik_map_source_get_license (map) != NULL) {
550 if ( ! vml->license_notice_shown ) {
551 a_dialog_license (VIK_GTK_WINDOW_FROM_WIDGET(vp), vik_map_source_get_label (map),
552 vik_map_source_get_license (map), vik_map_source_get_license_url (map) );
553 vml->license_notice_shown = TRUE;
559 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml )
561 return vik_maps_layer_get_map_label ( vml );
564 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
566 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
569 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
571 VikMapsLayer *rv = maps_layer_new ( vvp );
572 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
576 /*********************/
577 /****** DRAWING ******/
578 /*********************/
580 static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
583 gint width, height, iii, jjj;
585 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
587 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
588 g_object_unref(G_OBJECT(pixbuf));
592 pixels = gdk_pixbuf_get_pixels(pixbuf);
593 width = gdk_pixbuf_get_width(pixbuf);
594 height = gdk_pixbuf_get_height(pixbuf);
596 /* r,g,b,a,r,g,b,a.... */
597 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
605 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
608 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
609 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_NEAREST);
610 g_object_unref ( G_OBJECT(pixbuf) );
614 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
619 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
620 mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
623 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
624 vml->cache_dir, mode,
625 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
626 if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
629 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
631 /* free the pixbuf on error */
634 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
635 g_warning ( _("Couldn't open image file: %s"), gx->message );
639 g_object_unref ( G_OBJECT(pixbuf) );
642 if ( vml->alpha < 255 )
643 pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
644 if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
645 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
647 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
648 mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
649 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
656 gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
658 const VikCoord *center = vik_viewport_get_center ( vvp );
660 if (vik_window_get_pan_move (VIK_WINDOW(VIK_GTK_WINDOW_FROM_WIDGET(GTK_WIDGET(vvp)))))
661 /* D'n'D pan in action: do not download */
664 if (vml->last_center == NULL) {
665 VikCoord *new_center = g_malloc(sizeof(VikCoord));
666 *new_center = *center;
667 vml->last_center = new_center;
668 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
669 vml->last_ympp = vik_viewport_get_ympp(vvp);
673 /* TODO: perhaps vik_coord_diff() */
674 if (vik_coord_equals(vml->last_center, center)
675 && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
676 && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
679 *(vml->last_center) = *center;
680 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
681 vml->last_ympp = vik_viewport_get_ympp(vvp);
685 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
688 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
689 gdouble yzoom = vik_viewport_get_ympp ( vvp );
690 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
691 gdouble existence_only = FALSE;
693 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
694 xshrinkfactor = vml->xmapzoom / xzoom;
695 yshrinkfactor = vml->ymapzoom / yzoom;
696 xzoom = vml->xmapzoom;
697 yzoom = vml->xmapzoom;
698 if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
699 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
700 if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR )
701 existence_only = TRUE;
703 g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
710 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
711 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
712 vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
716 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
717 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
718 gint mode = vik_map_source_get_uniq_id(map);
721 gint xx, yy, width, height;
724 guint max_path_len = strlen(vml->cache_dir) + 40;
725 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
727 if ( (!existence_only) && vml->autodownload && should_start_autodownload(vml, vvp)) {
728 g_debug("%s: Starting autodownload", __FUNCTION__);
729 if ( vik_map_source_supports_download_only_new (map) )
730 // Try to download newer tiles
731 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NEW );
733 // Download only missing tiles
734 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
737 if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
738 for ( x = xmin; x <= xmax; x++ ) {
739 for ( y = ymin; y <= ymax; y++ ) {
742 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
744 width = gdk_pixbuf_get_width ( pixbuf );
745 height = gdk_pixbuf_get_height ( pixbuf );
747 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
748 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
752 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
756 } else { /* tilesize is known, don't have to keep converting coords */
757 gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
758 gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
759 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
760 gint tilesize_x_ceil = ceil ( tilesize_x );
761 gint tilesize_y_ceil = ceil ( tilesize_y );
762 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
763 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
764 gdouble xx, yy; gint xx_tmp, yy_tmp;
765 gint base_yy, xend, yend;
767 GdkGC *black_gc = GTK_WIDGET(vvp)->style->black_gc;
769 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
770 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
772 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
773 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
774 xx = xx_tmp; yy = yy_tmp;
775 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
776 * eg if tile size 128, shrinkfactor 0.333 */
777 xx -= (tilesize_x/2);
778 base_yy = yy - (tilesize_y/2);
780 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
782 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
786 if ( existence_only ) {
787 g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE,
788 vml->cache_dir, mode,
789 ulm.scale, ulm.z, ulm.x, ulm.y );
790 if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
791 vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
795 for (scale_inc = 0; scale_inc < 4; scale_inc ++) {
796 /* try with correct then smaller zooms */
797 int scale_factor = 1 << scale_inc; /* 2^scale_inc */
799 ulm2.x = ulm.x / scale_factor;
800 ulm2.y = ulm.y / scale_factor;
801 ulm2.scale = ulm.scale + scale_inc;
802 pixbuf = get_pixbuf ( vml, mode, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
804 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
805 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
807 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);
809 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
814 /* retry with bigger zooms */
816 for (scale_dec = 1; scale_dec < 2; scale_dec ++) {
818 int scale_factor = 1 << scale_dec; /* 2^scale_dec */
820 ulm2.x = ulm.x * scale_factor;
821 ulm2.y = ulm.y * scale_factor;
822 ulm2.scale = ulm.scale - scale_dec;
823 for (pict_x = 0; pict_x < scale_factor; pict_x ++) {
824 for (pict_y = 0; pict_y < scale_factor; pict_y ++) {
825 MapCoord ulm3 = ulm2;
828 pixbuf = get_pixbuf ( vml, mode, &ulm3, path_buf, max_path_len, xshrinkfactor / scale_factor, yshrinkfactor / scale_factor );
832 gint dest_x = xx + pict_x * (tilesize_x_ceil / scale_factor);
833 gint dest_y = yy + pict_y * (tilesize_y_ceil / scale_factor);
834 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, dest_x, dest_y, tilesize_x_ceil / scale_factor, tilesize_y_ceil / scale_factor );
852 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
854 if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
859 const gchar *copyright = vik_map_source_get_copyright ( MAPS_LAYER_NTH_TYPE(vml->maptype) );
860 vik_viewport_add_copyright ( vvp, copyright );
862 /* get corner coords */
863 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
864 /* UTM multi-zone stuff by Kit Transue */
865 gchar leftmost_zone, rightmost_zone, i;
866 leftmost_zone = vik_viewport_leftmost_zone( vvp );
867 rightmost_zone = vik_viewport_rightmost_zone( vvp );
868 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
869 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
870 maps_layer_draw_section ( vml, vvp, &ul, &br );
874 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
875 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
877 maps_layer_draw_section ( vml, vvp, &ul, &br );
882 /*************************/
883 /****** DOWNLOADING ******/
884 /*************************/
886 /* pass along data to thread, exists even if layer is deleted. */
896 gboolean refresh_display;
899 gboolean map_layer_alive;
903 static void mdi_free ( MapDownloadInfo *mdi )
905 g_mutex_free(mdi->mutex);
906 g_free ( mdi->cache_dir );
907 mdi->cache_dir = NULL;
908 g_free ( mdi->filename_buf );
909 mdi->filename_buf = NULL;
913 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
915 MapDownloadInfo *mdi = ptr;
916 g_mutex_lock(mdi->mutex);
917 mdi->map_layer_alive = FALSE;
918 g_mutex_unlock(mdi->mutex);
921 static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
923 void *handle = vik_map_source_download_handle_init(MAPS_LAYER_NTH_TYPE(mdi->maptype));
926 for ( x = mdi->x0; x <= mdi->xf; x++ )
928 for ( y = mdi->y0; y <= mdi->yf; y++ )
930 gboolean remove_mem_cache = FALSE;
931 gboolean need_download = FALSE;
932 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
933 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
934 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
937 int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
939 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
943 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
944 need_download = TRUE;
945 remove_mem_cache = TRUE;
947 } else { /* in case map file already exists */
948 switch (mdi->redownload) {
949 case REDOWNLOAD_NONE:
954 /* see if this one is bad or what */
956 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
957 if (gx || (!pixbuf)) {
958 g_remove ( mdi->filename_buf );
959 need_download = TRUE;
960 remove_mem_cache = TRUE;
964 g_object_unref ( pixbuf );
970 need_download = TRUE;
971 remove_mem_cache = TRUE;
975 /* FIXME: need a better way than to erase file in case of server/network problem */
976 g_remove ( mdi->filename_buf );
977 need_download = TRUE;
978 remove_mem_cache = TRUE;
981 case DOWNLOAD_OR_REFRESH:
982 remove_mem_cache = TRUE;
986 g_warning ( "redownload state %d unknown\n", mdi->redownload);
990 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
993 if ( vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf, handle))
998 g_mutex_lock(mdi->mutex);
999 if (remove_mem_cache)
1000 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 );
1001 if (mdi->refresh_display && mdi->map_layer_alive) {
1002 /* TODO: check if it's on visible area */
1003 vik_layer_emit_update ( VIK_LAYER(mdi->vml) );
1005 g_mutex_unlock(mdi->mutex);
1006 gdk_threads_leave();
1007 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
1011 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1012 g_mutex_lock(mdi->mutex);
1013 if (mdi->map_layer_alive)
1014 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1015 g_mutex_unlock(mdi->mutex);
1019 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
1021 if ( mdi->mapcoord.x || mdi->mapcoord.y )
1023 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1024 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1025 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
1026 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
1028 g_remove ( mdi->filename_buf );
1033 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
1035 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1036 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1038 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1039 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm )
1040 && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
1042 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
1047 mdi->map_layer_alive = TRUE;
1048 mdi->mutex = g_mutex_new();
1049 mdi->refresh_display = TRUE;
1051 /* cache_dir and buffer for dest filename */
1052 mdi->cache_dir = g_strdup ( vml->cache_dir );
1053 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1054 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1055 mdi->maptype = vml->maptype;
1057 mdi->mapcoord = ulm;
1059 mdi->redownload = redownload;
1061 mdi->x0 = MIN(ulm.x, brm.x);
1062 mdi->xf = MAX(ulm.x, brm.x);
1063 mdi->y0 = MIN(ulm.y, brm.y);
1064 mdi->yf = MAX(ulm.y, brm.y);
1068 if ( mdi->redownload ) {
1069 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1071 /* calculate how many we need */
1072 for ( a = mdi->x0; a <= mdi->xf; a++ )
1074 for ( b = mdi->y0; b <= mdi->yf; b++ )
1076 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1077 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1079 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1085 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1087 if ( mdi->mapstoget )
1089 const gchar *tmp_str;
1094 if (redownload == REDOWNLOAD_BAD)
1095 tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
1097 tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
1101 tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
1103 tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
1105 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1106 /* launch the thread */
1107 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1108 tmp, /* description string */
1109 (vik_thr_func) map_download_thread, /* function to call within thread */
1110 mdi, /* pass along data */
1111 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1112 (vik_thr_free_func) mdi_cancel_cleanup,
1121 void maps_layer_download_section_without_redraw( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
1124 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1126 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
1127 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
1128 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
1132 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1137 mdi->map_layer_alive = TRUE;
1138 mdi->mutex = g_mutex_new();
1139 mdi->refresh_display = FALSE;
1141 mdi->cache_dir = g_strdup ( vml->cache_dir );
1142 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1143 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1144 mdi->maptype = vml->maptype;
1146 mdi->mapcoord = ulm;
1148 mdi->redownload = REDOWNLOAD_NONE;
1150 mdi->x0 = MIN(ulm.x, brm.x);
1151 mdi->xf = MAX(ulm.x, brm.x);
1152 mdi->y0 = MIN(ulm.y, brm.y);
1153 mdi->yf = MAX(ulm.y, brm.y);
1157 for (i = mdi->x0; i <= mdi->xf; i++) {
1158 for (j = mdi->y0; j <= mdi->yf; j++) {
1159 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1160 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1162 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1167 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1169 if (mdi->mapstoget) {
1172 fmt = ngettext("Downloading %d %s map...",
1173 "Downloading %d %s maps...",
1175 tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
1177 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1178 /* launch the thread */
1179 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1180 tmp, /* description string */
1181 (vik_thr_func) map_download_thread, /* function to call within thread */
1182 mdi, /* pass along data */
1183 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1184 (vik_thr_free_func) mdi_cancel_cleanup,
1192 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1194 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1197 static void maps_layer_redownload_all ( VikMapsLayer *vml )
1199 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1202 static void maps_layer_redownload_new ( VikMapsLayer *vml )
1204 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
1207 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1209 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1211 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1213 if ( event->button == 1 )
1216 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 );
1217 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 );
1218 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
1219 vml->dl_tool_x = vml->dl_tool_y = -1;
1224 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) );
1225 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) );
1227 vml->redownload_vvp = vvp;
1229 vml->dl_tool_x = vml->dl_tool_y = -1;
1231 if ( ! vml->dl_right_click_menu ) {
1233 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1235 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _Bad Map(s)") );
1236 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1237 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1239 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _New Map(s)") );
1240 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), vml );
1241 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1243 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _All Map(s)") );
1244 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1245 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1248 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1249 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1255 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1260 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1263 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1265 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1266 if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
1267 vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
1268 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1269 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1271 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1278 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1282 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1283 if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1284 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1285 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1287 gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1288 vml->cache_dir, __map_types[vml->maptype].uniq_id,
1289 mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1291 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1292 g_free ( filename_buf );
1293 vik_layer_emit_update ( VIK_LAYER(vml) );
1301 static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
1303 VikMapsLayer *vml = vml_vvp[0];
1304 VikViewport *vvp = vml_vvp[1];
1305 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
1307 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1308 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1313 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1314 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1316 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1317 if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
1318 vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
1319 vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
1320 start_download_thread ( vml, vvp, &ul, &br, redownload );
1321 else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
1322 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
1323 gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
1324 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1328 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
1332 static void maps_layer_download_missing_onscreen_maps ( gpointer vml_vvp[2] )
1334 download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1337 static void maps_layer_download_new_onscreen_maps ( gpointer vml_vvp[2] )
1339 download_onscreen_maps( vml_vvp, REDOWNLOAD_NEW);
1342 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1344 download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1347 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1349 static gpointer pass_along[2];
1351 pass_along[0] = vml;
1352 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1354 item = gtk_menu_item_new();
1355 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1356 gtk_widget_show ( item );
1358 /* Now with icons */
1359 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _Missing Onscreen Maps") );
1360 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
1361 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), pass_along );
1362 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1363 gtk_widget_show ( item );
1365 if ( vik_map_source_supports_download_only_new (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
1366 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _New Onscreen Maps") );
1367 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REDO, GTK_ICON_SIZE_MENU) );
1368 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), pass_along );
1369 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1370 gtk_widget_show ( item );
1373 item = gtk_image_menu_item_new_with_mnemonic ( _("Reload _All Onscreen Maps") );
1374 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
1375 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1376 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1377 gtk_widget_show ( item );