]> git.street.me.uk Git - andy/viking.git/blob - src/vikmapslayer.c
Add Terraserver
[andy/viking.git] / src / vikmapslayer.c
1 /*
2  * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3  *
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>
7  *
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.
12  *
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.
17  *
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
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #define MAX_SHRINKFACTOR 8.0000001 /* zoom 1 viewing 8-tiles */
29 #define MIN_SHRINKFACTOR 0.0312499 /* zoom 32 viewing 1-tiles */
30
31 #define REAL_MIN_SHRINKFACTOR 0.0039062499 /* if shrinkfactor is between MAX and REAL_MAX, will only check for existence */
32
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>
38
39 #include <string.h>
40 #include <math.h>
41 #include "globals.h"
42 #include "coords.h"
43 #include "vikcoord.h"
44 #include "viktreeview.h"
45 #include "vikviewport.h"
46 #include "viklayer.h"
47 #include "vikmapslayer.h"
48
49 #ifdef HAVE_UNISTD_H
50 #include <unistd.h>
51 #endif
52
53 #include "mapcache.h"
54 /* only for dialog.h -- ugh */
55 #include "vikwaypoint.h"
56 #include "dialog.h"
57
58 #include "vikstatus.h"
59 #include "background.h"
60
61 #include "vikaggregatelayer.h"
62 #include "viklayerspanel.h"
63
64 #include "mapcoord.h"
65 #include "terraserver.h"
66
67 #include "icons/icons.h"
68
69 /****** MAP TYPES ******/
70
71 static GList *__map_types = NULL;
72
73 #define NUM_MAP_TYPES g_list_length(__map_types)
74
75 /* List of label for each map type */
76 static GList *params_maptypes = NULL;
77
78 /* Corresponding IDS. (Cf. field uniq_id in VikMapsLayer struct) */
79 static GList *params_maptypes_ids = NULL;
80
81 /******** MAPZOOMS *********/
82
83 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 };
84 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 };
85 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 };
86
87 #define NUM_MAPZOOMS (sizeof(params_mapzooms)/sizeof(params_mapzooms[0]) - 1)
88
89 /**************************/
90
91
92 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file);
93 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len );
94 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
95 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp );
96 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id );
97 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp );
98 static VikMapsLayer *maps_layer_new ( VikViewport *vvp );
99 static void maps_layer_free ( VikMapsLayer *vml );
100 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
101 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
102 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp );
103 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir );
104 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload );
105 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp );
106
107
108 static VikLayerParamScale params_scales[] = {
109   /* min, max, step, digits (decimal places) */
110  { 0, 255, 3, 0 }, /* alpha */
111 };
112
113 VikLayerParam maps_layer_params[] = {
114   { "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Map Type:"), VIK_LAYER_WIDGET_RADIOGROUP, NULL, NULL },
115   { "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Maps Directory (Optional):"), VIK_LAYER_WIDGET_FILEENTRY },
116   { "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales },
117   { "autodownload", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload maps:"), VIK_LAYER_WIDGET_CHECKBUTTON },
118   { "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Zoom Level:"), VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms },
119 };
120
121 enum { PARAM_MAPTYPE=0, PARAM_CACHE_DIR, PARAM_ALPHA, PARAM_AUTODOWNLOAD, PARAM_MAPZOOM, NUM_PARAMS };
122
123 static VikToolInterface maps_tools[] = {
124   { N_("Maps Download"), (VikToolConstructorFunc) maps_layer_download_create, NULL, NULL, NULL,  
125     (VikToolMouseFunc) maps_layer_download_click, NULL,  (VikToolMouseFunc) maps_layer_download_release,
126     (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_mapdl_pixbuf },
127 };
128
129 VikLayerInterface vik_maps_layer_interface = {
130   N_("Map"),
131   &vikmapslayer_pixbuf,
132
133   maps_tools,
134   sizeof(maps_tools) / sizeof(maps_tools[0]),
135
136   maps_layer_params,
137   NUM_PARAMS,
138   NULL,
139   0,
140
141   VIK_MENU_ITEM_ALL,
142
143   (VikLayerFuncCreate)                  maps_layer_new,
144   (VikLayerFuncRealize)                 NULL,
145                                         maps_layer_post_read,
146   (VikLayerFuncFree)                    maps_layer_free,
147
148   (VikLayerFuncProperties)              NULL,
149   (VikLayerFuncDraw)                    maps_layer_draw,
150   (VikLayerFuncChangeCoordMode)         NULL,
151
152   (VikLayerFuncSetMenuItemsSelection)   NULL,
153   (VikLayerFuncGetMenuItemsSelection)   NULL,
154
155   (VikLayerFuncAddMenuItems)            maps_layer_add_menu_items,
156   (VikLayerFuncSublayerAddMenuItems)    NULL,
157
158   (VikLayerFuncSublayerRenameRequest)   NULL,
159   (VikLayerFuncSublayerToggleVisible)   NULL,
160
161   (VikLayerFuncMarshall)                maps_layer_marshall,
162   (VikLayerFuncUnmarshall)              maps_layer_unmarshall,
163
164   (VikLayerFuncSetParam)                maps_layer_set_param,
165   (VikLayerFuncGetParam)                maps_layer_get_param,
166
167   (VikLayerFuncReadFileData)            NULL,
168   (VikLayerFuncWriteFileData)           NULL,
169
170   (VikLayerFuncDeleteItem)              NULL,
171   (VikLayerFuncCopyItem)                NULL,
172   (VikLayerFuncPasteItem)               NULL,
173   (VikLayerFuncFreeCopiedItem)          NULL,
174   (VikLayerFuncDragDropRequest)         NULL,
175 };
176
177 struct _VikMapsLayer {
178   VikLayer vl;
179   guint maptype;
180   gchar *cache_dir;
181   guint8 alpha;
182   guint mapzoom_id;
183   gdouble xmapzoom, ymapzoom;
184
185   gboolean autodownload;
186   VikCoord *last_center;
187   gdouble last_xmpp;
188   gdouble last_ympp;
189
190   gint dl_tool_x, dl_tool_y;
191
192   GtkMenu *dl_right_click_menu;
193   VikCoord redownload_ul, redownload_br; /* right click menu only */
194   VikViewport *redownload_vvp;
195 };
196
197 enum { REDOWNLOAD_NONE = 0, REDOWNLOAD_BAD, REDOWNLOAD_ALL, DOWNLOAD_OR_REFRESH };
198
199
200 /****************************************/
201 /******** MAPS LAYER TYPES **************/
202 /****************************************/
203
204 void maps_layer_register_type ( const char *label, guint id, VikMapsLayer_MapType *map_type )
205 {
206   g_assert(label != NULL);
207   g_assert(map_type != NULL);
208   g_assert(id == map_type->uniq_id);
209
210   /* Add the label */
211   params_maptypes = g_list_append(params_maptypes, g_strdup(label));
212
213   /* Add the id */
214   params_maptypes_ids = g_list_append(params_maptypes_ids, GUINT_TO_POINTER (id));
215
216   /* We have to clone */
217   VikMapsLayer_MapType *clone = g_memdup(map_type, sizeof(VikMapsLayer_MapType));
218   /* Register the clone in the list */
219   __map_types = g_list_append(__map_types, clone);
220
221   /* Hack
222      We have to ensure the mode LayerParam reference the up-to-date
223      GLists.
224   */
225   /*
226   memcpy(&maps_layer_params[0].widget_data, &params_maptypes, sizeof(gpointer));
227   memcpy(&maps_layer_params[0].extra_widget_data, &params_maptypes_ids, sizeof(gpointer));
228   */
229   maps_layer_params[0].widget_data = params_maptypes;
230   maps_layer_params[0].extra_widget_data = params_maptypes_ids;
231 }
232
233 #define MAPS_LAYER_NTH_LABEL(n) ((gchar*)g_list_nth_data(params_maptypes, (n)))
234 #define MAPS_LAYER_NTH_ID(n) ((guint)g_list_nth_data(params_maptypes_ids, (n)))
235 #define MAPS_LAYER_NTH_TYPE(n) ((VikMapsLayer_MapType*)g_list_nth_data(__map_types, (n)))
236
237 gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
238 {
239   return(vml->maptype);
240 }
241
242 gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
243 {
244   return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
245 }
246
247 /****************************************/
248 /******** CACHE DIR STUFF ***************/
249 /****************************************/
250
251 #define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
252 #define MAPS_CACHE_DIR maps_layer_default_dir()
253
254 #ifdef WINDOWS
255 #include <io.h>
256 #define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
257 #define LOCAL_MAPS_DIR "VIKING-MAPS"
258 #else /* POSIX */
259 #include <stdlib.h>
260 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
261 #define LOCAL_MAPS_DIR ".viking-maps"
262 #endif
263
264 gchar *maps_layer_default_dir ()
265 {
266   static gchar *defaultdir = NULL;
267   if ( ! defaultdir )
268   {
269     /* Thanks to Mike Davison for the $VIKING_MAPS usage */
270     const gchar *mapdir = g_getenv("VIKING_MAPS");
271     if ( mapdir ) {
272       defaultdir = g_strdup ( mapdir );
273     } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
274       defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
275     } else {
276       const gchar *home = g_get_home_dir();
277       if (!home || g_access(home, W_OK))
278         home = g_get_home_dir ();
279       if ( home )
280         defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
281       else
282         defaultdir = g_strdup ( LOCAL_MAPS_DIR );
283     }
284     if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
285     {
286       /* Add the separator at the end */
287       gchar *tmp = defaultdir;
288       defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
289       g_free(tmp);
290     }
291     g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
292   }
293   return defaultdir;
294 }
295
296 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
297 {
298   if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
299   {
300     g_mkdir ( vml->cache_dir, 0777 );
301   }
302 }
303
304 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
305 {
306   guint len;
307   g_assert ( vml != NULL);
308   g_free ( vml->cache_dir );
309   vml->cache_dir = NULL;
310
311   if ( dir == NULL || dir[0] == '\0' )
312     vml->cache_dir = g_strdup ( MAPS_CACHE_DIR );
313   else
314   {
315     len = strlen(dir);
316     if ( dir[len-1] != G_DIR_SEPARATOR )
317     {
318       vml->cache_dir = g_malloc ( len+2 );
319       strncpy ( vml->cache_dir, dir, len );
320       vml->cache_dir[len] = G_DIR_SEPARATOR;
321       vml->cache_dir[len+1] = '\0';
322     }
323     else
324       vml->cache_dir = g_strdup ( dir );
325   }
326   maps_layer_mkdir_if_default_dir ( vml );
327 }
328
329 /****************************************/
330 /******** GOBJECT STUFF *****************/
331 /****************************************/
332
333 GType vik_maps_layer_get_type ()
334 {
335   static GType vml_type = 0;
336
337   if (!vml_type)
338   {
339     static const GTypeInfo vml_info =
340     {
341       sizeof (VikMapsLayerClass),
342       NULL, /* base_init */
343       NULL, /* base_finalize */
344       NULL, /* class init */
345       NULL, /* class_finalize */
346       NULL, /* class_data */
347       sizeof (VikMapsLayer),
348       0,
349       NULL /* instance init */
350     };
351     vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
352   }
353
354   return vml_type;
355 }
356
357 /****************************************/
358 /************** PARAMETERS **************/
359 /****************************************/
360
361 static guint map_index_to_uniq_id (guint8 index)
362 {
363   g_assert ( index < NUM_MAP_TYPES );
364   return MAPS_LAYER_NTH_TYPE(index)->uniq_id;
365 }
366
367 static guint map_uniq_id_to_index ( guint uniq_id )
368 {
369   gint i;
370   for ( i = 0; i < NUM_MAP_TYPES; i++ )
371     if ( MAPS_LAYER_NTH_TYPE(i)->uniq_id == uniq_id )
372       return i;
373   return NUM_MAP_TYPES; /* no such thing */
374 }
375
376 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp )
377 {
378   switch ( id )
379   {
380     case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
381     case PARAM_MAPTYPE: {
382       gint maptype = map_uniq_id_to_index(data.u);
383       if ( maptype == NUM_MAP_TYPES ) g_warning(_("Unknown map type"));
384       else vml->maptype = maptype;
385       break;
386     }
387     case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
388     case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
389     case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
390                           vml->mapzoom_id = data.u;
391                           vml->xmapzoom = __mapzooms_x [data.u];
392                           vml->ymapzoom = __mapzooms_y [data.u];
393                         }else g_warning (_("Unknown Map Zoom")); break;
394   }
395   return TRUE;
396 }
397
398 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id )
399 {
400   VikLayerParamData rv;
401   switch ( id )
402   {
403     case PARAM_CACHE_DIR: rv.s = (vml->cache_dir && strcmp(vml->cache_dir, MAPS_CACHE_DIR) != 0) ? vml->cache_dir : ""; break;
404     case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
405     case PARAM_ALPHA: rv.u = vml->alpha; break;
406     case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
407     case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
408   }
409   return rv;
410 }
411
412 /****************************************/
413 /****** CREATING, COPYING, FREEING ******/
414 /****************************************/
415
416 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
417 {
418   int idx;
419   VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
420   vik_layer_init ( VIK_LAYER(vml), VIK_LAYER_MAPS );
421   idx = map_uniq_id_to_index(7); /* 7 is id for google maps */
422     vml->maptype = (idx < NUM_MAP_TYPES) ? idx : 0;
423   vml->alpha = 255;
424   vml->mapzoom_id = 0;
425   vml->dl_tool_x = vml->dl_tool_y = -1;
426   maps_layer_set_cache_dir ( vml, NULL );
427   vml->autodownload = FALSE;
428   vml->last_center = NULL;
429   vml->last_xmpp = 0.0;
430   vml->last_ympp = 0.0;
431
432   vml->dl_right_click_menu = NULL;
433
434   return vml;
435 }
436
437 static void maps_layer_free ( VikMapsLayer *vml )
438 {
439   g_free ( vml->cache_dir );
440   vml->cache_dir = NULL;
441   if ( vml->dl_right_click_menu )
442     gtk_object_sink ( GTK_OBJECT(vml->dl_right_click_menu) );
443   g_free(vml->last_center);
444   vml->last_center = NULL;
445 }
446
447 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
448 {
449   if (from_file != TRUE)
450   {
451     /* If this method is not called in file reading context
452      * it is called in GUI context.
453      * So, we can check if we have to inform the user about inconsistency */
454     VikViewportDrawMode vp_drawmode;
455     VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
456     VikMapsLayer_MapType *map_type = NULL;
457  
458     vp_drawmode = vik_viewport_get_drawmode ( VIK_VIEWPORT(vp) );
459     map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
460     if (map_type->drawmode != vp_drawmode) {
461       const gchar *drawmode_name = vik_viewport_get_drawmode_name (VIK_VIEWPORT(vp), map_type->drawmode);
462       gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
463       a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), msg );
464       g_free(msg);
465     }
466   }
467 }
468
469 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
470 {
471   vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
472 }
473
474 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
475 {
476   VikMapsLayer *rv = maps_layer_new ( vvp );
477   vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
478   return rv;
479 }
480
481 /*********************/
482 /****** DRAWING ******/
483 /*********************/
484
485 static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
486 {
487   guchar *pixels;
488   gint width, height, iii, jjj;
489
490   if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
491   {
492     GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
493     g_object_unref(G_OBJECT(pixbuf));
494     pixbuf = tmp;
495   }
496
497   pixels = gdk_pixbuf_get_pixels(pixbuf);
498   width = gdk_pixbuf_get_width(pixbuf);
499   height = gdk_pixbuf_get_height(pixbuf);
500
501   /* r,g,b,a,r,g,b,a.... */
502   for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
503   {
504     pixels += 3;
505     *pixels++ = alpha;
506   }
507   return pixbuf;
508 }
509
510 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
511 {
512   GdkPixbuf *tmp;
513   guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
514   tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_BILINEAR);
515   g_object_unref ( G_OBJECT(pixbuf) );
516   return tmp;
517 }
518
519 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
520 {
521   GdkPixbuf *pixbuf;
522
523   /* get the thing */
524   pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
525                             mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
526
527   if ( ! pixbuf ) {
528     g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
529                      vml->cache_dir, mode,
530                      mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
531     if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE) {
532     {
533       GError *gx = NULL;
534       pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
535
536       if (gx)
537       {
538         if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
539           g_warning ( _("Couldn't open image file: %s"), gx->message );
540
541           g_error_free ( gx );
542           if ( pixbuf )
543             g_object_unref ( G_OBJECT(pixbuf) );
544           pixbuf = NULL;
545         } else {
546           if ( vml->alpha < 255 )
547             pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
548           if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
549             pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
550
551           a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y, 
552               mapcoord->z, MAPS_LAYER_NTH_TYPE(vml->maptype)->uniq_id, 
553               mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
554         }
555       }
556     }
557   }
558   return pixbuf;
559 }
560
561 gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
562 {
563   const VikCoord *center = vik_viewport_get_center ( vvp );
564
565   if (vml->last_center == NULL) {
566     VikCoord *new_center = g_malloc(sizeof(VikCoord));
567     *new_center = *center;
568     vml->last_center = new_center;
569     vml->last_xmpp = vik_viewport_get_xmpp(vvp);
570     vml->last_ympp = vik_viewport_get_ympp(vvp);
571     return TRUE;
572   }
573
574   /* TODO: perhaps vik_coord_diff() */
575   if (vik_coord_equals(vml->last_center, center)
576       && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
577       && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
578     return FALSE;
579
580   *(vml->last_center) = *center;
581     vml->last_xmpp = vik_viewport_get_xmpp(vvp);
582     vml->last_ympp = vik_viewport_get_ympp(vvp);
583   return TRUE;
584 }
585
586 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
587 {
588   MapCoord ulm, brm;
589   gdouble xzoom = vik_viewport_get_xmpp ( vvp );
590   gdouble yzoom = vik_viewport_get_ympp ( vvp );
591   gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
592   gdouble existence_only = FALSE;
593
594   if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
595     xshrinkfactor = vml->xmapzoom / xzoom;
596     yshrinkfactor = vml->ymapzoom / yzoom;
597     xzoom = vml->xmapzoom;
598     yzoom = vml->xmapzoom;
599     if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
600          yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
601       if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR )
602         existence_only = TRUE;
603       else {
604         g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
605         return;
606       }
607     }
608   }
609
610   /* coord -> ID */
611   VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
612   if ( map_type->coord_to_mapcoord ( ul, xzoom, yzoom, &ulm ) &&
613        map_type->coord_to_mapcoord ( br, xzoom, yzoom, &brm ) ) {
614
615     /* loop & draw */
616     gint x, y;
617     gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
618     gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
619     gint mode = map_type->uniq_id;
620
621     VikCoord coord;
622     gint xx, yy, width, height;
623     GdkPixbuf *pixbuf;
624
625     guint max_path_len = strlen(vml->cache_dir) + 40;
626     gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
627
628     if ( (!existence_only) && vml->autodownload  && should_start_autodownload(vml, vvp)) {
629 #ifdef DEBUG
630       fputs(stderr, "DEBUG: Starting autodownload\n");
631 #endif
632       start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
633     }
634
635     if ( map_type->tilesize_x == 0 && !existence_only ) {
636       for ( x = xmin; x <= xmax; x++ ) {
637         for ( y = ymin; y <= ymax; y++ ) {
638           ulm.x = x;
639           ulm.y = y;
640           pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
641           if ( pixbuf ) {
642             width = gdk_pixbuf_get_width ( pixbuf );
643             height = gdk_pixbuf_get_height ( pixbuf );
644
645             map_type->mapcoord_to_center_coord ( &ulm, &coord );
646             vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
647             xx -= (width/2);
648             yy -= (height/2);
649
650             vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
651           }
652         }
653       }
654     } else { /* tilesize is known, don't have to keep converting coords */
655       gdouble tilesize_x = map_type->tilesize_x * xshrinkfactor;
656       gdouble tilesize_y = map_type->tilesize_y * yshrinkfactor;
657       /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
658       gint tilesize_x_ceil = ceil ( tilesize_x );
659       gint tilesize_y_ceil = ceil ( tilesize_y );
660       gint8 xinc = (ulm.x == xmin) ? 1 : -1;
661       gint8 yinc = (ulm.y == ymin) ? 1 : -1;
662       gdouble xx, yy; gint xx_tmp, yy_tmp;
663       gint base_yy, xend, yend;
664
665       GdkGC *black_gc = GTK_WIDGET(vvp)->style->black_gc;
666
667       xend = (xinc == 1) ? (xmax+1) : (xmin-1);
668       yend = (yinc == 1) ? (ymax+1) : (ymin-1);
669
670       map_type->mapcoord_to_center_coord ( &ulm, &coord );
671       vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
672       xx = xx_tmp; yy = yy_tmp;
673       /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
674        * eg if tile size 128, shrinkfactor 0.333 */
675       xx -= (tilesize_x/2);
676       base_yy = yy - (tilesize_y/2);
677
678       for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
679         yy = base_yy;
680         for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
681           ulm.x = x;
682           ulm.y = y;
683
684           if ( existence_only ) {
685             g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE,
686                      vml->cache_dir, mode,
687                      ulm.scale, ulm.z, ulm.x, ulm.y );
688             if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
689               vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
690             }
691           } else {
692             pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
693             if ( pixbuf )
694               vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
695           }
696
697           yy += tilesize_y;
698         }
699         xx += tilesize_x;
700       }
701     }
702
703     g_free ( path_buf );
704   }
705 }
706
707 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
708 {
709   if ( MAPS_LAYER_NTH_TYPE(vml->maptype)->drawmode == vik_viewport_get_drawmode ( vvp ) )
710   {
711     VikCoord ul, br;
712
713     /* get corner coords */
714     if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
715       /* UTM multi-zone stuff by Kit Transue */
716       gchar leftmost_zone, rightmost_zone, i;
717       leftmost_zone = vik_viewport_leftmost_zone( vvp );
718       rightmost_zone = vik_viewport_rightmost_zone( vvp );
719       for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
720         vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
721         maps_layer_draw_section ( vml, vvp, &ul, &br );
722       }
723     }
724     else {
725       vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
726       vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
727
728       maps_layer_draw_section ( vml, vvp, &ul, &br );
729     }
730   }
731 }
732
733 /*************************/
734 /****** DOWNLOADING ******/
735 /*************************/
736
737 /* pass along data to thread, exists even if layer is deleted. */
738 typedef struct {
739   gchar *cache_dir;
740   gchar *filename_buf;
741   gint x0, y0, xf, yf;
742   MapCoord mapcoord;
743   gint maptype;
744   gint maxlen;
745   gint mapstoget;
746   gint redownload;
747   gboolean refresh_display;
748   VikMapsLayer *vml;
749   VikViewport *vvp;
750   gboolean map_layer_alive;
751   GMutex *mutex;
752 } MapDownloadInfo;
753
754 static void mdi_free ( MapDownloadInfo *mdi )
755 {
756   g_mutex_free(mdi->mutex);
757   g_free ( mdi->cache_dir );
758   mdi->cache_dir = NULL;
759   g_free ( mdi->filename_buf );
760   mdi->filename_buf = NULL;
761   g_free ( mdi );
762 }
763
764 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
765 {
766   MapDownloadInfo *mdi = ptr;
767   g_mutex_lock(mdi->mutex);
768   mdi->map_layer_alive = FALSE;
769   g_mutex_unlock(mdi->mutex);
770 }
771
772 static void map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
773 {
774   guint donemaps = 0;
775   gint x, y;
776   for ( x = mdi->x0; x <= mdi->xf; x++ )
777   {
778     for ( y = mdi->y0; y <= mdi->yf; y++ )
779     {
780       gboolean remove_mem_cache = FALSE;
781       gboolean need_download = FALSE;
782       g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
783                      mdi->cache_dir, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id,
784                      mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
785
786       donemaps++;
787       a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
788
789       if ( mdi->redownload == REDOWNLOAD_ALL)
790         g_remove ( mdi->filename_buf );
791
792       else if ( (mdi->redownload == REDOWNLOAD_BAD) && (g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE) )
793       {
794         /* see if this one is bad or what */
795         GError *gx = NULL;
796         GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
797         if (gx || (!pixbuf))
798           g_remove ( mdi->filename_buf );
799         if ( pixbuf )
800           g_object_unref ( pixbuf );
801         if ( gx )
802           g_error_free ( gx );
803       }
804
805       if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
806       {
807         need_download = TRUE;
808         if (( mdi->redownload != REDOWNLOAD_NONE ) &&
809             ( mdi->redownload != DOWNLOAD_OR_REFRESH ))
810           remove_mem_cache = TRUE;
811       } else if ( mdi->redownload == DOWNLOAD_OR_REFRESH ) {
812         remove_mem_cache = TRUE;
813       } else
814         continue;
815
816       mdi->mapcoord.x = x; mdi->mapcoord.y = y;
817
818       if (need_download) {
819         if ( MAPS_LAYER_NTH_TYPE(mdi->maptype)->download ( &(mdi->mapcoord), mdi->filename_buf ))
820           continue;
821       }
822
823       gdk_threads_enter();
824       g_mutex_lock(mdi->mutex);
825       if (remove_mem_cache)
826           a_mapcache_remove_all_shrinkfactors ( x, y, mdi->mapcoord.z, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id, mdi->mapcoord.scale );
827       if (mdi->refresh_display && mdi->map_layer_alive) {
828         /* TODO: check if it's on visible area */
829         vik_layer_emit_update ( VIK_LAYER(mdi->vml) );
830       }
831       g_mutex_unlock(mdi->mutex);
832       gdk_threads_leave();
833       mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
834
835     }
836   }
837   g_mutex_lock(mdi->mutex);
838   if (mdi->map_layer_alive)
839     g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
840   g_mutex_unlock(mdi->mutex); 
841 }
842
843 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
844 {
845   if ( mdi->mapcoord.x || mdi->mapcoord.y )
846   {
847     g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
848                      mdi->cache_dir, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id,
849                      mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
850     if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
851     {
852       g_remove ( mdi->filename_buf );
853     }
854   }
855 }
856
857 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
858 {
859   gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
860   gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
861   MapCoord ulm, brm;
862   VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
863   if ( map_type->coord_to_mapcoord ( ul, xzoom, yzoom, &ulm ) 
864     && map_type->coord_to_mapcoord ( br, xzoom, yzoom, &brm ) )
865   {
866     MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
867     gint a, b;
868
869     mdi->vml = vml;
870     mdi->vvp = vvp;
871     mdi->map_layer_alive = TRUE;
872     mdi->mutex = g_mutex_new();
873     mdi->refresh_display = TRUE;
874
875     /* cache_dir and buffer for dest filename */
876     mdi->cache_dir = g_strdup ( vml->cache_dir );
877     mdi->maxlen = strlen ( vml->cache_dir ) + 40;
878     mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
879     mdi->maptype = vml->maptype;
880
881     mdi->mapcoord = ulm;
882
883     mdi->redownload = redownload;
884
885     mdi->x0 = MIN(ulm.x, brm.x);
886     mdi->xf = MAX(ulm.x, brm.x);
887     mdi->y0 = MIN(ulm.y, brm.y);
888     mdi->yf = MAX(ulm.y, brm.y);
889
890     mdi->mapstoget = 0;
891
892     if ( mdi->redownload ) {
893       mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
894     } else {
895       /* calculate how many we need */
896       for ( a = mdi->x0; a <= mdi->xf; a++ )
897       {
898         for ( b = mdi->y0; b <= mdi->yf; b++ )
899         {
900           g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
901                        vml->cache_dir, map_type->uniq_id, ulm.scale,
902                        ulm.z, a, b );
903           if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
904             mdi->mapstoget++;
905         }
906       }
907     }
908
909     mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
910
911     if ( mdi->mapstoget )
912     {
913       const gchar *tmp_str;
914       gchar *tmp;
915
916       if (redownload) 
917       {
918         if (redownload == REDOWNLOAD_BAD)
919           tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
920         else
921           tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
922       } 
923       else 
924       {
925         tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
926       }
927       tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
928  
929       g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
930       /* launch the thread */
931       a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
932                             tmp,                                              /* description string */
933                             (vik_thr_func) map_download_thread,               /* function to call within thread */
934                             mdi,                                              /* pass along data */
935                             (vik_thr_free_func) mdi_free,                     /* function to free pass along data */
936                             (vik_thr_free_func) mdi_cancel_cleanup,
937                             mdi->mapstoget );
938       g_free ( tmp );
939     }
940     else
941       mdi_free ( mdi );
942   }
943 }
944
945 void maps_layer_download_section_without_redraw( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
946 {
947   MapCoord ulm, brm;
948   VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
949
950   if (!map_type->coord_to_mapcoord(ul, zoom, zoom, &ulm) 
951     || !map_type->coord_to_mapcoord(br, zoom, zoom, &brm)) {
952     g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
953     return;
954   }
955
956   MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
957   gint i, j;
958
959   mdi->vml = vml;
960   mdi->vvp = vvp;
961   mdi->map_layer_alive = TRUE;
962   mdi->mutex = g_mutex_new();
963   mdi->refresh_display = FALSE;
964
965   mdi->cache_dir = g_strdup ( vml->cache_dir );
966   mdi->maxlen = strlen ( vml->cache_dir ) + 40;
967   mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
968   mdi->maptype = vml->maptype;
969
970   mdi->mapcoord = ulm;
971
972   mdi->redownload = REDOWNLOAD_NONE;
973
974   mdi->x0 = MIN(ulm.x, brm.x);
975   mdi->xf = MAX(ulm.x, brm.x);
976   mdi->y0 = MIN(ulm.y, brm.y);
977   mdi->yf = MAX(ulm.y, brm.y);
978
979   mdi->mapstoget = 0;
980
981   for (i = mdi->x0; i <= mdi->xf; i++) {
982     for (j = mdi->y0; j <= mdi->yf; j++) {
983       g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
984                    vml->cache_dir, map_type->uniq_id, ulm.scale,
985                    ulm.z, i, j );
986       if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
987             mdi->mapstoget++;
988     }
989   }
990
991   mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
992
993   if (mdi->mapstoget) {
994     gchar *tmp;
995     const gchar *fmt;
996     fmt = ngettext("Downloading %d %s map...",
997                    "Downloading %d %s maps...",
998                    mdi->mapstoget);
999     tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
1000
1001     g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1002       /* launch the thread */
1003     a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1004       tmp,                                /* description string */
1005       (vik_thr_func) map_download_thread, /* function to call within thread */
1006       mdi,                                /* pass along data */
1007       (vik_thr_free_func) mdi_free,       /* function to free pass along data */
1008       (vik_thr_free_func) mdi_cancel_cleanup,
1009       mdi->mapstoget );
1010     g_free ( tmp );
1011   }
1012   else
1013     mdi_free ( mdi );
1014 }
1015
1016 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1017 {
1018   start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1019 }
1020 static void maps_layer_redownload_all ( VikMapsLayer *vml )
1021 {
1022   start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1023 }
1024
1025 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1026 {
1027   if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1028     return FALSE;
1029   if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1030   {
1031     if ( event->button == 1 )
1032     {
1033       VikCoord ul, br;
1034       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 );
1035       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 );
1036       start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
1037       vml->dl_tool_x = vml->dl_tool_y = -1;
1038       return TRUE;
1039     }
1040     else
1041     {
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)), &(vml->redownload_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 ) ), &(vml->redownload_br) );
1044
1045       vml->redownload_vvp = vvp;
1046
1047       vml->dl_tool_x = vml->dl_tool_y = -1;
1048
1049       if ( ! vml->dl_right_click_menu ) {
1050         GtkWidget *item;
1051         vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1052
1053         item = gtk_menu_item_new_with_label ( _("Redownload bad map(s)") );
1054         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1055         gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1056
1057         item = gtk_menu_item_new_with_label ( _("Redownload all map(s)") );
1058         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1059         gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1060       }
1061
1062       gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1063       gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1064     }
1065   }
1066   return FALSE;
1067 }
1068
1069 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1070 {
1071   return vvp;
1072 }
1073
1074 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1075 {
1076   MapCoord tmp;
1077   if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1078     return FALSE;
1079   VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
1080   if ( map_type->drawmode == vik_viewport_get_drawmode ( vvp ) &&
1081        map_type->coord_to_mapcoord ( vik_viewport_get_center ( vvp ),
1082            vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1083            vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1084            &tmp ) ) {
1085     vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1086     return TRUE;
1087   }
1088   return FALSE;
1089
1090  
1091 #if 0
1092   if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1093   {
1094     VikCoord coord;
1095     MapCoord mapcoord;
1096     vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1097     if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1098                 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1099                 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1100                 &mapcoord ) ) {
1101       gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1102                      vml->cache_dir, __map_types[vml->maptype].uniq_id,
1103                      mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1104
1105       __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1106       g_free ( filename_buf );
1107       vik_layer_emit_update ( VIK_LAYER(vml) );
1108       return TRUE;
1109     }
1110   }
1111   return FALSE;
1112 #endif
1113 }
1114
1115 static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
1116 {
1117   VikMapsLayer *vml = vml_vvp[0];
1118   VikViewport *vvp = vml_vvp[1];
1119   VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
1120
1121   gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1122   gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1123
1124   VikCoord ul, br;
1125   MapCoord ulm, brm;
1126
1127   vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1128   vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1129
1130   VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
1131   if ( map_type->drawmode == vp_drawmode &&
1132        map_type->coord_to_mapcoord ( &ul, xzoom, yzoom, &ulm ) &&
1133        map_type->coord_to_mapcoord ( &br, xzoom, yzoom, &brm ) )
1134     start_download_thread ( vml, vvp, &ul, &br, redownload );
1135   else if (map_type->drawmode != vp_drawmode) {
1136     const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, map_type->drawmode);
1137     gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
1138     a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1139     g_free(err);
1140   }
1141   else
1142     a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
1143
1144 }
1145
1146 static void maps_layer_download_onscreen_maps ( gpointer vml_vvp[2] )
1147 {
1148   download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1149 }
1150
1151 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1152 {
1153   download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1154 }
1155
1156 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1157 {
1158   static gpointer pass_along[2];
1159   GtkWidget *item;
1160   pass_along[0] = vml;
1161   pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1162
1163   item = gtk_menu_item_new();
1164   gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1165   gtk_widget_show ( item );
1166
1167   item = gtk_menu_item_new_with_label ( _("Download Onscreen Maps") );
1168   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_onscreen_maps), pass_along );
1169   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1170   gtk_widget_show ( item );
1171
1172   item = gtk_menu_item_new_with_label ( _("Refresh Onscreen Tiles") );
1173   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1174   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1175   gtk_widget_show ( item );
1176 }