]>
Commit | Line | Data |
---|---|---|
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 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License as published by | |
9 | * the Free Software Foundation; either version 2 of the License, or | |
10 | * (at your option) any later version. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with this program; if not, write to the Free Software | |
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
20 | * | |
21 | */ | |
22 | ||
23 | #define MAX_SHRINKFACTOR 8.0000001 /* zoom 1 viewing 8-tiles */ | |
24 | #define MIN_SHRINKFACTOR 0.0312499 /* zoom 32 viewing 1-tiles */ | |
25 | ||
26 | #include <gtk/gtk.h> | |
27 | #include <gdk-pixbuf/gdk-pixdata.h> | |
28 | #include <stdio.h> | |
29 | #include <string.h> | |
30 | #include <math.h> | |
31 | #include "globals.h" | |
32 | #include "coords.h" | |
33 | #include "vikcoord.h" | |
34 | #include "viktreeview.h" | |
35 | #include "vikviewport.h" | |
36 | #include "viklayer.h" | |
37 | #include "vikmapslayer.h" | |
38 | #include "vikmapslayer_pixmap.h" | |
39 | ||
40 | #include <unistd.h> | |
41 | #include <sys/stat.h> | |
42 | #include <sys/types.h> | |
43 | ||
44 | #include "mapcache.h" | |
45 | /* only for dialog.h -- ugh */ | |
46 | #include "vikwaypoint.h" | |
47 | #include "dialog.h" | |
48 | ||
49 | #include "vikstatus.h" | |
50 | #include "background.h" | |
51 | ||
52 | #include "vikaggregatelayer.h" | |
53 | #include "viklayerspanel.h" | |
54 | ||
55 | #include "mapcoord.h" | |
56 | #include "terraserver.h" | |
57 | #include "googlemaps.h" | |
58 | #include "google.h" | |
59 | #include "khmaps.h" | |
60 | #include "expedia.h" | |
61 | ||
62 | typedef struct { | |
63 | guint8 uniq_id; | |
64 | guint16 tilesize_x; | |
65 | guint16 tilesize_y; | |
66 | guint drawmode; | |
67 | gboolean (*coord_to_mapcoord) ( const VikCoord *src, gdouble xzoom, gdouble yzoom, MapCoord *dest ); | |
68 | void (*mapcoord_to_center_coord) ( MapCoord *src, VikCoord *dest ); | |
69 | void (*download) ( MapCoord *src, const gchar *dest_fn ); | |
70 | /* TODO: constant size (yay!) */ | |
71 | } VikMapsLayer_MapType; | |
72 | ||
73 | ||
74 | /****** MAP TYPES ******/ | |
75 | ||
76 | static const VikMapsLayer_MapType __map_types[] = { | |
77 | ||
78 | { 2, 200, 200, VIK_VIEWPORT_DRAWMODE_UTM, terraserver_topo_coord_to_mapcoord, terraserver_mapcoord_to_center_coord, terraserver_topo_download }, | |
79 | { 1, 200, 200, VIK_VIEWPORT_DRAWMODE_UTM, terraserver_aerial_coord_to_mapcoord, terraserver_mapcoord_to_center_coord, terraserver_aerial_download }, | |
80 | { 4, 200, 200, VIK_VIEWPORT_DRAWMODE_UTM, terraserver_urban_coord_to_mapcoord, terraserver_mapcoord_to_center_coord, terraserver_urban_download }, | |
81 | { 5, 0, 0, VIK_VIEWPORT_DRAWMODE_EXPEDIA, expedia_coord_to_mapcoord, expedia_mapcoord_to_center_coord, expedia_download }, | |
82 | { 9, 128, 128, VIK_VIEWPORT_DRAWMODE_GOOGLE, googlemaps_coord_to_mapcoord, googlemaps_mapcoord_to_center_coord, googlemaps_download }, | |
83 | { 8, 256, 256, VIK_VIEWPORT_DRAWMODE_KH, khmaps_coord_to_mapcoord, khmaps_mapcoord_to_center_coord, khmaps_download }, | |
84 | { 7, 256, 256, VIK_VIEWPORT_DRAWMODE_MERCATOR, google_coord_to_mapcoord, google_mapcoord_to_center_coord, google_download }, | |
85 | { 10, 256, 256, VIK_VIEWPORT_DRAWMODE_MERCATOR, google_coord_to_mapcoord, google_mapcoord_to_center_coord, google_trans_download }, | |
86 | { 11, 256, 256, VIK_VIEWPORT_DRAWMODE_MERCATOR, google_coord_to_mapcoord, google_mapcoord_to_center_coord, google_kh_download }, | |
87 | }; | |
88 | ||
89 | #define NUM_MAP_TYPES (sizeof(__map_types)/sizeof(__map_types[0])) | |
90 | ||
91 | /******** MAPZOOMS *********/ | |
92 | ||
93 | static gchar *params_mapzooms[] = { "Use Viking Zoom Level", "0.25", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", "USGS 10k", "USGS 24k", "USGS 25k", "USGS 50k", "USGS 100k", "USGS 200k", "USGS 250k" }; | |
94 | 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 }; | |
95 | 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 }; | |
96 | ||
97 | static gchar *params_maptypes[] = { "Terraserver Topos", "Terraserver Aerials", "Terraserver Urban Areas", "Expedia (Street Maps)", "Google Maps (Street)", "KH Maps", "New (Mercator) Google", "Transparent Google", "New (Mercator) KH" }; | |
98 | static guint params_maptypes_ids[] = { 2, 1, 4, 5, 9, 8, 7, 10, 11 }; | |
99 | #define NUM_MAPZOOMS (sizeof(params_mapzooms)/sizeof(params_mapzooms[0])) | |
100 | ||
101 | /**************************/ | |
102 | ||
103 | ||
104 | static VikMapsLayer *maps_layer_copy ( VikMapsLayer *vml, VikViewport *vvp ); | |
105 | static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp ); | |
106 | static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id ); | |
107 | static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp ); | |
108 | static VikMapsLayer *maps_layer_new ( VikViewport *vvp ); | |
109 | static void maps_layer_free ( VikMapsLayer *vml ); | |
110 | static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp ); | |
111 | static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp ); | |
112 | static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir ); | |
113 | static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload ); | |
114 | static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp ); | |
115 | ||
116 | ||
117 | static VikLayerParamScale params_scales[] = { | |
118 | /* min, max, step, digits (decimal places) */ | |
119 | { 0, 255, 3, 0 }, /* alpha */ | |
120 | }; | |
121 | ||
122 | VikLayerParam maps_layer_params[] = { | |
123 | { "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, "Map Type:", VIK_LAYER_WIDGET_RADIOGROUP, params_maptypes, params_maptypes_ids }, | |
124 | { "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, "Maps Directory (Optional):", VIK_LAYER_WIDGET_FILEENTRY }, | |
125 | { "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, "Alpha:", VIK_LAYER_WIDGET_HSCALE, params_scales }, | |
126 | { "autodownload", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, "Autodownload maps:", VIK_LAYER_WIDGET_CHECKBUTTON }, | |
127 | { "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, "Zoom Level:", VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms }, | |
128 | }; | |
129 | ||
130 | enum { PARAM_MAPTYPE=0, PARAM_CACHE_DIR, PARAM_ALPHA, PARAM_AUTODOWNLOAD, PARAM_MAPZOOM, NUM_PARAMS }; | |
131 | ||
132 | static VikToolInterface maps_tools[] = { | |
133 | { "Maps Download", (VikToolInterfaceFunc) maps_layer_download_click, (VikToolInterfaceFunc) maps_layer_download_release }, | |
134 | }; | |
135 | ||
136 | VikLayerInterface vik_maps_layer_interface = { | |
137 | "Map", | |
138 | &mapslayer_pixbuf, | |
139 | ||
140 | maps_tools, | |
141 | sizeof(maps_tools) / sizeof(maps_tools[0]), | |
142 | ||
143 | maps_layer_params, | |
144 | NUM_PARAMS, | |
145 | NULL, | |
146 | 0, | |
147 | ||
148 | (VikLayerFuncCreate) maps_layer_new, | |
149 | (VikLayerFuncRealize) NULL, | |
150 | (VikLayerFuncPostRead) NULL, | |
151 | (VikLayerFuncFree) maps_layer_free, | |
152 | ||
153 | (VikLayerFuncProperties) NULL, | |
154 | (VikLayerFuncDraw) maps_layer_draw, | |
155 | (VikLayerFuncChangeCoordMode) NULL, | |
156 | ||
157 | (VikLayerFuncAddMenuItems) maps_layer_add_menu_items, | |
158 | (VikLayerFuncSublayerAddMenuItems) NULL, | |
159 | ||
160 | (VikLayerFuncSublayerRenameRequest) NULL, | |
161 | (VikLayerFuncSublayerToggleVisible) NULL, | |
162 | ||
163 | (VikLayerFuncCopy) maps_layer_copy, | |
164 | ||
165 | (VikLayerFuncSetParam) maps_layer_set_param, | |
166 | (VikLayerFuncGetParam) maps_layer_get_param, | |
167 | ||
168 | (VikLayerFuncReadFileData) NULL, | |
169 | (VikLayerFuncWriteFileData) NULL, | |
170 | ||
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 | ||
187 | gint dl_tool_x, dl_tool_y; | |
188 | ||
189 | GtkMenu *dl_right_click_menu; | |
190 | VikCoord redownload_ul, redownload_br; /* right click menu only */ | |
191 | VikViewport *redownload_vvp; | |
192 | }; | |
193 | ||
194 | enum { REDOWNLOAD_NONE = 0, REDOWNLOAD_BAD, REDOWNLOAD_ALL }; | |
195 | ||
196 | ||
197 | /****************************************/ | |
198 | /******** CACHE DIR STUFF ***************/ | |
199 | /****************************************/ | |
200 | ||
201 | #ifdef WINDOWS | |
202 | #define MAPS_CACHE_DIR "C:\\VIKING-MAPS\\" | |
203 | #define DIRSTRUCTURE "%st%ds%dz%d\\%d\\%d" | |
204 | #else /* POSIX */ | |
205 | ||
206 | #include <stdlib.h> | |
207 | ||
208 | #define MAPS_CACHE_DIR maps_layer_default_dir() | |
209 | #define GLOBAL_MAPS_DIR "/var/cache/maps/" | |
210 | #define DIRSTRUCTURE "%st%ds%dz%d/%d/%d" | |
211 | ||
212 | static gchar *maps_layer_default_dir () | |
213 | { | |
214 | static gchar defaultdir[512]; | |
215 | static gboolean already_run = 0; | |
216 | if ( ! already_run ) | |
217 | { | |
218 | /* Thanks to Mike Davison for the $VIKING_MAPS usage */ | |
219 | gchar *mapdir = getenv("VIKING_MAPS"); | |
220 | if ( mapdir && strlen(mapdir) < 497 ) { | |
221 | strcpy ( defaultdir, mapdir ); | |
222 | } else if ( access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) { | |
223 | strcpy ( defaultdir, GLOBAL_MAPS_DIR ); | |
224 | } else { | |
225 | gchar *home = getenv("HOME"); | |
226 | if ( home && strlen(home) < 497 ) | |
227 | { | |
228 | strcpy ( defaultdir, home ); | |
229 | strcat ( defaultdir, "/.viking-maps/" ); | |
230 | } | |
231 | else | |
232 | { | |
233 | strcpy ( defaultdir, ".viking-maps/" ); | |
234 | } | |
235 | } | |
236 | already_run = 1; | |
237 | } | |
238 | return defaultdir; | |
239 | } | |
240 | ||
241 | #endif | |
242 | ||
243 | static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml ) | |
244 | { | |
245 | if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && access ( vml->cache_dir, F_OK ) != 0 ) | |
246 | { | |
247 | #ifdef WINDOWS | |
248 | mkdir ( vml->cache_dir ); | |
249 | #else | |
250 | mkdir ( vml->cache_dir, 0777 ); | |
251 | #endif | |
252 | } | |
253 | } | |
254 | ||
255 | static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir ) | |
256 | { | |
257 | guint len; | |
258 | g_assert ( vml != NULL); | |
259 | if ( vml->cache_dir ) | |
260 | g_free ( vml->cache_dir ); | |
261 | ||
262 | if ( dir == NULL || dir[0] == '\0' ) | |
263 | vml->cache_dir = g_strdup ( MAPS_CACHE_DIR ); | |
264 | else | |
265 | { | |
266 | len = strlen(dir); | |
267 | if ( dir[len-1] != VIKING_FILE_SEP ) | |
268 | { | |
269 | vml->cache_dir = g_malloc ( len+2 ); | |
270 | strncpy ( vml->cache_dir, dir, len ); | |
271 | vml->cache_dir[len] = VIKING_FILE_SEP; | |
272 | vml->cache_dir[len+1] = '\0'; | |
273 | } | |
274 | else | |
275 | vml->cache_dir = g_strdup ( dir ); | |
276 | } | |
277 | maps_layer_mkdir_if_default_dir ( vml ); | |
278 | } | |
279 | ||
280 | /****************************************/ | |
281 | /******** GOBJECT STUFF *****************/ | |
282 | /****************************************/ | |
283 | ||
284 | GType vik_maps_layer_get_type () | |
285 | { | |
286 | static GType vml_type = 0; | |
287 | ||
288 | if (!vml_type) | |
289 | { | |
290 | static const GTypeInfo vml_info = | |
291 | { | |
292 | sizeof (VikMapsLayerClass), | |
293 | NULL, /* base_init */ | |
294 | NULL, /* base_finalize */ | |
295 | NULL, /* class init */ | |
296 | NULL, /* class_finalize */ | |
297 | NULL, /* class_data */ | |
298 | sizeof (VikMapsLayer), | |
299 | 0, | |
300 | NULL /* instance init */ | |
301 | }; | |
302 | vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 ); | |
303 | } | |
304 | ||
305 | return vml_type; | |
306 | } | |
307 | ||
308 | /****************************************/ | |
309 | /************** PARAMETERS **************/ | |
310 | /****************************************/ | |
311 | ||
312 | static guint map_index_to_uniq_id (guint8 index) | |
313 | { | |
314 | g_assert ( index < NUM_MAP_TYPES ); | |
315 | return __map_types[index].uniq_id; | |
316 | } | |
317 | ||
318 | static guint map_uniq_id_to_index ( guint uniq_id ) | |
319 | { | |
320 | gint i; | |
321 | for ( i = 0; i < NUM_MAP_TYPES; i++ ) | |
322 | if ( __map_types[i].uniq_id == uniq_id ) | |
323 | return i; | |
324 | return NUM_MAP_TYPES; /* no such thing */ | |
325 | } | |
326 | ||
327 | static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp ) | |
328 | { | |
329 | switch ( id ) | |
330 | { | |
331 | case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break; | |
332 | case PARAM_MAPTYPE: { | |
333 | gint maptype = map_uniq_id_to_index(data.u); | |
334 | if ( maptype == NUM_MAP_TYPES ) g_warning("Unknown map type"); | |
335 | else vml->maptype = maptype; | |
336 | break; | |
337 | } | |
338 | case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break; | |
339 | case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break; | |
340 | case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) { | |
341 | vml->mapzoom_id = data.u; | |
342 | vml->xmapzoom = __mapzooms_x [data.u]; | |
343 | vml->ymapzoom = __mapzooms_y [data.u]; | |
344 | }else g_warning ("Unknown Map Zoom"); break; | |
345 | } | |
346 | return TRUE; | |
347 | } | |
348 | ||
349 | static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id ) | |
350 | { | |
351 | VikLayerParamData rv; | |
352 | switch ( id ) | |
353 | { | |
354 | case PARAM_CACHE_DIR: rv.s = (vml->cache_dir && strcmp(vml->cache_dir, MAPS_CACHE_DIR) != 0) ? vml->cache_dir : ""; break; | |
355 | case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break; | |
356 | case PARAM_ALPHA: rv.u = vml->alpha; break; | |
357 | case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break; | |
358 | case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break; | |
359 | } | |
360 | return rv; | |
361 | } | |
362 | ||
363 | /****************************************/ | |
364 | /****** CREATING, COPYING, FREEING ******/ | |
365 | /****************************************/ | |
366 | ||
367 | static VikMapsLayer *maps_layer_new ( VikViewport *vvp ) | |
368 | { | |
369 | VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) ); | |
370 | vik_layer_init ( VIK_LAYER(vml), VIK_LAYER_MAPS ); | |
371 | vml->maptype = 0; | |
372 | vml->alpha = 255; | |
373 | vml->mapzoom_id = 0; | |
374 | vml->dl_tool_x = vml->dl_tool_y = -1; | |
375 | maps_layer_set_cache_dir ( vml, NULL ); | |
376 | vml->autodownload = FALSE; | |
377 | ||
378 | vml->dl_right_click_menu = NULL; | |
379 | ||
380 | return vml; | |
381 | } | |
382 | ||
383 | static void maps_layer_free ( VikMapsLayer *vml ) | |
384 | { | |
385 | if ( vml->cache_dir ) | |
386 | g_free ( vml->cache_dir ); | |
387 | if ( vml->dl_right_click_menu ) | |
388 | gtk_object_sink ( GTK_OBJECT(vml->dl_right_click_menu) ); | |
389 | } | |
390 | ||
391 | static VikMapsLayer *maps_layer_copy ( VikMapsLayer *vml, VikViewport *vvp ) | |
392 | { | |
393 | VikMapsLayer *rv = maps_layer_new ( vvp ); | |
394 | *rv = *vml; | |
395 | rv->cache_dir = g_strdup(rv->cache_dir); | |
396 | VIK_LAYER(rv)->name = NULL; | |
397 | return rv; | |
398 | } | |
399 | ||
400 | /*********************/ | |
401 | /****** DRAWING ******/ | |
402 | /*********************/ | |
403 | ||
404 | static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha ) | |
405 | { | |
406 | guchar *pixels; | |
407 | gint width, height, iii, jjj; | |
408 | ||
409 | if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) ) | |
410 | { | |
411 | GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0); | |
412 | g_object_unref(G_OBJECT(pixbuf)); | |
413 | pixbuf = tmp; | |
414 | } | |
415 | ||
416 | pixels = gdk_pixbuf_get_pixels(pixbuf); | |
417 | width = gdk_pixbuf_get_width(pixbuf); | |
418 | height = gdk_pixbuf_get_height(pixbuf); | |
419 | ||
420 | /* r,g,b,a,r,g,b,a.... */ | |
421 | for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++) | |
422 | { | |
423 | pixels += 3; | |
424 | *pixels++ = alpha; | |
425 | } | |
426 | return pixbuf; | |
427 | } | |
428 | ||
429 | static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor ) | |
430 | { | |
431 | GdkPixbuf *tmp; | |
432 | guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf); | |
433 | tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_BILINEAR); | |
434 | g_object_unref ( G_OBJECT(pixbuf) ); | |
435 | return tmp; | |
436 | } | |
437 | ||
438 | static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor ) | |
439 | { | |
440 | GdkPixbuf *pixbuf; | |
441 | ||
442 | /* get the thing */ | |
443 | pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z, | |
444 | mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor ); | |
445 | ||
446 | if ( ! pixbuf ) { | |
447 | g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE, | |
448 | vml->cache_dir, mode, | |
449 | mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y ); | |
450 | if ( access ( filename_buf, R_OK ) == 0) { | |
451 | { | |
452 | GError *gx = NULL; | |
453 | pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx ); | |
454 | ||
455 | if (gx) | |
456 | { | |
457 | if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE ) | |
458 | g_warning ( "Couldn't open image file: %s", gx->message ); | |
459 | ||
460 | g_error_free ( gx ); | |
461 | if ( pixbuf ) | |
462 | g_object_unref ( G_OBJECT(pixbuf) ); | |
463 | pixbuf = NULL; | |
464 | } else { | |
465 | if ( vml->alpha < 255 ) | |
466 | pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha ); | |
467 | if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 ) | |
468 | pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor ); | |
469 | ||
470 | a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y, | |
471 | mapcoord->z, __map_types[vml->maptype].uniq_id, | |
472 | mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor ); | |
473 | } | |
474 | } | |
475 | } | |
476 | } | |
477 | return pixbuf; | |
478 | } | |
479 | ||
480 | static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br ) | |
481 | { | |
482 | MapCoord ulm, brm; | |
483 | gdouble xzoom = vik_viewport_get_xmpp ( vvp ); | |
484 | gdouble yzoom = vik_viewport_get_ympp ( vvp ); | |
485 | gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0; | |
486 | ||
487 | if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) { | |
488 | xshrinkfactor = vml->xmapzoom / xzoom; | |
489 | yshrinkfactor = vml->ymapzoom / yzoom; | |
490 | if ( xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR && | |
491 | yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) { | |
492 | xzoom = vml->xmapzoom; | |
493 | yzoom = vml->xmapzoom; | |
494 | } else { | |
495 | g_warning ( "Cowardly refusing to draw tiles at a shrinkfactor more than %.3f (zoomed out) or less than %.3f (zoomed in).", 1/MIN_SHRINKFACTOR, 1/MAX_SHRINKFACTOR ); | |
496 | } | |
497 | } | |
498 | ||
499 | /* coord -> ID */ | |
500 | if ( __map_types[vml->maptype].coord_to_mapcoord ( ul, xzoom, yzoom, &ulm ) && | |
501 | __map_types[vml->maptype].coord_to_mapcoord ( br, xzoom, yzoom, &brm ) ) { | |
502 | ||
503 | /* loop & draw */ | |
504 | gint x, y; | |
505 | gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x); | |
506 | gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y); | |
507 | gint mode = __map_types[vml->maptype].uniq_id; | |
508 | ||
509 | VikCoord coord; | |
510 | gint xx, yy, width, height; | |
511 | GdkPixbuf *pixbuf; | |
512 | ||
513 | guint max_path_len = strlen(vml->cache_dir) + 40; | |
514 | gchar *path_buf = g_malloc ( max_path_len * sizeof(char) ); | |
515 | ||
516 | if ( vml->autodownload ) | |
517 | start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE ); | |
518 | ||
519 | if ( __map_types[vml->maptype].tilesize_x == 0 ) { | |
520 | for ( x = xmin; x <= xmax; x++ ) { | |
521 | for ( y = ymin; y <= ymax; y++ ) { | |
522 | ulm.x = x; | |
523 | ulm.y = y; | |
524 | pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor ); | |
525 | if ( pixbuf ) { | |
526 | width = gdk_pixbuf_get_width ( pixbuf ); | |
527 | height = gdk_pixbuf_get_height ( pixbuf ); | |
528 | ||
529 | __map_types[vml->maptype].mapcoord_to_center_coord ( &ulm, &coord ); | |
530 | vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy ); | |
531 | xx -= (width/2); | |
532 | yy -= (height/2); | |
533 | ||
534 | vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height ); | |
535 | } | |
536 | } | |
537 | } | |
538 | } else { /* tilesize is known, don't have to keep converting coords */ | |
539 | gdouble tilesize_x = __map_types[vml->maptype].tilesize_x * xshrinkfactor; | |
540 | gdouble tilesize_y = __map_types[vml->maptype].tilesize_y * yshrinkfactor; | |
541 | /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */ | |
542 | gint tilesize_x_ceil = ceil ( tilesize_x ); | |
543 | gint tilesize_y_ceil = ceil ( tilesize_y ); | |
544 | gint8 xinc = (ulm.x == xmin) ? 1 : -1; | |
545 | gint8 yinc = (ulm.y == ymin) ? 1 : -1; | |
546 | gdouble xx, yy; gint xx_tmp, yy_tmp; | |
547 | gint base_yy, xend, yend; | |
548 | xend = (xinc == 1) ? (xmax+1) : (xmin-1); | |
549 | yend = (yinc == 1) ? (ymax+1) : (ymin-1); | |
550 | ||
551 | __map_types[vml->maptype].mapcoord_to_center_coord ( &ulm, &coord ); | |
552 | vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp ); | |
553 | xx = xx_tmp; yy = yy_tmp; | |
554 | /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off | |
555 | * eg if tile size 128, shrinkfactor 0.333 */ | |
556 | xx -= (tilesize_x/2); | |
557 | base_yy = yy - (tilesize_y/2); | |
558 | ||
559 | for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) { | |
560 | yy = base_yy; | |
561 | for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) { | |
562 | ulm.x = x; | |
563 | ulm.y = y; | |
564 | pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor ); | |
565 | if ( pixbuf ) | |
566 | vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, tilesize_x_ceil, tilesize_y_ceil ); | |
567 | ||
568 | yy += tilesize_y; | |
569 | } | |
570 | xx += tilesize_x; | |
571 | } | |
572 | } | |
573 | ||
574 | g_free ( path_buf ); | |
575 | } | |
576 | } | |
577 | ||
578 | static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp ) | |
579 | { | |
580 | if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) ) | |
581 | { | |
582 | VikCoord ul, br; | |
583 | ||
584 | /* get corner coords */ | |
585 | if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) { | |
586 | /* UTM multi-zone stuff by Kit Transue */ | |
587 | gchar leftmost_zone, rightmost_zone, i; | |
588 | leftmost_zone = vik_viewport_leftmost_zone( vvp ); | |
589 | rightmost_zone = vik_viewport_rightmost_zone( vvp ); | |
590 | for ( i = leftmost_zone; i <= rightmost_zone; ++i ) { | |
591 | vik_viewport_corners_for_zonen ( vvp, i, &ul, &br ); | |
592 | maps_layer_draw_section ( vml, vvp, &ul, &br ); | |
593 | } | |
594 | } | |
595 | else { | |
596 | vik_viewport_screen_to_coord ( vvp, 0, 0, &ul ); | |
597 | vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br ); | |
598 | ||
599 | maps_layer_draw_section ( vml, vvp, &ul, &br ); | |
600 | } | |
601 | } | |
602 | } | |
603 | ||
604 | /*************************/ | |
605 | /****** DOWNLOADING ******/ | |
606 | /*************************/ | |
607 | ||
608 | /* pass along data to thread, exists even if layer is deleted. */ | |
609 | typedef struct { | |
610 | gchar *cache_dir; | |
611 | gchar *filename_buf; | |
612 | gint x0, y0, xf, yf; | |
613 | MapCoord mapcoord; | |
614 | gint maptype; | |
615 | gint maxlen; | |
616 | gint mapstoget; | |
617 | gint redownload; | |
618 | } MapDownloadInfo; | |
619 | ||
620 | static void mdi_free ( MapDownloadInfo *mdi ) | |
621 | { | |
622 | g_free ( mdi->cache_dir ); | |
623 | g_free ( mdi->filename_buf ); | |
624 | g_free ( mdi ); | |
625 | } | |
626 | ||
627 | static void map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata ) | |
628 | { | |
629 | guint donemaps = 0; | |
630 | gint x, y; | |
631 | for ( x = mdi->x0; x <= mdi->xf; x++ ) | |
632 | { | |
633 | for ( y = mdi->y0; y <= mdi->yf; y++ ) | |
634 | { | |
635 | g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE, | |
636 | mdi->cache_dir, __map_types[mdi->maptype].uniq_id, | |
637 | mdi->mapcoord.scale, mdi->mapcoord.z, x, y ); | |
638 | ||
639 | if ( mdi->redownload == REDOWNLOAD_ALL) | |
640 | remove ( mdi->filename_buf ); | |
641 | else if ( mdi->redownload == REDOWNLOAD_BAD && access ( mdi->filename_buf, F_OK ) == 0 ) | |
642 | { | |
643 | /* see if this one is bad or what */ | |
644 | GError *gx = NULL; | |
645 | GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx ); | |
646 | if (gx || (!pixbuf)) | |
647 | remove ( mdi->filename_buf ); | |
648 | if ( pixbuf ) | |
649 | g_object_unref ( pixbuf ); | |
650 | if ( gx ) | |
651 | g_error_free ( gx ); | |
652 | } | |
653 | ||
654 | if ( access ( mdi->filename_buf, F_OK ) != 0 ) | |
655 | { | |
656 | mdi->mapcoord.x = x; mdi->mapcoord.y = y; | |
657 | __map_types[mdi->maptype].download ( &(mdi->mapcoord), mdi->filename_buf ); | |
658 | mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */ | |
659 | ||
660 | if ( mdi->redownload !=- REDOWNLOAD_NONE ) | |
661 | a_mapcache_remove_all_shrinkfactors ( x, y, mdi->mapcoord.z, mdi->maptype, mdi->mapcoord.scale ); | |
662 | ||
663 | ||
664 | donemaps++; | |
665 | a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */ | |
666 | } | |
667 | } | |
668 | } | |
669 | } | |
670 | ||
671 | static void mdi_cancel_cleanup ( MapDownloadInfo *mdi ) | |
672 | { | |
673 | if ( mdi->mapcoord.x || mdi->mapcoord.y ) | |
674 | { | |
675 | g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE, | |
676 | mdi->cache_dir, __map_types[mdi->maptype].uniq_id, | |
677 | mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y ); | |
678 | if ( access ( mdi->filename_buf, F_OK ) == 0) | |
679 | { | |
680 | remove ( mdi->filename_buf ); | |
681 | } | |
682 | } | |
683 | } | |
684 | ||
685 | static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload ) | |
686 | { | |
687 | gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ); | |
688 | gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ); | |
689 | MapCoord ulm, brm; | |
690 | if ( __map_types[vml->maptype].coord_to_mapcoord ( ul, xzoom, yzoom, &ulm ) | |
691 | && __map_types[vml->maptype].coord_to_mapcoord ( br, xzoom, yzoom, &brm ) ) | |
692 | { | |
693 | MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) ); | |
694 | gint a, b; | |
695 | ||
696 | /* cache_dir and buffer for dest filename */ | |
697 | mdi->cache_dir = g_strdup ( vml->cache_dir ); | |
698 | mdi->maxlen = strlen ( vml->cache_dir ) + 40; | |
699 | mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) ); | |
700 | mdi->maptype = vml->maptype; | |
701 | ||
702 | mdi->mapcoord = ulm; | |
703 | ||
704 | mdi->redownload = redownload; | |
705 | ||
706 | mdi->x0 = MIN(ulm.x, brm.x); | |
707 | mdi->xf = MAX(ulm.x, brm.x); | |
708 | mdi->y0 = MIN(ulm.y, brm.y); | |
709 | mdi->yf = MAX(ulm.y, brm.y); | |
710 | ||
711 | mdi->mapstoget = 0; | |
712 | ||
713 | if ( mdi->redownload ) { | |
714 | mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1); | |
715 | } else { | |
716 | /* calculate how many we need */ | |
717 | for ( a = mdi->x0; a <= mdi->xf; a++ ) | |
718 | { | |
719 | for ( b = mdi->y0; b <= mdi->yf; b++ ) | |
720 | { | |
721 | g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE, | |
722 | vml->cache_dir, __map_types[vml->maptype].uniq_id, ulm.scale, | |
723 | ulm.z, a, b ); | |
724 | if ( access ( mdi->filename_buf, F_OK ) != 0) | |
725 | mdi->mapstoget++; | |
726 | } | |
727 | } | |
728 | } | |
729 | ||
730 | mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */ | |
731 | ||
732 | if ( mdi->mapstoget ) | |
733 | { | |
734 | gchar *tmp = g_strdup_printf ( "%s %s%d %s %s...", redownload ? "Redownloading" : "Downloading", redownload == REDOWNLOAD_BAD ? "up to " : "", mdi->mapstoget, params_maptypes[vml->maptype], (mdi->mapstoget == 1) ? "map" : "maps" ); | |
735 | ||
736 | /* launch the thread */ | |
737 | a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */ | |
738 | tmp, /* description string */ | |
739 | (vik_thr_func) map_download_thread, /* function to call within thread */ | |
740 | mdi, /* pass along data */ | |
741 | (vik_thr_free_func) mdi_free, /* function to free pass along data */ | |
742 | (vik_thr_free_func) mdi_cancel_cleanup, | |
743 | mdi->mapstoget ); | |
744 | g_free ( tmp ); | |
745 | } | |
746 | else | |
747 | mdi_free ( mdi ); | |
748 | } | |
749 | } | |
750 | ||
751 | static void maps_layer_redownload_bad ( VikMapsLayer *vml ) | |
752 | { | |
753 | start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD ); | |
754 | } | |
755 | static void maps_layer_redownload_all ( VikMapsLayer *vml ) | |
756 | { | |
757 | start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL ); | |
758 | } | |
759 | ||
760 | static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp ) | |
761 | { | |
762 | ||
763 | if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 ) | |
764 | { | |
765 | if ( event->button == 1 ) | |
766 | { | |
767 | VikCoord ul, br; | |
768 | 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 ); | |
769 | 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 ); | |
770 | start_download_thread ( vml, vvp, &ul, &br, REDOWNLOAD_NONE ); | |
771 | vml->dl_tool_x = vml->dl_tool_y = -1; | |
772 | return TRUE; | |
773 | } | |
774 | else | |
775 | { | |
776 | 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) ); | |
777 | 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) ); | |
778 | ||
779 | vml->redownload_vvp = vvp; | |
780 | ||
781 | vml->dl_tool_x = vml->dl_tool_y = -1; | |
782 | ||
783 | if ( ! vml->dl_right_click_menu ) { | |
784 | GtkWidget *item; | |
785 | vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () ); | |
786 | ||
787 | item = gtk_menu_item_new_with_label ( "Redownload bad map(s)" ); | |
788 | g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml ); | |
789 | gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item ); | |
790 | ||
791 | item = gtk_menu_item_new_with_label ( "Redownload all map(s)" ); | |
792 | g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml ); | |
793 | gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item ); | |
794 | } | |
795 | ||
796 | gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time ); | |
797 | gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) ); | |
798 | } | |
799 | } | |
800 | return FALSE; | |
801 | } | |
802 | ||
803 | static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp ) | |
804 | { | |
805 | MapCoord tmp; | |
806 | if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) && | |
807 | __map_types[vml->maptype].coord_to_mapcoord ( vik_viewport_get_center ( vvp ), | |
808 | vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ), | |
809 | vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ), | |
810 | &tmp ) ) { | |
811 | vml->dl_tool_x = event->x, vml->dl_tool_y = event->y; | |
812 | return TRUE; | |
813 | } | |
814 | return FALSE; | |
815 | ||
816 | ||
817 | #if 0 | |
818 | if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) ) | |
819 | { | |
820 | VikCoord coord; | |
821 | MapCoord mapcoord; | |
822 | vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord ); | |
823 | if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord, | |
824 | vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ), | |
825 | vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ), | |
826 | &mapcoord ) ) { | |
827 | gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE, | |
828 | vml->cache_dir, __map_types[vml->maptype].uniq_id, | |
829 | mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y ); | |
830 | ||
831 | __map_types[vml->maptype].download ( &mapcoord, filename_buf ); | |
832 | g_free ( filename_buf ); | |
833 | vik_layer_emit_update ( VIK_LAYER(vml) ); | |
834 | return TRUE; | |
835 | } | |
836 | } | |
837 | return FALSE; | |
838 | #endif | |
839 | } | |
840 | ||
841 | static void maps_layer_download_onscreen_maps ( gpointer vml_vvp[2] ) | |
842 | { | |
843 | VikMapsLayer *vml = vml_vvp[0]; | |
844 | VikViewport *vvp = vml_vvp[1]; | |
845 | ||
846 | gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ); | |
847 | gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ); | |
848 | ||
849 | VikCoord ul, br; | |
850 | MapCoord ulm, brm; | |
851 | ||
852 | vik_viewport_screen_to_coord ( vvp, 0, 0, &ul ); | |
853 | vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br ); | |
854 | ||
855 | if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) && | |
856 | __map_types[vml->maptype].coord_to_mapcoord ( &ul, xzoom, yzoom, &ulm ) && | |
857 | __map_types[vml->maptype].coord_to_mapcoord ( &br, xzoom, yzoom, &brm ) ) | |
858 | start_download_thread ( vml, vvp, &ul, &br, REDOWNLOAD_NONE ); | |
859 | else | |
860 | a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), "Wrong drawmode / zoom level for this map." ); | |
861 | ||
862 | } | |
863 | ||
864 | static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp ) | |
865 | { | |
866 | static gpointer pass_along[2]; | |
867 | GtkWidget *item; | |
868 | pass_along[0] = vml; | |
869 | pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) ); | |
870 | ||
871 | item = gtk_menu_item_new(); | |
872 | gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); | |
873 | gtk_widget_show ( item ); | |
874 | ||
875 | item = gtk_menu_item_new_with_label ( "Download Onscreen Maps" ); | |
876 | g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_onscreen_maps), pass_along ); | |
877 | gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); | |
878 | gtk_widget_show ( item ); | |
879 | } |