]> git.street.me.uk Git - andy/viking.git/blame - src/vikmapslayer.c
Create the geonames search as an VikXmlSearchTool
[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,
b112cbf5 150 (VikLayerFuncPostRead) 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
db03733a 209void maps_layer_register_map_source ( VikMapSource *map )
cdcaf41c 210{
820c59f4 211 g_assert(map != NULL);
6846aafb 212
820c59f4 213 guint id = vik_map_source_get_uniq_id(map);
db03733a 214 const char *label = vik_map_source_get_label(map);
cdcaf41c 215 g_assert(label != NULL);
cdcaf41c
QT
216
217 /* Add the label */
218 params_maptypes = g_list_append(params_maptypes, g_strdup(label));
219
220 /* Add the id */
dc2c040e 221 params_maptypes_ids = g_list_append(params_maptypes_ids, GUINT_TO_POINTER (id));
cdcaf41c
QT
222
223 /* We have to clone */
820c59f4 224 VikMapSource *clone = VIK_MAP_SOURCE(g_object_ref(map));
cdcaf41c
QT
225 /* Register the clone in the list */
226 __map_types = g_list_append(__map_types, clone);
227
228 /* Hack
229 We have to ensure the mode LayerParam reference the up-to-date
230 GLists.
231 */
232 /*
233 memcpy(&maps_layer_params[0].widget_data, &params_maptypes, sizeof(gpointer));
234 memcpy(&maps_layer_params[0].extra_widget_data, &params_maptypes_ids, sizeof(gpointer));
235 */
236 maps_layer_params[0].widget_data = params_maptypes;
237 maps_layer_params[0].extra_widget_data = params_maptypes_ids;
238}
239
240#define MAPS_LAYER_NTH_LABEL(n) ((gchar*)g_list_nth_data(params_maptypes, (n)))
241#define MAPS_LAYER_NTH_ID(n) ((guint)g_list_nth_data(params_maptypes_ids, (n)))
820c59f4 242#define MAPS_LAYER_NTH_TYPE(n) (VIK_MAP_SOURCE(g_list_nth_data(__map_types, (n))))
cdcaf41c 243
7114e879
QT
244gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
245{
246 return(vml->maptype);
247}
248
249gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
250{
251 return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
252}
253
50a14534
EB
254/****************************************/
255/******** CACHE DIR STUFF ***************/
256/****************************************/
257
3d9454e6 258#define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
6a27c1bc
MA
259#define MAPS_CACHE_DIR maps_layer_default_dir()
260
50a14534 261#ifdef WINDOWS
6a27c1bc
MA
262#include <io.h>
263#define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
264#define LOCAL_MAPS_DIR "VIKING-MAPS"
50a14534 265#else /* POSIX */
50a14534 266#include <stdlib.h>
50a14534 267#define GLOBAL_MAPS_DIR "/var/cache/maps/"
6a27c1bc
MA
268#define LOCAL_MAPS_DIR ".viking-maps"
269#endif
50a14534 270
0c1044e9 271gchar *maps_layer_default_dir ()
50a14534 272{
3d9454e6
GB
273 static gchar *defaultdir = NULL;
274 if ( ! defaultdir )
50a14534
EB
275 {
276 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
3d9454e6
GB
277 const gchar *mapdir = g_getenv("VIKING_MAPS");
278 if ( mapdir ) {
279 defaultdir = g_strdup ( mapdir );
45acf79e 280 } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
3d9454e6 281 defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
50a14534 282 } else {
6a27c1bc 283 const gchar *home = g_get_home_dir();
45acf79e 284 if (!home || g_access(home, W_OK))
3d9454e6
GB
285 home = g_get_home_dir ();
286 if ( home )
6a27c1bc 287 defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
50a14534 288 else
6a27c1bc 289 defaultdir = g_strdup ( LOCAL_MAPS_DIR );
50a14534 290 }
3d9454e6
GB
291 if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
292 {
293 /* Add the separator at the end */
294 gchar *tmp = defaultdir;
295 defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
296 g_free(tmp);
297 }
298 g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
50a14534
EB
299 }
300 return defaultdir;
301}
302
50a14534
EB
303static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
304{
45acf79e 305 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
50a14534 306 {
f83131b9 307 g_mkdir ( vml->cache_dir, 0777 );
50a14534
EB
308 }
309}
310
311static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
312{
313 guint len;
314 g_assert ( vml != NULL);
e65028db
GB
315 g_free ( vml->cache_dir );
316 vml->cache_dir = NULL;
50a14534
EB
317
318 if ( dir == NULL || dir[0] == '\0' )
319 vml->cache_dir = g_strdup ( MAPS_CACHE_DIR );
320 else
321 {
322 len = strlen(dir);
3d9454e6 323 if ( dir[len-1] != G_DIR_SEPARATOR )
50a14534
EB
324 {
325 vml->cache_dir = g_malloc ( len+2 );
326 strncpy ( vml->cache_dir, dir, len );
3d9454e6 327 vml->cache_dir[len] = G_DIR_SEPARATOR;
50a14534
EB
328 vml->cache_dir[len+1] = '\0';
329 }
330 else
331 vml->cache_dir = g_strdup ( dir );
332 }
333 maps_layer_mkdir_if_default_dir ( vml );
334}
335
336/****************************************/
337/******** GOBJECT STUFF *****************/
338/****************************************/
339
340GType vik_maps_layer_get_type ()
341{
342 static GType vml_type = 0;
343
344 if (!vml_type)
345 {
346 static const GTypeInfo vml_info =
347 {
348 sizeof (VikMapsLayerClass),
349 NULL, /* base_init */
350 NULL, /* base_finalize */
351 NULL, /* class init */
352 NULL, /* class_finalize */
353 NULL, /* class_data */
354 sizeof (VikMapsLayer),
355 0,
356 NULL /* instance init */
357 };
358 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
359 }
360
361 return vml_type;
362}
363
364/****************************************/
365/************** PARAMETERS **************/
366/****************************************/
367
368static guint map_index_to_uniq_id (guint8 index)
369{
370 g_assert ( index < NUM_MAP_TYPES );
820c59f4 371 return vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(index));
50a14534
EB
372}
373
374static guint map_uniq_id_to_index ( guint uniq_id )
375{
376 gint i;
377 for ( i = 0; i < NUM_MAP_TYPES; i++ )
820c59f4 378 if ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(i)) == uniq_id )
50a14534
EB
379 return i;
380 return NUM_MAP_TYPES; /* no such thing */
381}
382
383static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp )
384{
385 switch ( id )
386 {
387 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
388 case PARAM_MAPTYPE: {
389 gint maptype = map_uniq_id_to_index(data.u);
4c77d5e0 390 if ( maptype == NUM_MAP_TYPES ) g_warning(_("Unknown map type"));
50a14534
EB
391 else vml->maptype = maptype;
392 break;
393 }
394 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
395 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
396 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
397 vml->mapzoom_id = data.u;
398 vml->xmapzoom = __mapzooms_x [data.u];
399 vml->ymapzoom = __mapzooms_y [data.u];
4c77d5e0 400 }else g_warning (_("Unknown Map Zoom")); break;
50a14534
EB
401 }
402 return TRUE;
403}
404
405static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id )
406{
407 VikLayerParamData rv;
408 switch ( id )
409 {
e6fd9b70 410 case PARAM_CACHE_DIR: rv.s = vml->cache_dir ? vml->cache_dir : ""; break;
50a14534
EB
411 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
412 case PARAM_ALPHA: rv.u = vml->alpha; break;
413 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
414 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
415 }
416 return rv;
417}
418
419/****************************************/
420/****** CREATING, COPYING, FREEING ******/
421/****************************************/
422
423static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
424{
36c78d6d 425 int idx;
50a14534
EB
426 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
427 vik_layer_init ( VIK_LAYER(vml), VIK_LAYER_MAPS );
36c78d6d
QT
428 idx = map_uniq_id_to_index(7); /* 7 is id for google maps */
429 vml->maptype = (idx < NUM_MAP_TYPES) ? idx : 0;
50a14534
EB
430 vml->alpha = 255;
431 vml->mapzoom_id = 0;
432 vml->dl_tool_x = vml->dl_tool_y = -1;
433 maps_layer_set_cache_dir ( vml, NULL );
434 vml->autodownload = FALSE;
10ca2bfe
QT
435 vml->last_center = NULL;
436 vml->last_xmpp = 0.0;
437 vml->last_ympp = 0.0;
50a14534
EB
438
439 vml->dl_right_click_menu = NULL;
440
441 return vml;
442}
443
444static void maps_layer_free ( VikMapsLayer *vml )
445{
e65028db
GB
446 g_free ( vml->cache_dir );
447 vml->cache_dir = NULL;
50a14534
EB
448 if ( vml->dl_right_click_menu )
449 gtk_object_sink ( GTK_OBJECT(vml->dl_right_click_menu) );
e65028db
GB
450 g_free(vml->last_center);
451 vml->last_center = NULL;
50a14534
EB
452}
453
07059501 454static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
dc5758d3 455{
07059501
GB
456 if (from_file != TRUE)
457 {
458 /* If this method is not called in file reading context
459 * it is called in GUI context.
460 * So, we can check if we have to inform the user about inconsistency */
461 VikViewportDrawMode vp_drawmode;
462 VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
820c59f4 463 VikMapSource *map = NULL;
dc5758d3 464
07059501 465 vp_drawmode = vik_viewport_get_drawmode ( VIK_VIEWPORT(vp) );
820c59f4
GB
466 map = MAPS_LAYER_NTH_TYPE(vml->maptype);
467 if (vik_map_source_get_drawmode(map) != vp_drawmode) {
468 const gchar *drawmode_name = vik_viewport_get_drawmode_name (VIK_VIEWPORT(vp), vik_map_source_get_drawmode(map));
4c77d5e0 469 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
470 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), msg );
471 g_free(msg);
472 }
dc5758d3
GB
473 }
474}
475
911400b5
AF
476static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
477{
478 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
479}
480
481static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
482{
483 VikMapsLayer *rv = maps_layer_new ( vvp );
484 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
485 return rv;
486}
487
50a14534
EB
488/*********************/
489/****** DRAWING ******/
490/*********************/
491
492static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
493{
494 guchar *pixels;
495 gint width, height, iii, jjj;
496
497 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
498 {
499 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
500 g_object_unref(G_OBJECT(pixbuf));
501 pixbuf = tmp;
502 }
503
504 pixels = gdk_pixbuf_get_pixels(pixbuf);
505 width = gdk_pixbuf_get_width(pixbuf);
506 height = gdk_pixbuf_get_height(pixbuf);
507
508 /* r,g,b,a,r,g,b,a.... */
509 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
510 {
511 pixels += 3;
512 *pixels++ = alpha;
513 }
514 return pixbuf;
515}
516
517static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
518{
519 GdkPixbuf *tmp;
520 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
9fdb940f 521 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_NEAREST);
50a14534
EB
522 g_object_unref ( G_OBJECT(pixbuf) );
523 return tmp;
524}
525
526static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
527{
528 GdkPixbuf *pixbuf;
529
530 /* get the thing */
531 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
532 mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
533
534 if ( ! pixbuf ) {
535 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
536 vml->cache_dir, mode,
537 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
45acf79e 538 if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE) {
50a14534
EB
539 {
540 GError *gx = NULL;
541 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
542
543 if (gx)
544 {
545 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
4c77d5e0 546 g_warning ( _("Couldn't open image file: %s"), gx->message );
50a14534
EB
547
548 g_error_free ( gx );
549 if ( pixbuf )
550 g_object_unref ( G_OBJECT(pixbuf) );
551 pixbuf = NULL;
552 } else {
553 if ( vml->alpha < 255 )
554 pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
555 if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
556 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
557
558 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
820c59f4 559 mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
50a14534
EB
560 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
561 }
562 }
563 }
564 }
565 return pixbuf;
566}
567
10ca2bfe
QT
568gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
569{
570 const VikCoord *center = vik_viewport_get_center ( vvp );
571
572 if (vml->last_center == NULL) {
573 VikCoord *new_center = g_malloc(sizeof(VikCoord));
574 *new_center = *center;
575 vml->last_center = new_center;
576 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
577 vml->last_ympp = vik_viewport_get_ympp(vvp);
578 return TRUE;
579 }
580
581 /* TODO: perhaps vik_coord_diff() */
582 if (vik_coord_equals(vml->last_center, center)
583 && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
584 && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
585 return FALSE;
586
587 *(vml->last_center) = *center;
588 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
589 vml->last_ympp = vik_viewport_get_ympp(vvp);
590 return TRUE;
591}
592
50a14534
EB
593static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
594{
595 MapCoord ulm, brm;
596 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
597 gdouble yzoom = vik_viewport_get_ympp ( vvp );
598 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
732d1e25 599 gdouble existence_only = FALSE;
50a14534
EB
600
601 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
602 xshrinkfactor = vml->xmapzoom / xzoom;
603 yshrinkfactor = vml->ymapzoom / yzoom;
732d1e25
EB
604 xzoom = vml->xmapzoom;
605 yzoom = vml->xmapzoom;
606 if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
607 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
608 if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR )
609 existence_only = TRUE;
610 else {
4c77d5e0 611 g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
732d1e25
EB
612 return;
613 }
50a14534
EB
614 }
615 }
616
617 /* coord -> ID */
820c59f4
GB
618 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
619 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
620 vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
50a14534
EB
621
622 /* loop & draw */
623 gint x, y;
624 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
625 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
820c59f4 626 gint mode = vik_map_source_get_uniq_id(map);
50a14534
EB
627
628 VikCoord coord;
629 gint xx, yy, width, height;
630 GdkPixbuf *pixbuf;
631
632 guint max_path_len = strlen(vml->cache_dir) + 40;
633 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
634
732d1e25 635 if ( (!existence_only) && vml->autodownload && should_start_autodownload(vml, vvp)) {
214f9ac2
QT
636#ifdef DEBUG
637 fputs(stderr, "DEBUG: Starting autodownload\n");
638#endif
50a14534 639 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
10ca2bfe 640 }
50a14534 641
820c59f4 642 if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
50a14534
EB
643 for ( x = xmin; x <= xmax; x++ ) {
644 for ( y = ymin; y <= ymax; y++ ) {
645 ulm.x = x;
646 ulm.y = y;
647 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
648 if ( pixbuf ) {
649 width = gdk_pixbuf_get_width ( pixbuf );
650 height = gdk_pixbuf_get_height ( pixbuf );
651
820c59f4 652 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
50a14534
EB
653 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
654 xx -= (width/2);
655 yy -= (height/2);
656
657 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
658 }
659 }
660 }
661 } else { /* tilesize is known, don't have to keep converting coords */
820c59f4
GB
662 gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
663 gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
50a14534
EB
664 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
665 gint tilesize_x_ceil = ceil ( tilesize_x );
666 gint tilesize_y_ceil = ceil ( tilesize_y );
667 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
668 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
669 gdouble xx, yy; gint xx_tmp, yy_tmp;
670 gint base_yy, xend, yend;
732d1e25
EB
671
672 GdkGC *black_gc = GTK_WIDGET(vvp)->style->black_gc;
673
50a14534
EB
674 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
675 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
676
820c59f4 677 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
50a14534
EB
678 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
679 xx = xx_tmp; yy = yy_tmp;
680 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
681 * eg if tile size 128, shrinkfactor 0.333 */
682 xx -= (tilesize_x/2);
683 base_yy = yy - (tilesize_y/2);
684
685 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
686 yy = base_yy;
687 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
688 ulm.x = x;
689 ulm.y = y;
732d1e25
EB
690
691 if ( existence_only ) {
692 g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE,
693 vml->cache_dir, mode,
694 ulm.scale, ulm.z, ulm.x, ulm.y );
45acf79e 695 if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
732d1e25
EB
696 vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
697 }
698 } else {
699 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
700 if ( pixbuf )
701 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
91dc4449
JJ
702 else {
703 /* retry with bigger shrinkfactor */
704 int scale_inc;
705 for (scale_inc = 1; scale_inc < 4; scale_inc ++) {
706 int scale_factor = 1 << scale_inc; /* 2^scale_inc */
707 MapCoord ulm2 = ulm;
708 ulm2.x = ulm.x / scale_factor;
709 ulm2.y = ulm.y / scale_factor;
710 ulm2.scale = ulm.scale + scale_inc;
711 pixbuf = get_pixbuf ( vml, mode, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
712 if ( pixbuf ) {
713 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
714 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
715 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
716 break;
717 }
718 }
719 }
732d1e25 720 }
50a14534
EB
721
722 yy += tilesize_y;
723 }
724 xx += tilesize_x;
725 }
726 }
727
728 g_free ( path_buf );
729 }
730}
731
732static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
733{
820c59f4 734 if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
50a14534
EB
735 {
736 VikCoord ul, br;
737
738 /* get corner coords */
739 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
740 /* UTM multi-zone stuff by Kit Transue */
741 gchar leftmost_zone, rightmost_zone, i;
742 leftmost_zone = vik_viewport_leftmost_zone( vvp );
743 rightmost_zone = vik_viewport_rightmost_zone( vvp );
744 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
745 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
746 maps_layer_draw_section ( vml, vvp, &ul, &br );
747 }
748 }
749 else {
750 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
751 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
752
753 maps_layer_draw_section ( vml, vvp, &ul, &br );
754 }
755 }
756}
757
758/*************************/
759/****** DOWNLOADING ******/
760/*************************/
761
762/* pass along data to thread, exists even if layer is deleted. */
763typedef struct {
764 gchar *cache_dir;
765 gchar *filename_buf;
766 gint x0, y0, xf, yf;
767 MapCoord mapcoord;
768 gint maptype;
769 gint maxlen;
770 gint mapstoget;
771 gint redownload;
7114e879 772 gboolean refresh_display;
550fd035
QT
773 VikMapsLayer *vml;
774 VikViewport *vvp;
775 gboolean map_layer_alive;
776 GMutex *mutex;
50a14534
EB
777} MapDownloadInfo;
778
779static void mdi_free ( MapDownloadInfo *mdi )
780{
550fd035 781 g_mutex_free(mdi->mutex);
50a14534 782 g_free ( mdi->cache_dir );
e65028db 783 mdi->cache_dir = NULL;
50a14534 784 g_free ( mdi->filename_buf );
e65028db 785 mdi->filename_buf = NULL;
50a14534
EB
786 g_free ( mdi );
787}
788
7bb60307 789static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
550fd035 790{
7bb60307 791 MapDownloadInfo *mdi = ptr;
550fd035
QT
792 g_mutex_lock(mdi->mutex);
793 mdi->map_layer_alive = FALSE;
794 g_mutex_unlock(mdi->mutex);
795}
796
634eca0a 797static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
50a14534
EB
798{
799 guint donemaps = 0;
800 gint x, y;
801 for ( x = mdi->x0; x <= mdi->xf; x++ )
802 {
803 for ( y = mdi->y0; y <= mdi->yf; y++ )
804 {
94493114 805 gboolean remove_mem_cache = FALSE;
84628352 806 gboolean need_download = FALSE;
50a14534 807 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
820c59f4 808 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
50a14534
EB
809 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
810
84628352 811 donemaps++;
634eca0a
JJ
812 int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
813 if (res != 0)
814 return -1;
84628352 815
50a14534 816 if ( mdi->redownload == REDOWNLOAD_ALL)
8c060406 817 g_remove ( mdi->filename_buf );
093c5c71 818
45acf79e 819 else if ( (mdi->redownload == REDOWNLOAD_BAD) && (g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE) )
50a14534
EB
820 {
821 /* see if this one is bad or what */
822 GError *gx = NULL;
823 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
824 if (gx || (!pixbuf))
8c060406 825 g_remove ( mdi->filename_buf );
50a14534
EB
826 if ( pixbuf )
827 g_object_unref ( pixbuf );
828 if ( gx )
829 g_error_free ( gx );
830 }
831
45acf79e 832 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
50a14534 833 {
84628352
QT
834 need_download = TRUE;
835 if (( mdi->redownload != REDOWNLOAD_NONE ) &&
a0b59f2f 836 ( mdi->redownload != DOWNLOAD_OR_REFRESH ))
94493114
QT
837 remove_mem_cache = TRUE;
838 } else if ( mdi->redownload == DOWNLOAD_OR_REFRESH ) {
839 remove_mem_cache = TRUE;
840 } else
841 continue;
842
94493114 843 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
84628352
QT
844
845 if (need_download) {
820c59f4 846 if ( vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf ))
94493114 847 continue;
84628352 848 }
94493114
QT
849
850 gdk_threads_enter();
851 g_mutex_lock(mdi->mutex);
852 if (remove_mem_cache)
820c59f4 853 a_mapcache_remove_all_shrinkfactors ( x, y, mdi->mapcoord.z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)), mdi->mapcoord.scale );
7114e879 854 if (mdi->refresh_display && mdi->map_layer_alive) {
94493114
QT
855 /* TODO: check if it's on visible area */
856 vik_layer_emit_update ( VIK_LAYER(mdi->vml) );
a0b59f2f 857 }
94493114
QT
858 g_mutex_unlock(mdi->mutex);
859 gdk_threads_leave();
860 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
861
50a14534
EB
862 }
863 }
04e54492
QT
864 g_mutex_lock(mdi->mutex);
865 if (mdi->map_layer_alive)
7bb60307 866 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
04e54492 867 g_mutex_unlock(mdi->mutex);
634eca0a 868 return 0;
50a14534
EB
869}
870
871static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
872{
873 if ( mdi->mapcoord.x || mdi->mapcoord.y )
874 {
875 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
820c59f4 876 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
50a14534 877 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
45acf79e 878 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
50a14534 879 {
8c060406 880 g_remove ( mdi->filename_buf );
50a14534
EB
881 }
882 }
883}
884
885static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
886{
887 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
888 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
889 MapCoord ulm, brm;
820c59f4
GB
890 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
891 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm )
892 && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
50a14534
EB
893 {
894 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
895 gint a, b;
896
550fd035
QT
897 mdi->vml = vml;
898 mdi->vvp = vvp;
899 mdi->map_layer_alive = TRUE;
900 mdi->mutex = g_mutex_new();
7114e879 901 mdi->refresh_display = TRUE;
550fd035 902
50a14534
EB
903 /* cache_dir and buffer for dest filename */
904 mdi->cache_dir = g_strdup ( vml->cache_dir );
905 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
906 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
907 mdi->maptype = vml->maptype;
908
909 mdi->mapcoord = ulm;
910
911 mdi->redownload = redownload;
912
913 mdi->x0 = MIN(ulm.x, brm.x);
914 mdi->xf = MAX(ulm.x, brm.x);
915 mdi->y0 = MIN(ulm.y, brm.y);
916 mdi->yf = MAX(ulm.y, brm.y);
917
918 mdi->mapstoget = 0;
919
920 if ( mdi->redownload ) {
921 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
922 } else {
923 /* calculate how many we need */
924 for ( a = mdi->x0; a <= mdi->xf; a++ )
925 {
926 for ( b = mdi->y0; b <= mdi->yf; b++ )
927 {
928 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
820c59f4 929 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
50a14534 930 ulm.z, a, b );
45acf79e 931 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
50a14534
EB
932 mdi->mapstoget++;
933 }
934 }
935 }
936
937 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
938
939 if ( mdi->mapstoget )
940 {
97634600
GB
941 const gchar *tmp_str;
942 gchar *tmp;
50a14534 943
97634600
GB
944 if (redownload)
945 {
946 if (redownload == REDOWNLOAD_BAD)
947 tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
948 else
949 tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
950 }
951 else
952 {
953 tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
954 }
955 tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
956
7bb60307 957 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
50a14534
EB
958 /* launch the thread */
959 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
960 tmp, /* description string */
961 (vik_thr_func) map_download_thread, /* function to call within thread */
962 mdi, /* pass along data */
963 (vik_thr_free_func) mdi_free, /* function to free pass along data */
964 (vik_thr_free_func) mdi_cancel_cleanup,
965 mdi->mapstoget );
966 g_free ( tmp );
967 }
968 else
969 mdi_free ( mdi );
970 }
971}
972
7114e879
QT
973void maps_layer_download_section_without_redraw( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
974{
7114e879 975 MapCoord ulm, brm;
820c59f4 976 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
7114e879 977
820c59f4
GB
978 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
979 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
4258f4e2 980 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
7114e879
QT
981 return;
982 }
983
984 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
985 gint i, j;
986
987 mdi->vml = vml;
988 mdi->vvp = vvp;
989 mdi->map_layer_alive = TRUE;
990 mdi->mutex = g_mutex_new();
991 mdi->refresh_display = FALSE;
992
993 mdi->cache_dir = g_strdup ( vml->cache_dir );
994 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
995 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
996 mdi->maptype = vml->maptype;
997
998 mdi->mapcoord = ulm;
999
1000 mdi->redownload = REDOWNLOAD_NONE;
1001
1002 mdi->x0 = MIN(ulm.x, brm.x);
1003 mdi->xf = MAX(ulm.x, brm.x);
1004 mdi->y0 = MIN(ulm.y, brm.y);
1005 mdi->yf = MAX(ulm.y, brm.y);
1006
1007 mdi->mapstoget = 0;
1008
1009 for (i = mdi->x0; i <= mdi->xf; i++) {
1010 for (j = mdi->y0; j <= mdi->yf; j++) {
1011 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
820c59f4 1012 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
7114e879 1013 ulm.z, i, j );
45acf79e 1014 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
7114e879
QT
1015 mdi->mapstoget++;
1016 }
1017 }
1018
1019 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1020
1021 if (mdi->mapstoget) {
4c77d5e0
GB
1022 gchar *tmp;
1023 const gchar *fmt;
eb6b0125
JJ
1024 fmt = ngettext("Downloading %d %s map...",
1025 "Downloading %d %s maps...",
1026 mdi->mapstoget);
4c77d5e0 1027 tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
7114e879
QT
1028
1029 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1030 /* launch the thread */
1031 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1032 tmp, /* description string */
1033 (vik_thr_func) map_download_thread, /* function to call within thread */
1034 mdi, /* pass along data */
1035 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1036 (vik_thr_free_func) mdi_cancel_cleanup,
1037 mdi->mapstoget );
1038 g_free ( tmp );
1039 }
1040 else
1041 mdi_free ( mdi );
1042}
1043
50a14534
EB
1044static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1045{
1046 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1047}
1048static void maps_layer_redownload_all ( VikMapsLayer *vml )
1049{
1050 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1051}
1052
1053static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1054{
941aa6e9
AF
1055 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1056 return FALSE;
50a14534
EB
1057 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1058 {
1059 if ( event->button == 1 )
1060 {
1061 VikCoord ul, br;
1062 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 );
1063 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 1064 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
50a14534
EB
1065 vml->dl_tool_x = vml->dl_tool_y = -1;
1066 return TRUE;
1067 }
1068 else
1069 {
1070 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) );
1071 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) );
1072
1073 vml->redownload_vvp = vvp;
1074
1075 vml->dl_tool_x = vml->dl_tool_y = -1;
1076
1077 if ( ! vml->dl_right_click_menu ) {
1078 GtkWidget *item;
1079 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1080
4c77d5e0 1081 item = gtk_menu_item_new_with_label ( _("Redownload bad map(s)") );
50a14534
EB
1082 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1083 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1084
4c77d5e0 1085 item = gtk_menu_item_new_with_label ( _("Redownload all map(s)") );
50a14534
EB
1086 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1087 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1088 }
1089
1090 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1091 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1092 }
1093 }
1094 return FALSE;
1095}
1096
941aa6e9
AF
1097static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1098{
1099 return vvp;
1100}
1101
50a14534
EB
1102static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1103{
1104 MapCoord tmp;
941aa6e9
AF
1105 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1106 return FALSE;
820c59f4
GB
1107 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1108 if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
1109 vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
50a14534
EB
1110 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1111 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1112 &tmp ) ) {
1113 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1114 return TRUE;
1115 }
1116 return FALSE;
1117
1118
1119#if 0
1120 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1121 {
1122 VikCoord coord;
1123 MapCoord mapcoord;
1124 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1125 if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1126 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1127 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1128 &mapcoord ) ) {
1129 gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1130 vml->cache_dir, __map_types[vml->maptype].uniq_id,
1131 mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1132
1133 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1134 g_free ( filename_buf );
1135 vik_layer_emit_update ( VIK_LAYER(vml) );
1136 return TRUE;
1137 }
1138 }
1139 return FALSE;
1140#endif
1141}
1142
50817314 1143static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
50a14534
EB
1144{
1145 VikMapsLayer *vml = vml_vvp[0];
1146 VikViewport *vvp = vml_vvp[1];
314c1ccc 1147 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
50a14534
EB
1148
1149 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1150 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1151
1152 VikCoord ul, br;
1153 MapCoord ulm, brm;
1154
1155 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1156 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1157
820c59f4
GB
1158 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1159 if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
1160 vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
1161 vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
50817314 1162 start_download_thread ( vml, vvp, &ul, &br, redownload );
820c59f4
GB
1163 else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
1164 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
4c77d5e0 1165 gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
314c1ccc
QT
1166 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1167 g_free(err);
1168 }
50a14534 1169 else
4c77d5e0 1170 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
50a14534
EB
1171
1172}
1173
50817314
GB
1174static void maps_layer_download_onscreen_maps ( gpointer vml_vvp[2] )
1175{
1176 download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1177}
1178
1179static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1180{
1181 download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1182}
1183
50a14534
EB
1184static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1185{
1186 static gpointer pass_along[2];
1187 GtkWidget *item;
1188 pass_along[0] = vml;
1189 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1190
1191 item = gtk_menu_item_new();
1192 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1193 gtk_widget_show ( item );
1194
4c77d5e0 1195 item = gtk_menu_item_new_with_label ( _("Download Onscreen Maps") );
50a14534
EB
1196 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_onscreen_maps), pass_along );
1197 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1198 gtk_widget_show ( item );
50817314 1199
1b86e056 1200 /* TODO Add GTK_STOCK_REFRESH icon */
4c77d5e0 1201 item = gtk_menu_item_new_with_label ( _("Refresh Onscreen Tiles") );
50817314
GB
1202 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1203 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1204 gtk_widget_show ( item );
50a14534 1205}