Add src/mapcache.c as source file containing translatable strings
[viking/guyou.git] / src / vikmapslayer.c
blob8289d301760feb0d2182f29f7133deea8c569f0e
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:"), VIK_LAYER_WIDGET_FOLDERENTRY },
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, REDOWNLOAD_BAD, REDOWNLOAD_ALL, DOWNLOAD_OR_REFRESH };
205 /****************************************/
206 /******** MAPS LAYER TYPES **************/
207 /****************************************/
209 void maps_layer_register_type ( const char *label, guint id, VikMapsLayer_MapType *map_type )
211 g_assert(label != NULL);
212 g_assert(map_type != NULL);
213 g_assert(id == map_type->uniq_id);
215 /* Add the label */
216 params_maptypes = g_list_append(params_maptypes, g_strdup(label));
218 /* Add the id */
219 params_maptypes_ids = g_list_append(params_maptypes_ids, GUINT_TO_POINTER (id));
221 /* We have to clone */
222 VikMapsLayer_MapType *clone = g_memdup(map_type, sizeof(VikMapsLayer_MapType));
223 /* Register the clone in the list */
224 __map_types = g_list_append(__map_types, clone);
226 /* Hack
227 We have to ensure the mode LayerParam reference the up-to-date
228 GLists.
231 memcpy(&maps_layer_params[0].widget_data, &params_maptypes, sizeof(gpointer));
232 memcpy(&maps_layer_params[0].extra_widget_data, &params_maptypes_ids, sizeof(gpointer));
234 maps_layer_params[0].widget_data = params_maptypes;
235 maps_layer_params[0].extra_widget_data = params_maptypes_ids;
238 #define MAPS_LAYER_NTH_LABEL(n) ((gchar*)g_list_nth_data(params_maptypes, (n)))
239 #define MAPS_LAYER_NTH_ID(n) ((guint)g_list_nth_data(params_maptypes_ids, (n)))
240 #define MAPS_LAYER_NTH_TYPE(n) ((VikMapsLayer_MapType*)g_list_nth_data(__map_types, (n)))
242 gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
244 return(vml->maptype);
247 gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
249 return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
252 /****************************************/
253 /******** CACHE DIR STUFF ***************/
254 /****************************************/
256 #define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
257 #define MAPS_CACHE_DIR maps_layer_default_dir()
259 #ifdef WINDOWS
260 #include <io.h>
261 #define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
262 #define LOCAL_MAPS_DIR "VIKING-MAPS"
263 #else /* POSIX */
264 #include <stdlib.h>
265 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
266 #define LOCAL_MAPS_DIR ".viking-maps"
267 #endif
269 gchar *maps_layer_default_dir ()
271 static gchar *defaultdir = NULL;
272 if ( ! defaultdir )
274 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
275 const gchar *mapdir = g_getenv("VIKING_MAPS");
276 if ( mapdir ) {
277 defaultdir = g_strdup ( mapdir );
278 } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
279 defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
280 } else {
281 const gchar *home = g_get_home_dir();
282 if (!home || g_access(home, W_OK))
283 home = g_get_home_dir ();
284 if ( home )
285 defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
286 else
287 defaultdir = g_strdup ( LOCAL_MAPS_DIR );
289 if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
291 /* Add the separator at the end */
292 gchar *tmp = defaultdir;
293 defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
294 g_free(tmp);
296 g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
298 return defaultdir;
301 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
303 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
305 g_mkdir ( vml->cache_dir, 0777 );
309 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
311 guint len;
312 g_assert ( vml != NULL);
313 g_free ( vml->cache_dir );
314 vml->cache_dir = NULL;
316 if ( dir == NULL || dir[0] == '\0' )
317 vml->cache_dir = g_strdup ( MAPS_CACHE_DIR );
318 else
320 len = strlen(dir);
321 if ( dir[len-1] != G_DIR_SEPARATOR )
323 vml->cache_dir = g_malloc ( len+2 );
324 strncpy ( vml->cache_dir, dir, len );
325 vml->cache_dir[len] = G_DIR_SEPARATOR;
326 vml->cache_dir[len+1] = '\0';
328 else
329 vml->cache_dir = g_strdup ( dir );
331 maps_layer_mkdir_if_default_dir ( vml );
334 /****************************************/
335 /******** GOBJECT STUFF *****************/
336 /****************************************/
338 GType vik_maps_layer_get_type ()
340 static GType vml_type = 0;
342 if (!vml_type)
344 static const GTypeInfo vml_info =
346 sizeof (VikMapsLayerClass),
347 NULL, /* base_init */
348 NULL, /* base_finalize */
349 NULL, /* class init */
350 NULL, /* class_finalize */
351 NULL, /* class_data */
352 sizeof (VikMapsLayer),
354 NULL /* instance init */
356 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
359 return vml_type;
362 /****************************************/
363 /************** PARAMETERS **************/
364 /****************************************/
366 static guint map_index_to_uniq_id (guint8 index)
368 g_assert ( index < NUM_MAP_TYPES );
369 return MAPS_LAYER_NTH_TYPE(index)->uniq_id;
372 static guint map_uniq_id_to_index ( guint uniq_id )
374 gint i;
375 for ( i = 0; i < NUM_MAP_TYPES; i++ )
376 if ( MAPS_LAYER_NTH_TYPE(i)->uniq_id == uniq_id )
377 return i;
378 return NUM_MAP_TYPES; /* no such thing */
381 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp )
383 switch ( id )
385 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
386 case PARAM_MAPTYPE: {
387 gint maptype = map_uniq_id_to_index(data.u);
388 if ( maptype == NUM_MAP_TYPES ) g_warning(_("Unknown map type"));
389 else vml->maptype = maptype;
390 break;
392 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
393 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
394 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
395 vml->mapzoom_id = data.u;
396 vml->xmapzoom = __mapzooms_x [data.u];
397 vml->ymapzoom = __mapzooms_y [data.u];
398 }else g_warning (_("Unknown Map Zoom")); break;
400 return TRUE;
403 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id )
405 VikLayerParamData rv;
406 switch ( id )
408 case PARAM_CACHE_DIR: rv.s = vml->cache_dir ? vml->cache_dir : ""; break;
409 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
410 case PARAM_ALPHA: rv.u = vml->alpha; break;
411 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
412 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
414 return rv;
417 /****************************************/
418 /****** CREATING, COPYING, FREEING ******/
419 /****************************************/
421 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
423 int idx;
424 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
425 vik_layer_init ( VIK_LAYER(vml), VIK_LAYER_MAPS );
426 idx = map_uniq_id_to_index(7); /* 7 is id for google maps */
427 vml->maptype = (idx < NUM_MAP_TYPES) ? idx : 0;
428 vml->alpha = 255;
429 vml->mapzoom_id = 0;
430 vml->dl_tool_x = vml->dl_tool_y = -1;
431 maps_layer_set_cache_dir ( vml, NULL );
432 vml->autodownload = FALSE;
433 vml->last_center = NULL;
434 vml->last_xmpp = 0.0;
435 vml->last_ympp = 0.0;
437 vml->dl_right_click_menu = NULL;
439 return vml;
442 static void maps_layer_free ( VikMapsLayer *vml )
444 g_free ( vml->cache_dir );
445 vml->cache_dir = NULL;
446 if ( vml->dl_right_click_menu )
447 gtk_object_sink ( GTK_OBJECT(vml->dl_right_click_menu) );
448 g_free(vml->last_center);
449 vml->last_center = NULL;
452 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
454 if (from_file != TRUE)
456 /* If this method is not called in file reading context
457 * it is called in GUI context.
458 * So, we can check if we have to inform the user about inconsistency */
459 VikViewportDrawMode vp_drawmode;
460 VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
461 VikMapsLayer_MapType *map_type = NULL;
463 vp_drawmode = vik_viewport_get_drawmode ( VIK_VIEWPORT(vp) );
464 map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
465 if (map_type->drawmode != vp_drawmode) {
466 const gchar *drawmode_name = vik_viewport_get_drawmode_name (VIK_VIEWPORT(vp), map_type->drawmode);
467 gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
468 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), msg );
469 g_free(msg);
474 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
476 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
479 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
481 VikMapsLayer *rv = maps_layer_new ( vvp );
482 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
483 return rv;
486 /*********************/
487 /****** DRAWING ******/
488 /*********************/
490 static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
492 guchar *pixels;
493 gint width, height, iii, jjj;
495 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
497 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
498 g_object_unref(G_OBJECT(pixbuf));
499 pixbuf = tmp;
502 pixels = gdk_pixbuf_get_pixels(pixbuf);
503 width = gdk_pixbuf_get_width(pixbuf);
504 height = gdk_pixbuf_get_height(pixbuf);
506 /* r,g,b,a,r,g,b,a.... */
507 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
509 pixels += 3;
510 *pixels++ = alpha;
512 return pixbuf;
515 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
517 GdkPixbuf *tmp;
518 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
519 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_BILINEAR);
520 g_object_unref ( G_OBJECT(pixbuf) );
521 return tmp;
524 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
526 GdkPixbuf *pixbuf;
528 /* get the thing */
529 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
530 mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
532 if ( ! pixbuf ) {
533 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
534 vml->cache_dir, mode,
535 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
536 if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE) {
538 GError *gx = NULL;
539 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
541 if (gx)
543 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
544 g_warning ( _("Couldn't open image file: %s"), gx->message );
546 g_error_free ( gx );
547 if ( pixbuf )
548 g_object_unref ( G_OBJECT(pixbuf) );
549 pixbuf = NULL;
550 } else {
551 if ( vml->alpha < 255 )
552 pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
553 if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
554 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
556 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
557 mapcoord->z, MAPS_LAYER_NTH_TYPE(vml->maptype)->uniq_id,
558 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
563 return pixbuf;
566 gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
568 const VikCoord *center = vik_viewport_get_center ( vvp );
570 if (vml->last_center == NULL) {
571 VikCoord *new_center = g_malloc(sizeof(VikCoord));
572 *new_center = *center;
573 vml->last_center = new_center;
574 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
575 vml->last_ympp = vik_viewport_get_ympp(vvp);
576 return TRUE;
579 /* TODO: perhaps vik_coord_diff() */
580 if (vik_coord_equals(vml->last_center, center)
581 && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
582 && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
583 return FALSE;
585 *(vml->last_center) = *center;
586 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
587 vml->last_ympp = vik_viewport_get_ympp(vvp);
588 return TRUE;
591 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
593 MapCoord ulm, brm;
594 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
595 gdouble yzoom = vik_viewport_get_ympp ( vvp );
596 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
597 gdouble existence_only = FALSE;
599 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
600 xshrinkfactor = vml->xmapzoom / xzoom;
601 yshrinkfactor = vml->ymapzoom / yzoom;
602 xzoom = vml->xmapzoom;
603 yzoom = vml->xmapzoom;
604 if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
605 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
606 if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR )
607 existence_only = TRUE;
608 else {
609 g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
610 return;
615 /* coord -> ID */
616 VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
617 if ( map_type->coord_to_mapcoord ( ul, xzoom, yzoom, &ulm ) &&
618 map_type->coord_to_mapcoord ( br, xzoom, yzoom, &brm ) ) {
620 /* loop & draw */
621 gint x, y;
622 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
623 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
624 gint mode = map_type->uniq_id;
626 VikCoord coord;
627 gint xx, yy, width, height;
628 GdkPixbuf *pixbuf;
630 guint max_path_len = strlen(vml->cache_dir) + 40;
631 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
633 if ( (!existence_only) && vml->autodownload && should_start_autodownload(vml, vvp)) {
634 #ifdef DEBUG
635 fputs(stderr, "DEBUG: Starting autodownload\n");
636 #endif
637 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
640 if ( map_type->tilesize_x == 0 && !existence_only ) {
641 for ( x = xmin; x <= xmax; x++ ) {
642 for ( y = ymin; y <= ymax; y++ ) {
643 ulm.x = x;
644 ulm.y = y;
645 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
646 if ( pixbuf ) {
647 width = gdk_pixbuf_get_width ( pixbuf );
648 height = gdk_pixbuf_get_height ( pixbuf );
650 map_type->mapcoord_to_center_coord ( &ulm, &coord );
651 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
652 xx -= (width/2);
653 yy -= (height/2);
655 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
659 } else { /* tilesize is known, don't have to keep converting coords */
660 gdouble tilesize_x = map_type->tilesize_x * xshrinkfactor;
661 gdouble tilesize_y = map_type->tilesize_y * yshrinkfactor;
662 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
663 gint tilesize_x_ceil = ceil ( tilesize_x );
664 gint tilesize_y_ceil = ceil ( tilesize_y );
665 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
666 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
667 gdouble xx, yy; gint xx_tmp, yy_tmp;
668 gint base_yy, xend, yend;
670 GdkGC *black_gc = GTK_WIDGET(vvp)->style->black_gc;
672 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
673 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
675 map_type->mapcoord_to_center_coord ( &ulm, &coord );
676 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
677 xx = xx_tmp; yy = yy_tmp;
678 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
679 * eg if tile size 128, shrinkfactor 0.333 */
680 xx -= (tilesize_x/2);
681 base_yy = yy - (tilesize_y/2);
683 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
684 yy = base_yy;
685 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
686 ulm.x = x;
687 ulm.y = y;
689 if ( existence_only ) {
690 g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE,
691 vml->cache_dir, mode,
692 ulm.scale, ulm.z, ulm.x, ulm.y );
693 if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
694 vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
696 } else {
697 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
698 if ( pixbuf )
699 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
702 yy += tilesize_y;
704 xx += tilesize_x;
708 g_free ( path_buf );
712 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
714 if ( MAPS_LAYER_NTH_TYPE(vml->maptype)->drawmode == vik_viewport_get_drawmode ( vvp ) )
716 VikCoord ul, br;
718 /* get corner coords */
719 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
720 /* UTM multi-zone stuff by Kit Transue */
721 gchar leftmost_zone, rightmost_zone, i;
722 leftmost_zone = vik_viewport_leftmost_zone( vvp );
723 rightmost_zone = vik_viewport_rightmost_zone( vvp );
724 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
725 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
726 maps_layer_draw_section ( vml, vvp, &ul, &br );
729 else {
730 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
731 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
733 maps_layer_draw_section ( vml, vvp, &ul, &br );
738 /*************************/
739 /****** DOWNLOADING ******/
740 /*************************/
742 /* pass along data to thread, exists even if layer is deleted. */
743 typedef struct {
744 gchar *cache_dir;
745 gchar *filename_buf;
746 gint x0, y0, xf, yf;
747 MapCoord mapcoord;
748 gint maptype;
749 gint maxlen;
750 gint mapstoget;
751 gint redownload;
752 gboolean refresh_display;
753 VikMapsLayer *vml;
754 VikViewport *vvp;
755 gboolean map_layer_alive;
756 GMutex *mutex;
757 } MapDownloadInfo;
759 static void mdi_free ( MapDownloadInfo *mdi )
761 g_mutex_free(mdi->mutex);
762 g_free ( mdi->cache_dir );
763 mdi->cache_dir = NULL;
764 g_free ( mdi->filename_buf );
765 mdi->filename_buf = NULL;
766 g_free ( mdi );
769 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
771 MapDownloadInfo *mdi = ptr;
772 g_mutex_lock(mdi->mutex);
773 mdi->map_layer_alive = FALSE;
774 g_mutex_unlock(mdi->mutex);
777 static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
779 guint donemaps = 0;
780 gint x, y;
781 for ( x = mdi->x0; x <= mdi->xf; x++ )
783 for ( y = mdi->y0; y <= mdi->yf; y++ )
785 gboolean remove_mem_cache = FALSE;
786 gboolean need_download = FALSE;
787 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
788 mdi->cache_dir, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id,
789 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
791 donemaps++;
792 int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
793 if (res != 0)
794 return -1;
796 if ( mdi->redownload == REDOWNLOAD_ALL)
797 g_remove ( mdi->filename_buf );
799 else if ( (mdi->redownload == REDOWNLOAD_BAD) && (g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE) )
801 /* see if this one is bad or what */
802 GError *gx = NULL;
803 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
804 if (gx || (!pixbuf))
805 g_remove ( mdi->filename_buf );
806 if ( pixbuf )
807 g_object_unref ( pixbuf );
808 if ( gx )
809 g_error_free ( gx );
812 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
814 need_download = TRUE;
815 if (( mdi->redownload != REDOWNLOAD_NONE ) &&
816 ( mdi->redownload != DOWNLOAD_OR_REFRESH ))
817 remove_mem_cache = TRUE;
818 } else if ( mdi->redownload == DOWNLOAD_OR_REFRESH ) {
819 remove_mem_cache = TRUE;
820 } else
821 continue;
823 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
825 if (need_download) {
826 if ( MAPS_LAYER_NTH_TYPE(mdi->maptype)->download ( &(mdi->mapcoord), mdi->filename_buf ))
827 continue;
830 gdk_threads_enter();
831 g_mutex_lock(mdi->mutex);
832 if (remove_mem_cache)
833 a_mapcache_remove_all_shrinkfactors ( x, y, mdi->mapcoord.z, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id, mdi->mapcoord.scale );
834 if (mdi->refresh_display && mdi->map_layer_alive) {
835 /* TODO: check if it's on visible area */
836 vik_layer_emit_update ( VIK_LAYER(mdi->vml) );
838 g_mutex_unlock(mdi->mutex);
839 gdk_threads_leave();
840 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
844 g_mutex_lock(mdi->mutex);
845 if (mdi->map_layer_alive)
846 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
847 g_mutex_unlock(mdi->mutex);
848 return 0;
851 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
853 if ( mdi->mapcoord.x || mdi->mapcoord.y )
855 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
856 mdi->cache_dir, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id,
857 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
858 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
860 g_remove ( mdi->filename_buf );
865 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
867 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
868 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
869 MapCoord ulm, brm;
870 VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
871 if ( map_type->coord_to_mapcoord ( ul, xzoom, yzoom, &ulm )
872 && map_type->coord_to_mapcoord ( br, xzoom, yzoom, &brm ) )
874 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
875 gint a, b;
877 mdi->vml = vml;
878 mdi->vvp = vvp;
879 mdi->map_layer_alive = TRUE;
880 mdi->mutex = g_mutex_new();
881 mdi->refresh_display = TRUE;
883 /* cache_dir and buffer for dest filename */
884 mdi->cache_dir = g_strdup ( vml->cache_dir );
885 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
886 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
887 mdi->maptype = vml->maptype;
889 mdi->mapcoord = ulm;
891 mdi->redownload = redownload;
893 mdi->x0 = MIN(ulm.x, brm.x);
894 mdi->xf = MAX(ulm.x, brm.x);
895 mdi->y0 = MIN(ulm.y, brm.y);
896 mdi->yf = MAX(ulm.y, brm.y);
898 mdi->mapstoget = 0;
900 if ( mdi->redownload ) {
901 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
902 } else {
903 /* calculate how many we need */
904 for ( a = mdi->x0; a <= mdi->xf; a++ )
906 for ( b = mdi->y0; b <= mdi->yf; b++ )
908 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
909 vml->cache_dir, map_type->uniq_id, ulm.scale,
910 ulm.z, a, b );
911 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
912 mdi->mapstoget++;
917 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
919 if ( mdi->mapstoget )
921 const gchar *tmp_str;
922 gchar *tmp;
924 if (redownload)
926 if (redownload == REDOWNLOAD_BAD)
927 tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
928 else
929 tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
931 else
933 tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
935 tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
937 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
938 /* launch the thread */
939 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
940 tmp, /* description string */
941 (vik_thr_func) map_download_thread, /* function to call within thread */
942 mdi, /* pass along data */
943 (vik_thr_free_func) mdi_free, /* function to free pass along data */
944 (vik_thr_free_func) mdi_cancel_cleanup,
945 mdi->mapstoget );
946 g_free ( tmp );
948 else
949 mdi_free ( mdi );
953 void maps_layer_download_section_without_redraw( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
955 MapCoord ulm, brm;
956 VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
958 if (!map_type->coord_to_mapcoord(ul, zoom, zoom, &ulm)
959 || !map_type->coord_to_mapcoord(br, zoom, zoom, &brm)) {
960 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
961 return;
964 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
965 gint i, j;
967 mdi->vml = vml;
968 mdi->vvp = vvp;
969 mdi->map_layer_alive = TRUE;
970 mdi->mutex = g_mutex_new();
971 mdi->refresh_display = FALSE;
973 mdi->cache_dir = g_strdup ( vml->cache_dir );
974 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
975 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
976 mdi->maptype = vml->maptype;
978 mdi->mapcoord = ulm;
980 mdi->redownload = REDOWNLOAD_NONE;
982 mdi->x0 = MIN(ulm.x, brm.x);
983 mdi->xf = MAX(ulm.x, brm.x);
984 mdi->y0 = MIN(ulm.y, brm.y);
985 mdi->yf = MAX(ulm.y, brm.y);
987 mdi->mapstoget = 0;
989 for (i = mdi->x0; i <= mdi->xf; i++) {
990 for (j = mdi->y0; j <= mdi->yf; j++) {
991 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
992 vml->cache_dir, map_type->uniq_id, ulm.scale,
993 ulm.z, i, j );
994 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
995 mdi->mapstoget++;
999 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1001 if (mdi->mapstoget) {
1002 gchar *tmp;
1003 const gchar *fmt;
1004 fmt = ngettext("Downloading %d %s map...",
1005 "Downloading %d %s maps...",
1006 mdi->mapstoget);
1007 tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
1009 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1010 /* launch the thread */
1011 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1012 tmp, /* description string */
1013 (vik_thr_func) map_download_thread, /* function to call within thread */
1014 mdi, /* pass along data */
1015 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1016 (vik_thr_free_func) mdi_cancel_cleanup,
1017 mdi->mapstoget );
1018 g_free ( tmp );
1020 else
1021 mdi_free ( mdi );
1024 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1026 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1028 static void maps_layer_redownload_all ( VikMapsLayer *vml )
1030 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1033 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1035 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1036 return FALSE;
1037 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1039 if ( event->button == 1 )
1041 VikCoord ul, br;
1042 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 );
1043 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 );
1044 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
1045 vml->dl_tool_x = vml->dl_tool_y = -1;
1046 return TRUE;
1048 else
1050 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) );
1051 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) );
1053 vml->redownload_vvp = vvp;
1055 vml->dl_tool_x = vml->dl_tool_y = -1;
1057 if ( ! vml->dl_right_click_menu ) {
1058 GtkWidget *item;
1059 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1061 item = gtk_menu_item_new_with_label ( _("Redownload bad map(s)") );
1062 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1063 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1065 item = gtk_menu_item_new_with_label ( _("Redownload all map(s)") );
1066 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1067 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1070 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1071 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1074 return FALSE;
1077 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1079 return vvp;
1082 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1084 MapCoord tmp;
1085 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1086 return FALSE;
1087 VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
1088 if ( map_type->drawmode == vik_viewport_get_drawmode ( vvp ) &&
1089 map_type->coord_to_mapcoord ( vik_viewport_get_center ( vvp ),
1090 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1091 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1092 &tmp ) ) {
1093 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1094 return TRUE;
1096 return FALSE;
1099 #if 0
1100 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1102 VikCoord coord;
1103 MapCoord mapcoord;
1104 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1105 if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1106 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1107 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1108 &mapcoord ) ) {
1109 gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1110 vml->cache_dir, __map_types[vml->maptype].uniq_id,
1111 mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1113 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1114 g_free ( filename_buf );
1115 vik_layer_emit_update ( VIK_LAYER(vml) );
1116 return TRUE;
1119 return FALSE;
1120 #endif
1123 static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
1125 VikMapsLayer *vml = vml_vvp[0];
1126 VikViewport *vvp = vml_vvp[1];
1127 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
1129 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1130 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1132 VikCoord ul, br;
1133 MapCoord ulm, brm;
1135 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1136 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1138 VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
1139 if ( map_type->drawmode == vp_drawmode &&
1140 map_type->coord_to_mapcoord ( &ul, xzoom, yzoom, &ulm ) &&
1141 map_type->coord_to_mapcoord ( &br, xzoom, yzoom, &brm ) )
1142 start_download_thread ( vml, vvp, &ul, &br, redownload );
1143 else if (map_type->drawmode != vp_drawmode) {
1144 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, map_type->drawmode);
1145 gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
1146 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1147 g_free(err);
1149 else
1150 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
1154 static void maps_layer_download_onscreen_maps ( gpointer vml_vvp[2] )
1156 download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1159 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1161 download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1164 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1166 static gpointer pass_along[2];
1167 GtkWidget *item;
1168 pass_along[0] = vml;
1169 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1171 item = gtk_menu_item_new();
1172 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1173 gtk_widget_show ( item );
1175 item = gtk_menu_item_new_with_label ( _("Download Onscreen Maps") );
1176 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_onscreen_maps), pass_along );
1177 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1178 gtk_widget_show ( item );
1180 /* TODO Add GTK_STOCK_REFRESH icon */
1181 item = gtk_menu_item_new_with_label ( _("Refresh Onscreen Tiles") );
1182 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1183 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1184 gtk_widget_show ( item );