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 g_object_ref_sink ( G_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 gdouble level = vik_viewport_get_zoom ( vvp );
861 vik_viewport_get_min_max_lat_lon ( vvp, &bbox.south, &bbox.north, &bbox.west, &bbox.east );
862 vik_map_source_get_copyright ( MAPS_LAYER_NTH_TYPE(vml->maptype), bbox, level, vik_viewport_add_copyright, vvp );
865 const GdkPixbuf *logo = vik_map_source_get_logo ( MAPS_LAYER_NTH_TYPE(vml->maptype) );
866 vik_viewport_add_logo ( vvp, logo );
868 /* get corner coords */
869 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
870 /* UTM multi-zone stuff by Kit Transue */
871 gchar leftmost_zone, rightmost_zone, i;
872 leftmost_zone = vik_viewport_leftmost_zone( vvp );
873 rightmost_zone = vik_viewport_rightmost_zone( vvp );
874 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
875 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
876 maps_layer_draw_section ( vml, vvp, &ul, &br );
880 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
881 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
883 maps_layer_draw_section ( vml, vvp, &ul, &br );
888 /*************************/
889 /****** DOWNLOADING ******/
890 /*************************/
892 /* pass along data to thread, exists even if layer is deleted. */
902 gboolean refresh_display;
905 gboolean map_layer_alive;
909 static void mdi_free ( MapDownloadInfo *mdi )
911 g_mutex_free(mdi->mutex);
912 g_free ( mdi->cache_dir );
913 mdi->cache_dir = NULL;
914 g_free ( mdi->filename_buf );
915 mdi->filename_buf = NULL;
919 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
921 MapDownloadInfo *mdi = ptr;
922 g_mutex_lock(mdi->mutex);
923 mdi->map_layer_alive = FALSE;
924 g_mutex_unlock(mdi->mutex);
927 static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
929 void *handle = vik_map_source_download_handle_init(MAPS_LAYER_NTH_TYPE(mdi->maptype));
932 for ( x = mdi->x0; x <= mdi->xf; x++ )
934 for ( y = mdi->y0; y <= mdi->yf; y++ )
936 gboolean remove_mem_cache = FALSE;
937 gboolean need_download = FALSE;
938 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
939 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
940 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
943 int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
945 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
949 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
950 need_download = TRUE;
951 remove_mem_cache = TRUE;
953 } else { /* in case map file already exists */
954 switch (mdi->redownload) {
955 case REDOWNLOAD_NONE:
960 /* see if this one is bad or what */
962 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
963 if (gx || (!pixbuf)) {
964 g_remove ( mdi->filename_buf );
965 need_download = TRUE;
966 remove_mem_cache = TRUE;
970 g_object_unref ( pixbuf );
976 need_download = TRUE;
977 remove_mem_cache = TRUE;
981 /* FIXME: need a better way than to erase file in case of server/network problem */
982 g_remove ( mdi->filename_buf );
983 need_download = TRUE;
984 remove_mem_cache = TRUE;
987 case DOWNLOAD_OR_REFRESH:
988 remove_mem_cache = TRUE;
992 g_warning ( "redownload state %d unknown\n", mdi->redownload);
996 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
999 if ( vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf, handle))
1003 gdk_threads_enter();
1004 g_mutex_lock(mdi->mutex);
1005 if (remove_mem_cache)
1006 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 );
1007 if (mdi->refresh_display && mdi->map_layer_alive) {
1008 /* TODO: check if it's on visible area */
1009 vik_layer_emit_update ( VIK_LAYER(mdi->vml) );
1011 g_mutex_unlock(mdi->mutex);
1012 gdk_threads_leave();
1013 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
1017 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1018 g_mutex_lock(mdi->mutex);
1019 if (mdi->map_layer_alive)
1020 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1021 g_mutex_unlock(mdi->mutex);
1025 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
1027 if ( mdi->mapcoord.x || mdi->mapcoord.y )
1029 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1030 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1031 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
1032 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
1034 g_remove ( mdi->filename_buf );
1039 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
1041 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1042 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1044 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1045 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm )
1046 && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
1048 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
1053 mdi->map_layer_alive = TRUE;
1054 mdi->mutex = g_mutex_new();
1055 mdi->refresh_display = TRUE;
1057 /* cache_dir and buffer for dest filename */
1058 mdi->cache_dir = g_strdup ( vml->cache_dir );
1059 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1060 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1061 mdi->maptype = vml->maptype;
1063 mdi->mapcoord = ulm;
1065 mdi->redownload = redownload;
1067 mdi->x0 = MIN(ulm.x, brm.x);
1068 mdi->xf = MAX(ulm.x, brm.x);
1069 mdi->y0 = MIN(ulm.y, brm.y);
1070 mdi->yf = MAX(ulm.y, brm.y);
1074 if ( mdi->redownload ) {
1075 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1077 /* calculate how many we need */
1078 for ( a = mdi->x0; a <= mdi->xf; a++ )
1080 for ( b = mdi->y0; b <= mdi->yf; b++ )
1082 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1083 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1085 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1091 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1093 if ( mdi->mapstoget )
1095 const gchar *tmp_str;
1100 if (redownload == REDOWNLOAD_BAD)
1101 tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
1103 tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
1107 tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
1109 tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
1111 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1112 /* launch the thread */
1113 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1114 tmp, /* description string */
1115 (vik_thr_func) map_download_thread, /* function to call within thread */
1116 mdi, /* pass along data */
1117 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1118 (vik_thr_free_func) mdi_cancel_cleanup,
1127 void maps_layer_download_section_without_redraw( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
1130 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1132 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
1133 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
1134 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
1138 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1143 mdi->map_layer_alive = TRUE;
1144 mdi->mutex = g_mutex_new();
1145 mdi->refresh_display = FALSE;
1147 mdi->cache_dir = g_strdup ( vml->cache_dir );
1148 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1149 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1150 mdi->maptype = vml->maptype;
1152 mdi->mapcoord = ulm;
1154 mdi->redownload = REDOWNLOAD_NONE;
1156 mdi->x0 = MIN(ulm.x, brm.x);
1157 mdi->xf = MAX(ulm.x, brm.x);
1158 mdi->y0 = MIN(ulm.y, brm.y);
1159 mdi->yf = MAX(ulm.y, brm.y);
1163 for (i = mdi->x0; i <= mdi->xf; i++) {
1164 for (j = mdi->y0; j <= mdi->yf; j++) {
1165 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1166 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1168 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1173 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1175 if (mdi->mapstoget) {
1178 fmt = ngettext("Downloading %d %s map...",
1179 "Downloading %d %s maps...",
1181 tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
1183 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1184 /* launch the thread */
1185 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1186 tmp, /* description string */
1187 (vik_thr_func) map_download_thread, /* function to call within thread */
1188 mdi, /* pass along data */
1189 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1190 (vik_thr_free_func) mdi_cancel_cleanup,
1198 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1200 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1203 static void maps_layer_redownload_all ( VikMapsLayer *vml )
1205 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1208 static void maps_layer_redownload_new ( VikMapsLayer *vml )
1210 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
1213 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1215 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1217 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1219 if ( event->button == 1 )
1222 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 );
1223 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 );
1224 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
1225 vml->dl_tool_x = vml->dl_tool_y = -1;
1230 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) );
1231 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) );
1233 vml->redownload_vvp = vvp;
1235 vml->dl_tool_x = vml->dl_tool_y = -1;
1237 if ( ! vml->dl_right_click_menu ) {
1239 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1241 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _Bad Map(s)") );
1242 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1243 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1245 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _New Map(s)") );
1246 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), vml );
1247 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1249 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _All Map(s)") );
1250 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1251 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1254 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1255 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1261 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1266 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1269 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1271 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1272 if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
1273 vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
1274 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1275 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1277 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1284 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1288 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1289 if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1290 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1291 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1293 gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1294 vml->cache_dir, __map_types[vml->maptype].uniq_id,
1295 mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1297 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1298 g_free ( filename_buf );
1299 vik_layer_emit_update ( VIK_LAYER(vml) );
1307 static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
1309 VikMapsLayer *vml = vml_vvp[0];
1310 VikViewport *vvp = vml_vvp[1];
1311 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
1313 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1314 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1319 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1320 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1322 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1323 if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
1324 vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
1325 vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
1326 start_download_thread ( vml, vvp, &ul, &br, redownload );
1327 else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
1328 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
1329 gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
1330 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1334 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
1338 static void maps_layer_download_missing_onscreen_maps ( gpointer vml_vvp[2] )
1340 download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1343 static void maps_layer_download_new_onscreen_maps ( gpointer vml_vvp[2] )
1345 download_onscreen_maps( vml_vvp, REDOWNLOAD_NEW);
1348 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1350 download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1353 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1355 static gpointer pass_along[2];
1357 pass_along[0] = vml;
1358 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1360 item = gtk_menu_item_new();
1361 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1362 gtk_widget_show ( item );
1364 /* Now with icons */
1365 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _Missing Onscreen Maps") );
1366 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
1367 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), pass_along );
1368 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1369 gtk_widget_show ( item );
1371 if ( vik_map_source_supports_download_only_new (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
1372 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _New Onscreen Maps") );
1373 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REDO, GTK_ICON_SIZE_MENU) );
1374 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), pass_along );
1375 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1376 gtk_widget_show ( item );
1379 item = gtk_image_menu_item_new_with_mnemonic ( _("Reload _All Onscreen Maps") );
1380 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
1381 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1382 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1383 gtk_widget_show ( item );