Use combobox to select map type
[viking/guyou.git] / src / vikmapslayer.c
blob2f65002a173c307a5ef708261f0d06073676c369
1 /*
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
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
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 */
34 #include <gtk/gtk.h>
35 #include <gdk-pixbuf/gdk-pixdata.h>
36 #include <glib.h>
37 #include <glib/gstdio.h>
38 #include <glib/gi18n.h>
40 #ifdef HAVE_STRING_H
41 #include <string.h>
42 #endif
43 #ifdef HAVE_MATH_H
44 #include <math.h>
45 #endif
47 #include "globals.h"
48 #include "coords.h"
49 #include "vikcoord.h"
50 #include "viktreeview.h"
51 #include "vikviewport.h"
52 #include "viklayer.h"
53 #include "vikmapslayer.h"
55 #ifdef HAVE_UNISTD_H
56 #include <unistd.h>
57 #endif
59 #include "mapcache.h"
60 /* only for dialog.h -- ugh */
61 #include "vikwaypoint.h"
62 #include "dialog.h"
64 #include "vikstatus.h"
65 #include "background.h"
67 #include "vikaggregatelayer.h"
68 #include "viklayerspanel.h"
70 #include "mapcoord.h"
71 #include "terraserver.h"
73 #include "icons/icons.h"
75 /****** MAP TYPES ******/
77 static GList *__map_types = NULL;
79 #define NUM_MAP_TYPES g_list_length(__map_types)
81 /* List of label for each map type */
82 static gchar **params_maptypes = NULL;
84 /* Corresponding IDS. (Cf. field uniq_id in VikMapsLayer struct) */
85 static guint *params_maptypes_ids = NULL;
87 /******** MAPZOOMS *********/
89 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 };
90 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 };
91 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 };
93 #define NUM_MAPZOOMS (sizeof(params_mapzooms)/sizeof(params_mapzooms[0]) - 1)
95 /**************************/
98 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file);
99 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len );
100 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
101 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp );
102 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id );
103 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp );
104 static VikMapsLayer *maps_layer_new ( VikViewport *vvp );
105 static void maps_layer_free ( VikMapsLayer *vml );
106 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
107 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
108 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp );
109 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir );
110 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload );
111 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp );
114 static VikLayerParamScale params_scales[] = {
115 /* min, max, step, digits (decimal places) */
116 { 0, 255, 3, 0 }, /* alpha */
119 VikLayerParam maps_layer_params[] = {
120 { "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Map Type:"), VIK_LAYER_WIDGET_COMBOBOX, NULL, NULL },
121 { "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Maps Directory:"), VIK_LAYER_WIDGET_FOLDERENTRY },
122 { "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales },
123 { "autodownload", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload maps:"), VIK_LAYER_WIDGET_CHECKBUTTON },
124 { "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Zoom Level:"), VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms, NULL },
127 enum { PARAM_MAPTYPE=0, PARAM_CACHE_DIR, PARAM_ALPHA, PARAM_AUTODOWNLOAD, PARAM_MAPZOOM, NUM_PARAMS };
129 static VikToolInterface maps_tools[] = {
130 { N_("Maps Download"), (VikToolConstructorFunc) maps_layer_download_create, NULL, NULL, NULL,
131 (VikToolMouseFunc) maps_layer_download_click, NULL, (VikToolMouseFunc) maps_layer_download_release,
132 (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_mapdl_pixbuf },
135 VikLayerInterface vik_maps_layer_interface = {
136 N_("Map"),
137 &vikmapslayer_pixbuf,
139 maps_tools,
140 sizeof(maps_tools) / sizeof(maps_tools[0]),
142 maps_layer_params,
143 NUM_PARAMS,
144 NULL,
147 VIK_MENU_ITEM_ALL,
149 (VikLayerFuncCreate) maps_layer_new,
150 (VikLayerFuncRealize) NULL,
151 (VikLayerFuncPostRead) maps_layer_post_read,
152 (VikLayerFuncFree) maps_layer_free,
154 (VikLayerFuncProperties) NULL,
155 (VikLayerFuncDraw) maps_layer_draw,
156 (VikLayerFuncChangeCoordMode) NULL,
158 (VikLayerFuncSetMenuItemsSelection) NULL,
159 (VikLayerFuncGetMenuItemsSelection) NULL,
161 (VikLayerFuncAddMenuItems) maps_layer_add_menu_items,
162 (VikLayerFuncSublayerAddMenuItems) NULL,
164 (VikLayerFuncSublayerRenameRequest) NULL,
165 (VikLayerFuncSublayerToggleVisible) NULL,
167 (VikLayerFuncMarshall) maps_layer_marshall,
168 (VikLayerFuncUnmarshall) maps_layer_unmarshall,
170 (VikLayerFuncSetParam) maps_layer_set_param,
171 (VikLayerFuncGetParam) maps_layer_get_param,
173 (VikLayerFuncReadFileData) NULL,
174 (VikLayerFuncWriteFileData) NULL,
176 (VikLayerFuncDeleteItem) NULL,
177 (VikLayerFuncCopyItem) NULL,
178 (VikLayerFuncPasteItem) NULL,
179 (VikLayerFuncFreeCopiedItem) NULL,
180 (VikLayerFuncDragDropRequest) NULL,
183 struct _VikMapsLayer {
184 VikLayer vl;
185 guint maptype;
186 gchar *cache_dir;
187 guint8 alpha;
188 guint mapzoom_id;
189 gdouble xmapzoom, ymapzoom;
191 gboolean autodownload;
192 VikCoord *last_center;
193 gdouble last_xmpp;
194 gdouble last_ympp;
196 gint dl_tool_x, dl_tool_y;
198 GtkMenu *dl_right_click_menu;
199 VikCoord redownload_ul, redownload_br; /* right click menu only */
200 VikViewport *redownload_vvp;
203 enum { REDOWNLOAD_NONE = 0, /* download only missing maps */
204 REDOWNLOAD_BAD, /* download missing and bad maps */
205 REDOWNLOAD_NEW, /* download missing maps that are newer on server only */
206 REDOWNLOAD_ALL, /* download all maps */
207 DOWNLOAD_OR_REFRESH }; /* download missing maps and refresh cache */
210 /****************************************/
211 /******** MAPS LAYER TYPES **************/
212 /****************************************/
214 void maps_layer_register_map_source ( VikMapSource *map )
216 g_assert(map != NULL);
218 guint id = vik_map_source_get_uniq_id(map);
219 const char *label = vik_map_source_get_label(map);
220 g_assert(label != NULL);
222 gsize len = 0;
223 if (params_maptypes)
224 len = g_strv_length (params_maptypes);
225 /* Add the label */
226 params_maptypes = g_realloc (params_maptypes, (len+2)*sizeof(gchar*));
227 params_maptypes[len] = g_strdup (label);
228 params_maptypes[len+1] = NULL;
230 /* Add the id */
231 params_maptypes_ids = g_realloc (params_maptypes_ids, (len+2)*sizeof(guint));
232 params_maptypes_ids[len] = id;
233 params_maptypes_ids[len+1] = 0;
235 /* We have to clone */
236 VikMapSource *clone = VIK_MAP_SOURCE(g_object_ref(map));
237 /* Register the clone in the list */
238 __map_types = g_list_append(__map_types, clone);
240 /* Hack
241 We have to ensure the mode LayerParam reference the up-to-date
242 GLists.
245 memcpy(&maps_layer_params[0].widget_data, &params_maptypes, sizeof(gpointer));
246 memcpy(&maps_layer_params[0].extra_widget_data, &params_maptypes_ids, sizeof(gpointer));
248 maps_layer_params[0].widget_data = params_maptypes;
249 maps_layer_params[0].extra_widget_data = params_maptypes_ids;
252 #define MAPS_LAYER_NTH_LABEL(n) (params_maptypes[n])
253 #define MAPS_LAYER_NTH_ID(n) (params_maptypes_ids[n])
254 #define MAPS_LAYER_NTH_TYPE(n) (VIK_MAP_SOURCE(g_list_nth_data(__map_types, (n))))
256 gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
258 return(vml->maptype);
261 gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
263 return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
266 /****************************************/
267 /******** CACHE DIR STUFF ***************/
268 /****************************************/
270 #define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
271 #define MAPS_CACHE_DIR maps_layer_default_dir()
273 #ifdef WINDOWS
274 #include <io.h>
275 #define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
276 #define LOCAL_MAPS_DIR "VIKING-MAPS"
277 #else /* POSIX */
278 #include <stdlib.h>
279 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
280 #define LOCAL_MAPS_DIR ".viking-maps"
281 #endif
283 gchar *maps_layer_default_dir ()
285 static gchar *defaultdir = NULL;
286 if ( ! defaultdir )
288 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
289 const gchar *mapdir = g_getenv("VIKING_MAPS");
290 if ( mapdir ) {
291 defaultdir = g_strdup ( mapdir );
292 } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
293 defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
294 } else {
295 const gchar *home = g_get_home_dir();
296 if (!home || g_access(home, W_OK))
297 home = g_get_home_dir ();
298 if ( home )
299 defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
300 else
301 defaultdir = g_strdup ( LOCAL_MAPS_DIR );
303 if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
305 /* Add the separator at the end */
306 gchar *tmp = defaultdir;
307 defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
308 g_free(tmp);
310 g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
312 return defaultdir;
315 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
317 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
319 g_mkdir ( vml->cache_dir, 0777 );
323 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
325 guint len;
326 g_assert ( vml != NULL);
327 g_free ( vml->cache_dir );
328 vml->cache_dir = NULL;
330 if ( dir == NULL || dir[0] == '\0' )
331 vml->cache_dir = g_strdup ( MAPS_CACHE_DIR );
332 else
334 len = strlen(dir);
335 if ( dir[len-1] != G_DIR_SEPARATOR )
337 vml->cache_dir = g_malloc ( len+2 );
338 strncpy ( vml->cache_dir, dir, len );
339 vml->cache_dir[len] = G_DIR_SEPARATOR;
340 vml->cache_dir[len+1] = '\0';
342 else
343 vml->cache_dir = g_strdup ( dir );
345 maps_layer_mkdir_if_default_dir ( vml );
348 /****************************************/
349 /******** GOBJECT STUFF *****************/
350 /****************************************/
352 GType vik_maps_layer_get_type ()
354 static GType vml_type = 0;
356 if (!vml_type)
358 static const GTypeInfo vml_info =
360 sizeof (VikMapsLayerClass),
361 NULL, /* base_init */
362 NULL, /* base_finalize */
363 NULL, /* class init */
364 NULL, /* class_finalize */
365 NULL, /* class_data */
366 sizeof (VikMapsLayer),
368 NULL /* instance init */
370 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
373 return vml_type;
376 /****************************************/
377 /************** PARAMETERS **************/
378 /****************************************/
380 static guint map_index_to_uniq_id (guint8 index)
382 g_assert ( index < NUM_MAP_TYPES );
383 return vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(index));
386 static guint map_uniq_id_to_index ( guint uniq_id )
388 gint i;
389 for ( i = 0; i < NUM_MAP_TYPES; i++ )
390 if ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(i)) == uniq_id )
391 return i;
392 return NUM_MAP_TYPES; /* no such thing */
395 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp )
397 switch ( id )
399 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
400 case PARAM_MAPTYPE: {
401 gint maptype = map_uniq_id_to_index(data.u);
402 if ( maptype == NUM_MAP_TYPES ) g_warning(_("Unknown map type"));
403 else vml->maptype = maptype;
404 break;
406 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
407 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
408 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
409 vml->mapzoom_id = data.u;
410 vml->xmapzoom = __mapzooms_x [data.u];
411 vml->ymapzoom = __mapzooms_y [data.u];
412 }else g_warning (_("Unknown Map Zoom")); break;
414 return TRUE;
417 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id )
419 VikLayerParamData rv;
420 switch ( id )
422 case PARAM_CACHE_DIR: rv.s = vml->cache_dir ? vml->cache_dir : ""; break;
423 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
424 case PARAM_ALPHA: rv.u = vml->alpha; break;
425 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
426 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
428 return rv;
431 /****************************************/
432 /****** CREATING, COPYING, FREEING ******/
433 /****************************************/
435 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
437 int idx;
438 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
439 vik_layer_init ( VIK_LAYER(vml), VIK_LAYER_MAPS );
440 idx = map_uniq_id_to_index(13); /* 13 is id for OSM Mapnik maps */
441 vml->maptype = (idx < NUM_MAP_TYPES) ? idx : 0;
442 vml->alpha = 255;
443 vml->mapzoom_id = 0;
444 vml->dl_tool_x = vml->dl_tool_y = -1;
445 maps_layer_set_cache_dir ( vml, NULL );
446 vml->autodownload = FALSE;
447 vml->last_center = NULL;
448 vml->last_xmpp = 0.0;
449 vml->last_ympp = 0.0;
451 vml->dl_right_click_menu = NULL;
453 return vml;
456 static void maps_layer_free ( VikMapsLayer *vml )
458 g_free ( vml->cache_dir );
459 vml->cache_dir = NULL;
460 if ( vml->dl_right_click_menu )
461 gtk_object_sink ( GTK_OBJECT(vml->dl_right_click_menu) );
462 g_free(vml->last_center);
463 vml->last_center = NULL;
466 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
468 if (from_file != TRUE)
470 /* If this method is not called in file reading context
471 * it is called in GUI context.
472 * So, we can check if we have to inform the user about inconsistency */
473 VikViewportDrawMode vp_drawmode;
474 VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
475 VikMapSource *map = NULL;
477 vp_drawmode = vik_viewport_get_drawmode ( VIK_VIEWPORT(vp) );
478 map = MAPS_LAYER_NTH_TYPE(vml->maptype);
479 if (vik_map_source_get_drawmode(map) != vp_drawmode) {
480 const gchar *drawmode_name = vik_viewport_get_drawmode_name (VIK_VIEWPORT(vp), vik_map_source_get_drawmode(map));
481 gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
482 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), msg );
483 g_free(msg);
488 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
490 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
493 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
495 VikMapsLayer *rv = maps_layer_new ( vvp );
496 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
497 return rv;
500 /*********************/
501 /****** DRAWING ******/
502 /*********************/
504 static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
506 guchar *pixels;
507 gint width, height, iii, jjj;
509 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
511 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
512 g_object_unref(G_OBJECT(pixbuf));
513 pixbuf = tmp;
516 pixels = gdk_pixbuf_get_pixels(pixbuf);
517 width = gdk_pixbuf_get_width(pixbuf);
518 height = gdk_pixbuf_get_height(pixbuf);
520 /* r,g,b,a,r,g,b,a.... */
521 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
523 pixels += 3;
524 *pixels++ = alpha;
526 return pixbuf;
529 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
531 GdkPixbuf *tmp;
532 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
533 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_NEAREST);
534 g_object_unref ( G_OBJECT(pixbuf) );
535 return tmp;
538 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
540 GdkPixbuf *pixbuf;
542 /* get the thing */
543 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
544 mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
546 if ( ! pixbuf ) {
547 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
548 vml->cache_dir, mode,
549 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
550 if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE) {
552 GError *gx = NULL;
553 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
555 if (gx)
557 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
558 g_warning ( _("Couldn't open image file: %s"), gx->message );
560 g_error_free ( gx );
561 if ( pixbuf )
562 g_object_unref ( G_OBJECT(pixbuf) );
563 pixbuf = NULL;
564 } else {
565 if ( vml->alpha < 255 )
566 pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
567 if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
568 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
570 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
571 mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
572 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
577 return pixbuf;
580 gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
582 const VikCoord *center = vik_viewport_get_center ( vvp );
584 if (vml->last_center == NULL) {
585 VikCoord *new_center = g_malloc(sizeof(VikCoord));
586 *new_center = *center;
587 vml->last_center = new_center;
588 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
589 vml->last_ympp = vik_viewport_get_ympp(vvp);
590 return TRUE;
593 /* TODO: perhaps vik_coord_diff() */
594 if (vik_coord_equals(vml->last_center, center)
595 && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
596 && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
597 return FALSE;
599 *(vml->last_center) = *center;
600 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
601 vml->last_ympp = vik_viewport_get_ympp(vvp);
602 return TRUE;
605 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
607 MapCoord ulm, brm;
608 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
609 gdouble yzoom = vik_viewport_get_ympp ( vvp );
610 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
611 gdouble existence_only = FALSE;
613 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
614 xshrinkfactor = vml->xmapzoom / xzoom;
615 yshrinkfactor = vml->ymapzoom / yzoom;
616 xzoom = vml->xmapzoom;
617 yzoom = vml->xmapzoom;
618 if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
619 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
620 if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR )
621 existence_only = TRUE;
622 else {
623 g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
624 return;
629 /* coord -> ID */
630 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
631 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
632 vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
634 /* loop & draw */
635 gint x, y;
636 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
637 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
638 gint mode = vik_map_source_get_uniq_id(map);
640 VikCoord coord;
641 gint xx, yy, width, height;
642 GdkPixbuf *pixbuf;
644 guint max_path_len = strlen(vml->cache_dir) + 40;
645 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
647 if ( (!existence_only) && vml->autodownload && should_start_autodownload(vml, vvp)) {
648 #ifdef DEBUG
649 fputs(stderr, "DEBUG: Starting autodownload\n");
650 #endif
651 if ( vik_map_source_supports_if_modified_since (map) )
652 // Try to download newer tiles
653 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NEW );
654 else
655 // Download only missing tiles
656 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
659 if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
660 for ( x = xmin; x <= xmax; x++ ) {
661 for ( y = ymin; y <= ymax; y++ ) {
662 ulm.x = x;
663 ulm.y = y;
664 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
665 if ( pixbuf ) {
666 width = gdk_pixbuf_get_width ( pixbuf );
667 height = gdk_pixbuf_get_height ( pixbuf );
669 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
670 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
671 xx -= (width/2);
672 yy -= (height/2);
674 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
678 } else { /* tilesize is known, don't have to keep converting coords */
679 gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
680 gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
681 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
682 gint tilesize_x_ceil = ceil ( tilesize_x );
683 gint tilesize_y_ceil = ceil ( tilesize_y );
684 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
685 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
686 gdouble xx, yy; gint xx_tmp, yy_tmp;
687 gint base_yy, xend, yend;
689 GdkGC *black_gc = GTK_WIDGET(vvp)->style->black_gc;
691 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
692 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
694 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
695 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
696 xx = xx_tmp; yy = yy_tmp;
697 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
698 * eg if tile size 128, shrinkfactor 0.333 */
699 xx -= (tilesize_x/2);
700 base_yy = yy - (tilesize_y/2);
702 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
703 yy = base_yy;
704 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
705 ulm.x = x;
706 ulm.y = y;
708 if ( existence_only ) {
709 g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE,
710 vml->cache_dir, mode,
711 ulm.scale, ulm.z, ulm.x, ulm.y );
712 if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
713 vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
715 } else {
716 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
717 if ( pixbuf )
718 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
719 else {
720 /* retry with bigger shrinkfactor */
721 int scale_inc;
722 for (scale_inc = 1; scale_inc < 4; scale_inc ++) {
723 int scale_factor = 1 << scale_inc; /* 2^scale_inc */
724 MapCoord ulm2 = ulm;
725 ulm2.x = ulm.x / scale_factor;
726 ulm2.y = ulm.y / scale_factor;
727 ulm2.scale = ulm.scale + scale_inc;
728 pixbuf = get_pixbuf ( vml, mode, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
729 if ( pixbuf ) {
730 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
731 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
732 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
733 break;
739 yy += tilesize_y;
741 xx += tilesize_x;
745 g_free ( path_buf );
749 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
751 if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
753 VikCoord ul, br;
755 /* get corner coords */
756 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
757 /* UTM multi-zone stuff by Kit Transue */
758 gchar leftmost_zone, rightmost_zone, i;
759 leftmost_zone = vik_viewport_leftmost_zone( vvp );
760 rightmost_zone = vik_viewport_rightmost_zone( vvp );
761 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
762 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
763 maps_layer_draw_section ( vml, vvp, &ul, &br );
766 else {
767 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
768 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
770 maps_layer_draw_section ( vml, vvp, &ul, &br );
775 /*************************/
776 /****** DOWNLOADING ******/
777 /*************************/
779 /* pass along data to thread, exists even if layer is deleted. */
780 typedef struct {
781 gchar *cache_dir;
782 gchar *filename_buf;
783 gint x0, y0, xf, yf;
784 MapCoord mapcoord;
785 gint maptype;
786 gint maxlen;
787 gint mapstoget;
788 gint redownload;
789 gboolean refresh_display;
790 VikMapsLayer *vml;
791 VikViewport *vvp;
792 gboolean map_layer_alive;
793 GMutex *mutex;
794 } MapDownloadInfo;
796 static void mdi_free ( MapDownloadInfo *mdi )
798 g_mutex_free(mdi->mutex);
799 g_free ( mdi->cache_dir );
800 mdi->cache_dir = NULL;
801 g_free ( mdi->filename_buf );
802 mdi->filename_buf = NULL;
803 g_free ( mdi );
806 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
808 MapDownloadInfo *mdi = ptr;
809 g_mutex_lock(mdi->mutex);
810 mdi->map_layer_alive = FALSE;
811 g_mutex_unlock(mdi->mutex);
814 static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
816 guint donemaps = 0;
817 gint x, y;
818 for ( x = mdi->x0; x <= mdi->xf; x++ )
820 for ( y = mdi->y0; y <= mdi->yf; y++ )
822 gboolean remove_mem_cache = FALSE;
823 gboolean need_download = FALSE;
824 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
825 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
826 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
828 donemaps++;
829 int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
830 if (res != 0)
831 return -1;
833 if ( mdi->redownload == REDOWNLOAD_ALL)
834 g_remove ( mdi->filename_buf );
836 else if ( (mdi->redownload == REDOWNLOAD_BAD) && (g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE) )
838 /* see if this one is bad or what */
839 GError *gx = NULL;
840 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
841 if (gx || (!pixbuf))
842 g_remove ( mdi->filename_buf );
843 if ( pixbuf )
844 g_object_unref ( pixbuf );
845 if ( gx )
846 g_error_free ( gx );
849 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
851 need_download = TRUE;
852 if (( mdi->redownload != REDOWNLOAD_NONE ) &&
853 ( mdi->redownload != DOWNLOAD_OR_REFRESH ))
854 remove_mem_cache = TRUE;
855 } else if ( mdi->redownload == DOWNLOAD_OR_REFRESH ) {
856 remove_mem_cache = TRUE;
857 } else if ( mdi->redownload == REDOWNLOAD_NEW) {
858 need_download = TRUE;
859 remove_mem_cache = TRUE;
860 } else
861 continue;
863 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
865 if (need_download) {
866 if ( vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf ))
867 continue;
870 gdk_threads_enter();
871 g_mutex_lock(mdi->mutex);
872 if (remove_mem_cache)
873 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 );
874 if (mdi->refresh_display && mdi->map_layer_alive) {
875 /* TODO: check if it's on visible area */
876 vik_layer_emit_update ( VIK_LAYER(mdi->vml) );
878 g_mutex_unlock(mdi->mutex);
879 gdk_threads_leave();
880 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
884 g_mutex_lock(mdi->mutex);
885 if (mdi->map_layer_alive)
886 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
887 g_mutex_unlock(mdi->mutex);
888 return 0;
891 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
893 if ( mdi->mapcoord.x || mdi->mapcoord.y )
895 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
896 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
897 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
898 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
900 g_remove ( mdi->filename_buf );
905 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
907 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
908 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
909 MapCoord ulm, brm;
910 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
911 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm )
912 && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
914 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
915 gint a, b;
917 mdi->vml = vml;
918 mdi->vvp = vvp;
919 mdi->map_layer_alive = TRUE;
920 mdi->mutex = g_mutex_new();
921 mdi->refresh_display = TRUE;
923 /* cache_dir and buffer for dest filename */
924 mdi->cache_dir = g_strdup ( vml->cache_dir );
925 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
926 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
927 mdi->maptype = vml->maptype;
929 mdi->mapcoord = ulm;
931 mdi->redownload = redownload;
933 mdi->x0 = MIN(ulm.x, brm.x);
934 mdi->xf = MAX(ulm.x, brm.x);
935 mdi->y0 = MIN(ulm.y, brm.y);
936 mdi->yf = MAX(ulm.y, brm.y);
938 mdi->mapstoget = 0;
940 if ( mdi->redownload ) {
941 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
942 } else {
943 /* calculate how many we need */
944 for ( a = mdi->x0; a <= mdi->xf; a++ )
946 for ( b = mdi->y0; b <= mdi->yf; b++ )
948 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
949 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
950 ulm.z, a, b );
951 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
952 mdi->mapstoget++;
957 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
959 if ( mdi->mapstoget )
961 const gchar *tmp_str;
962 gchar *tmp;
964 if (redownload)
966 if (redownload == REDOWNLOAD_BAD)
967 tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
968 else
969 tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
971 else
973 tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
975 tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
977 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
978 /* launch the thread */
979 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
980 tmp, /* description string */
981 (vik_thr_func) map_download_thread, /* function to call within thread */
982 mdi, /* pass along data */
983 (vik_thr_free_func) mdi_free, /* function to free pass along data */
984 (vik_thr_free_func) mdi_cancel_cleanup,
985 mdi->mapstoget );
986 g_free ( tmp );
988 else
989 mdi_free ( mdi );
993 void maps_layer_download_section_without_redraw( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
995 MapCoord ulm, brm;
996 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
998 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
999 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
1000 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
1001 return;
1004 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1005 gint i, j;
1007 mdi->vml = vml;
1008 mdi->vvp = vvp;
1009 mdi->map_layer_alive = TRUE;
1010 mdi->mutex = g_mutex_new();
1011 mdi->refresh_display = FALSE;
1013 mdi->cache_dir = g_strdup ( vml->cache_dir );
1014 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1015 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1016 mdi->maptype = vml->maptype;
1018 mdi->mapcoord = ulm;
1020 mdi->redownload = REDOWNLOAD_NONE;
1022 mdi->x0 = MIN(ulm.x, brm.x);
1023 mdi->xf = MAX(ulm.x, brm.x);
1024 mdi->y0 = MIN(ulm.y, brm.y);
1025 mdi->yf = MAX(ulm.y, brm.y);
1027 mdi->mapstoget = 0;
1029 for (i = mdi->x0; i <= mdi->xf; i++) {
1030 for (j = mdi->y0; j <= mdi->yf; j++) {
1031 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1032 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1033 ulm.z, i, j );
1034 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1035 mdi->mapstoget++;
1039 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1041 if (mdi->mapstoget) {
1042 gchar *tmp;
1043 const gchar *fmt;
1044 fmt = ngettext("Downloading %d %s map...",
1045 "Downloading %d %s maps...",
1046 mdi->mapstoget);
1047 tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
1049 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1050 /* launch the thread */
1051 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1052 tmp, /* description string */
1053 (vik_thr_func) map_download_thread, /* function to call within thread */
1054 mdi, /* pass along data */
1055 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1056 (vik_thr_free_func) mdi_cancel_cleanup,
1057 mdi->mapstoget );
1058 g_free ( tmp );
1060 else
1061 mdi_free ( mdi );
1064 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1066 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1069 static void maps_layer_redownload_all ( VikMapsLayer *vml )
1071 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1074 static void maps_layer_redownload_new ( VikMapsLayer *vml )
1076 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
1079 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1081 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1082 return FALSE;
1083 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1085 if ( event->button == 1 )
1087 VikCoord ul, br;
1088 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 );
1089 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 );
1090 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
1091 vml->dl_tool_x = vml->dl_tool_y = -1;
1092 return TRUE;
1094 else
1096 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) );
1097 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) );
1099 vml->redownload_vvp = vvp;
1101 vml->dl_tool_x = vml->dl_tool_y = -1;
1103 if ( ! vml->dl_right_click_menu ) {
1104 GtkWidget *item;
1105 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1107 item = gtk_menu_item_new_with_label ( _("Redownload bad map(s)") );
1108 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1109 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1111 item = gtk_menu_item_new_with_label ( _("Redownload new map(s)") );
1112 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), vml );
1113 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1115 item = gtk_menu_item_new_with_label ( _("Redownload all map(s)") );
1116 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1117 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1120 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1121 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1124 return FALSE;
1127 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1129 return vvp;
1132 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1134 MapCoord tmp;
1135 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1136 return FALSE;
1137 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1138 if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
1139 vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
1140 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1141 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1142 &tmp ) ) {
1143 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1144 return TRUE;
1146 return FALSE;
1149 #if 0
1150 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1152 VikCoord coord;
1153 MapCoord mapcoord;
1154 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1155 if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1156 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1157 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1158 &mapcoord ) ) {
1159 gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1160 vml->cache_dir, __map_types[vml->maptype].uniq_id,
1161 mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1163 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1164 g_free ( filename_buf );
1165 vik_layer_emit_update ( VIK_LAYER(vml) );
1166 return TRUE;
1169 return FALSE;
1170 #endif
1173 static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
1175 VikMapsLayer *vml = vml_vvp[0];
1176 VikViewport *vvp = vml_vvp[1];
1177 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
1179 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1180 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1182 VikCoord ul, br;
1183 MapCoord ulm, brm;
1185 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1186 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1188 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1189 if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
1190 vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
1191 vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
1192 start_download_thread ( vml, vvp, &ul, &br, redownload );
1193 else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
1194 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
1195 gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
1196 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1197 g_free(err);
1199 else
1200 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
1204 static void maps_layer_download_missing_onscreen_maps ( gpointer vml_vvp[2] )
1206 download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1209 static void maps_layer_download_new_onscreen_maps ( gpointer vml_vvp[2] )
1211 download_onscreen_maps( vml_vvp, REDOWNLOAD_NEW);
1214 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1216 download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1219 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1221 static gpointer pass_along[2];
1222 GtkWidget *item;
1223 pass_along[0] = vml;
1224 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1226 item = gtk_menu_item_new();
1227 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1228 gtk_widget_show ( item );
1230 item = gtk_menu_item_new_with_label ( _("Download missing Onscreen Maps") );
1231 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), pass_along );
1232 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1233 gtk_widget_show ( item );
1235 if ( vik_map_source_supports_if_modified_since (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
1236 item = gtk_menu_item_new_with_label ( _("Download new Onscreen Maps from server") );
1237 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), pass_along );
1238 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1239 gtk_widget_show ( item );
1242 /* TODO Add GTK_STOCK_REFRESH icon */
1243 item = gtk_menu_item_new_with_label ( _("Refresh Onscreen Tiles") );
1244 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1245 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1246 gtk_widget_show ( item );