Change interpolation to a faster one
[viking/libcurl_modification.git] / src / vikmapslayer.c
blob2179581b23ab528434884a777791ecfad939fb0a
1 /*
2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
4 * Copyright (C) 2005, Evan Battaglia <viking@greentorch.org>
5 * UTM multi-zone stuff by Kit Transue <notlostyet@didactek.com>
6 * Dynamic map type by Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
28 #define MAX_SHRINKFACTOR 8.0000001 /* zoom 1 viewing 8-tiles */
29 #define MIN_SHRINKFACTOR 0.0312499 /* zoom 32 viewing 1-tiles */
31 #define REAL_MIN_SHRINKFACTOR 0.0039062499 /* if shrinkfactor is between MAX and REAL_MAX, will only check for existence */
33 #include <gtk/gtk.h>
34 #include <gdk-pixbuf/gdk-pixdata.h>
35 #include <glib.h>
36 #include <glib/gstdio.h>
37 #include <glib/gi18n.h>
39 #ifdef HAVE_STRING_H
40 #include <string.h>
41 #endif
42 #ifdef HAVE_MATH_H
43 #include <math.h>
44 #endif
46 #include "globals.h"
47 #include "coords.h"
48 #include "vikcoord.h"
49 #include "viktreeview.h"
50 #include "vikviewport.h"
51 #include "viklayer.h"
52 #include "vikmapslayer.h"
54 #ifdef HAVE_UNISTD_H
55 #include <unistd.h>
56 #endif
58 #include "mapcache.h"
59 /* only for dialog.h -- ugh */
60 #include "vikwaypoint.h"
61 #include "dialog.h"
63 #include "vikstatus.h"
64 #include "background.h"
66 #include "vikaggregatelayer.h"
67 #include "viklayerspanel.h"
69 #include "mapcoord.h"
70 #include "terraserver.h"
72 #include "icons/icons.h"
74 /****** MAP TYPES ******/
76 static GList *__map_types = NULL;
78 #define NUM_MAP_TYPES g_list_length(__map_types)
80 /* List of label for each map type */
81 static GList *params_maptypes = NULL;
83 /* Corresponding IDS. (Cf. field uniq_id in VikMapsLayer struct) */
84 static GList *params_maptypes_ids = NULL;
86 /******** MAPZOOMS *********/
88 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 };
89 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 };
90 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 };
92 #define NUM_MAPZOOMS (sizeof(params_mapzooms)/sizeof(params_mapzooms[0]) - 1)
94 /**************************/
97 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file);
98 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len );
99 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
100 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp );
101 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id );
102 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp );
103 static VikMapsLayer *maps_layer_new ( VikViewport *vvp );
104 static void maps_layer_free ( VikMapsLayer *vml );
105 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
106 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
107 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp );
108 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir );
109 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload );
110 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp );
113 static VikLayerParamScale params_scales[] = {
114 /* min, max, step, digits (decimal places) */
115 { 0, 255, 3, 0 }, /* alpha */
118 VikLayerParam maps_layer_params[] = {
119 { "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Map Type:"), VIK_LAYER_WIDGET_RADIOGROUP, NULL, NULL },
120 { "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Maps Directory (Optional):"), VIK_LAYER_WIDGET_FILEENTRY },
121 { "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales },
122 { "autodownload", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload maps:"), VIK_LAYER_WIDGET_CHECKBUTTON },
123 { "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Zoom Level:"), VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms },
126 enum { PARAM_MAPTYPE=0, PARAM_CACHE_DIR, PARAM_ALPHA, PARAM_AUTODOWNLOAD, PARAM_MAPZOOM, NUM_PARAMS };
128 static VikToolInterface maps_tools[] = {
129 { N_("Maps Download"), (VikToolConstructorFunc) maps_layer_download_create, NULL, NULL, NULL,
130 (VikToolMouseFunc) maps_layer_download_click, NULL, (VikToolMouseFunc) maps_layer_download_release,
131 (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_mapdl_pixbuf },
134 VikLayerInterface vik_maps_layer_interface = {
135 N_("Map"),
136 &vikmapslayer_pixbuf,
138 maps_tools,
139 sizeof(maps_tools) / sizeof(maps_tools[0]),
141 maps_layer_params,
142 NUM_PARAMS,
143 NULL,
146 VIK_MENU_ITEM_ALL,
148 (VikLayerFuncCreate) maps_layer_new,
149 (VikLayerFuncRealize) NULL,
150 (VikLayerFuncPostRead) maps_layer_post_read,
151 (VikLayerFuncFree) maps_layer_free,
153 (VikLayerFuncProperties) NULL,
154 (VikLayerFuncDraw) maps_layer_draw,
155 (VikLayerFuncChangeCoordMode) NULL,
157 (VikLayerFuncSetMenuItemsSelection) NULL,
158 (VikLayerFuncGetMenuItemsSelection) NULL,
160 (VikLayerFuncAddMenuItems) maps_layer_add_menu_items,
161 (VikLayerFuncSublayerAddMenuItems) NULL,
163 (VikLayerFuncSublayerRenameRequest) NULL,
164 (VikLayerFuncSublayerToggleVisible) NULL,
166 (VikLayerFuncMarshall) maps_layer_marshall,
167 (VikLayerFuncUnmarshall) maps_layer_unmarshall,
169 (VikLayerFuncSetParam) maps_layer_set_param,
170 (VikLayerFuncGetParam) maps_layer_get_param,
172 (VikLayerFuncReadFileData) NULL,
173 (VikLayerFuncWriteFileData) NULL,
175 (VikLayerFuncDeleteItem) NULL,
176 (VikLayerFuncCopyItem) NULL,
177 (VikLayerFuncPasteItem) NULL,
178 (VikLayerFuncFreeCopiedItem) NULL,
179 (VikLayerFuncDragDropRequest) NULL,
182 struct _VikMapsLayer {
183 VikLayer vl;
184 guint maptype;
185 gchar *cache_dir;
186 guint8 alpha;
187 guint mapzoom_id;
188 gdouble xmapzoom, ymapzoom;
190 gboolean autodownload;
191 VikCoord *last_center;
192 gdouble last_xmpp;
193 gdouble last_ympp;
195 gint dl_tool_x, dl_tool_y;
197 GtkMenu *dl_right_click_menu;
198 VikCoord redownload_ul, redownload_br; /* right click menu only */
199 VikViewport *redownload_vvp;
202 enum { REDOWNLOAD_NONE = 0, /* download only missing maps */
203 REDOWNLOAD_BAD, /* download missing and bad maps */
204 REDOWNLOAD_NEW, /* download missing maps that are newer on server only */
205 REDOWNLOAD_ALL, /* download all maps */
206 DOWNLOAD_OR_REFRESH }; /* download missing maps and refresh cache */
209 /****************************************/
210 /******** MAPS LAYER TYPES **************/
211 /****************************************/
213 void maps_layer_register_type ( const char *label, guint id, VikMapsLayer_MapType *map_type )
215 g_assert(label != NULL);
216 g_assert(map_type != NULL);
217 g_assert(id == map_type->uniq_id);
219 /* Add the label */
220 params_maptypes = g_list_append(params_maptypes, g_strdup(label));
222 /* Add the id */
223 params_maptypes_ids = g_list_append(params_maptypes_ids, GUINT_TO_POINTER (id));
225 /* We have to clone */
226 VikMapsLayer_MapType *clone = g_memdup(map_type, sizeof(VikMapsLayer_MapType));
227 /* Register the clone in the list */
228 __map_types = g_list_append(__map_types, clone);
230 /* Hack
231 We have to ensure the mode LayerParam reference the up-to-date
232 GLists.
235 memcpy(&maps_layer_params[0].widget_data, &params_maptypes, sizeof(gpointer));
236 memcpy(&maps_layer_params[0].extra_widget_data, &params_maptypes_ids, sizeof(gpointer));
238 maps_layer_params[0].widget_data = params_maptypes;
239 maps_layer_params[0].extra_widget_data = params_maptypes_ids;
242 #define MAPS_LAYER_NTH_LABEL(n) ((gchar*)g_list_nth_data(params_maptypes, (n)))
243 #define MAPS_LAYER_NTH_ID(n) ((guint)g_list_nth_data(params_maptypes_ids, (n)))
244 #define MAPS_LAYER_NTH_TYPE(n) ((VikMapsLayer_MapType*)g_list_nth_data(__map_types, (n)))
246 gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
248 return(vml->maptype);
251 gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
253 return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
256 /****************************************/
257 /******** CACHE DIR STUFF ***************/
258 /****************************************/
260 #define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
261 #define MAPS_CACHE_DIR maps_layer_default_dir()
263 #ifdef WINDOWS
264 #include <io.h>
265 #define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
266 #define LOCAL_MAPS_DIR "VIKING-MAPS"
267 #else /* POSIX */
268 #include <stdlib.h>
269 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
270 #define LOCAL_MAPS_DIR ".viking-maps"
271 #endif
273 gchar *maps_layer_default_dir ()
275 static gchar *defaultdir = NULL;
276 if ( ! defaultdir )
278 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
279 const gchar *mapdir = g_getenv("VIKING_MAPS");
280 if ( mapdir ) {
281 defaultdir = g_strdup ( mapdir );
282 } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
283 defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
284 } else {
285 const gchar *home = g_get_home_dir();
286 if (!home || g_access(home, W_OK))
287 home = g_get_home_dir ();
288 if ( home )
289 defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
290 else
291 defaultdir = g_strdup ( LOCAL_MAPS_DIR );
293 if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
295 /* Add the separator at the end */
296 gchar *tmp = defaultdir;
297 defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
298 g_free(tmp);
300 g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
302 return defaultdir;
305 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
307 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
309 g_mkdir ( vml->cache_dir, 0777 );
313 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
315 guint len;
316 g_assert ( vml != NULL);
317 g_free ( vml->cache_dir );
318 vml->cache_dir = NULL;
320 if ( dir == NULL || dir[0] == '\0' )
321 vml->cache_dir = g_strdup ( MAPS_CACHE_DIR );
322 else
324 len = strlen(dir);
325 if ( dir[len-1] != G_DIR_SEPARATOR )
327 vml->cache_dir = g_malloc ( len+2 );
328 strncpy ( vml->cache_dir, dir, len );
329 vml->cache_dir[len] = G_DIR_SEPARATOR;
330 vml->cache_dir[len+1] = '\0';
332 else
333 vml->cache_dir = g_strdup ( dir );
335 maps_layer_mkdir_if_default_dir ( vml );
338 /****************************************/
339 /******** GOBJECT STUFF *****************/
340 /****************************************/
342 GType vik_maps_layer_get_type ()
344 static GType vml_type = 0;
346 if (!vml_type)
348 static const GTypeInfo vml_info =
350 sizeof (VikMapsLayerClass),
351 NULL, /* base_init */
352 NULL, /* base_finalize */
353 NULL, /* class init */
354 NULL, /* class_finalize */
355 NULL, /* class_data */
356 sizeof (VikMapsLayer),
358 NULL /* instance init */
360 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
363 return vml_type;
366 /****************************************/
367 /************** PARAMETERS **************/
368 /****************************************/
370 static guint map_index_to_uniq_id (guint8 index)
372 g_assert ( index < NUM_MAP_TYPES );
373 return MAPS_LAYER_NTH_TYPE(index)->uniq_id;
376 static guint map_uniq_id_to_index ( guint uniq_id )
378 gint i;
379 for ( i = 0; i < NUM_MAP_TYPES; i++ )
380 if ( MAPS_LAYER_NTH_TYPE(i)->uniq_id == uniq_id )
381 return i;
382 return NUM_MAP_TYPES; /* no such thing */
385 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp )
387 switch ( id )
389 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
390 case PARAM_MAPTYPE: {
391 gint maptype = map_uniq_id_to_index(data.u);
392 if ( maptype == NUM_MAP_TYPES ) g_warning(_("Unknown map type"));
393 else vml->maptype = maptype;
394 break;
396 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
397 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
398 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
399 vml->mapzoom_id = data.u;
400 vml->xmapzoom = __mapzooms_x [data.u];
401 vml->ymapzoom = __mapzooms_y [data.u];
402 }else g_warning (_("Unknown Map Zoom")); break;
404 return TRUE;
407 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id )
409 VikLayerParamData rv;
410 switch ( id )
412 case PARAM_CACHE_DIR: rv.s = (vml->cache_dir && strcmp(vml->cache_dir, MAPS_CACHE_DIR) != 0) ? vml->cache_dir : ""; break;
413 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
414 case PARAM_ALPHA: rv.u = vml->alpha; break;
415 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
416 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
418 return rv;
421 /****************************************/
422 /****** CREATING, COPYING, FREEING ******/
423 /****************************************/
425 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
427 int idx;
428 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
429 vik_layer_init ( VIK_LAYER(vml), VIK_LAYER_MAPS );
430 idx = map_uniq_id_to_index(7); /* 7 is id for google maps */
431 vml->maptype = (idx < NUM_MAP_TYPES) ? idx : 0;
432 vml->alpha = 255;
433 vml->mapzoom_id = 0;
434 vml->dl_tool_x = vml->dl_tool_y = -1;
435 maps_layer_set_cache_dir ( vml, NULL );
436 vml->autodownload = FALSE;
437 vml->last_center = NULL;
438 vml->last_xmpp = 0.0;
439 vml->last_ympp = 0.0;
441 vml->dl_right_click_menu = NULL;
443 return vml;
446 static void maps_layer_free ( VikMapsLayer *vml )
448 g_free ( vml->cache_dir );
449 vml->cache_dir = NULL;
450 if ( vml->dl_right_click_menu )
451 gtk_object_sink ( GTK_OBJECT(vml->dl_right_click_menu) );
452 g_free(vml->last_center);
453 vml->last_center = NULL;
456 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
458 if (from_file != TRUE)
460 /* If this method is not called in file reading context
461 * it is called in GUI context.
462 * So, we can check if we have to inform the user about inconsistency */
463 VikViewportDrawMode vp_drawmode;
464 VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
465 VikMapsLayer_MapType *map_type = NULL;
467 vp_drawmode = vik_viewport_get_drawmode ( VIK_VIEWPORT(vp) );
468 map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
469 if (map_type->drawmode != vp_drawmode) {
470 const gchar *drawmode_name = vik_viewport_get_drawmode_name (VIK_VIEWPORT(vp), map_type->drawmode);
471 gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
472 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), msg );
473 g_free(msg);
478 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
480 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
483 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
485 VikMapsLayer *rv = maps_layer_new ( vvp );
486 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
487 return rv;
490 /*********************/
491 /****** DRAWING ******/
492 /*********************/
494 static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
496 guchar *pixels;
497 gint width, height, iii, jjj;
499 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
501 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
502 g_object_unref(G_OBJECT(pixbuf));
503 pixbuf = tmp;
506 pixels = gdk_pixbuf_get_pixels(pixbuf);
507 width = gdk_pixbuf_get_width(pixbuf);
508 height = gdk_pixbuf_get_height(pixbuf);
510 /* r,g,b,a,r,g,b,a.... */
511 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
513 pixels += 3;
514 *pixels++ = alpha;
516 return pixbuf;
519 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
521 GdkPixbuf *tmp;
522 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
523 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_NEAREST);
524 g_object_unref ( G_OBJECT(pixbuf) );
525 return tmp;
528 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
530 GdkPixbuf *pixbuf;
532 /* get the thing */
533 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
534 mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
536 if ( ! pixbuf ) {
537 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
538 vml->cache_dir, mode,
539 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
540 if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE) {
542 GError *gx = NULL;
543 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
545 if (gx)
547 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
548 g_warning ( _("Couldn't open image file: %s"), gx->message );
550 g_error_free ( gx );
551 if ( pixbuf )
552 g_object_unref ( G_OBJECT(pixbuf) );
553 pixbuf = NULL;
554 } else {
555 if ( vml->alpha < 255 )
556 pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
557 if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
558 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
560 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
561 mapcoord->z, MAPS_LAYER_NTH_TYPE(vml->maptype)->uniq_id,
562 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
567 return pixbuf;
570 gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
572 const VikCoord *center = vik_viewport_get_center ( vvp );
574 if (vml->last_center == NULL) {
575 VikCoord *new_center = g_malloc(sizeof(VikCoord));
576 *new_center = *center;
577 vml->last_center = new_center;
578 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
579 vml->last_ympp = vik_viewport_get_ympp(vvp);
580 return TRUE;
583 /* TODO: perhaps vik_coord_diff() */
584 if (vik_coord_equals(vml->last_center, center)
585 && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
586 && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
587 return FALSE;
589 *(vml->last_center) = *center;
590 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
591 vml->last_ympp = vik_viewport_get_ympp(vvp);
592 return TRUE;
595 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
597 MapCoord ulm, brm;
598 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
599 gdouble yzoom = vik_viewport_get_ympp ( vvp );
600 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
601 gdouble existence_only = FALSE;
603 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
604 xshrinkfactor = vml->xmapzoom / xzoom;
605 yshrinkfactor = vml->ymapzoom / yzoom;
606 xzoom = vml->xmapzoom;
607 yzoom = vml->xmapzoom;
608 if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
609 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
610 if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR )
611 existence_only = TRUE;
612 else {
613 g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
614 return;
619 /* coord -> ID */
620 VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
621 if ( map_type->coord_to_mapcoord ( ul, xzoom, yzoom, &ulm ) &&
622 map_type->coord_to_mapcoord ( br, xzoom, yzoom, &brm ) ) {
624 /* loop & draw */
625 gint x, y;
626 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
627 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
628 gint mode = map_type->uniq_id;
630 VikCoord coord;
631 gint xx, yy, width, height;
632 GdkPixbuf *pixbuf;
634 guint max_path_len = strlen(vml->cache_dir) + 40;
635 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
637 if ( (!existence_only) && vml->autodownload && should_start_autodownload(vml, vvp)) {
638 #ifdef DEBUG
639 fputs(stderr, "DEBUG: Starting autodownload\n");
640 #endif
641 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
644 if ( map_type->tilesize_x == 0 && !existence_only ) {
645 for ( x = xmin; x <= xmax; x++ ) {
646 for ( y = ymin; y <= ymax; y++ ) {
647 ulm.x = x;
648 ulm.y = y;
649 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
650 if ( pixbuf ) {
651 width = gdk_pixbuf_get_width ( pixbuf );
652 height = gdk_pixbuf_get_height ( pixbuf );
654 map_type->mapcoord_to_center_coord ( &ulm, &coord );
655 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
656 xx -= (width/2);
657 yy -= (height/2);
659 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
663 } else { /* tilesize is known, don't have to keep converting coords */
664 gdouble tilesize_x = map_type->tilesize_x * xshrinkfactor;
665 gdouble tilesize_y = map_type->tilesize_y * yshrinkfactor;
666 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
667 gint tilesize_x_ceil = ceil ( tilesize_x );
668 gint tilesize_y_ceil = ceil ( tilesize_y );
669 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
670 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
671 gdouble xx, yy; gint xx_tmp, yy_tmp;
672 gint base_yy, xend, yend;
674 GdkGC *black_gc = GTK_WIDGET(vvp)->style->black_gc;
676 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
677 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
679 map_type->mapcoord_to_center_coord ( &ulm, &coord );
680 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
681 xx = xx_tmp; yy = yy_tmp;
682 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
683 * eg if tile size 128, shrinkfactor 0.333 */
684 xx -= (tilesize_x/2);
685 base_yy = yy - (tilesize_y/2);
687 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
688 yy = base_yy;
689 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
690 ulm.x = x;
691 ulm.y = y;
693 if ( existence_only ) {
694 g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE,
695 vml->cache_dir, mode,
696 ulm.scale, ulm.z, ulm.x, ulm.y );
697 if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
698 vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
700 } else {
701 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
702 if ( pixbuf )
703 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
704 else {
705 /* retry with bigger shrinkfactor */
706 int scale_inc;
707 for (scale_inc = 1; scale_inc < 4; scale_inc ++) {
708 int scale_factor = 1 << scale_inc; /* 2^scale_inc */
709 MapCoord ulm2 = ulm;
710 ulm2.x = ulm.x / scale_factor;
711 ulm2.y = ulm.y / scale_factor;
712 ulm2.scale = ulm.scale + scale_inc;
713 pixbuf = get_pixbuf ( vml, mode, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
714 if ( pixbuf ) {
715 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
716 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
717 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
718 break;
724 yy += tilesize_y;
726 xx += tilesize_x;
730 g_free ( path_buf );
734 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
736 if ( MAPS_LAYER_NTH_TYPE(vml->maptype)->drawmode == vik_viewport_get_drawmode ( vvp ) )
738 VikCoord ul, br;
740 /* get corner coords */
741 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
742 /* UTM multi-zone stuff by Kit Transue */
743 gchar leftmost_zone, rightmost_zone, i;
744 leftmost_zone = vik_viewport_leftmost_zone( vvp );
745 rightmost_zone = vik_viewport_rightmost_zone( vvp );
746 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
747 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
748 maps_layer_draw_section ( vml, vvp, &ul, &br );
751 else {
752 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
753 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
755 maps_layer_draw_section ( vml, vvp, &ul, &br );
760 /*************************/
761 /****** DOWNLOADING ******/
762 /*************************/
764 /* pass along data to thread, exists even if layer is deleted. */
765 typedef struct {
766 gchar *cache_dir;
767 gchar *filename_buf;
768 gint x0, y0, xf, yf;
769 MapCoord mapcoord;
770 gint maptype;
771 gint maxlen;
772 gint mapstoget;
773 gint redownload;
774 gboolean refresh_display;
775 VikMapsLayer *vml;
776 VikViewport *vvp;
777 gboolean map_layer_alive;
778 GMutex *mutex;
779 } MapDownloadInfo;
781 static void mdi_free ( MapDownloadInfo *mdi )
783 g_mutex_free(mdi->mutex);
784 g_free ( mdi->cache_dir );
785 mdi->cache_dir = NULL;
786 g_free ( mdi->filename_buf );
787 mdi->filename_buf = NULL;
788 g_free ( mdi );
791 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
793 MapDownloadInfo *mdi = ptr;
794 g_mutex_lock(mdi->mutex);
795 mdi->map_layer_alive = FALSE;
796 g_mutex_unlock(mdi->mutex);
799 static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
801 guint donemaps = 0;
802 gint x, y;
803 for ( x = mdi->x0; x <= mdi->xf; x++ )
805 for ( y = mdi->y0; y <= mdi->yf; y++ )
807 gboolean remove_mem_cache = FALSE;
808 gboolean need_download = FALSE;
809 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
810 mdi->cache_dir, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id,
811 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
813 donemaps++;
814 int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
815 if (res != 0)
816 return -1;
818 if ( mdi->redownload == REDOWNLOAD_ALL)
819 g_remove ( mdi->filename_buf );
821 else if ( (mdi->redownload == REDOWNLOAD_BAD) && (g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE) )
823 /* see if this one is bad or what */
824 GError *gx = NULL;
825 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
826 if (gx || (!pixbuf))
827 g_remove ( mdi->filename_buf );
828 if ( pixbuf )
829 g_object_unref ( pixbuf );
830 if ( gx )
831 g_error_free ( gx );
834 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
836 need_download = TRUE;
837 if (( mdi->redownload != REDOWNLOAD_NONE ) &&
838 ( mdi->redownload != DOWNLOAD_OR_REFRESH ))
839 remove_mem_cache = TRUE;
840 } else if ( mdi->redownload == DOWNLOAD_OR_REFRESH ) {
841 remove_mem_cache = TRUE;
842 } else if ( mdi->redownload == REDOWNLOAD_NEW) {
843 need_download = TRUE;
844 remove_mem_cache = TRUE;
845 } else
846 continue;
848 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
850 if (need_download) {
851 if ( MAPS_LAYER_NTH_TYPE(mdi->maptype)->download ( &(mdi->mapcoord), mdi->filename_buf ))
852 continue;
855 gdk_threads_enter();
856 g_mutex_lock(mdi->mutex);
857 if (remove_mem_cache)
858 a_mapcache_remove_all_shrinkfactors ( x, y, mdi->mapcoord.z, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id, mdi->mapcoord.scale );
859 if (mdi->refresh_display && mdi->map_layer_alive) {
860 /* TODO: check if it's on visible area */
861 vik_layer_emit_update ( VIK_LAYER(mdi->vml) );
863 g_mutex_unlock(mdi->mutex);
864 gdk_threads_leave();
865 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
869 g_mutex_lock(mdi->mutex);
870 if (mdi->map_layer_alive)
871 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
872 g_mutex_unlock(mdi->mutex);
873 return 0;
876 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
878 if ( mdi->mapcoord.x || mdi->mapcoord.y )
880 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
881 mdi->cache_dir, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id,
882 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
883 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
885 g_remove ( mdi->filename_buf );
890 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
892 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
893 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
894 MapCoord ulm, brm;
895 VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
896 if ( map_type->coord_to_mapcoord ( ul, xzoom, yzoom, &ulm )
897 && map_type->coord_to_mapcoord ( br, xzoom, yzoom, &brm ) )
899 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
900 gint a, b;
902 mdi->vml = vml;
903 mdi->vvp = vvp;
904 mdi->map_layer_alive = TRUE;
905 mdi->mutex = g_mutex_new();
906 mdi->refresh_display = TRUE;
908 /* cache_dir and buffer for dest filename */
909 mdi->cache_dir = g_strdup ( vml->cache_dir );
910 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
911 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
912 mdi->maptype = vml->maptype;
914 mdi->mapcoord = ulm;
916 mdi->redownload = redownload;
918 mdi->x0 = MIN(ulm.x, brm.x);
919 mdi->xf = MAX(ulm.x, brm.x);
920 mdi->y0 = MIN(ulm.y, brm.y);
921 mdi->yf = MAX(ulm.y, brm.y);
923 mdi->mapstoget = 0;
925 if ( mdi->redownload ) {
926 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
927 } else {
928 /* calculate how many we need */
929 for ( a = mdi->x0; a <= mdi->xf; a++ )
931 for ( b = mdi->y0; b <= mdi->yf; b++ )
933 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
934 vml->cache_dir, map_type->uniq_id, ulm.scale,
935 ulm.z, a, b );
936 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
937 mdi->mapstoget++;
942 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
944 if ( mdi->mapstoget )
946 const gchar *tmp_str;
947 gchar *tmp;
949 if (redownload)
951 if (redownload == REDOWNLOAD_BAD)
952 tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
953 else
954 tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
956 else
958 tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
960 tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
962 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
963 /* launch the thread */
964 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
965 tmp, /* description string */
966 (vik_thr_func) map_download_thread, /* function to call within thread */
967 mdi, /* pass along data */
968 (vik_thr_free_func) mdi_free, /* function to free pass along data */
969 (vik_thr_free_func) mdi_cancel_cleanup,
970 mdi->mapstoget );
971 g_free ( tmp );
973 else
974 mdi_free ( mdi );
978 void maps_layer_download_section_without_redraw( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
980 MapCoord ulm, brm;
981 VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
983 if (!map_type->coord_to_mapcoord(ul, zoom, zoom, &ulm)
984 || !map_type->coord_to_mapcoord(br, zoom, zoom, &brm)) {
985 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
986 return;
989 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
990 gint i, j;
992 mdi->vml = vml;
993 mdi->vvp = vvp;
994 mdi->map_layer_alive = TRUE;
995 mdi->mutex = g_mutex_new();
996 mdi->refresh_display = FALSE;
998 mdi->cache_dir = g_strdup ( vml->cache_dir );
999 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1000 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1001 mdi->maptype = vml->maptype;
1003 mdi->mapcoord = ulm;
1005 mdi->redownload = REDOWNLOAD_NONE;
1007 mdi->x0 = MIN(ulm.x, brm.x);
1008 mdi->xf = MAX(ulm.x, brm.x);
1009 mdi->y0 = MIN(ulm.y, brm.y);
1010 mdi->yf = MAX(ulm.y, brm.y);
1012 mdi->mapstoget = 0;
1014 for (i = mdi->x0; i <= mdi->xf; i++) {
1015 for (j = mdi->y0; j <= mdi->yf; j++) {
1016 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1017 vml->cache_dir, map_type->uniq_id, ulm.scale,
1018 ulm.z, i, j );
1019 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1020 mdi->mapstoget++;
1024 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1026 if (mdi->mapstoget) {
1027 gchar *tmp;
1028 const gchar *fmt;
1029 fmt = ngettext("Downloading %d %s map...",
1030 "Downloading %d %s maps...",
1031 mdi->mapstoget);
1032 tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
1034 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1035 /* launch the thread */
1036 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1037 tmp, /* description string */
1038 (vik_thr_func) map_download_thread, /* function to call within thread */
1039 mdi, /* pass along data */
1040 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1041 (vik_thr_free_func) mdi_cancel_cleanup,
1042 mdi->mapstoget );
1043 g_free ( tmp );
1045 else
1046 mdi_free ( mdi );
1049 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1051 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1053 static void maps_layer_redownload_all ( VikMapsLayer *vml )
1055 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1058 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1060 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1061 return FALSE;
1062 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1064 if ( event->button == 1 )
1066 VikCoord ul, br;
1067 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 );
1068 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 );
1069 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
1070 vml->dl_tool_x = vml->dl_tool_y = -1;
1071 return TRUE;
1073 else
1075 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) );
1076 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) );
1078 vml->redownload_vvp = vvp;
1080 vml->dl_tool_x = vml->dl_tool_y = -1;
1082 if ( ! vml->dl_right_click_menu ) {
1083 GtkWidget *item;
1084 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1086 item = gtk_menu_item_new_with_label ( _("Redownload bad map(s)") );
1087 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1088 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1090 item = gtk_menu_item_new_with_label ( _("Redownload all map(s)") );
1091 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1092 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1095 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1096 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1099 return FALSE;
1102 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1104 return vvp;
1107 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1109 MapCoord tmp;
1110 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1111 return FALSE;
1112 VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
1113 if ( map_type->drawmode == vik_viewport_get_drawmode ( vvp ) &&
1114 map_type->coord_to_mapcoord ( vik_viewport_get_center ( vvp ),
1115 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1116 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1117 &tmp ) ) {
1118 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1119 return TRUE;
1121 return FALSE;
1124 #if 0
1125 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1127 VikCoord coord;
1128 MapCoord mapcoord;
1129 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1130 if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1131 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1132 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1133 &mapcoord ) ) {
1134 gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1135 vml->cache_dir, __map_types[vml->maptype].uniq_id,
1136 mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1138 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1139 g_free ( filename_buf );
1140 vik_layer_emit_update ( VIK_LAYER(vml) );
1141 return TRUE;
1144 return FALSE;
1145 #endif
1148 static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
1150 VikMapsLayer *vml = vml_vvp[0];
1151 VikViewport *vvp = vml_vvp[1];
1152 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
1154 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1155 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1157 VikCoord ul, br;
1158 MapCoord ulm, brm;
1160 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1161 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1163 VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
1164 if ( map_type->drawmode == vp_drawmode &&
1165 map_type->coord_to_mapcoord ( &ul, xzoom, yzoom, &ulm ) &&
1166 map_type->coord_to_mapcoord ( &br, xzoom, yzoom, &brm ) )
1167 start_download_thread ( vml, vvp, &ul, &br, redownload );
1168 else if (map_type->drawmode != vp_drawmode) {
1169 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, map_type->drawmode);
1170 gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
1171 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1172 g_free(err);
1174 else
1175 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
1179 static void maps_layer_download_missing_onscreen_maps ( gpointer vml_vvp[2] )
1181 download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1184 static void maps_layer_download_new_onscreen_maps ( gpointer vml_vvp[2] )
1186 download_onscreen_maps( vml_vvp, REDOWNLOAD_NEW);
1189 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1191 download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1194 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1196 static gpointer pass_along[2];
1197 GtkWidget *item;
1198 pass_along[0] = vml;
1199 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1201 item = gtk_menu_item_new();
1202 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1203 gtk_widget_show ( item );
1205 item = gtk_menu_item_new_with_label ( _("Download missing Onscreen Maps") );
1206 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), pass_along );
1207 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1208 gtk_widget_show ( item );
1210 if ( MAPS_LAYER_NTH_TYPE(vml->maptype)->options != NULL &&
1211 MAPS_LAYER_NTH_TYPE(vml->maptype)->options->check_file_server_time ) {
1212 item = gtk_menu_item_new_with_label ( _("Download new Onscreen Maps from server") );
1213 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), pass_along );
1214 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1215 gtk_widget_show ( item );
1218 /* TODO Add GTK_STOCK_REFRESH icon */
1219 item = gtk_menu_item_new_with_label ( _("Refresh Onscreen Tiles") );
1220 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1221 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1222 gtk_widget_show ( item );