Converting printf calls
[viking/gosmore.git] / src / vikmapslayer.c
blob0dbd5e80aca1ab02a4b94a9a764679095020c30c
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 #define MAX_SHRINKFACTOR 8.0000001 /* zoom 1 viewing 8-tiles */
25 #define MIN_SHRINKFACTOR 0.0312499 /* zoom 32 viewing 1-tiles */
27 #include <gtk/gtk.h>
28 #include <gdk-pixbuf/gdk-pixdata.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <math.h>
32 #include "globals.h"
33 #include "coords.h"
34 #include "vikcoord.h"
35 #include "viktreeview.h"
36 #include "vikviewport.h"
37 #include "viklayer.h"
38 #include "vikmapslayer.h"
39 #include "vikmapslayer_pixmap.h"
41 #include <unistd.h>
42 #include <sys/stat.h>
43 #include <sys/types.h>
45 #include "mapcache.h"
46 /* only for dialog.h -- ugh */
47 #include "vikwaypoint.h"
48 #include "dialog.h"
50 #include "vikstatus.h"
51 #include "background.h"
53 #include "vikaggregatelayer.h"
54 #include "viklayerspanel.h"
56 #include "mapcoord.h"
57 #include "terraserver.h"
59 /****** MAP TYPES ******/
61 static GList *__map_types = NULL;
63 #define NUM_MAP_TYPES g_list_length(__map_types)
65 /* List of label for each map type */
66 static GList *params_maptypes = NULL;
68 /* Corresponding IDS. (Cf. field uniq_id in VikMapsLayer struct) */
69 static GList *params_maptypes_ids = NULL;
71 /******** MAPZOOMS *********/
73 static gchar *params_mapzooms[] = { "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 };
74 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 };
75 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 };
77 #define NUM_MAPZOOMS (sizeof(params_mapzooms)/sizeof(params_mapzooms[0]) - 1)
79 /**************************/
82 static VikMapsLayer *maps_layer_copy ( VikMapsLayer *vml, VikViewport *vvp );
83 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len );
84 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
85 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp );
86 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id );
87 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp );
88 static VikMapsLayer *maps_layer_new ( VikViewport *vvp );
89 static void maps_layer_free ( VikMapsLayer *vml );
90 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
91 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
92 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp );
93 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir );
94 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload );
95 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp );
98 static VikLayerParamScale params_scales[] = {
99 /* min, max, step, digits (decimal places) */
100 { 0, 255, 3, 0 }, /* alpha */
103 VikLayerParam maps_layer_params[] = {
104 { "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, "Map Type:", VIK_LAYER_WIDGET_RADIOGROUP, NULL, NULL },
105 { "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, "Maps Directory (Optional):", VIK_LAYER_WIDGET_FILEENTRY },
106 { "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, "Alpha:", VIK_LAYER_WIDGET_HSCALE, params_scales },
107 { "autodownload", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, "Autodownload maps:", VIK_LAYER_WIDGET_CHECKBUTTON },
108 { "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, "Zoom Level:", VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms },
111 enum { PARAM_MAPTYPE=0, PARAM_CACHE_DIR, PARAM_ALPHA, PARAM_AUTODOWNLOAD, PARAM_MAPZOOM, NUM_PARAMS };
113 static VikToolInterface maps_tools[] = {
114 { "Maps Download", (VikToolConstructorFunc) maps_layer_download_create, NULL, NULL, NULL,
115 (VikToolMouseFunc) maps_layer_download_click, NULL, (VikToolMouseFunc) maps_layer_download_release },
118 VikLayerInterface vik_maps_layer_interface = {
119 "Map",
120 &mapslayer_pixbuf,
122 maps_tools,
123 sizeof(maps_tools) / sizeof(maps_tools[0]),
125 maps_layer_params,
126 NUM_PARAMS,
127 NULL,
130 VIK_MENU_ITEM_ALL,
132 (VikLayerFuncCreate) maps_layer_new,
133 (VikLayerFuncRealize) NULL,
134 (VikLayerFuncPostRead) NULL,
135 (VikLayerFuncFree) maps_layer_free,
137 (VikLayerFuncProperties) NULL,
138 (VikLayerFuncDraw) maps_layer_draw,
139 (VikLayerFuncChangeCoordMode) NULL,
141 (VikLayerFuncSetMenuItemsSelection) NULL,
142 (VikLayerFuncGetMenuItemsSelection) NULL,
144 (VikLayerFuncAddMenuItems) maps_layer_add_menu_items,
145 (VikLayerFuncSublayerAddMenuItems) NULL,
147 (VikLayerFuncSublayerRenameRequest) NULL,
148 (VikLayerFuncSublayerToggleVisible) NULL,
150 (VikLayerFuncCopy) maps_layer_copy,
151 (VikLayerFuncMarshall) maps_layer_marshall,
152 (VikLayerFuncUnmarshall) maps_layer_unmarshall,
154 (VikLayerFuncSetParam) maps_layer_set_param,
155 (VikLayerFuncGetParam) maps_layer_get_param,
157 (VikLayerFuncReadFileData) NULL,
158 (VikLayerFuncWriteFileData) NULL,
160 (VikLayerFuncDeleteItem) NULL,
161 (VikLayerFuncCopyItem) NULL,
162 (VikLayerFuncPasteItem) NULL,
163 (VikLayerFuncFreeCopiedItem) NULL,
164 (VikLayerFuncDragDropRequest) NULL,
167 struct _VikMapsLayer {
168 VikLayer vl;
169 guint maptype;
170 gchar *cache_dir;
171 guint8 alpha;
172 guint mapzoom_id;
173 gdouble xmapzoom, ymapzoom;
175 gboolean autodownload;
176 VikCoord *last_center;
177 gdouble last_xmpp;
178 gdouble last_ympp;
180 gint dl_tool_x, dl_tool_y;
182 GtkMenu *dl_right_click_menu;
183 VikCoord redownload_ul, redownload_br; /* right click menu only */
184 VikViewport *redownload_vvp;
187 enum { REDOWNLOAD_NONE = 0, REDOWNLOAD_BAD, REDOWNLOAD_ALL, DOWNLOAD_OR_REFRESH };
190 /****************************************/
191 /******** MAPS LAYER TYPES **************/
192 /****************************************/
194 void maps_layer_register_type ( const char *label, guint id, VikMapsLayer_MapType *map_type )
196 g_assert(label != NULL);
197 g_assert(map_type != NULL);
198 g_assert(id == map_type->uniq_id);
200 /* Add the label */
201 params_maptypes = g_list_append(params_maptypes, g_strdup(label));
203 /* Add the id */
204 params_maptypes_ids = g_list_append(params_maptypes_ids, (gpointer)id);
206 /* We have to clone */
207 VikMapsLayer_MapType *clone = g_memdup(map_type, sizeof(VikMapsLayer_MapType));
208 /* Register the clone in the list */
209 __map_types = g_list_append(__map_types, clone);
211 /* Hack
212 We have to ensure the mode LayerParam reference the up-to-date
213 GLists.
216 memcpy(&maps_layer_params[0].widget_data, &params_maptypes, sizeof(gpointer));
217 memcpy(&maps_layer_params[0].extra_widget_data, &params_maptypes_ids, sizeof(gpointer));
219 maps_layer_params[0].widget_data = params_maptypes;
220 maps_layer_params[0].extra_widget_data = params_maptypes_ids;
223 #define MAPS_LAYER_NTH_LABEL(n) ((gchar*)g_list_nth_data(params_maptypes, (n)))
224 #define MAPS_LAYER_NTH_ID(n) ((guint)g_list_nth_data(params_maptypes_ids, (n)))
225 #define MAPS_LAYER_NTH_TYPE(n) ((VikMapsLayer_MapType*)g_list_nth_data(__map_types, (n)))
227 gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
229 return(vml->maptype);
232 gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
234 return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
237 /****************************************/
238 /******** CACHE DIR STUFF ***************/
239 /****************************************/
241 #ifdef WINDOWS
242 #define MAPS_CACHE_DIR "C:\\VIKING-MAPS\\"
243 #define DIRSTRUCTURE "%st%ds%dz%d\\%d\\%d"
244 #else /* POSIX */
246 #include <stdlib.h>
248 #define MAPS_CACHE_DIR maps_layer_default_dir()
249 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
250 #define DIRSTRUCTURE "%st%ds%dz%d/%d/%d"
252 static gchar *maps_layer_default_dir ()
254 static gchar defaultdir[512];
255 static gboolean already_run = 0;
256 if ( ! already_run )
258 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
259 gchar *mapdir = getenv("VIKING_MAPS");
260 if ( mapdir && strlen(mapdir) < 497 ) {
261 strcpy ( defaultdir, mapdir );
262 } else if ( access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
263 strcpy ( defaultdir, GLOBAL_MAPS_DIR );
264 } else {
265 gchar *home = getenv("HOME");
266 if ( home && strlen(home) < 497 )
268 strcpy ( defaultdir, home );
269 strcat ( defaultdir, "/.viking-maps/" );
271 else
273 strcpy ( defaultdir, ".viking-maps/" );
276 already_run = 1;
278 return defaultdir;
281 #endif
283 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
285 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && access ( vml->cache_dir, F_OK ) != 0 )
287 #ifdef WINDOWS
288 mkdir ( vml->cache_dir );
289 #else
290 mkdir ( vml->cache_dir, 0777 );
291 #endif
295 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
297 guint len;
298 g_assert ( vml != NULL);
299 if ( vml->cache_dir )
300 g_free ( vml->cache_dir );
302 if ( dir == NULL || dir[0] == '\0' )
303 vml->cache_dir = g_strdup ( MAPS_CACHE_DIR );
304 else
306 len = strlen(dir);
307 if ( dir[len-1] != VIKING_FILE_SEP )
309 vml->cache_dir = g_malloc ( len+2 );
310 strncpy ( vml->cache_dir, dir, len );
311 vml->cache_dir[len] = VIKING_FILE_SEP;
312 vml->cache_dir[len+1] = '\0';
314 else
315 vml->cache_dir = g_strdup ( dir );
317 maps_layer_mkdir_if_default_dir ( vml );
320 /****************************************/
321 /******** GOBJECT STUFF *****************/
322 /****************************************/
324 GType vik_maps_layer_get_type ()
326 static GType vml_type = 0;
328 if (!vml_type)
330 static const GTypeInfo vml_info =
332 sizeof (VikMapsLayerClass),
333 NULL, /* base_init */
334 NULL, /* base_finalize */
335 NULL, /* class init */
336 NULL, /* class_finalize */
337 NULL, /* class_data */
338 sizeof (VikMapsLayer),
340 NULL /* instance init */
342 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
345 return vml_type;
348 /****************************************/
349 /************** PARAMETERS **************/
350 /****************************************/
352 static guint map_index_to_uniq_id (guint8 index)
354 g_assert ( index < NUM_MAP_TYPES );
355 return MAPS_LAYER_NTH_TYPE(index)->uniq_id;
358 static guint map_uniq_id_to_index ( guint uniq_id )
360 gint i;
361 for ( i = 0; i < NUM_MAP_TYPES; i++ )
362 if ( MAPS_LAYER_NTH_TYPE(i)->uniq_id == uniq_id )
363 return i;
364 return NUM_MAP_TYPES; /* no such thing */
367 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp )
369 switch ( id )
371 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
372 case PARAM_MAPTYPE: {
373 gint maptype = map_uniq_id_to_index(data.u);
374 if ( maptype == NUM_MAP_TYPES ) g_warning("Unknown map type");
375 else vml->maptype = maptype;
376 break;
378 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
379 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
380 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
381 vml->mapzoom_id = data.u;
382 vml->xmapzoom = __mapzooms_x [data.u];
383 vml->ymapzoom = __mapzooms_y [data.u];
384 }else g_warning ("Unknown Map Zoom"); break;
386 return TRUE;
389 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id )
391 VikLayerParamData rv;
392 switch ( id )
394 case PARAM_CACHE_DIR: rv.s = (vml->cache_dir && strcmp(vml->cache_dir, MAPS_CACHE_DIR) != 0) ? vml->cache_dir : ""; break;
395 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
396 case PARAM_ALPHA: rv.u = vml->alpha; break;
397 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
398 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
400 return rv;
403 /****************************************/
404 /****** CREATING, COPYING, FREEING ******/
405 /****************************************/
407 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
409 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
410 vik_layer_init ( VIK_LAYER(vml), VIK_LAYER_MAPS );
411 vml->maptype = 0;
412 vml->alpha = 255;
413 vml->mapzoom_id = 0;
414 vml->dl_tool_x = vml->dl_tool_y = -1;
415 maps_layer_set_cache_dir ( vml, NULL );
416 vml->autodownload = FALSE;
417 vml->last_center = NULL;
418 vml->last_xmpp = 0.0;
419 vml->last_ympp = 0.0;
421 vml->dl_right_click_menu = NULL;
423 return vml;
426 static void maps_layer_free ( VikMapsLayer *vml )
428 if ( vml->cache_dir )
429 g_free ( vml->cache_dir );
430 if ( vml->dl_right_click_menu )
431 gtk_object_sink ( GTK_OBJECT(vml->dl_right_click_menu) );
432 if (vml->last_center)
433 g_free(vml->last_center);
436 static VikMapsLayer *maps_layer_copy ( VikMapsLayer *vml, VikViewport *vvp )
438 VikMapsLayer *rv = maps_layer_new ( vvp );
439 *rv = *vml;
440 rv->cache_dir = g_strdup(rv->cache_dir);
441 VIK_LAYER(rv)->name = NULL;
442 return rv;
445 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
447 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
450 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
452 VikMapsLayer *rv = maps_layer_new ( vvp );
453 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
454 return rv;
457 /*********************/
458 /****** DRAWING ******/
459 /*********************/
461 static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
463 guchar *pixels;
464 gint width, height, iii, jjj;
466 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
468 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
469 g_object_unref(G_OBJECT(pixbuf));
470 pixbuf = tmp;
473 pixels = gdk_pixbuf_get_pixels(pixbuf);
474 width = gdk_pixbuf_get_width(pixbuf);
475 height = gdk_pixbuf_get_height(pixbuf);
477 /* r,g,b,a,r,g,b,a.... */
478 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
480 pixels += 3;
481 *pixels++ = alpha;
483 return pixbuf;
486 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
488 GdkPixbuf *tmp;
489 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
490 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_BILINEAR);
491 g_object_unref ( G_OBJECT(pixbuf) );
492 return tmp;
495 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
497 GdkPixbuf *pixbuf;
499 /* get the thing */
500 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
501 mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
503 if ( ! pixbuf ) {
504 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
505 vml->cache_dir, mode,
506 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
507 if ( access ( filename_buf, R_OK ) == 0) {
509 GError *gx = NULL;
510 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
512 if (gx)
514 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
515 g_warning ( "Couldn't open image file: %s", gx->message );
517 g_error_free ( gx );
518 if ( pixbuf )
519 g_object_unref ( G_OBJECT(pixbuf) );
520 pixbuf = NULL;
521 } else {
522 if ( vml->alpha < 255 )
523 pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
524 if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
525 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
527 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
528 mapcoord->z, MAPS_LAYER_NTH_TYPE(vml->maptype)->uniq_id,
529 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
534 return pixbuf;
537 gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
539 const VikCoord *center = vik_viewport_get_center ( vvp );
541 if (vml->last_center == NULL) {
542 VikCoord *new_center = g_malloc(sizeof(VikCoord));
543 *new_center = *center;
544 vml->last_center = new_center;
545 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
546 vml->last_ympp = vik_viewport_get_ympp(vvp);
547 return TRUE;
550 /* TODO: perhaps vik_coord_diff() */
551 if (vik_coord_equals(vml->last_center, center)
552 && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
553 && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
554 return FALSE;
556 *(vml->last_center) = *center;
557 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
558 vml->last_ympp = vik_viewport_get_ympp(vvp);
559 return TRUE;
562 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
564 MapCoord ulm, brm;
565 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
566 gdouble yzoom = vik_viewport_get_ympp ( vvp );
567 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
569 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
570 xshrinkfactor = vml->xmapzoom / xzoom;
571 yshrinkfactor = vml->ymapzoom / yzoom;
572 if ( xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
573 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) {
574 xzoom = vml->xmapzoom;
575 yzoom = vml->xmapzoom;
576 } else {
577 g_warning ( "Cowardly refusing to draw tiles at a shrinkfactor more than %.3f (zoomed out) or less than %.3f (zoomed in).", 1/MIN_SHRINKFACTOR, 1/MAX_SHRINKFACTOR );
581 /* coord -> ID */
582 VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
583 if ( map_type->coord_to_mapcoord ( ul, xzoom, yzoom, &ulm ) &&
584 map_type->coord_to_mapcoord ( br, xzoom, yzoom, &brm ) ) {
586 /* loop & draw */
587 gint x, y;
588 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
589 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
590 gint mode = map_type->uniq_id;
592 VikCoord coord;
593 gint xx, yy, width, height;
594 GdkPixbuf *pixbuf;
596 guint max_path_len = strlen(vml->cache_dir) + 40;
597 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
599 if ( vml->autodownload && should_start_autodownload(vml, vvp)) {
600 g_debug("DEBUG: Starting autodownload\n");
601 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
604 if ( map_type->tilesize_x == 0 ) {
605 for ( x = xmin; x <= xmax; x++ ) {
606 for ( y = ymin; y <= ymax; y++ ) {
607 ulm.x = x;
608 ulm.y = y;
609 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
610 if ( pixbuf ) {
611 width = gdk_pixbuf_get_width ( pixbuf );
612 height = gdk_pixbuf_get_height ( pixbuf );
614 map_type->mapcoord_to_center_coord ( &ulm, &coord );
615 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
616 xx -= (width/2);
617 yy -= (height/2);
619 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
623 } else { /* tilesize is known, don't have to keep converting coords */
624 gdouble tilesize_x = map_type->tilesize_x * xshrinkfactor;
625 gdouble tilesize_y = map_type->tilesize_y * yshrinkfactor;
626 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
627 gint tilesize_x_ceil = ceil ( tilesize_x );
628 gint tilesize_y_ceil = ceil ( tilesize_y );
629 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
630 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
631 gdouble xx, yy; gint xx_tmp, yy_tmp;
632 gint base_yy, xend, yend;
633 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
634 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
636 map_type->mapcoord_to_center_coord ( &ulm, &coord );
637 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
638 xx = xx_tmp; yy = yy_tmp;
639 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
640 * eg if tile size 128, shrinkfactor 0.333 */
641 xx -= (tilesize_x/2);
642 base_yy = yy - (tilesize_y/2);
644 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
645 yy = base_yy;
646 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
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 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
653 yy += tilesize_y;
655 xx += tilesize_x;
659 g_free ( path_buf );
663 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
665 if ( MAPS_LAYER_NTH_TYPE(vml->maptype)->drawmode == vik_viewport_get_drawmode ( vvp ) )
667 VikCoord ul, br;
669 /* get corner coords */
670 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
671 /* UTM multi-zone stuff by Kit Transue */
672 gchar leftmost_zone, rightmost_zone, i;
673 leftmost_zone = vik_viewport_leftmost_zone( vvp );
674 rightmost_zone = vik_viewport_rightmost_zone( vvp );
675 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
676 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
677 maps_layer_draw_section ( vml, vvp, &ul, &br );
680 else {
681 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
682 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
684 maps_layer_draw_section ( vml, vvp, &ul, &br );
689 /*************************/
690 /****** DOWNLOADING ******/
691 /*************************/
693 /* pass along data to thread, exists even if layer is deleted. */
694 typedef struct {
695 gchar *cache_dir;
696 gchar *filename_buf;
697 gint x0, y0, xf, yf;
698 MapCoord mapcoord;
699 gint maptype;
700 gint maxlen;
701 gint mapstoget;
702 gint redownload;
703 gboolean refresh_display;
704 VikMapsLayer *vml;
705 VikViewport *vvp;
706 gboolean map_layer_alive;
707 GMutex *mutex;
708 } MapDownloadInfo;
710 static void mdi_free ( MapDownloadInfo *mdi )
712 g_mutex_free(mdi->mutex);
713 g_free ( mdi->cache_dir );
714 g_free ( mdi->filename_buf );
715 g_free ( mdi );
718 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
720 MapDownloadInfo *mdi = ptr;
721 g_mutex_lock(mdi->mutex);
722 mdi->map_layer_alive = FALSE;
723 g_mutex_unlock(mdi->mutex);
726 static void map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
728 guint donemaps = 0;
729 gint x, y;
730 for ( x = mdi->x0; x <= mdi->xf; x++ )
732 for ( y = mdi->y0; y <= mdi->yf; y++ )
734 gboolean remove_mem_cache = FALSE;
735 gboolean need_download = FALSE;
736 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
737 mdi->cache_dir, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id,
738 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
740 donemaps++;
741 a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
743 if ( mdi->redownload == REDOWNLOAD_ALL)
744 remove ( mdi->filename_buf );
746 else if ( (mdi->redownload == REDOWNLOAD_BAD) && (access ( mdi->filename_buf, F_OK ) == 0) )
748 /* see if this one is bad or what */
749 GError *gx = NULL;
750 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
751 if (gx || (!pixbuf))
752 remove ( mdi->filename_buf );
753 if ( pixbuf )
754 g_object_unref ( pixbuf );
755 if ( gx )
756 g_error_free ( gx );
759 if ( access ( mdi->filename_buf, F_OK ) != 0 )
761 need_download = TRUE;
762 if (( mdi->redownload != REDOWNLOAD_NONE ) &&
763 ( mdi->redownload != DOWNLOAD_OR_REFRESH ))
764 remove_mem_cache = TRUE;
765 } else if ( mdi->redownload == DOWNLOAD_OR_REFRESH ) {
766 remove_mem_cache = TRUE;
767 } else
768 continue;
770 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
772 if (need_download) {
773 if ( MAPS_LAYER_NTH_TYPE(mdi->maptype)->download ( &(mdi->mapcoord), mdi->filename_buf ))
774 continue;
777 gdk_threads_enter();
778 g_mutex_lock(mdi->mutex);
779 if (remove_mem_cache)
780 a_mapcache_remove_all_shrinkfactors ( x, y, mdi->mapcoord.z, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id, mdi->mapcoord.scale );
781 if (mdi->refresh_display && mdi->map_layer_alive) {
782 /* TODO: check if it's on visible area */
783 vik_layer_emit_update ( VIK_LAYER(mdi->vml) );
785 g_mutex_unlock(mdi->mutex);
786 gdk_threads_leave();
787 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
791 g_mutex_lock(mdi->mutex);
792 if (mdi->map_layer_alive)
793 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
794 g_mutex_unlock(mdi->mutex);
797 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
799 if ( mdi->mapcoord.x || mdi->mapcoord.y )
801 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
802 mdi->cache_dir, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id,
803 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
804 if ( access ( mdi->filename_buf, F_OK ) == 0)
806 remove ( mdi->filename_buf );
811 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
813 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
814 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
815 MapCoord ulm, brm;
816 VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
817 if ( map_type->coord_to_mapcoord ( ul, xzoom, yzoom, &ulm )
818 && map_type->coord_to_mapcoord ( br, xzoom, yzoom, &brm ) )
820 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
821 gint a, b;
823 mdi->vml = vml;
824 mdi->vvp = vvp;
825 mdi->map_layer_alive = TRUE;
826 mdi->mutex = g_mutex_new();
827 mdi->refresh_display = TRUE;
829 /* cache_dir and buffer for dest filename */
830 mdi->cache_dir = g_strdup ( vml->cache_dir );
831 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
832 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
833 mdi->maptype = vml->maptype;
835 mdi->mapcoord = ulm;
837 mdi->redownload = redownload;
839 mdi->x0 = MIN(ulm.x, brm.x);
840 mdi->xf = MAX(ulm.x, brm.x);
841 mdi->y0 = MIN(ulm.y, brm.y);
842 mdi->yf = MAX(ulm.y, brm.y);
844 mdi->mapstoget = 0;
846 if ( mdi->redownload ) {
847 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
848 } else {
849 /* calculate how many we need */
850 for ( a = mdi->x0; a <= mdi->xf; a++ )
852 for ( b = mdi->y0; b <= mdi->yf; b++ )
854 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
855 vml->cache_dir, map_type->uniq_id, ulm.scale,
856 ulm.z, a, b );
857 if ( access ( mdi->filename_buf, F_OK ) != 0)
858 mdi->mapstoget++;
863 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
865 if ( mdi->mapstoget )
867 gchar *tmp = g_strdup_printf ( "%s %s%d %s %s...", redownload ? "Redownloading" : "Downloading", redownload == REDOWNLOAD_BAD ? "up to " : "", mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype), (mdi->mapstoget == 1) ? "map" : "maps" );
869 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
870 /* launch the thread */
871 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
872 tmp, /* description string */
873 (vik_thr_func) map_download_thread, /* function to call within thread */
874 mdi, /* pass along data */
875 (vik_thr_free_func) mdi_free, /* function to free pass along data */
876 (vik_thr_free_func) mdi_cancel_cleanup,
877 mdi->mapstoget );
878 g_free ( tmp );
880 else
881 mdi_free ( mdi );
885 void maps_layer_download_section_without_redraw( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
887 MapCoord ulm, brm;
888 VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
890 if (!map_type->coord_to_mapcoord(ul, zoom, zoom, &ulm)
891 || !map_type->coord_to_mapcoord(br, zoom, zoom, &brm)) {
892 g_warning("%s() coord_to_mapcoord() failed\n", __PRETTY_FUNCTION__);
893 return;
896 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
897 gint i, j;
899 mdi->vml = vml;
900 mdi->vvp = vvp;
901 mdi->map_layer_alive = TRUE;
902 mdi->mutex = g_mutex_new();
903 mdi->refresh_display = FALSE;
905 mdi->cache_dir = g_strdup ( vml->cache_dir );
906 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
907 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
908 mdi->maptype = vml->maptype;
910 mdi->mapcoord = ulm;
912 mdi->redownload = REDOWNLOAD_NONE;
914 mdi->x0 = MIN(ulm.x, brm.x);
915 mdi->xf = MAX(ulm.x, brm.x);
916 mdi->y0 = MIN(ulm.y, brm.y);
917 mdi->yf = MAX(ulm.y, brm.y);
919 mdi->mapstoget = 0;
921 for (i = mdi->x0; i <= mdi->xf; i++) {
922 for (j = mdi->y0; j <= mdi->yf; j++) {
923 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
924 vml->cache_dir, map_type->uniq_id, ulm.scale,
925 ulm.z, i, j );
926 if ( access ( mdi->filename_buf, F_OK ) != 0)
927 mdi->mapstoget++;
931 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
933 if (mdi->mapstoget) {
934 gchar *tmp = g_strdup_printf ( "%s %d %s %s...", "Downloading", mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype), (mdi->mapstoget == 1) ? "map" : "maps" );
936 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
937 /* launch the thread */
938 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
939 tmp, /* description string */
940 (vik_thr_func) map_download_thread, /* function to call within thread */
941 mdi, /* pass along data */
942 (vik_thr_free_func) mdi_free, /* function to free pass along data */
943 (vik_thr_free_func) mdi_cancel_cleanup,
944 mdi->mapstoget );
945 g_free ( tmp );
947 else
948 mdi_free ( mdi );
951 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
953 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
955 static void maps_layer_redownload_all ( VikMapsLayer *vml )
957 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
960 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
962 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
963 return FALSE;
964 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
966 if ( event->button == 1 )
968 VikCoord ul, br;
969 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 );
970 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 );
971 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
972 vml->dl_tool_x = vml->dl_tool_y = -1;
973 return TRUE;
975 else
977 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) );
978 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) );
980 vml->redownload_vvp = vvp;
982 vml->dl_tool_x = vml->dl_tool_y = -1;
984 if ( ! vml->dl_right_click_menu ) {
985 GtkWidget *item;
986 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
988 item = gtk_menu_item_new_with_label ( "Redownload bad map(s)" );
989 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
990 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
992 item = gtk_menu_item_new_with_label ( "Redownload all map(s)" );
993 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
994 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
997 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
998 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1001 return FALSE;
1004 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1006 return vvp;
1009 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1011 MapCoord tmp;
1012 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1013 return FALSE;
1014 VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
1015 if ( map_type->drawmode == vik_viewport_get_drawmode ( vvp ) &&
1016 map_type->coord_to_mapcoord ( vik_viewport_get_center ( vvp ),
1017 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1018 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1019 &tmp ) ) {
1020 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1021 return TRUE;
1023 return FALSE;
1026 #if 0
1027 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1029 VikCoord coord;
1030 MapCoord mapcoord;
1031 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1032 if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1033 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1034 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1035 &mapcoord ) ) {
1036 gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1037 vml->cache_dir, __map_types[vml->maptype].uniq_id,
1038 mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1040 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1041 g_free ( filename_buf );
1042 vik_layer_emit_update ( VIK_LAYER(vml) );
1043 return TRUE;
1046 return FALSE;
1047 #endif
1050 static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
1052 VikMapsLayer *vml = vml_vvp[0];
1053 VikViewport *vvp = vml_vvp[1];
1055 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1056 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1058 VikCoord ul, br;
1059 MapCoord ulm, brm;
1061 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1062 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1064 VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
1065 if ( map_type->drawmode == vik_viewport_get_drawmode ( vvp ) &&
1066 map_type->coord_to_mapcoord ( &ul, xzoom, yzoom, &ulm ) &&
1067 map_type->coord_to_mapcoord ( &br, xzoom, yzoom, &brm ) )
1068 start_download_thread ( vml, vvp, &ul, &br, redownload );
1069 else
1070 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), "Wrong drawmode / zoom level for this map." );
1074 static void maps_layer_download_onscreen_maps ( gpointer vml_vvp[2] )
1076 download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1079 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1081 download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1084 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1086 static gpointer pass_along[2];
1087 GtkWidget *item;
1088 pass_along[0] = vml;
1089 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1091 item = gtk_menu_item_new();
1092 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1093 gtk_widget_show ( item );
1095 item = gtk_menu_item_new_with_label ( "Download Onscreen Maps" );
1096 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_onscreen_maps), pass_along );
1097 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1098 gtk_widget_show ( item );
1100 item = gtk_menu_item_new_with_label ( "Refresh Onscreen Tiles" );
1101 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1102 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1103 gtk_widget_show ( item );