]> git.street.me.uk Git - andy/viking.git/blame - src/vikmapslayer.c
Filter out irrelevant modifiers.
[andy/viking.git] / src / vikmapslayer.c
CommitLineData
50a14534
EB
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>
cdcaf41c 6 * Dynamic map type by Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
50a14534
EB
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
4c77d5e0
GB
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
50a14534
EB
28#define MAX_SHRINKFACTOR 8.0000001 /* zoom 1 viewing 8-tiles */
29#define MIN_SHRINKFACTOR 0.0312499 /* zoom 32 viewing 1-tiles */
30
732d1e25
EB
31#define REAL_MIN_SHRINKFACTOR 0.0039062499 /* if shrinkfactor is between MAX and REAL_MAX, will only check for existence */
32
50a14534
EB
33#include <gtk/gtk.h>
34#include <gdk-pixbuf/gdk-pixdata.h>
45acf79e
MA
35#include <glib.h>
36#include <glib/gstdio.h>
4c77d5e0
GB
37#include <glib/gi18n.h>
38
8c00358d 39#ifdef HAVE_STRING_H
50a14534 40#include <string.h>
8c00358d
GB
41#endif
42#ifdef HAVE_MATH_H
50a14534 43#include <math.h>
8c00358d
GB
44#endif
45
50a14534
EB
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"
50a14534 53
45acf79e 54#ifdef HAVE_UNISTD_H
50a14534 55#include <unistd.h>
45acf79e 56#endif
50a14534
EB
57
58#include "mapcache.h"
59/* only for dialog.h -- ugh */
60#include "vikwaypoint.h"
61#include "dialog.h"
62
63#include "vikstatus.h"
64#include "background.h"
65
66#include "vikaggregatelayer.h"
67#include "viklayerspanel.h"
68
69#include "mapcoord.h"
70#include "terraserver.h"
50a14534 71
bce3a7b0
EB
72#include "icons/icons.h"
73
50a14534
EB
74/****** MAP TYPES ******/
75
cdcaf41c
QT
76static GList *__map_types = NULL;
77
78#define NUM_MAP_TYPES g_list_length(__map_types)
50a14534 79
cdcaf41c
QT
80/* List of label for each map type */
81static GList *params_maptypes = NULL;
82
83/* Corresponding IDS. (Cf. field uniq_id in VikMapsLayer struct) */
84static GList *params_maptypes_ids = NULL;
50a14534
EB
85
86/******** MAPZOOMS *********/
87
4c77d5e0 88static 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 };
50a14534
EB
89static 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 };
90static 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 };
91
d756fb5c 92#define NUM_MAPZOOMS (sizeof(params_mapzooms)/sizeof(params_mapzooms[0]) - 1)
50a14534
EB
93
94/**************************/
95
96
07059501 97static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file);
911400b5
AF
98static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len );
99static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
50a14534
EB
100static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp );
101static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id );
102static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp );
103static VikMapsLayer *maps_layer_new ( VikViewport *vvp );
104static void maps_layer_free ( VikMapsLayer *vml );
105static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
106static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
941aa6e9 107static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp );
50a14534
EB
108static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir );
109static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload );
110static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp );
111
112
113static VikLayerParamScale params_scales[] = {
114 /* min, max, step, digits (decimal places) */
115 { 0, 255, 3, 0 }, /* alpha */
116};
117
118VikLayerParam maps_layer_params[] = {
4c77d5e0 119 { "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Map Type:"), VIK_LAYER_WIDGET_RADIOGROUP, NULL, NULL },
e6fd9b70 120 { "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Maps Directory:"), VIK_LAYER_WIDGET_FOLDERENTRY },
4c77d5e0
GB
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 },
50a14534
EB
124};
125
126enum { PARAM_MAPTYPE=0, PARAM_CACHE_DIR, PARAM_ALPHA, PARAM_AUTODOWNLOAD, PARAM_MAPZOOM, NUM_PARAMS };
127
128static VikToolInterface maps_tools[] = {
4c77d5e0 129 { N_("Maps Download"), (VikToolConstructorFunc) maps_layer_download_create, NULL, NULL, NULL,
bce3a7b0 130 (VikToolMouseFunc) maps_layer_download_click, NULL, (VikToolMouseFunc) maps_layer_download_release,
5bfafde9 131 (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_mapdl_pixbuf },
50a14534
EB
132};
133
134VikLayerInterface vik_maps_layer_interface = {
4c77d5e0 135 N_("Map"),
5bfafde9 136 &vikmapslayer_pixbuf,
50a14534
EB
137
138 maps_tools,
139 sizeof(maps_tools) / sizeof(maps_tools[0]),
140
141 maps_layer_params,
142 NUM_PARAMS,
143 NULL,
144 0,
145
5a4a28bf
QT
146 VIK_MENU_ITEM_ALL,
147
50a14534
EB
148 (VikLayerFuncCreate) maps_layer_new,
149 (VikLayerFuncRealize) NULL,
94933cb8 150 maps_layer_post_read,
50a14534
EB
151 (VikLayerFuncFree) maps_layer_free,
152
153 (VikLayerFuncProperties) NULL,
154 (VikLayerFuncDraw) maps_layer_draw,
155 (VikLayerFuncChangeCoordMode) NULL,
156
20c7a3a0
QT
157 (VikLayerFuncSetMenuItemsSelection) NULL,
158 (VikLayerFuncGetMenuItemsSelection) NULL,
159
50a14534
EB
160 (VikLayerFuncAddMenuItems) maps_layer_add_menu_items,
161 (VikLayerFuncSublayerAddMenuItems) NULL,
162
163 (VikLayerFuncSublayerRenameRequest) NULL,
164 (VikLayerFuncSublayerToggleVisible) NULL,
165
911400b5
AF
166 (VikLayerFuncMarshall) maps_layer_marshall,
167 (VikLayerFuncUnmarshall) maps_layer_unmarshall,
50a14534
EB
168
169 (VikLayerFuncSetParam) maps_layer_set_param,
170 (VikLayerFuncGetParam) maps_layer_get_param,
171
172 (VikLayerFuncReadFileData) NULL,
173 (VikLayerFuncWriteFileData) NULL,
174
33534cd8 175 (VikLayerFuncDeleteItem) NULL,
50a14534
EB
176 (VikLayerFuncCopyItem) NULL,
177 (VikLayerFuncPasteItem) NULL,
178 (VikLayerFuncFreeCopiedItem) NULL,
70a23263 179 (VikLayerFuncDragDropRequest) NULL,
50a14534
EB
180};
181
182struct _VikMapsLayer {
183 VikLayer vl;
184 guint maptype;
185 gchar *cache_dir;
186 guint8 alpha;
187 guint mapzoom_id;
188 gdouble xmapzoom, ymapzoom;
189
190 gboolean autodownload;
10ca2bfe
QT
191 VikCoord *last_center;
192 gdouble last_xmpp;
193 gdouble last_ympp;
50a14534
EB
194
195 gint dl_tool_x, dl_tool_y;
196
197 GtkMenu *dl_right_click_menu;
198 VikCoord redownload_ul, redownload_br; /* right click menu only */
199 VikViewport *redownload_vvp;
200};
201
a0b59f2f 202enum { REDOWNLOAD_NONE = 0, REDOWNLOAD_BAD, REDOWNLOAD_ALL, DOWNLOAD_OR_REFRESH };
50a14534
EB
203
204
cdcaf41c
QT
205/****************************************/
206/******** MAPS LAYER TYPES **************/
207/****************************************/
208
209void maps_layer_register_type ( const char *label, guint id, VikMapsLayer_MapType *map_type )
210{
211 g_assert(label != NULL);
212 g_assert(map_type != NULL);
213 g_assert(id == map_type->uniq_id);
214
215 /* Add the label */
216 params_maptypes = g_list_append(params_maptypes, g_strdup(label));
217
218 /* Add the id */
dc2c040e 219 params_maptypes_ids = g_list_append(params_maptypes_ids, GUINT_TO_POINTER (id));
cdcaf41c
QT
220
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);
225
226 /* Hack
227 We have to ensure the mode LayerParam reference the up-to-date
228 GLists.
229 */
230 /*
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));
233 */
234 maps_layer_params[0].widget_data = params_maptypes;
235 maps_layer_params[0].extra_widget_data = params_maptypes_ids;
236}
237
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)))
241
7114e879
QT
242gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
243{
244 return(vml->maptype);
245}
246
247gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
248{
249 return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
250}
251
50a14534
EB
252/****************************************/
253/******** CACHE DIR STUFF ***************/
254/****************************************/
255
3d9454e6 256#define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
6a27c1bc
MA
257#define MAPS_CACHE_DIR maps_layer_default_dir()
258
50a14534 259#ifdef WINDOWS
6a27c1bc
MA
260#include <io.h>
261#define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
262#define LOCAL_MAPS_DIR "VIKING-MAPS"
50a14534 263#else /* POSIX */
50a14534 264#include <stdlib.h>
50a14534 265#define GLOBAL_MAPS_DIR "/var/cache/maps/"
6a27c1bc
MA
266#define LOCAL_MAPS_DIR ".viking-maps"
267#endif
50a14534 268
0c1044e9 269gchar *maps_layer_default_dir ()
50a14534 270{
3d9454e6
GB
271 static gchar *defaultdir = NULL;
272 if ( ! defaultdir )
50a14534
EB
273 {
274 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
3d9454e6
GB
275 const gchar *mapdir = g_getenv("VIKING_MAPS");
276 if ( mapdir ) {
277 defaultdir = g_strdup ( mapdir );
45acf79e 278 } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
3d9454e6 279 defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
50a14534 280 } else {
6a27c1bc 281 const gchar *home = g_get_home_dir();
45acf79e 282 if (!home || g_access(home, W_OK))
3d9454e6
GB
283 home = g_get_home_dir ();
284 if ( home )
6a27c1bc 285 defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
50a14534 286 else
6a27c1bc 287 defaultdir = g_strdup ( LOCAL_MAPS_DIR );
50a14534 288 }
3d9454e6
GB
289 if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
290 {
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);
295 }
296 g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
50a14534
EB
297 }
298 return defaultdir;
299}
300
50a14534
EB
301static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
302{
45acf79e 303 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
50a14534 304 {
f83131b9 305 g_mkdir ( vml->cache_dir, 0777 );
50a14534
EB
306 }
307}
308
309static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
310{
311 guint len;
312 g_assert ( vml != NULL);
e65028db
GB
313 g_free ( vml->cache_dir );
314 vml->cache_dir = NULL;
50a14534
EB
315
316 if ( dir == NULL || dir[0] == '\0' )
317 vml->cache_dir = g_strdup ( MAPS_CACHE_DIR );
318 else
319 {
320 len = strlen(dir);
3d9454e6 321 if ( dir[len-1] != G_DIR_SEPARATOR )
50a14534
EB
322 {
323 vml->cache_dir = g_malloc ( len+2 );
324 strncpy ( vml->cache_dir, dir, len );
3d9454e6 325 vml->cache_dir[len] = G_DIR_SEPARATOR;
50a14534
EB
326 vml->cache_dir[len+1] = '\0';
327 }
328 else
329 vml->cache_dir = g_strdup ( dir );
330 }
331 maps_layer_mkdir_if_default_dir ( vml );
332}
333
334/****************************************/
335/******** GOBJECT STUFF *****************/
336/****************************************/
337
338GType vik_maps_layer_get_type ()
339{
340 static GType vml_type = 0;
341
342 if (!vml_type)
343 {
344 static const GTypeInfo vml_info =
345 {
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),
353 0,
354 NULL /* instance init */
355 };
356 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
357 }
358
359 return vml_type;
360}
361
362/****************************************/
363/************** PARAMETERS **************/
364/****************************************/
365
366static guint map_index_to_uniq_id (guint8 index)
367{
368 g_assert ( index < NUM_MAP_TYPES );
cdcaf41c 369 return MAPS_LAYER_NTH_TYPE(index)->uniq_id;
50a14534
EB
370}
371
372static guint map_uniq_id_to_index ( guint uniq_id )
373{
374 gint i;
375 for ( i = 0; i < NUM_MAP_TYPES; i++ )
cdcaf41c 376 if ( MAPS_LAYER_NTH_TYPE(i)->uniq_id == uniq_id )
50a14534
EB
377 return i;
378 return NUM_MAP_TYPES; /* no such thing */
379}
380
381static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp )
382{
383 switch ( id )
384 {
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);
4c77d5e0 388 if ( maptype == NUM_MAP_TYPES ) g_warning(_("Unknown map type"));
50a14534
EB
389 else vml->maptype = maptype;
390 break;
391 }
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];
4c77d5e0 398 }else g_warning (_("Unknown Map Zoom")); break;
50a14534
EB
399 }
400 return TRUE;
401}
402
403static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id )
404{
405 VikLayerParamData rv;
406 switch ( id )
407 {
e6fd9b70 408 case PARAM_CACHE_DIR: rv.s = vml->cache_dir ? vml->cache_dir : ""; break;
50a14534
EB
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;
413 }
414 return rv;
415}
416
417/****************************************/
418/****** CREATING, COPYING, FREEING ******/
419/****************************************/
420
421static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
422{
36c78d6d 423 int idx;
50a14534
EB
424 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
425 vik_layer_init ( VIK_LAYER(vml), VIK_LAYER_MAPS );
36c78d6d
QT
426 idx = map_uniq_id_to_index(7); /* 7 is id for google maps */
427 vml->maptype = (idx < NUM_MAP_TYPES) ? idx : 0;
50a14534
EB
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;
10ca2bfe
QT
433 vml->last_center = NULL;
434 vml->last_xmpp = 0.0;
435 vml->last_ympp = 0.0;
50a14534
EB
436
437 vml->dl_right_click_menu = NULL;
438
439 return vml;
440}
441
442static void maps_layer_free ( VikMapsLayer *vml )
443{
e65028db
GB
444 g_free ( vml->cache_dir );
445 vml->cache_dir = NULL;
50a14534
EB
446 if ( vml->dl_right_click_menu )
447 gtk_object_sink ( GTK_OBJECT(vml->dl_right_click_menu) );
e65028db
GB
448 g_free(vml->last_center);
449 vml->last_center = NULL;
50a14534
EB
450}
451
07059501 452static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
dc5758d3 453{
07059501
GB
454 if (from_file != TRUE)
455 {
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;
dc5758d3 462
07059501
GB
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);
4c77d5e0 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);
07059501
GB
468 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), msg );
469 g_free(msg);
470 }
dc5758d3
GB
471 }
472}
473
911400b5
AF
474static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
475{
476 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
477}
478
479static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
480{
481 VikMapsLayer *rv = maps_layer_new ( vvp );
482 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
483 return rv;
484}
485
50a14534
EB
486/*********************/
487/****** DRAWING ******/
488/*********************/
489
490static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
491{
492 guchar *pixels;
493 gint width, height, iii, jjj;
494
495 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
496 {
497 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
498 g_object_unref(G_OBJECT(pixbuf));
499 pixbuf = tmp;
500 }
501
502 pixels = gdk_pixbuf_get_pixels(pixbuf);
503 width = gdk_pixbuf_get_width(pixbuf);
504 height = gdk_pixbuf_get_height(pixbuf);
505
506 /* r,g,b,a,r,g,b,a.... */
507 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
508 {
509 pixels += 3;
510 *pixels++ = alpha;
511 }
512 return pixbuf;
513}
514
515static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
516{
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;
522}
523
524static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
525{
526 GdkPixbuf *pixbuf;
527
528 /* get the thing */
529 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
530 mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
531
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 );
45acf79e 536 if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE) {
50a14534
EB
537 {
538 GError *gx = NULL;
539 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
540
541 if (gx)
542 {
543 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
4c77d5e0 544 g_warning ( _("Couldn't open image file: %s"), gx->message );
50a14534
EB
545
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 );
555
556 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
cdcaf41c 557 mapcoord->z, MAPS_LAYER_NTH_TYPE(vml->maptype)->uniq_id,
50a14534
EB
558 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
559 }
560 }
561 }
562 }
563 return pixbuf;
564}
565
10ca2bfe
QT
566gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
567{
568 const VikCoord *center = vik_viewport_get_center ( vvp );
569
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;
577 }
578
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;
584
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;
589}
590
50a14534
EB
591static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
592{
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;
732d1e25 597 gdouble existence_only = FALSE;
50a14534
EB
598
599 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
600 xshrinkfactor = vml->xmapzoom / xzoom;
601 yshrinkfactor = vml->ymapzoom / yzoom;
732d1e25
EB
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 {
4c77d5e0 609 g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
732d1e25
EB
610 return;
611 }
50a14534
EB
612 }
613 }
614
615 /* coord -> ID */
cdcaf41c
QT
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 ) ) {
50a14534
EB
619
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);
cdcaf41c 624 gint mode = map_type->uniq_id;
50a14534
EB
625
626 VikCoord coord;
627 gint xx, yy, width, height;
628 GdkPixbuf *pixbuf;
629
630 guint max_path_len = strlen(vml->cache_dir) + 40;
631 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
632
732d1e25 633 if ( (!existence_only) && vml->autodownload && should_start_autodownload(vml, vvp)) {
214f9ac2
QT
634#ifdef DEBUG
635 fputs(stderr, "DEBUG: Starting autodownload\n");
636#endif
50a14534 637 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
10ca2bfe 638 }
50a14534 639
732d1e25 640 if ( map_type->tilesize_x == 0 && !existence_only ) {
50a14534
EB
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 );
649
cdcaf41c 650 map_type->mapcoord_to_center_coord ( &ulm, &coord );
50a14534
EB
651 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
652 xx -= (width/2);
653 yy -= (height/2);
654
655 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
656 }
657 }
658 }
659 } else { /* tilesize is known, don't have to keep converting coords */
cdcaf41c
QT
660 gdouble tilesize_x = map_type->tilesize_x * xshrinkfactor;
661 gdouble tilesize_y = map_type->tilesize_y * yshrinkfactor;
50a14534
EB
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;
732d1e25
EB
669
670 GdkGC *black_gc = GTK_WIDGET(vvp)->style->black_gc;
671
50a14534
EB
672 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
673 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
674
cdcaf41c 675 map_type->mapcoord_to_center_coord ( &ulm, &coord );
50a14534
EB
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);
682
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;
732d1e25
EB
688
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 );
45acf79e 693 if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
732d1e25
EB
694 vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
695 }
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 );
700 }
50a14534
EB
701
702 yy += tilesize_y;
703 }
704 xx += tilesize_x;
705 }
706 }
707
708 g_free ( path_buf );
709 }
710}
711
712static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
713{
cdcaf41c 714 if ( MAPS_LAYER_NTH_TYPE(vml->maptype)->drawmode == vik_viewport_get_drawmode ( vvp ) )
50a14534
EB
715 {
716 VikCoord ul, br;
717
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 );
727 }
728 }
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 );
732
733 maps_layer_draw_section ( vml, vvp, &ul, &br );
734 }
735 }
736}
737
738/*************************/
739/****** DOWNLOADING ******/
740/*************************/
741
742/* pass along data to thread, exists even if layer is deleted. */
743typedef 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;
7114e879 752 gboolean refresh_display;
550fd035
QT
753 VikMapsLayer *vml;
754 VikViewport *vvp;
755 gboolean map_layer_alive;
756 GMutex *mutex;
50a14534
EB
757} MapDownloadInfo;
758
759static void mdi_free ( MapDownloadInfo *mdi )
760{
550fd035 761 g_mutex_free(mdi->mutex);
50a14534 762 g_free ( mdi->cache_dir );
e65028db 763 mdi->cache_dir = NULL;
50a14534 764 g_free ( mdi->filename_buf );
e65028db 765 mdi->filename_buf = NULL;
50a14534
EB
766 g_free ( mdi );
767}
768
7bb60307 769static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
550fd035 770{
7bb60307 771 MapDownloadInfo *mdi = ptr;
550fd035
QT
772 g_mutex_lock(mdi->mutex);
773 mdi->map_layer_alive = FALSE;
774 g_mutex_unlock(mdi->mutex);
775}
776
634eca0a 777static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
50a14534
EB
778{
779 guint donemaps = 0;
780 gint x, y;
781 for ( x = mdi->x0; x <= mdi->xf; x++ )
782 {
783 for ( y = mdi->y0; y <= mdi->yf; y++ )
784 {
94493114 785 gboolean remove_mem_cache = FALSE;
84628352 786 gboolean need_download = FALSE;
50a14534 787 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
cdcaf41c 788 mdi->cache_dir, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id,
50a14534
EB
789 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
790
84628352 791 donemaps++;
634eca0a
JJ
792 int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
793 if (res != 0)
794 return -1;
84628352 795
50a14534 796 if ( mdi->redownload == REDOWNLOAD_ALL)
8c060406 797 g_remove ( mdi->filename_buf );
093c5c71 798
45acf79e 799 else if ( (mdi->redownload == REDOWNLOAD_BAD) && (g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE) )
50a14534
EB
800 {
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))
8c060406 805 g_remove ( mdi->filename_buf );
50a14534
EB
806 if ( pixbuf )
807 g_object_unref ( pixbuf );
808 if ( gx )
809 g_error_free ( gx );
810 }
811
45acf79e 812 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
50a14534 813 {
84628352
QT
814 need_download = TRUE;
815 if (( mdi->redownload != REDOWNLOAD_NONE ) &&
a0b59f2f 816 ( mdi->redownload != DOWNLOAD_OR_REFRESH ))
94493114
QT
817 remove_mem_cache = TRUE;
818 } else if ( mdi->redownload == DOWNLOAD_OR_REFRESH ) {
819 remove_mem_cache = TRUE;
820 } else
821 continue;
822
94493114 823 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
84628352
QT
824
825 if (need_download) {
826 if ( MAPS_LAYER_NTH_TYPE(mdi->maptype)->download ( &(mdi->mapcoord), mdi->filename_buf ))
94493114 827 continue;
84628352 828 }
94493114
QT
829
830 gdk_threads_enter();
831 g_mutex_lock(mdi->mutex);
832 if (remove_mem_cache)
50bb3d25 833 a_mapcache_remove_all_shrinkfactors ( x, y, mdi->mapcoord.z, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id, mdi->mapcoord.scale );
7114e879 834 if (mdi->refresh_display && mdi->map_layer_alive) {
94493114
QT
835 /* TODO: check if it's on visible area */
836 vik_layer_emit_update ( VIK_LAYER(mdi->vml) );
a0b59f2f 837 }
94493114
QT
838 g_mutex_unlock(mdi->mutex);
839 gdk_threads_leave();
840 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
841
50a14534
EB
842 }
843 }
04e54492
QT
844 g_mutex_lock(mdi->mutex);
845 if (mdi->map_layer_alive)
7bb60307 846 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
04e54492 847 g_mutex_unlock(mdi->mutex);
634eca0a 848 return 0;
50a14534
EB
849}
850
851static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
852{
853 if ( mdi->mapcoord.x || mdi->mapcoord.y )
854 {
855 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
cdcaf41c 856 mdi->cache_dir, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id,
50a14534 857 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
45acf79e 858 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
50a14534 859 {
8c060406 860 g_remove ( mdi->filename_buf );
50a14534
EB
861 }
862 }
863}
864
865static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
866{
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;
cdcaf41c
QT
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 ) )
50a14534
EB
873 {
874 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
875 gint a, b;
876
550fd035
QT
877 mdi->vml = vml;
878 mdi->vvp = vvp;
879 mdi->map_layer_alive = TRUE;
880 mdi->mutex = g_mutex_new();
7114e879 881 mdi->refresh_display = TRUE;
550fd035 882
50a14534
EB
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;
888
889 mdi->mapcoord = ulm;
890
891 mdi->redownload = redownload;
892
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);
897
898 mdi->mapstoget = 0;
899
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++ )
905 {
906 for ( b = mdi->y0; b <= mdi->yf; b++ )
907 {
908 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
cdcaf41c 909 vml->cache_dir, map_type->uniq_id, ulm.scale,
50a14534 910 ulm.z, a, b );
45acf79e 911 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
50a14534
EB
912 mdi->mapstoget++;
913 }
914 }
915 }
916
917 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
918
919 if ( mdi->mapstoget )
920 {
97634600
GB
921 const gchar *tmp_str;
922 gchar *tmp;
50a14534 923
97634600
GB
924 if (redownload)
925 {
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);
930 }
931 else
932 {
933 tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
934 }
935 tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
936
7bb60307 937 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
50a14534
EB
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 );
947 }
948 else
949 mdi_free ( mdi );
950 }
951}
952
7114e879
QT
953void maps_layer_download_section_without_redraw( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
954{
7114e879
QT
955 MapCoord ulm, brm;
956 VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
957
958 if (!map_type->coord_to_mapcoord(ul, zoom, zoom, &ulm)
959 || !map_type->coord_to_mapcoord(br, zoom, zoom, &brm)) {
4258f4e2 960 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
7114e879
QT
961 return;
962 }
963
964 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
965 gint i, j;
966
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;
972
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;
977
978 mdi->mapcoord = ulm;
979
980 mdi->redownload = REDOWNLOAD_NONE;
981
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);
986
987 mdi->mapstoget = 0;
988
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 );
45acf79e 994 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
7114e879
QT
995 mdi->mapstoget++;
996 }
997 }
998
999 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1000
1001 if (mdi->mapstoget) {
4c77d5e0
GB
1002 gchar *tmp;
1003 const gchar *fmt;
eb6b0125
JJ
1004 fmt = ngettext("Downloading %d %s map...",
1005 "Downloading %d %s maps...",
1006 mdi->mapstoget);
4c77d5e0 1007 tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
7114e879
QT
1008
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 );
1019 }
1020 else
1021 mdi_free ( mdi );
1022}
1023
50a14534
EB
1024static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1025{
1026 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1027}
1028static void maps_layer_redownload_all ( VikMapsLayer *vml )
1029{
1030 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1031}
1032
1033static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1034{
941aa6e9
AF
1035 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1036 return FALSE;
50a14534
EB
1037 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1038 {
1039 if ( event->button == 1 )
1040 {
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 );
a0b59f2f 1044 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
50a14534
EB
1045 vml->dl_tool_x = vml->dl_tool_y = -1;
1046 return TRUE;
1047 }
1048 else
1049 {
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) );
1052
1053 vml->redownload_vvp = vvp;
1054
1055 vml->dl_tool_x = vml->dl_tool_y = -1;
1056
1057 if ( ! vml->dl_right_click_menu ) {
1058 GtkWidget *item;
1059 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1060
4c77d5e0 1061 item = gtk_menu_item_new_with_label ( _("Redownload bad map(s)") );
50a14534
EB
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 );
1064
4c77d5e0 1065 item = gtk_menu_item_new_with_label ( _("Redownload all map(s)") );
50a14534
EB
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 );
1068 }
1069
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) );
1072 }
1073 }
1074 return FALSE;
1075}
1076
941aa6e9
AF
1077static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1078{
1079 return vvp;
1080}
1081
50a14534
EB
1082static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1083{
1084 MapCoord tmp;
941aa6e9
AF
1085 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1086 return FALSE;
cdcaf41c
QT
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 ),
50a14534
EB
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;
1095 }
1096 return FALSE;
1097
1098
1099#if 0
1100 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1101 {
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 );
1112
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;
1117 }
1118 }
1119 return FALSE;
1120#endif
1121}
1122
50817314 1123static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
50a14534
EB
1124{
1125 VikMapsLayer *vml = vml_vvp[0];
1126 VikViewport *vvp = vml_vvp[1];
314c1ccc 1127 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
50a14534
EB
1128
1129 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1130 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1131
1132 VikCoord ul, br;
1133 MapCoord ulm, brm;
1134
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 );
1137
cdcaf41c 1138 VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
314c1ccc 1139 if ( map_type->drawmode == vp_drawmode &&
cdcaf41c
QT
1140 map_type->coord_to_mapcoord ( &ul, xzoom, yzoom, &ulm ) &&
1141 map_type->coord_to_mapcoord ( &br, xzoom, yzoom, &brm ) )
50817314 1142 start_download_thread ( vml, vvp, &ul, &br, redownload );
314c1ccc 1143 else if (map_type->drawmode != vp_drawmode) {
94933cb8 1144 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, map_type->drawmode);
4c77d5e0 1145 gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
314c1ccc
QT
1146 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1147 g_free(err);
1148 }
50a14534 1149 else
4c77d5e0 1150 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
50a14534
EB
1151
1152}
1153
50817314
GB
1154static void maps_layer_download_onscreen_maps ( gpointer vml_vvp[2] )
1155{
1156 download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1157}
1158
1159static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1160{
1161 download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1162}
1163
50a14534
EB
1164static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1165{
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) );
1170
1171 item = gtk_menu_item_new();
1172 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1173 gtk_widget_show ( item );
1174
4c77d5e0 1175 item = gtk_menu_item_new_with_label ( _("Download Onscreen Maps") );
50a14534
EB
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 );
50817314 1179
1b86e056 1180 /* TODO Add GTK_STOCK_REFRESH icon */
4c77d5e0 1181 item = gtk_menu_item_new_with_label ( _("Refresh Onscreen Tiles") );
50817314
GB
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 );
50a14534 1185}