]> git.street.me.uk Git - andy/viking.git/blob - src/viktrwlayer.c
Merge branch 'TransformUtils'
[andy/viking.git] / src / viktrwlayer.c
1 /*
2  * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3  *
4  * Copyright (C) 2003-2007, Evan Battaglia <gtoevan@gmx.net>
5  * Copyright (C) 2005-2008, Alex Foobarian <foobarian@gmail.com>
6  * Copyright (C) 2007, Quy Tonthat <qtonthat@gmail.com>
7  * Copyright (C) 2009, Hein Ragas <viking@ragas.nl>
8  * Copyright (c) 2012, Rob Norris <rw_norris@hotmail.com>
9  * Copyright (c) 2012-2013, Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  *
25  */
26 /* WARNING: If you go beyond this point, we are NOT responsible for any ill effects on your sanity */
27 /* viktrwlayer.c -- 8000+ lines can make a difference in the state of things */
28
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #include "viking.h"
34 #include "vikmapslayer.h"
35 #include "vikgpslayer.h"
36 #include "viktrwlayer_tpwin.h"
37 #include "viktrwlayer_propwin.h"
38 #include "viktrwlayer_analysis.h"
39 #ifdef VIK_CONFIG_GEOTAG
40 #include "viktrwlayer_geotag.h"
41 #include "geotag_exif.h"
42 #endif
43 #include "garminsymbols.h"
44 #include "thumbnails.h"
45 #include "background.h"
46 #include "gpx.h"
47 #include "babel.h"
48 #include "dem.h"
49 #include "dems.h"
50 #include "geonamessearch.h"
51 #ifdef VIK_CONFIG_OPENSTREETMAP
52 #include "osm-traces.h"
53 #endif
54 #include "acquire.h"
55 #include "datasources.h"
56 #include "datasource_gps.h"
57 #include "vikexttool_datasources.h"
58 #include "util.h"
59
60 #include "vikrouting.h"
61
62 #include "icons/icons.h"
63
64 #ifdef HAVE_MATH_H
65 #include <math.h>
66 #endif
67 #ifdef HAVE_STRING_H
68 #include <string.h>
69 #endif
70 #ifdef HAVE_STDLIB_H
71 #include <stdlib.h>
72 #endif
73 #include <stdio.h>
74 #include <ctype.h>
75
76 #include <gdk/gdkkeysyms.h>
77 #include <glib.h>
78 #include <glib/gstdio.h>
79 #include <glib/gi18n.h>
80
81 #define VIK_TRW_LAYER_TRACK_GC 6
82 #define VIK_TRW_LAYER_TRACK_GCS 10
83 #define VIK_TRW_LAYER_TRACK_GC_BLACK 0
84 #define VIK_TRW_LAYER_TRACK_GC_SLOW 1
85 #define VIK_TRW_LAYER_TRACK_GC_AVER 2
86 #define VIK_TRW_LAYER_TRACK_GC_FAST 3
87 #define VIK_TRW_LAYER_TRACK_GC_STOP 4
88 #define VIK_TRW_LAYER_TRACK_GC_SINGLE 5
89
90 #define DRAWMODE_BY_TRACK 0
91 #define DRAWMODE_BY_SPEED 1
92 #define DRAWMODE_ALL_SAME_COLOR 2
93 // Note using DRAWMODE_BY_SPEED may be slow especially for vast numbers of trackpoints
94 //  as we are (re)calculating the colour for every point
95
96 #define POINTS 1
97 #define LINES 2
98
99 /* this is how it knows when you click if you are clicking close to a trackpoint. */
100 #define TRACKPOINT_SIZE_APPROX 5
101 #define WAYPOINT_SIZE_APPROX 5
102
103 #define MIN_STOP_LENGTH 15
104 #define MAX_STOP_LENGTH 86400
105 #define DRAW_ELEVATION_FACTOR 30 /* height of elevation plotting, sort of relative to zoom level ("mpp" that isn't mpp necessarily) */
106                                  /* this is multiplied by user-inputted value from 1-100. */
107
108 enum { WP_SYMBOL_FILLED_SQUARE, WP_SYMBOL_SQUARE, WP_SYMBOL_CIRCLE, WP_SYMBOL_X, WP_NUM_SYMBOLS };
109
110 // See http://developer.gnome.org/pango/stable/PangoMarkupFormat.html
111 typedef enum {
112   FS_XX_SMALL = 0, // 'xx-small'
113   FS_X_SMALL,
114   FS_SMALL,
115   FS_MEDIUM, // DEFAULT
116   FS_LARGE,
117   FS_X_LARGE,
118   FS_XX_LARGE,
119   FS_NUM_SIZES
120 } font_size_t;
121
122 struct _VikTrwLayer {
123   VikLayer vl;
124   GHashTable *tracks;
125   GHashTable *tracks_iters;
126   GHashTable *routes;
127   GHashTable *routes_iters;
128   GHashTable *waypoints_iters;
129   GHashTable *waypoints;
130   GtkTreeIter tracks_iter, routes_iter, waypoints_iter;
131   gboolean tracks_visible, routes_visible, waypoints_visible;
132   LatLonBBox waypoints_bbox;
133
134   guint8 drawmode;
135   guint8 drawpoints;
136   guint8 drawpoints_size;
137   guint8 drawelevation;
138   guint8 elevation_factor;
139   guint8 drawstops;
140   guint32 stop_length;
141   guint8 drawlines;
142   guint8 drawdirections;
143   guint8 drawdirections_size;
144   guint8 line_thickness;
145   guint8 bg_line_thickness;
146   vik_layer_sort_order_t track_sort_order;
147
148   guint8 wp_symbol;
149   guint8 wp_size;
150   gboolean wp_draw_symbols;
151   font_size_t wp_font_size;
152   gchar *wp_fsize_str;
153   vik_layer_sort_order_t wp_sort_order;
154
155   gdouble track_draw_speed_factor;
156   GArray *track_gc;
157   GdkGC *track_1color_gc;
158   GdkColor track_color;
159   GdkGC *current_track_gc;
160   // Separate GC for a track's potential new point as drawn via separate method
161   //  (compared to the actual track points drawn in the main trw_layer_draw_track function)
162   GdkGC *current_track_newpoint_gc;
163   GdkGC *track_bg_gc; GdkColor track_bg_color;
164   GdkGC *waypoint_gc; GdkColor waypoint_color;
165   GdkGC *waypoint_text_gc; GdkColor waypoint_text_color;
166   GdkGC *waypoint_bg_gc; GdkColor waypoint_bg_color;
167   gboolean wpbgand;
168   GdkFont *waypoint_font;
169   VikTrack *current_track; // ATM shared between new tracks and new routes
170   guint16 ct_x1, ct_y1, ct_x2, ct_y2;
171   gboolean draw_sync_done;
172   gboolean draw_sync_do;
173
174   VikCoordMode coord_mode;
175
176   /* wp editing tool */
177   VikWaypoint *current_wp;
178   gpointer current_wp_id;
179   gboolean moving_wp;
180   gboolean waypoint_rightclick;
181
182   /* track editing tool */
183   GList *current_tpl;
184   VikTrack *current_tp_track;
185   gpointer current_tp_id;
186   VikTrwLayerTpwin *tpwin;
187
188   /* track editing tool -- more specifically, moving tps */
189   gboolean moving_tp;
190
191   /* route finder tool */
192   gboolean route_finder_started;
193   VikCoord route_finder_coord;
194   gboolean route_finder_check_added_track;
195   VikTrack *route_finder_added_track;
196   VikTrack *route_finder_current_track;
197   gboolean route_finder_append;
198
199   gboolean drawlabels;
200   gboolean drawimages;
201   guint8 image_alpha;
202   GQueue *image_cache;
203   guint8 image_size;
204   guint16 image_cache_size;
205
206   /* for waypoint text */
207   PangoLayout *wplabellayout;
208
209   gboolean has_verified_thumbnails;
210
211   GtkMenu *wp_right_click_menu;
212   GtkMenu *track_right_click_menu;
213
214   /* menu */
215   VikStdLayerMenuItem menu_selection;
216
217   gint highest_wp_number;
218
219   // One per layer
220   GtkWidget *tracks_analysis_dialog;
221 };
222
223 /* A caached waypoint image. */
224 typedef struct {
225   GdkPixbuf *pixbuf;
226   gchar *image; /* filename */
227 } CachedPixbuf;
228
229 struct DrawingParams {
230   VikViewport *vp;
231   VikTrwLayer *vtl;
232   VikWindow *vw;
233   gdouble xmpp, ympp;
234   guint16 width, height;
235   gdouble cc; // Cosine factor in track directions
236   gdouble ss; // Sine factor in track directions
237   const VikCoord *center;
238   gboolean one_zone, lat_lon;
239   gdouble ce1, ce2, cn1, cn2;
240   LatLonBBox bbox;
241 };
242
243 static gboolean trw_layer_delete_waypoint ( VikTrwLayer *vtl, VikWaypoint *wp );
244
245 static void trw_layer_delete_item ( gpointer pass_along[6] );
246 static void trw_layer_copy_item_cb ( gpointer pass_along[6] );
247 static void trw_layer_cut_item_cb ( gpointer pass_along[6] );
248
249 static void trw_layer_find_maxmin_tracks ( const gpointer id, const VikTrack *trk, struct LatLon maxmin[2] );
250 static void trw_layer_find_maxmin (VikTrwLayer *vtl, struct LatLon maxmin[2]);
251
252 static void trw_layer_new_track_gcs ( VikTrwLayer *vtl, VikViewport *vp );
253 static void trw_layer_free_track_gcs ( VikTrwLayer *vtl );
254
255 static void trw_layer_draw_track_cb ( const gpointer id, VikTrack *track, struct DrawingParams *dp );
256 static void trw_layer_draw_waypoint ( const gpointer id, VikWaypoint *wp, struct DrawingParams *dp );
257
258 static void trw_layer_calculate_bounds_waypoints ( VikTrwLayer *vtl );
259
260 static void goto_coord ( gpointer *vlp, gpointer vvp, gpointer vl, const VikCoord *coord );
261 static void trw_layer_goto_track_startpoint ( gpointer pass_along[6] );
262 static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] );
263 static void trw_layer_goto_track_max_speed ( gpointer pass_along[6] );
264 static void trw_layer_goto_track_max_alt ( gpointer pass_along[6] );
265 static void trw_layer_goto_track_min_alt ( gpointer pass_along[6] );
266 static void trw_layer_goto_track_center ( gpointer pass_along[6] );
267 static void trw_layer_merge_by_segment ( gpointer pass_along[6] );
268 static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] );
269 static void trw_layer_merge_with_other ( gpointer pass_along[6] );
270 static void trw_layer_append_track ( gpointer pass_along[6] );
271 static void trw_layer_split_by_timestamp ( gpointer pass_along[6] );
272 static void trw_layer_split_by_n_points ( gpointer pass_along[6] );
273 static void trw_layer_split_at_trackpoint ( gpointer pass_along[6] );
274 static void trw_layer_split_segments ( gpointer pass_along[6] );
275 static void trw_layer_delete_points_same_position ( gpointer pass_along[6] );
276 static void trw_layer_delete_points_same_time ( gpointer pass_along[6] );
277 static void trw_layer_reverse ( gpointer pass_along[6] );
278 static void trw_layer_download_map_along_track_cb ( gpointer pass_along[6] );
279 static void trw_layer_edit_trackpoint ( gpointer pass_along[6] );
280 static void trw_layer_show_picture ( gpointer pass_along[6] );
281 static void trw_layer_gps_upload_any ( gpointer pass_along[6] );
282
283 static void trw_layer_centerize ( gpointer layer_and_vlp[2] );
284 static void trw_layer_auto_view ( gpointer layer_and_vlp[2] );
285 static void trw_layer_export ( gpointer layer_and_vlp[2], const gchar* title, const gchar* default_name, VikTrack* trk, guint file_type );
286 static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] );
287 static void trw_layer_new_wp ( gpointer lav[2] );
288 static void trw_layer_new_track ( gpointer lav[2] );
289 static void trw_layer_new_route ( gpointer lav[2] );
290 static void trw_layer_finish_track ( gpointer lav[2] );
291 static void trw_layer_auto_waypoints_view ( gpointer lav[2] );
292 static void trw_layer_auto_tracks_view ( gpointer lav[2] );
293 static void trw_layer_delete_all_tracks ( gpointer lav[2] );
294 static void trw_layer_delete_tracks_from_selection ( gpointer lav[2] );
295 static void trw_layer_delete_all_waypoints ( gpointer lav[2] );
296 static void trw_layer_delete_waypoints_from_selection ( gpointer lav[2] );
297 static void trw_layer_new_wikipedia_wp_viewport ( gpointer lav[2] );
298 static void trw_layer_new_wikipedia_wp_layer ( gpointer lav[2] );
299 #ifdef VIK_CONFIG_GEOTAG
300 static void trw_layer_geotagging_waypoint_mtime_keep ( gpointer pass_along[6] );
301 static void trw_layer_geotagging_waypoint_mtime_update ( gpointer pass_along[6] );
302 static void trw_layer_geotagging_track ( gpointer pass_along[6] );
303 static void trw_layer_geotagging ( gpointer lav[2] );
304 #endif
305 static void trw_layer_acquire_gps_cb ( gpointer lav[2] );
306 static void trw_layer_acquire_routing_cb ( gpointer lav[2] );
307 #ifdef VIK_CONFIG_OPENSTREETMAP
308 static void trw_layer_acquire_osm_cb ( gpointer lav[2] );
309 static void trw_layer_acquire_osm_my_traces_cb ( gpointer lav[2] );
310 #endif
311 #ifdef VIK_CONFIG_GEOCACHES
312 static void trw_layer_acquire_geocache_cb ( gpointer lav[2] );
313 #endif
314 #ifdef VIK_CONFIG_GEOTAG
315 static void trw_layer_acquire_geotagged_cb ( gpointer lav[2] );
316 #endif
317 static void trw_layer_acquire_file_cb ( gpointer lav[2] );
318 static void trw_layer_gps_upload ( gpointer lav[2] );
319
320 // Specific route versions:
321 //  Most track handling functions can handle operating on the route list
322 //  However these ones are easier in separate functions
323 static void trw_layer_auto_routes_view ( gpointer lav[2] );
324 static void trw_layer_delete_all_routes ( gpointer lav[2] );
325 static void trw_layer_delete_routes_from_selection ( gpointer lav[2] );
326
327 /* pop-up items */
328 static void trw_layer_properties_item ( gpointer pass_along[7] );
329 static void trw_layer_goto_waypoint ( gpointer pass_along[6] );
330 static void trw_layer_waypoint_gc_webpage ( gpointer pass_along[6] );
331 static void trw_layer_waypoint_webpage ( gpointer pass_along[6] );
332
333 static void trw_layer_realize_waypoint ( gpointer id, VikWaypoint *wp, gpointer pass_along[5] );
334 static void trw_layer_realize_track ( gpointer id, VikTrack *track, gpointer pass_along[5] );
335 static void init_drawing_params ( struct DrawingParams *dp, VikTrwLayer *vtl, VikViewport *vp );
336
337 static void trw_layer_insert_tp_after_current_tp ( VikTrwLayer *vtl );
338 static void trw_layer_cancel_current_tp ( VikTrwLayer *vtl, gboolean destroy );
339 static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response );
340 static void trw_layer_tpwin_init ( VikTrwLayer *vtl );
341
342 static gpointer tool_edit_trackpoint_create ( VikWindow *vw, VikViewport *vvp);
343 static void tool_edit_trackpoint_destroy ( tool_ed_t *t );
344 static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data );
345 static gboolean tool_edit_trackpoint_move ( VikTrwLayer *vtl, GdkEventMotion *event, gpointer data );
346 static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data );
347 static gpointer tool_show_picture_create ( VikWindow *vw, VikViewport *vvp);
348 static gboolean tool_show_picture_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); 
349 static gpointer tool_edit_waypoint_create ( VikWindow *vw, VikViewport *vvp);
350 static void tool_edit_waypoint_destroy ( tool_ed_t *t );
351 static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data );
352 static gboolean tool_edit_waypoint_move ( VikTrwLayer *vtl, GdkEventMotion *event, gpointer data );
353 static gboolean tool_edit_waypoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data );
354 static gpointer tool_new_route_create ( VikWindow *vw, VikViewport *vvp);
355 static gboolean tool_new_route_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
356 static gpointer tool_new_track_create ( VikWindow *vw, VikViewport *vvp);
357 static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp ); 
358 static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMotion *event, VikViewport *vvp ); 
359 static void tool_new_track_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
360 static gboolean tool_new_track_key_press ( VikTrwLayer *vtl, GdkEventKey *event, VikViewport *vvp ); 
361 static gpointer tool_new_waypoint_create ( VikWindow *vw, VikViewport *vvp);
362 static gboolean tool_new_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
363 static gpointer tool_route_finder_create ( VikWindow *vw, VikViewport *vvp);
364 static gboolean tool_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
365
366 static void cached_pixbuf_free ( CachedPixbuf *cp );
367 static gint cached_pixbuf_cmp ( CachedPixbuf *cp, const gchar *name );
368
369 static VikTrackpoint *closest_tp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y );
370 static VikWaypoint *closest_wp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y );
371
372 static void waypoint_convert ( const gpointer id, VikWaypoint *wp, VikCoordMode *dest_mode );
373 static void track_convert ( const gpointer id, VikTrack *tr, VikCoordMode *dest_mode );
374
375 static gchar *highest_wp_number_get(VikTrwLayer *vtl);
376 static void highest_wp_number_reset(VikTrwLayer *vtl);
377 static void highest_wp_number_add_wp(VikTrwLayer *vtl, const gchar *new_wp_name);
378 static void highest_wp_number_remove_wp(VikTrwLayer *vtl, const gchar *old_wp_name);
379
380 // Note for the following tool GtkRadioActionEntry texts:
381 //  the very first text value is an internal name not displayed anywhere
382 //  the first N_ text value is the name used for menu entries - hence has an underscore for the keyboard accelerator
383 //    * remember not to clash with the values used for VikWindow level tools (Pan, Zoom, Ruler + Select)
384 //  the second N_ text value is used for the button tooltip (i.e. generally don't want an underscore here)
385 //  the value is always set to 0 and the tool loader in VikWindow will set the actual appropriate value used
386 static VikToolInterface trw_layer_tools[] = {
387   { { "CreateWaypoint", "vik-icon-Create Waypoint", N_("Create _Waypoint"), "<control><shift>W", N_("Create Waypoint"), 0 },
388     (VikToolConstructorFunc) tool_new_waypoint_create,    NULL, NULL, NULL,
389     (VikToolMouseFunc) tool_new_waypoint_click,    NULL, NULL, (VikToolKeyFunc) NULL,
390     FALSE,
391     GDK_CURSOR_IS_PIXMAP, &cursor_addwp_pixbuf },
392
393   { { "CreateTrack", "vik-icon-Create Track", N_("Create _Track"), "<control><shift>T", N_("Create Track"), 0 },
394     (VikToolConstructorFunc) tool_new_track_create,       NULL, NULL, NULL,
395     (VikToolMouseFunc) tool_new_track_click,
396     (VikToolMouseMoveFunc) tool_new_track_move,
397     (VikToolMouseFunc) tool_new_track_release,
398     (VikToolKeyFunc) tool_new_track_key_press,
399     TRUE, // Still need to handle clicks when in PAN mode to disable the potential trackpoint drawing
400     GDK_CURSOR_IS_PIXMAP, &cursor_addtr_pixbuf },
401
402   { { "CreateRoute", "vik-icon-Create Route", N_("Create _Route"), "<control><shift>B", N_("Create Route"), 0 },
403     (VikToolConstructorFunc) tool_new_route_create,       NULL, NULL, NULL,
404     (VikToolMouseFunc) tool_new_route_click,
405     (VikToolMouseMoveFunc) tool_new_track_move, // -\#
406     (VikToolMouseFunc) tool_new_track_release,  //   -> Reuse these track methods on a route
407     (VikToolKeyFunc) tool_new_track_key_press,  // -/#
408     TRUE, // Still need to handle clicks when in PAN mode to disable the potential trackpoint drawing
409     GDK_CURSOR_IS_PIXMAP, &cursor_new_route_pixbuf },
410
411   { { "EditWaypoint", "vik-icon-Edit Waypoint", N_("_Edit Waypoint"), "<control><shift>E", N_("Edit Waypoint"), 0 },
412     (VikToolConstructorFunc) tool_edit_waypoint_create,
413     (VikToolDestructorFunc) tool_edit_waypoint_destroy,
414     NULL, NULL,
415     (VikToolMouseFunc) tool_edit_waypoint_click,   
416     (VikToolMouseMoveFunc) tool_edit_waypoint_move,
417     (VikToolMouseFunc) tool_edit_waypoint_release, (VikToolKeyFunc) NULL,
418     FALSE,
419     GDK_CURSOR_IS_PIXMAP, &cursor_edwp_pixbuf },
420
421   { { "EditTrackpoint", "vik-icon-Edit Trackpoint", N_("Edit Trac_kpoint"), "<control><shift>K", N_("Edit Trackpoint"), 0 },
422     (VikToolConstructorFunc) tool_edit_trackpoint_create,
423     (VikToolDestructorFunc) tool_edit_trackpoint_destroy,
424     NULL, NULL,
425     (VikToolMouseFunc) tool_edit_trackpoint_click,
426     (VikToolMouseMoveFunc) tool_edit_trackpoint_move,
427     (VikToolMouseFunc) tool_edit_trackpoint_release, (VikToolKeyFunc) NULL,
428     FALSE,
429     GDK_CURSOR_IS_PIXMAP, &cursor_edtr_pixbuf },
430
431   { { "ShowPicture", "vik-icon-Show Picture", N_("Show P_icture"), "<control><shift>I", N_("Show Picture"), 0 },
432     (VikToolConstructorFunc) tool_show_picture_create,    NULL, NULL, NULL,
433     (VikToolMouseFunc) tool_show_picture_click,    NULL, NULL, (VikToolKeyFunc) NULL,
434     FALSE,
435     GDK_CURSOR_IS_PIXMAP, &cursor_showpic_pixbuf },
436
437   { { "RouteFinder", "vik-icon-Route Finder", N_("Route _Finder"), "<control><shift>F", N_("Route Finder"), 0 },
438     (VikToolConstructorFunc) tool_route_finder_create,  NULL, NULL, NULL,
439     (VikToolMouseFunc) tool_route_finder_click, NULL, NULL, (VikToolKeyFunc) NULL,
440     FALSE,
441     GDK_CURSOR_IS_PIXMAP, &cursor_route_finder_pixbuf },
442 };
443
444 enum {
445   TOOL_CREATE_WAYPOINT=0,
446   TOOL_CREATE_TRACK,
447   TOOL_CREATE_ROUTE,
448   TOOL_EDIT_WAYPOINT,
449   TOOL_EDIT_TRACKPOINT,
450   TOOL_SHOW_PICTURE,
451   TOOL_ROUTE_FINDER,
452   NUM_TOOLS
453 };
454
455 /****** PARAMETERS ******/
456
457 static gchar *params_groups[] = { N_("Waypoints"), N_("Tracks"), N_("Waypoint Images") };
458 enum { GROUP_WAYPOINTS, GROUP_TRACKS, GROUP_IMAGES };
459
460 static gchar *params_drawmodes[] = { N_("Draw by Track"), N_("Draw by Speed"), N_("All Tracks Same Color"), NULL };
461 static gchar *params_wpsymbols[] = { N_("Filled Square"), N_("Square"), N_("Circle"), N_("X"), 0 };
462
463 #define MIN_POINT_SIZE 2
464 #define MAX_POINT_SIZE 10
465
466 #define MIN_ARROW_SIZE 3
467 #define MAX_ARROW_SIZE 20
468
469 static VikLayerParamScale params_scales[] = {
470  /* min  max    step digits */
471  {  1,   10,    1,   0 }, /* line_thickness */
472  {  0,   100,   1,   0 }, /* track draw speed factor */
473  {  1.0, 100.0, 1.0, 2 }, /* UNUSED */
474                 /* 5 * step == how much to turn */
475  {  16,   128,  4,   0 }, // 3: image_size - NB step size ignored when an HSCALE used
476  {   0,   255,  5,   0 }, // 4: image alpha -    "     "      "            "
477  {   5,   500,  5,   0 }, // 5: image cache_size -     "      "
478  {   0,   8,    1,   0 }, // 6: Background line thickness
479  {   1,  64,    1,   0 }, /* wpsize */
480  {   MIN_STOP_LENGTH, MAX_STOP_LENGTH, 1,   0 }, /* stop_length */
481  {   1, 100, 1,   0 }, // 9: elevation factor
482  {   MIN_POINT_SIZE,  MAX_POINT_SIZE,  1,   0 }, // 10: track point size
483  {   MIN_ARROW_SIZE,  MAX_ARROW_SIZE,  1,   0 }, // 11: direction arrow size
484 };
485
486 static gchar* params_font_sizes[] = {
487   N_("Extra Extra Small"),
488   N_("Extra Small"),
489   N_("Small"),
490   N_("Medium"),
491   N_("Large"),
492   N_("Extra Large"),
493   N_("Extra Extra Large"),
494   NULL };
495
496 // Needs to align with vik_layer_sort_order_t
497 static gchar* params_sort_order[] = {
498   N_("None"),
499   N_("Name Ascending"),
500   N_("Name Descending"),
501   NULL
502 };
503
504 static VikLayerParamData black_color_default ( void ) {
505   VikLayerParamData data; gdk_color_parse ( "#000000", &data.c ); return data; // Black
506 }
507 static VikLayerParamData drawmode_default ( void ) { return VIK_LPD_UINT ( DRAWMODE_BY_TRACK ); }
508 static VikLayerParamData line_thickness_default ( void ) { return VIK_LPD_UINT ( 1 ); }
509 static VikLayerParamData trkpointsize_default ( void ) { return VIK_LPD_UINT ( MIN_POINT_SIZE ); }
510 static VikLayerParamData trkdirectionsize_default ( void ) { return VIK_LPD_UINT ( 5 ); }
511 static VikLayerParamData bg_line_thickness_default ( void ) { return VIK_LPD_UINT ( 0 ); }
512 static VikLayerParamData trackbgcolor_default ( void ) {
513   VikLayerParamData data; gdk_color_parse ( "#FFFFFF", &data.c ); return data; // White
514 }
515 static VikLayerParamData elevation_factor_default ( void ) { return VIK_LPD_UINT ( 30 ); }
516 static VikLayerParamData stop_length_default ( void ) { return VIK_LPD_UINT ( 60 ); }
517 static VikLayerParamData speed_factor_default ( void ) { return VIK_LPD_DOUBLE ( 30.0 ); }
518
519 static VikLayerParamData wpfontsize_default ( void ) { return VIK_LPD_UINT ( FS_MEDIUM ); }
520 static VikLayerParamData wptextcolor_default ( void ) {
521   VikLayerParamData data; gdk_color_parse ( "#FFFFFF", &data.c ); return data; // White
522 }
523 static VikLayerParamData wpbgcolor_default ( void ) {
524   VikLayerParamData data; gdk_color_parse ( "#8383C4", &data.c ); return data; // Kind of Blue
525 }
526 static VikLayerParamData wpsize_default ( void ) { return VIK_LPD_UINT ( 4 ); }
527 static VikLayerParamData wpsymbol_default ( void ) { return VIK_LPD_UINT ( WP_SYMBOL_FILLED_SQUARE ); }
528
529 static VikLayerParamData image_size_default ( void ) { return VIK_LPD_UINT ( 64 ); }
530 static VikLayerParamData image_alpha_default ( void ) { return VIK_LPD_UINT ( 255 ); }
531 static VikLayerParamData image_cache_size_default ( void ) { return VIK_LPD_UINT ( 300 ); }
532
533 static VikLayerParamData sort_order_default ( void ) { return VIK_LPD_UINT ( 0 ); }
534
535 VikLayerParam trw_layer_params[] = {
536   { VIK_LAYER_TRW, "tracks_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
537   { VIK_LAYER_TRW, "waypoints_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
538   { VIK_LAYER_TRW, "routes_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
539
540   { VIK_LAYER_TRW, "drawmode", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Drawing Mode:"), VIK_LAYER_WIDGET_COMBOBOX, params_drawmodes, NULL, NULL, drawmode_default, NULL, NULL },
541   { VIK_LAYER_TRW, "trackcolor", VIK_LAYER_PARAM_COLOR, GROUP_TRACKS, N_("All Tracks Color:"), VIK_LAYER_WIDGET_COLOR, NULL, NULL,
542     N_("The color used when 'All Tracks Same Color' drawing mode is selected"), black_color_default, NULL, NULL },
543   { VIK_LAYER_TRW, "drawlines", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Track Lines"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
544   { VIK_LAYER_TRW, "line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, &params_scales[0], NULL, NULL, line_thickness_default, NULL, NULL },
545   { VIK_LAYER_TRW, "drawdirections", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Track Direction"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_false_default, NULL, NULL },
546   { VIK_LAYER_TRW, "trkdirectionsize", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Direction Size:"), VIK_LAYER_WIDGET_SPINBUTTON, &params_scales[11], NULL, NULL, trkdirectionsize_default, NULL, NULL },
547   { VIK_LAYER_TRW, "drawpoints", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Trackpoints"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
548   { VIK_LAYER_TRW, "trkpointsize", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Trackpoint Size:"), VIK_LAYER_WIDGET_SPINBUTTON, &params_scales[10], NULL, NULL, trkpointsize_default, NULL, NULL },
549   { VIK_LAYER_TRW, "drawelevation", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Elevation"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_false_default, NULL, NULL },
550   { VIK_LAYER_TRW, "elevation_factor", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Draw Elevation Height %:"), VIK_LAYER_WIDGET_HSCALE, &params_scales[9], NULL, NULL, elevation_factor_default, NULL, NULL },
551
552   { VIK_LAYER_TRW, "drawstops", VIK_LAYER_PARAM_BOOLEAN, GROUP_TRACKS, N_("Draw Stops"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL,
553     N_("Whether to draw a marker when trackpoints are at the same position but over the minimum stop length apart in time"), vik_lpd_false_default, NULL, NULL },
554   { VIK_LAYER_TRW, "stop_length", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Min Stop Length (seconds):"), VIK_LAYER_WIDGET_SPINBUTTON, &params_scales[8], NULL, NULL, stop_length_default, NULL, NULL },
555
556   { VIK_LAYER_TRW, "bg_line_thickness", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track BG Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, &params_scales[6], NULL, NULL, bg_line_thickness_default, NULL, NULL },
557   { VIK_LAYER_TRW, "trackbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_TRACKS, N_("Track Background Color"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, NULL, trackbgcolor_default, NULL, NULL },
558   { VIK_LAYER_TRW, "speed_factor", VIK_LAYER_PARAM_DOUBLE, GROUP_TRACKS, N_("Draw by Speed Factor (%):"), VIK_LAYER_WIDGET_HSCALE, &params_scales[1], NULL,
559     N_("The percentage factor away from the average speed determining the color used"), speed_factor_default, NULL, NULL },
560
561   { VIK_LAYER_TRW, "tracksortorder", VIK_LAYER_PARAM_UINT, GROUP_TRACKS, N_("Track Sort Order:"), VIK_LAYER_WIDGET_COMBOBOX, params_sort_order, NULL, NULL, sort_order_default, NULL, NULL },
562
563   { VIK_LAYER_TRW, "drawlabels", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Draw Labels"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
564   { VIK_LAYER_TRW, "wpfontsize", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint Font Size:"), VIK_LAYER_WIDGET_COMBOBOX, params_font_sizes, NULL, NULL, wpfontsize_default, NULL, NULL },
565   { VIK_LAYER_TRW, "wpcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Waypoint Color:"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, NULL, black_color_default, NULL, NULL },
566   { VIK_LAYER_TRW, "wptextcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Waypoint Text:"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, NULL, wptextcolor_default, NULL, NULL },
567   { VIK_LAYER_TRW, "wpbgcolor", VIK_LAYER_PARAM_COLOR, GROUP_WAYPOINTS, N_("Background:"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, NULL, wpbgcolor_default, NULL, NULL },
568   { VIK_LAYER_TRW, "wpbgand", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Fake BG Color Translucency:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_false_default, NULL, NULL },
569   { VIK_LAYER_TRW, "wpsymbol", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint marker:"), VIK_LAYER_WIDGET_COMBOBOX, params_wpsymbols, NULL, NULL, wpsymbol_default, NULL, NULL },
570   { VIK_LAYER_TRW, "wpsize", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint size:"), VIK_LAYER_WIDGET_SPINBUTTON, &params_scales[7], NULL, NULL, wpsize_default, NULL, NULL },
571   { VIK_LAYER_TRW, "wpsyms", VIK_LAYER_PARAM_BOOLEAN, GROUP_WAYPOINTS, N_("Draw Waypoint Symbols:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
572   { VIK_LAYER_TRW, "wpsortorder", VIK_LAYER_PARAM_UINT, GROUP_WAYPOINTS, N_("Waypoint Sort Order:"), VIK_LAYER_WIDGET_COMBOBOX, params_sort_order, NULL, NULL, sort_order_default, NULL, NULL },
573
574   { VIK_LAYER_TRW, "drawimages", VIK_LAYER_PARAM_BOOLEAN, GROUP_IMAGES, N_("Draw Waypoint Images"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
575   { VIK_LAYER_TRW, "image_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Size (pixels):"), VIK_LAYER_WIDGET_HSCALE, &params_scales[3], NULL, NULL, image_size_default, NULL, NULL },
576   { VIK_LAYER_TRW, "image_alpha", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Alpha:"), VIK_LAYER_WIDGET_HSCALE, &params_scales[4], NULL, NULL, image_alpha_default, NULL, NULL },
577   { VIK_LAYER_TRW, "image_cache_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Memory Cache Size:"), VIK_LAYER_WIDGET_HSCALE, &params_scales[5], NULL, NULL, image_cache_size_default, NULL, NULL },
578 };
579
580 // ENUMERATION MUST BE IN THE SAME ORDER AS THE NAMED PARAMS ABOVE
581 enum {
582   // Sublayer visibilities
583   PARAM_TV,
584   PARAM_WV,
585   PARAM_RV,
586   // Tracks
587   PARAM_DM,
588   PARAM_TC,
589   PARAM_DL,
590   PARAM_LT,
591   PARAM_DD,
592   PARAM_DDS,
593   PARAM_DP,
594   PARAM_DPS,
595   PARAM_DE,
596   PARAM_EF,
597   PARAM_DS,
598   PARAM_SL,
599   PARAM_BLT,
600   PARAM_TBGC,
601   PARAM_TDSF,
602   PARAM_TSO,
603   // Waypoints
604   PARAM_DLA,
605   PARAM_WPFONTSIZE,
606   PARAM_WPC,
607   PARAM_WPTC,
608   PARAM_WPBC,
609   PARAM_WPBA,
610   PARAM_WPSYM,
611   PARAM_WPSIZE,
612   PARAM_WPSYMS,
613   PARAM_WPSO,
614   // WP images
615   PARAM_DI,
616   PARAM_IS,
617   PARAM_IA,
618   PARAM_ICS,
619   NUM_PARAMS
620 };
621
622 /*** TO ADD A PARAM:
623  *** 1) Add to trw_layer_params and enumeration
624  *** 2) Handle in get_param & set_param (presumably adding on to VikTrwLayer struct)
625  ***/
626
627 /****** END PARAMETERS ******/
628
629 /* Layer Interface function definitions */
630 static VikTrwLayer* trw_layer_create ( VikViewport *vp );
631 static void trw_layer_realize ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter );
632 static void trw_layer_post_read ( VikTrwLayer *vtl, GtkWidget *vvp, gboolean from_file );
633 static void trw_layer_free ( VikTrwLayer *trwlayer );
634 static void trw_layer_draw ( VikTrwLayer *l, gpointer data );
635 static void trw_layer_change_coord_mode ( VikTrwLayer *vtl, VikCoordMode dest_mode );
636 static void trw_layer_set_menu_selection ( VikTrwLayer *vtl, guint16 );
637 static guint16 trw_layer_get_menu_selection ( VikTrwLayer *vtl );
638 static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vlp );
639 static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter, VikViewport *vvp );
640 static const gchar* trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gchar *newname, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter );
641 static gboolean trw_layer_sublayer_toggle_visible ( VikTrwLayer *l, gint subtype, gpointer sublayer );
642 static const gchar* trw_layer_layer_tooltip ( VikTrwLayer *vtl );
643 static const gchar* trw_layer_sublayer_tooltip ( VikTrwLayer *l, gint subtype, gpointer sublayer );
644 static gboolean trw_layer_selected ( VikTrwLayer *l, gint subtype, gpointer sublayer, gint type, gpointer vlp );
645 static void trw_layer_marshall ( VikTrwLayer *vtl, guint8 **data, gint *len );
646 static VikTrwLayer *trw_layer_unmarshall ( guint8 *data, gint len, VikViewport *vvp );
647 static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation );
648 static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id, gboolean is_file_operation );
649 static void trw_layer_del_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer );
650 static void trw_layer_cut_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer );
651 static void trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer, guint8 **item, guint *len );
652 static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, guint8 *item, guint len );
653 static void trw_layer_free_copied_item ( gint subtype, gpointer item );
654 static void trw_layer_drag_drop_request ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, GtkTreeIter *src_item_iter, GtkTreePath *dest_path );
655 static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t *t );
656 static gboolean trw_layer_select_move ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t *t );
657 static gboolean trw_layer_select_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t *t );
658 static gboolean trw_layer_show_selected_viewport_menu ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
659 /* End Layer Interface function definitions */
660
661 VikLayerInterface vik_trw_layer_interface = {
662   "TrackWaypoint",
663   N_("TrackWaypoint"),
664   "<control><shift>Y",
665   &viktrwlayer_pixbuf,
666
667   trw_layer_tools,
668   sizeof(trw_layer_tools) / sizeof(VikToolInterface),
669
670   trw_layer_params,
671   NUM_PARAMS,
672   params_groups, /* params_groups */
673   sizeof(params_groups)/sizeof(params_groups[0]),    /* number of groups */
674
675   VIK_MENU_ITEM_ALL,
676
677   (VikLayerFuncCreate)                  trw_layer_create,
678   (VikLayerFuncRealize)                 trw_layer_realize,
679   (VikLayerFuncPostRead)                trw_layer_post_read,
680   (VikLayerFuncFree)                    trw_layer_free,
681
682   (VikLayerFuncProperties)              NULL,
683   (VikLayerFuncDraw)                    trw_layer_draw,
684   (VikLayerFuncChangeCoordMode)         trw_layer_change_coord_mode,
685
686   (VikLayerFuncSetMenuItemsSelection)   trw_layer_set_menu_selection,
687   (VikLayerFuncGetMenuItemsSelection)   trw_layer_get_menu_selection,
688
689   (VikLayerFuncAddMenuItems)            trw_layer_add_menu_items,
690   (VikLayerFuncSublayerAddMenuItems)    trw_layer_sublayer_add_menu_items,
691
692   (VikLayerFuncSublayerRenameRequest)   trw_layer_sublayer_rename_request,
693   (VikLayerFuncSublayerToggleVisible)   trw_layer_sublayer_toggle_visible,
694   (VikLayerFuncSublayerTooltip)         trw_layer_sublayer_tooltip,
695   (VikLayerFuncLayerTooltip)            trw_layer_layer_tooltip,
696   (VikLayerFuncLayerSelected)           trw_layer_selected,
697
698   (VikLayerFuncMarshall)                trw_layer_marshall,
699   (VikLayerFuncUnmarshall)              trw_layer_unmarshall,
700
701   (VikLayerFuncSetParam)                trw_layer_set_param,
702   (VikLayerFuncGetParam)                trw_layer_get_param,
703
704   (VikLayerFuncReadFileData)            a_gpspoint_read_file,
705   (VikLayerFuncWriteFileData)           a_gpspoint_write_file,
706
707   (VikLayerFuncDeleteItem)              trw_layer_del_item,
708   (VikLayerFuncCutItem)                 trw_layer_cut_item,
709   (VikLayerFuncCopyItem)                trw_layer_copy_item,
710   (VikLayerFuncPasteItem)               trw_layer_paste_item,
711   (VikLayerFuncFreeCopiedItem)          trw_layer_free_copied_item,
712   
713   (VikLayerFuncDragDropRequest)         trw_layer_drag_drop_request,
714
715   (VikLayerFuncSelectClick)             trw_layer_select_click,
716   (VikLayerFuncSelectMove)              trw_layer_select_move,
717   (VikLayerFuncSelectRelease)           trw_layer_select_release,
718   (VikLayerFuncSelectedViewportMenu)    trw_layer_show_selected_viewport_menu,
719 };
720
721 GType vik_trw_layer_get_type ()
722 {
723   static GType vtl_type = 0;
724
725   if (!vtl_type)
726   {
727     static const GTypeInfo vtl_info =
728     {
729       sizeof (VikTrwLayerClass),
730       NULL, /* base_init */
731       NULL, /* base_finalize */
732       NULL, /* class init */
733       NULL, /* class_finalize */
734       NULL, /* class_data */
735       sizeof (VikTrwLayer),
736       0,
737       NULL /* instance init */
738     };
739     vtl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikTrwLayer", &vtl_info, 0 );
740   }
741
742   return vtl_type;
743 }
744
745 static void trw_layer_del_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer )
746 {
747   static gpointer pass_along[6];
748   if (!sublayer) {
749     return;
750   }
751   
752   pass_along[0] = vtl;
753   pass_along[1] = NULL;
754   pass_along[2] = GINT_TO_POINTER (subtype);
755   pass_along[3] = sublayer;
756   pass_along[4] = GINT_TO_POINTER (1); // Confirm delete request
757   pass_along[5] = NULL;
758
759   trw_layer_delete_item ( pass_along );
760 }
761
762 static void trw_layer_cut_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer )
763 {
764   static gpointer pass_along[6];
765   if (!sublayer) {
766     return;
767   }
768
769   pass_along[0] = vtl;
770   pass_along[1] = NULL;
771   pass_along[2] = GINT_TO_POINTER (subtype);
772   pass_along[3] = sublayer;
773   pass_along[4] = GINT_TO_POINTER (0); // No delete confirmation needed for auto delete
774   pass_along[5] = NULL;
775
776   trw_layer_copy_item_cb(pass_along);
777   trw_layer_cut_item_cb(pass_along);
778 }
779
780 static void trw_layer_copy_item_cb ( gpointer pass_along[6])
781 {
782   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
783   gint subtype = GPOINTER_TO_INT (pass_along[2]);
784   gpointer * sublayer = pass_along[3];
785   guint8 *data = NULL;
786   guint len;
787
788   trw_layer_copy_item( vtl, subtype, sublayer, &data, &len);
789
790   if (data) {
791     const gchar* name;
792     if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
793       VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, sublayer);
794       if ( wp && wp->name )
795         name = wp->name;
796       else
797         name = NULL; // Broken :(
798     }
799     else if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
800       VikTrack *trk = g_hash_table_lookup ( vtl->tracks, sublayer);
801       if ( trk && trk->name )
802         name = trk->name;
803       else
804         name = NULL; // Broken :(
805     }
806     else {
807       VikTrack *trk = g_hash_table_lookup ( vtl->routes, sublayer);
808       if ( trk && trk->name )
809         name = trk->name;
810       else
811         name = NULL; // Broken :(
812     }
813
814     a_clipboard_copy( VIK_CLIPBOARD_DATA_SUBLAYER, VIK_LAYER_TRW,
815                       subtype, len, name, data);
816   }
817 }
818
819 static void trw_layer_cut_item_cb ( gpointer pass_along[6])
820 {
821   trw_layer_copy_item_cb(pass_along);
822   pass_along[4] = GINT_TO_POINTER (0); // Never need to confirm automatic delete
823   trw_layer_delete_item(pass_along);
824 }
825
826 static void trw_layer_paste_item_cb ( gpointer pass_along[6])
827 {
828   // Slightly cheating method, routing via the panels capability
829   a_clipboard_paste (VIK_LAYERS_PANEL(pass_along[1]));
830 }
831
832 static void trw_layer_copy_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer, guint8 **item, guint *len )
833 {
834   guint8 *id;
835   guint il;
836
837   if (!sublayer) {
838     *item = NULL;
839     return;
840   }
841
842   GByteArray *ba = g_byte_array_new ();
843
844   if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
845     vik_waypoint_marshall ( g_hash_table_lookup ( vtl->waypoints, sublayer ), &id, &il );
846   } else if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
847     vik_track_marshall ( g_hash_table_lookup ( vtl->tracks, sublayer ), &id, &il );
848   } else {
849     vik_track_marshall ( g_hash_table_lookup ( vtl->routes, sublayer ), &id, &il );
850   }
851
852   g_byte_array_append ( ba, id, il );
853
854   g_free(id);
855
856   *len = ba->len;
857   *item = ba->data;
858 }
859
860 static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, guint8 *item, guint len )
861 {
862   if ( !item )
863     return FALSE;
864
865   gchar *name;
866
867   if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
868   {
869     VikWaypoint *w;
870
871     w = vik_waypoint_unmarshall ( item, len );
872     // When copying - we'll create a new name based on the original
873     name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, w->name);
874     vik_trw_layer_add_waypoint ( vtl, name, w );
875     waypoint_convert (NULL, w, &vtl->coord_mode);
876     g_free ( name );
877
878     trw_layer_calculate_bounds_waypoints ( vtl );
879
880     // Consider if redraw necessary for the new item
881     if ( vtl->vl.visible && vtl->waypoints_visible && w->visible )
882       vik_layer_emit_update ( VIK_LAYER(vtl) );
883     return TRUE;
884   }
885   if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
886   {
887     VikTrack *t;
888
889     t = vik_track_unmarshall ( item, len );
890     // When copying - we'll create a new name based on the original
891     name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, t->name);
892     vik_trw_layer_add_track ( vtl, name, t );
893     vik_track_convert (t, vtl->coord_mode);
894     g_free ( name );
895
896     // Consider if redraw necessary for the new item
897     if ( vtl->vl.visible && vtl->tracks_visible && t->visible )
898       vik_layer_emit_update ( VIK_LAYER(vtl) );
899     return TRUE;
900   }
901   if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE )
902   {
903     VikTrack *t;
904
905     t = vik_track_unmarshall ( item, len );
906     // When copying - we'll create a new name based on the original
907     name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_ROUTE, t->name);
908     vik_trw_layer_add_route ( vtl, name, t );
909     vik_track_convert (t, vtl->coord_mode);
910     g_free ( name );
911
912     // Consider if redraw necessary for the new item
913     if ( vtl->vl.visible && vtl->routes_visible && t->visible )
914       vik_layer_emit_update ( VIK_LAYER(vtl) );
915     return TRUE;
916   }
917   return FALSE;
918 }
919
920 static void trw_layer_free_copied_item ( gint subtype, gpointer item )
921 {
922   if (item) {
923     g_free(item);
924   }
925 }
926
927 static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
928 {
929   switch ( id )
930   {
931     case PARAM_TV: vtl->tracks_visible = data.b; break;
932     case PARAM_WV: vtl->waypoints_visible = data.b; break;
933     case PARAM_RV: vtl->routes_visible = data.b; break;
934     case PARAM_DM: vtl->drawmode = data.u; break;
935     case PARAM_TC:
936       vtl->track_color = data.c;
937       if ( vp ) trw_layer_new_track_gcs ( vtl, vp );
938       break;
939     case PARAM_DP: vtl->drawpoints = data.b; break;
940     case PARAM_DPS:
941       if ( data.u >= MIN_POINT_SIZE && data.u <= MAX_POINT_SIZE )
942         vtl->drawpoints_size = data.u;
943       break;
944     case PARAM_DE: vtl->drawelevation = data.b; break;
945     case PARAM_DS: vtl->drawstops = data.b; break;
946     case PARAM_DL: vtl->drawlines = data.b; break;
947     case PARAM_DD: vtl->drawdirections = data.b; break;
948     case PARAM_DDS:
949       if ( data.u >= MIN_ARROW_SIZE && data.u <= MAX_ARROW_SIZE )
950         vtl->drawdirections_size = data.u;
951       break;
952     case PARAM_SL: if ( data.u >= MIN_STOP_LENGTH && data.u <= MAX_STOP_LENGTH )
953                      vtl->stop_length = data.u;
954                    break;
955     case PARAM_EF: if ( data.u >= 1 && data.u <= 100 )
956                      vtl->elevation_factor = data.u;
957                    break;
958     case PARAM_LT: if ( data.u > 0 && data.u < 15 && data.u != vtl->line_thickness )
959                    {
960                      vtl->line_thickness = data.u;
961                      if ( vp ) trw_layer_new_track_gcs ( vtl, vp );
962                    }
963                    break;
964     case PARAM_BLT: if ( data.u <= 8 && data.u != vtl->bg_line_thickness )
965                    {
966                      vtl->bg_line_thickness = data.u;
967                      if ( vp ) trw_layer_new_track_gcs ( vtl, vp );
968                    }
969                    break;
970     case PARAM_TBGC:
971       vtl->track_bg_color = data.c;
972       if ( vtl->track_bg_gc )
973         gdk_gc_set_rgb_fg_color(vtl->track_bg_gc, &(vtl->track_bg_color));
974       break;
975     case PARAM_TDSF: vtl->track_draw_speed_factor = data.d; break;
976     case PARAM_TSO: if ( data.u < VL_SO_LAST ) vtl->track_sort_order = data.u; break;
977     case PARAM_DLA: vtl->drawlabels = data.b; break;
978     case PARAM_DI: vtl->drawimages = data.b; break;
979     case PARAM_IS: if ( data.u != vtl->image_size )
980       {
981         vtl->image_size = data.u;
982         g_list_foreach ( vtl->image_cache->head, (GFunc) cached_pixbuf_free, NULL );
983         g_queue_free ( vtl->image_cache );
984         vtl->image_cache = g_queue_new ();
985       }
986       break;
987     case PARAM_IA: vtl->image_alpha = data.u; break;
988     case PARAM_ICS: vtl->image_cache_size = data.u;
989       while ( vtl->image_cache->length > vtl->image_cache_size ) /* if shrinking cache_size, free pixbuf ASAP */
990           cached_pixbuf_free ( g_queue_pop_tail ( vtl->image_cache ) );
991       break;
992     case PARAM_WPC:
993       vtl->waypoint_color = data.c;
994       if ( vtl->waypoint_gc )
995         gdk_gc_set_rgb_fg_color(vtl->waypoint_gc, &(vtl->waypoint_color));
996       break;
997     case PARAM_WPTC:
998       vtl->waypoint_text_color = data.c;
999       if ( vtl->waypoint_text_gc )
1000         gdk_gc_set_rgb_fg_color(vtl->waypoint_text_gc, &(vtl->waypoint_text_color));
1001       break;
1002     case PARAM_WPBC:
1003       vtl->waypoint_bg_color = data.c;
1004       if ( vtl->waypoint_bg_gc )
1005         gdk_gc_set_rgb_fg_color(vtl->waypoint_bg_gc, &(vtl->waypoint_bg_color));
1006       break;
1007     case PARAM_WPBA:
1008       vtl->wpbgand = data.b;
1009       if ( vtl->waypoint_bg_gc )
1010         gdk_gc_set_function(vtl->waypoint_bg_gc, data.b ? GDK_AND : GDK_COPY );
1011       break;
1012     case PARAM_WPSYM: if ( data.u < WP_NUM_SYMBOLS ) vtl->wp_symbol = data.u; break;
1013     case PARAM_WPSIZE: if ( data.u > 0 && data.u <= 64 ) vtl->wp_size = data.u; break;
1014     case PARAM_WPSYMS: vtl->wp_draw_symbols = data.b; break;
1015     case PARAM_WPFONTSIZE:
1016       if ( data.u < FS_NUM_SIZES ) {
1017         vtl->wp_font_size = data.u;
1018         g_free ( vtl->wp_fsize_str );
1019         switch ( vtl->wp_font_size ) {
1020           case FS_XX_SMALL: vtl->wp_fsize_str = g_strdup ( "xx-small" ); break;
1021           case FS_X_SMALL: vtl->wp_fsize_str = g_strdup ( "x-small" ); break;
1022           case FS_SMALL: vtl->wp_fsize_str = g_strdup ( "small" ); break;
1023           case FS_LARGE: vtl->wp_fsize_str = g_strdup ( "large" ); break;
1024           case FS_X_LARGE: vtl->wp_fsize_str = g_strdup ( "x-large" ); break;
1025           case FS_XX_LARGE: vtl->wp_fsize_str = g_strdup ( "xx-large" ); break;
1026           default: vtl->wp_fsize_str = g_strdup ( "medium" ); break;
1027         }
1028       }
1029       break;
1030     case PARAM_WPSO: if ( data.u < VL_SO_LAST ) vtl->wp_sort_order = data.u; break;
1031   }
1032   return TRUE;
1033 }
1034
1035 static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id, gboolean is_file_operation )
1036 {
1037   VikLayerParamData rv;
1038   switch ( id )
1039   {
1040     case PARAM_TV: rv.b = vtl->tracks_visible; break;
1041     case PARAM_WV: rv.b = vtl->waypoints_visible; break;
1042     case PARAM_RV: rv.b = vtl->routes_visible; break;
1043     case PARAM_DM: rv.u = vtl->drawmode; break;
1044     case PARAM_TC: rv.c = vtl->track_color; break;
1045     case PARAM_DP: rv.b = vtl->drawpoints; break;
1046     case PARAM_DPS: rv.u = vtl->drawpoints_size; break;
1047     case PARAM_DE: rv.b = vtl->drawelevation; break;
1048     case PARAM_EF: rv.u = vtl->elevation_factor; break;
1049     case PARAM_DS: rv.b = vtl->drawstops; break;
1050     case PARAM_SL: rv.u = vtl->stop_length; break;
1051     case PARAM_DL: rv.b = vtl->drawlines; break;
1052     case PARAM_DD: rv.b = vtl->drawdirections; break;
1053     case PARAM_DDS: rv.u = vtl->drawdirections_size; break;
1054     case PARAM_LT: rv.u = vtl->line_thickness; break;
1055     case PARAM_BLT: rv.u = vtl->bg_line_thickness; break;
1056     case PARAM_DLA: rv.b = vtl->drawlabels; break;
1057     case PARAM_DI: rv.b = vtl->drawimages; break;
1058     case PARAM_TBGC: rv.c = vtl->track_bg_color; break;
1059     case PARAM_TDSF: rv.d = vtl->track_draw_speed_factor; break;
1060     case PARAM_TSO: rv.u = vtl->track_sort_order; break;
1061     case PARAM_IS: rv.u = vtl->image_size; break;
1062     case PARAM_IA: rv.u = vtl->image_alpha; break;
1063     case PARAM_ICS: rv.u = vtl->image_cache_size; break;
1064     case PARAM_WPC: rv.c = vtl->waypoint_color; break;
1065     case PARAM_WPTC: rv.c = vtl->waypoint_text_color; break;
1066     case PARAM_WPBC: rv.c = vtl->waypoint_bg_color; break;
1067     case PARAM_WPBA: rv.b = vtl->wpbgand; break;
1068     case PARAM_WPSYM: rv.u = vtl->wp_symbol; break;
1069     case PARAM_WPSIZE: rv.u = vtl->wp_size; break;
1070     case PARAM_WPSYMS: rv.b = vtl->wp_draw_symbols; break;
1071     case PARAM_WPFONTSIZE: rv.u = vtl->wp_font_size; break;
1072     case PARAM_WPSO: rv.u = vtl->wp_sort_order; break;
1073   }
1074   return rv;
1075 }
1076
1077 static void trw_layer_marshall( VikTrwLayer *vtl, guint8 **data, gint *len )
1078 {
1079   guint8 *pd;
1080   gint pl;
1081
1082   *data = NULL;
1083
1084   // Use byte arrays to store sublayer data
1085   // much like done elsewhere e.g. vik_layer_marshall_params()
1086   GByteArray *ba = g_byte_array_new ( );
1087
1088   guint8 *sl_data;
1089   guint sl_len;
1090
1091   guint object_length;
1092   guint subtype;
1093   // store:
1094   // the length of the item
1095   // the sublayer type of item
1096   // the the actual item
1097 #define tlm_append(object_pointer, size, type)  \
1098   subtype = (type); \
1099   object_length = (size); \
1100   g_byte_array_append ( ba, (guint8 *)&object_length, sizeof(object_length) ); \
1101   g_byte_array_append ( ba, (guint8 *)&subtype, sizeof(subtype) ); \
1102   g_byte_array_append ( ba, (object_pointer), object_length );
1103
1104   // Layer parameters first
1105   vik_layer_marshall_params(VIK_LAYER(vtl), &pd, &pl);
1106   g_byte_array_append ( ba, (guint8 *)&pl, sizeof(pl) ); \
1107   g_byte_array_append ( ba, pd, pl );
1108   g_free ( pd );
1109
1110   // Now sublayer data
1111   GHashTableIter iter;
1112   gpointer key, value;
1113
1114   // Waypoints
1115   g_hash_table_iter_init ( &iter, vtl->waypoints );
1116   while ( g_hash_table_iter_next (&iter, &key, &value) ) {
1117     vik_waypoint_marshall ( VIK_WAYPOINT(value), &sl_data, &sl_len );
1118     tlm_append ( sl_data, sl_len, VIK_TRW_LAYER_SUBLAYER_WAYPOINT );
1119     g_free ( sl_data );
1120   }
1121
1122   // Tracks
1123   g_hash_table_iter_init ( &iter, vtl->tracks );
1124   while ( g_hash_table_iter_next (&iter, &key, &value) ) {
1125     vik_track_marshall ( VIK_TRACK(value), &sl_data, &sl_len );
1126     tlm_append ( sl_data, sl_len, VIK_TRW_LAYER_SUBLAYER_TRACK );
1127     g_free ( sl_data );
1128   }
1129
1130   // Routes
1131   g_hash_table_iter_init ( &iter, vtl->routes );
1132   while ( g_hash_table_iter_next (&iter, &key, &value) ) {
1133     vik_track_marshall ( VIK_TRACK(value), &sl_data, &sl_len );
1134     tlm_append ( sl_data, sl_len, VIK_TRW_LAYER_SUBLAYER_ROUTE );
1135     g_free ( sl_data );
1136   }
1137
1138 #undef tlm_append
1139
1140   *data = ba->data;
1141   *len = ba->len;
1142 }
1143
1144 static VikTrwLayer *trw_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
1145 {
1146   VikTrwLayer *vtl = VIK_TRW_LAYER(vik_layer_create ( VIK_LAYER_TRW, vvp, NULL, FALSE ));
1147   gint pl;
1148   gint consumed_length;
1149
1150   // First the overall layer parameters
1151   memcpy(&pl, data, sizeof(pl));
1152   data += sizeof(pl);
1153   vik_layer_unmarshall_params ( VIK_LAYER(vtl), data, pl, vvp );
1154   data += pl;
1155
1156   consumed_length = pl;
1157   const gint sizeof_len_and_subtype = sizeof(gint) + sizeof(gint);
1158
1159 #define tlm_size (*(gint *)data)
1160   // See marshalling above for order of how this is written
1161 #define tlm_next \
1162   data += sizeof_len_and_subtype + tlm_size;
1163
1164   // Now the individual sublayers:
1165
1166   while ( *data && consumed_length < len ) {
1167     // Normally four extra bytes at the end of the datastream
1168     //  (since it's a GByteArray and that's where it's length is stored)
1169     //  So only attempt read when there's an actual block of sublayer data
1170     if ( consumed_length + tlm_size < len ) {
1171
1172       // Reuse pl to read the subtype from the data stream
1173       memcpy(&pl, data+sizeof(gint), sizeof(pl));
1174
1175       if ( pl == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
1176         VikTrack *trk = vik_track_unmarshall ( data + sizeof_len_and_subtype, 0 );
1177         gchar *name = g_strdup ( trk->name );
1178         vik_trw_layer_add_track ( vtl, name, trk );
1179         g_free ( name );
1180       }
1181       if ( pl == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
1182         VikWaypoint *wp = vik_waypoint_unmarshall ( data + sizeof_len_and_subtype, 0 );
1183         gchar *name = g_strdup ( wp->name );
1184         vik_trw_layer_add_waypoint ( vtl, name, wp );
1185         g_free ( name );
1186       }
1187       if ( pl == VIK_TRW_LAYER_SUBLAYER_ROUTE ) {
1188         VikTrack *trk = vik_track_unmarshall ( data + sizeof_len_and_subtype, 0 );
1189         gchar *name = g_strdup ( trk->name );
1190         vik_trw_layer_add_route ( vtl, name, trk );
1191         g_free ( name );
1192       }
1193     }
1194     consumed_length += tlm_size + sizeof_len_and_subtype;
1195     tlm_next;
1196   }
1197   //g_debug ("consumed_length %d vs len %d", consumed_length, len);
1198
1199   // Not stored anywhere else so need to regenerate
1200   trw_layer_calculate_bounds_waypoints ( vtl );
1201
1202   return vtl;
1203 }
1204
1205 // Keep interesting hash function at least visible
1206 /*
1207 static guint strcase_hash(gconstpointer v)
1208 {
1209   // 31 bit hash function
1210   int i;
1211   const gchar *t = v;
1212   gchar s[128];   // malloc is too slow for reading big files
1213   gchar *p = s;
1214
1215   for (i = 0; (i < (sizeof(s)- 1)) && t[i]; i++)
1216       p[i] = toupper(t[i]);
1217   p[i] = '\0';
1218
1219   p = s;
1220   guint32 h = *p;
1221   if (h) {
1222     for (p += 1; *p != '\0'; p++)
1223       h = (h << 5) - h + *p;
1224   }
1225
1226   return h;  
1227 }
1228 */
1229
1230 // Stick a 1 at the end of the function name to make it more unique
1231 //  thus more easily searchable in a simple text editor
1232 static VikTrwLayer* trw_layer_new1 ( VikViewport *vvp )
1233 {
1234   VikTrwLayer *rv = VIK_TRW_LAYER ( g_object_new ( VIK_TRW_LAYER_TYPE, NULL ) );
1235   vik_layer_set_type ( VIK_LAYER(rv), VIK_LAYER_TRW );
1236
1237   // It's not entirely clear the benefits of hash tables usage here - possibly the simplicity of first implementation for unique names
1238   // Now with the name of the item stored as part of the item - these tables are effectively straightforward lists
1239
1240   // For this reworking I've choosen to keep the use of hash tables since for the expected data sizes
1241   // - even many hundreds of waypoints and tracks is quite small in the grand scheme of things,
1242   //  and with normal PC processing capabilities - it has negligibile performance impact
1243   // This also minimized the amount of rework - as the management of the hash tables already exists.
1244
1245   // The hash tables are indexed by simple integers acting as a UUID hash, which again shouldn't affect performance much
1246   //   we have to maintain a uniqueness (as before when multiple names where not allowed),
1247   //   this is to ensure it refers to the same item in the data structures used on the viewport and on the layers panel
1248
1249   rv->waypoints = g_hash_table_new_full ( g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) vik_waypoint_free );
1250   rv->waypoints_iters = g_hash_table_new_full ( g_direct_hash, g_direct_equal, NULL, g_free );
1251   rv->tracks = g_hash_table_new_full ( g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) vik_track_free );
1252   rv->tracks_iters = g_hash_table_new_full ( g_direct_hash, g_direct_equal, NULL, g_free );
1253   rv->routes = g_hash_table_new_full ( g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) vik_track_free );
1254   rv->routes_iters = g_hash_table_new_full ( g_direct_hash, g_direct_equal, NULL, g_free );
1255
1256   rv->image_cache = g_queue_new(); // Must be performed before set_params via set_defaults
1257
1258   vik_layer_set_defaults ( VIK_LAYER(rv), vvp );
1259
1260   // Param settings that are not available via the GUI
1261   // Force to on after processing params (which defaults them to off with a zero value)
1262   rv->waypoints_visible = rv->tracks_visible = rv->routes_visible = TRUE;
1263
1264   rv->draw_sync_done = TRUE;
1265   rv->draw_sync_do = TRUE;
1266   // Everything else is 0, FALSE or NULL
1267
1268   return rv;
1269 }
1270
1271
1272 static void trw_layer_free ( VikTrwLayer *trwlayer )
1273 {
1274   g_hash_table_destroy(trwlayer->waypoints);
1275   g_hash_table_destroy(trwlayer->waypoints_iters);
1276   g_hash_table_destroy(trwlayer->tracks);
1277   g_hash_table_destroy(trwlayer->tracks_iters);
1278   g_hash_table_destroy(trwlayer->routes);
1279   g_hash_table_destroy(trwlayer->routes_iters);
1280
1281   /* ODC: replace with GArray */
1282   trw_layer_free_track_gcs ( trwlayer );
1283
1284   if ( trwlayer->wp_right_click_menu )
1285     g_object_ref_sink ( G_OBJECT(trwlayer->wp_right_click_menu) );
1286
1287   if ( trwlayer->track_right_click_menu )
1288     g_object_ref_sink ( G_OBJECT(trwlayer->track_right_click_menu) );
1289
1290   if ( trwlayer->wplabellayout != NULL)
1291     g_object_unref ( G_OBJECT ( trwlayer->wplabellayout ) );
1292
1293   if ( trwlayer->waypoint_gc != NULL )
1294     g_object_unref ( G_OBJECT ( trwlayer->waypoint_gc ) );
1295
1296   if ( trwlayer->waypoint_text_gc != NULL )
1297     g_object_unref ( G_OBJECT ( trwlayer->waypoint_text_gc ) );
1298
1299   if ( trwlayer->waypoint_bg_gc != NULL )
1300     g_object_unref ( G_OBJECT ( trwlayer->waypoint_bg_gc ) );
1301
1302   g_free ( trwlayer->wp_fsize_str );
1303
1304   if ( trwlayer->tpwin != NULL )
1305     gtk_widget_destroy ( GTK_WIDGET(trwlayer->tpwin) );
1306
1307   if ( trwlayer->tracks_analysis_dialog != NULL )
1308     gtk_widget_destroy ( GTK_WIDGET(trwlayer->tracks_analysis_dialog) );
1309
1310   g_list_foreach ( trwlayer->image_cache->head, (GFunc) cached_pixbuf_free, NULL );
1311   g_queue_free ( trwlayer->image_cache );
1312 }
1313
1314 static void init_drawing_params ( struct DrawingParams *dp, VikTrwLayer *vtl, VikViewport *vp )
1315 {
1316   dp->vtl = vtl;
1317   dp->vp = vp;
1318   dp->vw = (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl);
1319   dp->xmpp = vik_viewport_get_xmpp ( vp );
1320   dp->ympp = vik_viewport_get_ympp ( vp );
1321   dp->width = vik_viewport_get_width ( vp );
1322   dp->height = vik_viewport_get_height ( vp );
1323   dp->cc = vtl->drawdirections_size*cos(DEG2RAD(45)); // Calculate once per vtl update - even if not used
1324   dp->ss = vtl->drawdirections_size*sin(DEG2RAD(45)); // Calculate once per vtl update - even if not used
1325
1326   dp->center = vik_viewport_get_center ( vp );
1327   dp->one_zone = vik_viewport_is_one_zone ( vp ); /* false if some other projection besides UTM */
1328   dp->lat_lon = vik_viewport_get_coord_mode ( vp ) == VIK_COORD_LATLON;
1329
1330   if ( dp->one_zone )
1331   {
1332     gint w2, h2;
1333     w2 = dp->xmpp * (dp->width / 2) + 1600 / dp->xmpp; 
1334     h2 = dp->ympp * (dp->height / 2) + 1600 / dp->ympp;
1335     /* leniency -- for tracks. Obviously for waypoints this SHOULD be a lot smaller */
1336  
1337     dp->ce1 = dp->center->east_west-w2; 
1338     dp->ce2 = dp->center->east_west+w2;
1339     dp->cn1 = dp->center->north_south-h2;
1340     dp->cn2 = dp->center->north_south+h2;
1341   } else if ( dp->lat_lon ) {
1342     VikCoord upperleft, bottomright;
1343     /* quick & dirty calculation; really want to check all corners due to lat/lon smaller at top in northern hemisphere */
1344     /* this also DOESN'T WORK if you are crossing 180/-180 lon. I don't plan to in the near future...  */
1345     vik_viewport_screen_to_coord ( vp, -500, -500, &upperleft );
1346     vik_viewport_screen_to_coord ( vp, dp->width+500, dp->height+500, &bottomright );
1347     dp->ce1 = upperleft.east_west;
1348     dp->ce2 = bottomright.east_west;
1349     dp->cn1 = bottomright.north_south;
1350     dp->cn2 = upperleft.north_south;
1351   }
1352
1353   vik_viewport_get_min_max_lat_lon ( vp, &(dp->bbox.south), &(dp->bbox.north), &(dp->bbox.west), &(dp->bbox.east) );
1354 }
1355
1356 /*
1357  * Determine the colour of the trackpoint (and/or trackline) relative to the average speed
1358  * Here a simple traffic like light colour system is used:
1359  *  . slow points are red
1360  *  . average is yellow
1361  *  . fast points are green
1362  */
1363 static gint track_section_colour_by_speed ( VikTrwLayer *vtl, VikTrackpoint *tp1, VikTrackpoint *tp2, gdouble average_speed, gdouble low_speed, gdouble high_speed )
1364 {
1365   gdouble rv = 0;
1366   if ( tp1->has_timestamp && tp2->has_timestamp ) {
1367     if ( average_speed > 0 ) {
1368       rv = ( vik_coord_diff ( &(tp1->coord), &(tp2->coord) ) / (tp1->timestamp - tp2->timestamp) );
1369       if ( rv < low_speed )
1370         return VIK_TRW_LAYER_TRACK_GC_SLOW;
1371       else if ( rv > high_speed )
1372         return VIK_TRW_LAYER_TRACK_GC_FAST;
1373       else
1374         return VIK_TRW_LAYER_TRACK_GC_AVER;
1375     }
1376   }
1377   return VIK_TRW_LAYER_TRACK_GC_BLACK;
1378 }
1379
1380 static void draw_utm_skip_insignia ( VikViewport *vvp, GdkGC *gc, gint x, gint y )
1381 {
1382   vik_viewport_draw_line ( vvp, gc, x+5, y, x-5, y );
1383   vik_viewport_draw_line ( vvp, gc, x, y+5, x, y-5 );
1384   vik_viewport_draw_line ( vvp, gc, x+5, y+5, x-5, y-5 );
1385   vik_viewport_draw_line ( vvp, gc, x+5, y-5, x-5, y+5 );
1386 }
1387
1388 static void trw_layer_draw_track ( const gpointer id, VikTrack *track, struct DrawingParams *dp, gboolean draw_track_outline )
1389 {
1390   if ( ! track->visible )
1391     return;
1392
1393   /* TODO: this function is a mess, get rid of any redundancy */
1394   GList *list = track->trackpoints;
1395   GdkGC *main_gc;
1396   gboolean useoldvals = TRUE;
1397
1398   gboolean drawpoints;
1399   gboolean drawstops;
1400   gboolean drawelevation;
1401   gdouble min_alt, max_alt, alt_diff = 0;
1402
1403   const guint8 tp_size_reg = dp->vtl->drawpoints_size;
1404   const guint8 tp_size_cur = dp->vtl->drawpoints_size*2;
1405   guint8 tp_size;
1406
1407   if ( dp->vtl->drawelevation )
1408   {
1409     /* assume if it has elevation at the beginning, it has it throughout. not ness a true good assumption */
1410     if ( ( drawelevation = vik_track_get_minmax_alt ( track, &min_alt, &max_alt ) ) )
1411       alt_diff = max_alt - min_alt;
1412   }
1413
1414   /* admittedly this is not an efficient way to do it because we go through the whole GC thing all over... */
1415   if ( dp->vtl->bg_line_thickness && !draw_track_outline )
1416     trw_layer_draw_track ( id, track, dp, TRUE );
1417
1418   if ( draw_track_outline )
1419     drawpoints = drawstops = FALSE;
1420   else {
1421     drawpoints = dp->vtl->drawpoints;
1422     drawstops = dp->vtl->drawstops;
1423   }
1424
1425   gboolean drawing_highlight = FALSE;
1426   /* Current track - used for creation */
1427   if ( track == dp->vtl->current_track )
1428     main_gc = dp->vtl->current_track_gc;
1429   else {
1430     if ( vik_viewport_get_draw_highlight ( dp->vp ) ) {
1431       /* Draw all tracks of the layer in special colour */
1432       /* if track is member of selected layer or is the current selected track
1433          then draw in the highlight colour.
1434          NB this supercedes the drawmode */
1435       if ( ( dp->vtl == vik_window_get_selected_trw_layer ( dp->vw ) ) ||
1436            ( !track->is_route && ( dp->vtl->tracks == vik_window_get_selected_tracks ( dp->vw ) ) ) ||
1437            ( track->is_route && ( dp->vtl->routes == vik_window_get_selected_tracks ( dp->vw ) ) ) ||
1438            ( track == vik_window_get_selected_track ( dp->vw ) ) ) {
1439         main_gc = vik_viewport_get_gc_highlight (dp->vp);
1440         drawing_highlight = TRUE;
1441       }
1442     }
1443     if ( !drawing_highlight ) {
1444       // Still need to figure out the gc according to the drawing mode:
1445       switch ( dp->vtl->drawmode ) {
1446       case DRAWMODE_BY_TRACK:
1447         if ( dp->vtl->track_1color_gc )
1448           g_object_unref ( dp->vtl->track_1color_gc );
1449         dp->vtl->track_1color_gc = vik_viewport_new_gc_from_color ( dp->vp, &track->color, dp->vtl->line_thickness );
1450         main_gc = dp->vtl->track_1color_gc;
1451         break;
1452       default:
1453         // Mostly for DRAWMODE_ALL_SAME_COLOR
1454         // but includes DRAWMODE_BY_SPEED, main_gc is set later on as necessary
1455         main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, VIK_TRW_LAYER_TRACK_GC_SINGLE);
1456         break;
1457       }
1458     }
1459   }
1460
1461   if (list) {
1462     int x, y, oldx, oldy;
1463     VikTrackpoint *tp = VIK_TRACKPOINT(list->data);
1464   
1465     tp_size = (list == dp->vtl->current_tpl) ? tp_size_cur : tp_size_reg;
1466
1467     vik_viewport_coord_to_screen ( dp->vp, &(tp->coord), &x, &y );
1468
1469     // Draw the first point as something a bit different from the normal points
1470     // ATM it's slightly bigger and a triangle
1471     if ( drawpoints ) {
1472       GdkPoint trian[3] = { { x, y-(3*tp_size) }, { x-(2*tp_size), y+(2*tp_size) }, {x+(2*tp_size), y+(2*tp_size)} };
1473       vik_viewport_draw_polygon ( dp->vp, main_gc, TRUE, trian, 3 );
1474     }
1475
1476     oldx = x;
1477     oldy = y;
1478
1479     gdouble average_speed = 0.0;
1480     gdouble low_speed = 0.0;
1481     gdouble high_speed = 0.0;
1482     // If necessary calculate these values - which is done only once per track redraw
1483     if ( dp->vtl->drawmode == DRAWMODE_BY_SPEED ) {
1484       // the percentage factor away from the average speed determines transistions between the levels
1485       average_speed = vik_track_get_average_speed_moving(track, dp->vtl->stop_length);
1486       low_speed = average_speed - (average_speed*(dp->vtl->track_draw_speed_factor/100.0));
1487       high_speed = average_speed + (average_speed*(dp->vtl->track_draw_speed_factor/100.0));
1488     }
1489
1490     while ((list = g_list_next(list)))
1491     {
1492       tp = VIK_TRACKPOINT(list->data);
1493       tp_size = (list == dp->vtl->current_tpl) ? tp_size_cur : tp_size_reg;
1494
1495       /* check some stuff -- but only if we're in UTM and there's only ONE ZONE; or lat lon */
1496       if ( (!dp->one_zone && !dp->lat_lon) ||     /* UTM & zones; do everything */
1497              ( ((!dp->one_zone) || tp->coord.utm_zone == dp->center->utm_zone) &&   /* only check zones if UTM & one_zone */
1498              tp->coord.east_west < dp->ce2 && tp->coord.east_west > dp->ce1 &&  /* both UTM and lat lon */
1499              tp->coord.north_south > dp->cn1 && tp->coord.north_south < dp->cn2 ) )
1500       {
1501         vik_viewport_coord_to_screen ( dp->vp, &(tp->coord), &x, &y );
1502
1503         /*
1504          * If points are the same in display coordinates, don't draw.
1505          */
1506         if ( useoldvals && x == oldx && y == oldy )
1507         {
1508           // Still need to process points to ensure 'stops' are drawn if required
1509           if ( drawstops && drawpoints && ! draw_track_outline && list->next &&
1510                (VIK_TRACKPOINT(list->next->data)->timestamp - VIK_TRACKPOINT(list->data)->timestamp > dp->vtl->stop_length) )
1511             vik_viewport_draw_arc ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, 11), TRUE, x-(3*tp_size), y-(3*tp_size), 6*tp_size, 6*tp_size, 0, 360*64 );
1512
1513           goto skip;
1514         }
1515
1516         VikTrackpoint *tp2 = VIK_TRACKPOINT(list->prev->data);
1517         if ( drawpoints || dp->vtl->drawlines ) {
1518           // setup main_gc for both point and line drawing
1519           if ( !drawing_highlight && (dp->vtl->drawmode == DRAWMODE_BY_SPEED) ) {
1520             main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, track_section_colour_by_speed ( dp->vtl, tp, tp2, average_speed, low_speed, high_speed ) );
1521           }
1522         }
1523
1524         if ( drawpoints && ! draw_track_outline )
1525         {
1526
1527           if ( list->next ) {
1528             /*
1529              * The concept of drawing stops is that a trackpoint
1530              * that is if the next trackpoint has a timestamp far into
1531              * the future, we draw a circle of 6x trackpoint size,
1532              * instead of a rectangle of 2x trackpoint size.
1533              * This is drawn first so the trackpoint will be drawn on top
1534              */
1535             /* stops */
1536             if ( drawstops && VIK_TRACKPOINT(list->next->data)->timestamp - VIK_TRACKPOINT(list->data)->timestamp > dp->vtl->stop_length )
1537               /* Stop point.  Draw 6x circle. Always in redish colour */
1538               vik_viewport_draw_arc ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, VIK_TRW_LAYER_TRACK_GC_STOP), TRUE, x-(3*tp_size), y-(3*tp_size), 6*tp_size, 6*tp_size, 0, 360*64 );
1539
1540             /* Regular point - draw 2x square. */
1541             vik_viewport_draw_rectangle ( dp->vp, main_gc, TRUE, x-tp_size, y-tp_size, 2*tp_size, 2*tp_size );
1542           }
1543           else
1544             /* Final point - draw 4x circle. */
1545             vik_viewport_draw_arc ( dp->vp, main_gc, TRUE, x-(2*tp_size), y-(2*tp_size), 4*tp_size, 4*tp_size, 0, 360*64 );
1546         }
1547
1548         if ((!tp->newsegment) && (dp->vtl->drawlines))
1549         {
1550
1551           /* UTM only: zone check */
1552           if ( drawpoints && dp->vtl->coord_mode == VIK_COORD_UTM && tp->coord.utm_zone != dp->center->utm_zone )
1553             draw_utm_skip_insignia (  dp->vp, main_gc, x, y);
1554
1555           if (!useoldvals)
1556             vik_viewport_coord_to_screen ( dp->vp, &(tp2->coord), &oldx, &oldy );
1557
1558           if ( draw_track_outline ) {
1559             vik_viewport_draw_line ( dp->vp, dp->vtl->track_bg_gc, oldx, oldy, x, y);
1560           }
1561           else {
1562
1563             vik_viewport_draw_line ( dp->vp, main_gc, oldx, oldy, x, y);
1564
1565             if ( dp->vtl->drawelevation && list->next && VIK_TRACKPOINT(list->next->data)->altitude != VIK_DEFAULT_ALTITUDE ) {
1566               GdkPoint tmp[4];
1567               #define FIXALTITUDE(what) ((VIK_TRACKPOINT((what))->altitude-min_alt)/alt_diff*DRAW_ELEVATION_FACTOR*dp->vtl->elevation_factor/dp->xmpp)
1568
1569               tmp[0].x = oldx;
1570               tmp[0].y = oldy;
1571               tmp[1].x = oldx;
1572               tmp[1].y = oldy-FIXALTITUDE(list->data);
1573               tmp[2].x = x;
1574               tmp[2].y = y-FIXALTITUDE(list->next->data);
1575               tmp[3].x = x;
1576               tmp[3].y = y;
1577
1578               GdkGC *tmp_gc;
1579               if ( ((oldx - x) > 0 && (oldy - y) > 0) || ((oldx - x) < 0 && (oldy - y) < 0))
1580                 tmp_gc = gtk_widget_get_style(GTK_WIDGET(dp->vp))->light_gc[3];
1581               else
1582                 tmp_gc = gtk_widget_get_style(GTK_WIDGET(dp->vp))->dark_gc[0];
1583               vik_viewport_draw_polygon ( dp->vp, tmp_gc, TRUE, tmp, 4);
1584
1585               vik_viewport_draw_line ( dp->vp, main_gc, oldx, oldy-FIXALTITUDE(list->data), x, y-FIXALTITUDE(list->next->data));
1586             }
1587           }
1588         }
1589
1590         if ( (!tp->newsegment) && dp->vtl->drawdirections ) {
1591           // Draw an arrow at the mid point to show the direction of the track
1592           // Code is a rework from vikwindow::draw_ruler()
1593           gint midx = (oldx + x) / 2;
1594           gint midy = (oldy + y) / 2;
1595
1596           gdouble len = sqrt ( ((midx-oldx) * (midx-oldx)) + ((midy-oldy) * (midy-oldy)) );
1597           // Avoid divide by zero and ensure at least 1 pixel big
1598           if ( len > 1 ) {
1599             gdouble dx = (oldx - midx) / len;
1600             gdouble dy = (oldy - midy) / len;
1601             vik_viewport_draw_line ( dp->vp, main_gc, midx, midy, midx + (dx * dp->cc + dy * dp->ss), midy + (dy * dp->cc - dx * dp->ss) );
1602             vik_viewport_draw_line ( dp->vp, main_gc, midx, midy, midx + (dx * dp->cc - dy * dp->ss), midy + (dy * dp->cc + dx * dp->ss) );
1603           }
1604         }
1605
1606       skip:
1607         oldx = x;
1608         oldy = y;
1609         useoldvals = TRUE;
1610       }
1611       else {
1612         if (useoldvals && dp->vtl->drawlines && (!tp->newsegment))
1613         {
1614           VikTrackpoint *tp2 = VIK_TRACKPOINT(list->prev->data);
1615           if ( dp->vtl->coord_mode != VIK_COORD_UTM || tp->coord.utm_zone == dp->center->utm_zone )
1616           {
1617             vik_viewport_coord_to_screen ( dp->vp, &(tp->coord), &x, &y );
1618
1619             if ( !drawing_highlight && (dp->vtl->drawmode == DRAWMODE_BY_SPEED) ) {
1620               main_gc = g_array_index(dp->vtl->track_gc, GdkGC *, track_section_colour_by_speed ( dp->vtl, tp, tp2, average_speed, low_speed, high_speed ));
1621             }
1622
1623             /*
1624              * If points are the same in display coordinates, don't draw.
1625              */
1626             if ( x != oldx || y != oldy )
1627               {
1628                 if ( draw_track_outline )
1629                   vik_viewport_draw_line ( dp->vp, dp->vtl->track_bg_gc, oldx, oldy, x, y);
1630                 else
1631                   vik_viewport_draw_line ( dp->vp, main_gc, oldx, oldy, x, y);
1632               }
1633           }
1634           else 
1635           {
1636             /*
1637              * If points are the same in display coordinates, don't draw.
1638              */
1639             if ( x != oldx && y != oldy )
1640               {
1641                 vik_viewport_coord_to_screen ( dp->vp, &(tp2->coord), &x, &y );
1642                 draw_utm_skip_insignia ( dp->vp, main_gc, x, y );
1643               }
1644           }
1645         }
1646         useoldvals = FALSE;
1647       }
1648     }
1649   }
1650 }
1651
1652 static void trw_layer_draw_track_cb ( const gpointer id, VikTrack *track, struct DrawingParams *dp )
1653 {
1654   if ( BBOX_INTERSECT ( track->bbox, dp->bbox ) ) {
1655     trw_layer_draw_track ( id, track, dp, FALSE );
1656   }
1657 }
1658
1659 static void cached_pixbuf_free ( CachedPixbuf *cp )
1660 {
1661   g_object_unref ( G_OBJECT(cp->pixbuf) );
1662   g_free ( cp->image );
1663 }
1664
1665 static gint cached_pixbuf_cmp ( CachedPixbuf *cp, const gchar *name )
1666 {
1667   return strcmp ( cp->image, name );
1668 }
1669
1670 static void trw_layer_draw_waypoint ( const gpointer id, VikWaypoint *wp, struct DrawingParams *dp )
1671 {
1672   if ( wp->visible )
1673   if ( (!dp->one_zone && !dp->lat_lon) || ( ( dp->lat_lon || wp->coord.utm_zone == dp->center->utm_zone ) && 
1674              wp->coord.east_west < dp->ce2 && wp->coord.east_west > dp->ce1 && 
1675              wp->coord.north_south > dp->cn1 && wp->coord.north_south < dp->cn2 ) )
1676   {
1677     gint x, y;
1678     vik_viewport_coord_to_screen ( dp->vp, &(wp->coord), &x, &y );
1679
1680     /* if in shrunken_cache, get that. If not, get and add to shrunken_cache */
1681
1682     if ( wp->image && dp->vtl->drawimages )
1683     {
1684       GdkPixbuf *pixbuf = NULL;
1685       GList *l;
1686
1687       if ( dp->vtl->image_alpha == 0)
1688         return;
1689
1690       l = g_list_find_custom ( dp->vtl->image_cache->head, wp->image, (GCompareFunc) cached_pixbuf_cmp );
1691       if ( l )
1692         pixbuf = ((CachedPixbuf *) l->data)->pixbuf;
1693       else
1694       {
1695         gchar *image = wp->image;
1696         GdkPixbuf *regularthumb = a_thumbnails_get ( wp->image );
1697         if ( ! regularthumb )
1698         {
1699           regularthumb = a_thumbnails_get_default (); /* cache one 'not yet loaded' for all thumbs not loaded */
1700           image = "\x12\x00"; /* this shouldn't occur naturally. */
1701         }
1702         if ( regularthumb )
1703         {
1704           CachedPixbuf *cp = NULL;
1705           cp = g_malloc ( sizeof ( CachedPixbuf ) );
1706           if ( dp->vtl->image_size == 128 )
1707             cp->pixbuf = regularthumb;
1708           else
1709           {
1710             cp->pixbuf = a_thumbnails_scale_pixbuf(regularthumb, dp->vtl->image_size, dp->vtl->image_size);
1711             g_assert ( cp->pixbuf );
1712             g_object_unref ( G_OBJECT(regularthumb) );
1713           }
1714           cp->image = g_strdup ( image );
1715
1716           /* needed so 'click picture' tool knows how big the pic is; we don't
1717            * store it in cp because they may have been freed already. */
1718           wp->image_width = gdk_pixbuf_get_width ( cp->pixbuf );
1719           wp->image_height = gdk_pixbuf_get_height ( cp->pixbuf );
1720
1721           g_queue_push_head ( dp->vtl->image_cache, cp );
1722           if ( dp->vtl->image_cache->length > dp->vtl->image_cache_size )
1723             cached_pixbuf_free ( g_queue_pop_tail ( dp->vtl->image_cache ) );
1724
1725           pixbuf = cp->pixbuf;
1726         }
1727         else
1728         {
1729           pixbuf = a_thumbnails_get_default (); /* thumbnail not yet loaded */
1730         }
1731       }
1732       if ( pixbuf )
1733       {
1734         gint w, h;
1735         w = gdk_pixbuf_get_width ( pixbuf );
1736         h = gdk_pixbuf_get_height ( pixbuf );
1737
1738         if ( x+(w/2) > 0 && y+(h/2) > 0 && x-(w/2) < dp->width && y-(h/2) < dp->height ) /* always draw within boundaries */
1739         {
1740           if ( vik_viewport_get_draw_highlight ( dp->vp ) ) {
1741             if ( dp->vtl == vik_window_get_selected_trw_layer ( dp->vw ) ||
1742                  dp->vtl->waypoints == vik_window_get_selected_waypoints ( dp->vw ) ||
1743                  wp == vik_window_get_selected_waypoint ( dp->vw ) ) {
1744               // Highlighted - so draw a little border around the chosen one
1745               // single line seems a little weak so draw 2 of them
1746               vik_viewport_draw_rectangle (dp->vp, vik_viewport_get_gc_highlight (dp->vp), FALSE,
1747                                            x - (w/2) - 1, y - (h/2) - 1, w + 2, h + 2 );
1748               vik_viewport_draw_rectangle (dp->vp, vik_viewport_get_gc_highlight (dp->vp), FALSE,
1749                                            x - (w/2) - 2, y - (h/2) - 2, w + 4, h + 4 );
1750             }
1751           }
1752           if ( dp->vtl->image_alpha == 255 )
1753             vik_viewport_draw_pixbuf ( dp->vp, pixbuf, 0, 0, x - (w/2), y - (h/2), w, h );
1754           else
1755             vik_viewport_draw_pixbuf_with_alpha ( dp->vp, pixbuf, dp->vtl->image_alpha, 0, 0, x - (w/2), y - (h/2), w, h );
1756         }
1757         return; /* if failed to draw picture, default to drawing regular waypoint (below) */
1758       }
1759     }
1760
1761     // Draw appropriate symbol - either symbol image or simple types
1762     if ( dp->vtl->wp_draw_symbols && wp->symbol && wp->symbol_pixbuf ) {
1763       vik_viewport_draw_pixbuf ( dp->vp, wp->symbol_pixbuf, 0, 0, x - gdk_pixbuf_get_width(wp->symbol_pixbuf)/2, y - gdk_pixbuf_get_height(wp->symbol_pixbuf)/2, -1, -1 );
1764     } 
1765     else if ( wp == dp->vtl->current_wp ) {
1766       switch ( dp->vtl->wp_symbol ) {
1767         case WP_SYMBOL_FILLED_SQUARE: vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_gc, TRUE, x - (dp->vtl->wp_size), y - (dp->vtl->wp_size), dp->vtl->wp_size*2, dp->vtl->wp_size*2 ); break;
1768         case WP_SYMBOL_SQUARE: vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_gc, FALSE, x - (dp->vtl->wp_size), y - (dp->vtl->wp_size), dp->vtl->wp_size*2, dp->vtl->wp_size*2 ); break;
1769         case WP_SYMBOL_CIRCLE: vik_viewport_draw_arc ( dp->vp, dp->vtl->waypoint_gc, TRUE, x - dp->vtl->wp_size, y - dp->vtl->wp_size, dp->vtl->wp_size, dp->vtl->wp_size, 0, 360*64 ); break;
1770         case WP_SYMBOL_X: vik_viewport_draw_line ( dp->vp, dp->vtl->waypoint_gc, x - dp->vtl->wp_size*2, y - dp->vtl->wp_size*2, x + dp->vtl->wp_size*2, y + dp->vtl->wp_size*2 );
1771                           vik_viewport_draw_line ( dp->vp, dp->vtl->waypoint_gc, x - dp->vtl->wp_size*2, y + dp->vtl->wp_size*2, x + dp->vtl->wp_size*2, y - dp->vtl->wp_size*2 );
1772       }
1773     }
1774     else {
1775       switch ( dp->vtl->wp_symbol ) {
1776         case WP_SYMBOL_FILLED_SQUARE: vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_gc, TRUE, x - dp->vtl->wp_size/2, y - dp->vtl->wp_size/2, dp->vtl->wp_size, dp->vtl->wp_size ); break;
1777         case WP_SYMBOL_SQUARE: vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_gc, FALSE, x - dp->vtl->wp_size/2, y - dp->vtl->wp_size/2, dp->vtl->wp_size, dp->vtl->wp_size ); break;
1778         case WP_SYMBOL_CIRCLE: vik_viewport_draw_arc ( dp->vp, dp->vtl->waypoint_gc, TRUE, x-dp->vtl->wp_size/2, y-dp->vtl->wp_size/2, dp->vtl->wp_size, dp->vtl->wp_size, 0, 360*64 ); break;
1779         case WP_SYMBOL_X: vik_viewport_draw_line ( dp->vp, dp->vtl->waypoint_gc, x-dp->vtl->wp_size, y-dp->vtl->wp_size, x+dp->vtl->wp_size, y+dp->vtl->wp_size );
1780                           vik_viewport_draw_line ( dp->vp, dp->vtl->waypoint_gc, x-dp->vtl->wp_size, y+dp->vtl->wp_size, x+dp->vtl->wp_size, y-dp->vtl->wp_size ); break;
1781       }
1782     }
1783
1784     if ( dp->vtl->drawlabels )
1785     {
1786       /* thanks to the GPSDrive people (Fritz Ganter et al.) for hints on this part ... yah, I'm too lazy to study documentation */
1787       gint label_x, label_y;
1788       gint width, height;
1789       // Hopefully name won't break the markup (may need to sanitize - g_markup_escape_text())
1790
1791       // Could this stored in the waypoint rather than recreating each pass?
1792       gchar *wp_label_markup = g_strdup_printf ( "<span size=\"%s\">%s</span>", dp->vtl->wp_fsize_str, wp->name );
1793
1794       if ( pango_parse_markup ( wp_label_markup, -1, 0, NULL, NULL, NULL, NULL ) )
1795         pango_layout_set_markup ( dp->vtl->wplabellayout, wp_label_markup, -1 );
1796       else
1797         // Fallback if parse failure
1798         pango_layout_set_text ( dp->vtl->wplabellayout, wp->name, -1 );
1799
1800       g_free ( wp_label_markup );
1801
1802       pango_layout_get_pixel_size ( dp->vtl->wplabellayout, &width, &height );
1803       label_x = x - width/2;
1804       if ( wp->symbol_pixbuf )
1805         label_y = y - height - 2 - gdk_pixbuf_get_height(wp->symbol_pixbuf)/2;
1806       else
1807         label_y = y - dp->vtl->wp_size - height - 2;
1808
1809       /* if highlight mode on, then draw background text in highlight colour */
1810       if ( vik_viewport_get_draw_highlight ( dp->vp ) ) {
1811         if ( dp->vtl == vik_window_get_selected_trw_layer ( dp->vw ) ||
1812              dp->vtl->waypoints == vik_window_get_selected_waypoints ( dp->vw ) ||
1813              wp == vik_window_get_selected_waypoint ( dp->vw ) )
1814           vik_viewport_draw_rectangle ( dp->vp, vik_viewport_get_gc_highlight (dp->vp), TRUE, label_x - 1, label_y-1,width+2,height+2);
1815         else
1816           vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_bg_gc, TRUE, label_x - 1, label_y-1,width+2,height+2);
1817       }
1818       else {
1819         vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_bg_gc, TRUE, label_x - 1, label_y-1,width+2,height+2);
1820       }
1821       vik_viewport_draw_layout ( dp->vp, dp->vtl->waypoint_text_gc, label_x, label_y, dp->vtl->wplabellayout );
1822     }
1823   }
1824 }
1825
1826 static void trw_layer_draw_waypoint_cb ( gpointer id, VikWaypoint *wp, struct DrawingParams *dp )
1827 {
1828   if ( BBOX_INTERSECT ( dp->vtl->waypoints_bbox, dp->bbox ) ) {
1829     trw_layer_draw_waypoint ( id, wp, dp );
1830   }
1831 }
1832
1833 static void trw_layer_draw ( VikTrwLayer *l, gpointer data )
1834 {
1835   static struct DrawingParams dp;
1836   g_assert ( l != NULL );
1837
1838   init_drawing_params ( &dp, l, VIK_VIEWPORT(data) );
1839
1840   if ( l->tracks_visible )
1841     g_hash_table_foreach ( l->tracks, (GHFunc) trw_layer_draw_track_cb, &dp );
1842
1843   if ( l->routes_visible )
1844     g_hash_table_foreach ( l->routes, (GHFunc) trw_layer_draw_track_cb, &dp );
1845
1846   if (l->waypoints_visible)
1847     g_hash_table_foreach ( l->waypoints, (GHFunc) trw_layer_draw_waypoint_cb, &dp );
1848 }
1849
1850 static void trw_layer_free_track_gcs ( VikTrwLayer *vtl )
1851 {
1852   int i;
1853   if ( vtl->track_bg_gc ) 
1854   {
1855     g_object_unref ( vtl->track_bg_gc );
1856     vtl->track_bg_gc = NULL;
1857   }
1858   if ( vtl->track_1color_gc )
1859   {
1860     g_object_unref ( vtl->track_1color_gc );
1861     vtl->track_1color_gc = NULL;
1862   }
1863   if ( vtl->current_track_gc ) 
1864   {
1865     g_object_unref ( vtl->current_track_gc );
1866     vtl->current_track_gc = NULL;
1867   }
1868   if ( vtl->current_track_newpoint_gc )
1869   {
1870     g_object_unref ( vtl->current_track_newpoint_gc );
1871     vtl->current_track_newpoint_gc = NULL;
1872   }
1873
1874   if ( ! vtl->track_gc )
1875     return;
1876   for ( i = vtl->track_gc->len - 1; i >= 0; i-- )
1877     g_object_unref ( g_array_index ( vtl->track_gc, GObject *, i ) );
1878   g_array_free ( vtl->track_gc, TRUE );
1879   vtl->track_gc = NULL;
1880 }
1881
1882 static void trw_layer_new_track_gcs ( VikTrwLayer *vtl, VikViewport *vp )
1883 {
1884   GdkGC *gc[ VIK_TRW_LAYER_TRACK_GC ];
1885   gint width = vtl->line_thickness;
1886
1887   if ( vtl->track_gc )
1888     trw_layer_free_track_gcs ( vtl );
1889
1890   if ( vtl->track_bg_gc )
1891     g_object_unref ( vtl->track_bg_gc );
1892   vtl->track_bg_gc = vik_viewport_new_gc_from_color ( vp, &(vtl->track_bg_color), width + vtl->bg_line_thickness );
1893
1894   // Ensure new track drawing heeds line thickness setting
1895   //  however always have a minium of 2, as 1 pixel is really narrow
1896   gint new_track_width = (vtl->line_thickness < 2) ? 2 : vtl->line_thickness;
1897   
1898   if ( vtl->current_track_gc )
1899     g_object_unref ( vtl->current_track_gc );
1900   vtl->current_track_gc = vik_viewport_new_gc ( vp, "#FF0000", new_track_width );
1901   gdk_gc_set_line_attributes ( vtl->current_track_gc, new_track_width, GDK_LINE_ON_OFF_DASH, GDK_CAP_ROUND, GDK_JOIN_ROUND );
1902
1903   // 'newpoint' gc is exactly the same as the current track gc
1904   if ( vtl->current_track_newpoint_gc )
1905     g_object_unref ( vtl->current_track_newpoint_gc );
1906   vtl->current_track_newpoint_gc = vik_viewport_new_gc ( vp, "#FF0000", new_track_width );
1907   gdk_gc_set_line_attributes ( vtl->current_track_newpoint_gc, new_track_width, GDK_LINE_ON_OFF_DASH, GDK_CAP_ROUND, GDK_JOIN_ROUND );
1908
1909   vtl->track_gc = g_array_sized_new ( FALSE, FALSE, sizeof ( GdkGC * ), VIK_TRW_LAYER_TRACK_GC );
1910
1911   gc[VIK_TRW_LAYER_TRACK_GC_STOP] = vik_viewport_new_gc ( vp, "#874200", width );
1912   gc[VIK_TRW_LAYER_TRACK_GC_BLACK] = vik_viewport_new_gc ( vp, "#000000", width ); // black
1913
1914   gc[VIK_TRW_LAYER_TRACK_GC_SLOW] = vik_viewport_new_gc ( vp, "#E6202E", width ); // red-ish
1915   gc[VIK_TRW_LAYER_TRACK_GC_AVER] = vik_viewport_new_gc ( vp, "#D2CD26", width ); // yellow-ish
1916   gc[VIK_TRW_LAYER_TRACK_GC_FAST] = vik_viewport_new_gc ( vp, "#2B8700", width ); // green-ish
1917
1918   gc[VIK_TRW_LAYER_TRACK_GC_SINGLE] = vik_viewport_new_gc_from_color ( vp, &(vtl->track_color), width );
1919
1920   g_array_append_vals ( vtl->track_gc, gc, VIK_TRW_LAYER_TRACK_GC );
1921 }
1922
1923 static VikTrwLayer* trw_layer_create ( VikViewport *vp )
1924 {
1925   VikTrwLayer *rv = trw_layer_new1 ( vp );
1926   vik_layer_rename ( VIK_LAYER(rv), vik_trw_layer_interface.name );
1927
1928   if ( vp == NULL || gtk_widget_get_window(GTK_WIDGET(vp)) == NULL ) {
1929     /* early exit, as the rest is GUI related */
1930     return rv;
1931   }
1932
1933   rv->wplabellayout = gtk_widget_create_pango_layout (GTK_WIDGET(vp), NULL);
1934   pango_layout_set_font_description (rv->wplabellayout, gtk_widget_get_style(GTK_WIDGET(vp))->font_desc);
1935
1936   trw_layer_new_track_gcs ( rv, vp );
1937
1938   rv->waypoint_gc = vik_viewport_new_gc_from_color ( vp, &(rv->waypoint_color), 2 );
1939   rv->waypoint_text_gc = vik_viewport_new_gc_from_color ( vp, &(rv->waypoint_text_color), 1 );
1940   rv->waypoint_bg_gc = vik_viewport_new_gc_from_color ( vp, &(rv->waypoint_bg_color), 1 );
1941   gdk_gc_set_function ( rv->waypoint_bg_gc, rv->wpbgand );
1942
1943   rv->coord_mode = vik_viewport_get_coord_mode ( vp );
1944
1945   rv->menu_selection = vik_layer_get_interface(VIK_LAYER(rv)->type)->menu_items_selection;
1946
1947   return rv;
1948 }
1949
1950 #define SMALL_ICON_SIZE 18
1951 /*
1952  * Can accept a null symbol, and may return null value
1953  */
1954 static GdkPixbuf* get_wp_sym_small ( gchar *symbol )
1955 {
1956   GdkPixbuf* wp_icon = a_get_wp_sym (symbol);
1957   // ATM a_get_wp_sym returns a cached icon, with the size dependent on the preferences.
1958   //  So needing a small icon for the treeview may need some resizing:
1959   if ( wp_icon && gdk_pixbuf_get_width ( wp_icon ) != SMALL_ICON_SIZE )
1960     wp_icon = gdk_pixbuf_scale_simple ( wp_icon, SMALL_ICON_SIZE, SMALL_ICON_SIZE, GDK_INTERP_BILINEAR );
1961   return wp_icon;
1962 }
1963
1964 static void trw_layer_realize_track ( gpointer id, VikTrack *track, gpointer pass_along[5] )
1965 {
1966   GtkTreeIter *new_iter = g_malloc(sizeof(GtkTreeIter));
1967
1968   GdkPixbuf *pixbuf = NULL;
1969
1970   if ( track->has_color ) {
1971     pixbuf = gdk_pixbuf_new ( GDK_COLORSPACE_RGB, FALSE, 8, SMALL_ICON_SIZE, SMALL_ICON_SIZE );
1972     // Annoyingly the GdkColor.pixel does not give the correct color when passed to gdk_pixbuf_fill (even when alloc'ed)
1973     // Here is some magic found to do the conversion
1974     // http://www.cs.binghamton.edu/~sgreene/cs360-2011s/topics/gtk+-2.20.1/gtk/gtkcolorbutton.c
1975     guint32 pixel = ((track->color.red & 0xff00) << 16) |
1976       ((track->color.green & 0xff00) << 8) |
1977       (track->color.blue & 0xff00);
1978
1979     gdk_pixbuf_fill ( pixbuf, pixel );
1980   }
1981
1982   vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], track->name, pass_along[2], id, GPOINTER_TO_INT (pass_along[4]), pixbuf, TRUE, TRUE );
1983
1984   if ( pixbuf )
1985     g_object_unref (pixbuf);
1986
1987   *new_iter = *((GtkTreeIter *) pass_along[1]);
1988   if ( track->is_route )
1989     g_hash_table_insert ( VIK_TRW_LAYER(pass_along[2])->routes_iters, id, new_iter );
1990   else
1991     g_hash_table_insert ( VIK_TRW_LAYER(pass_along[2])->tracks_iters, id, new_iter );
1992
1993   if ( ! track->visible )
1994     vik_treeview_item_set_visible ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[1], FALSE );
1995 }
1996
1997 static void trw_layer_realize_waypoint ( gpointer id, VikWaypoint *wp, gpointer pass_along[5] )
1998 {
1999   GtkTreeIter *new_iter = g_malloc(sizeof(GtkTreeIter));
2000
2001   vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], wp->name, pass_along[2], id, GPOINTER_TO_UINT (pass_along[4]), get_wp_sym_small (wp->symbol), TRUE, TRUE );
2002
2003   *new_iter = *((GtkTreeIter *) pass_along[1]);
2004   g_hash_table_insert ( VIK_TRW_LAYER(pass_along[2])->waypoints_iters, id, new_iter );
2005
2006   if ( ! wp->visible )
2007     vik_treeview_item_set_visible ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[1], FALSE );
2008 }
2009
2010 static void trw_layer_add_sublayer_tracks ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter )
2011 {
2012   vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->tracks_iter), _("Tracks"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_TRACKS, NULL, TRUE, FALSE );
2013 }
2014
2015 static void trw_layer_add_sublayer_waypoints ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter )
2016 {
2017   vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->waypoints_iter), _("Waypoints"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINTS, NULL, TRUE, FALSE );
2018 }
2019
2020 static void trw_layer_add_sublayer_routes ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter )
2021 {
2022   vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->routes_iter), _("Routes"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_ROUTES, NULL, TRUE, FALSE );
2023 }
2024
2025 static void trw_layer_realize ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter )
2026 {
2027   GtkTreeIter iter2;
2028   gpointer pass_along[5] = { &(vtl->tracks_iter), &iter2, vtl, vt, GINT_TO_POINTER(VIK_TRW_LAYER_SUBLAYER_TRACK) };
2029
2030   if ( g_hash_table_size (vtl->tracks) > 0 ) {
2031     trw_layer_add_sublayer_tracks ( vtl, vt , layer_iter );
2032
2033     g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_realize_track, pass_along );
2034
2035     vik_treeview_item_set_visible ( vt, &(vtl->tracks_iter), vtl->tracks_visible );
2036   }
2037
2038   if ( g_hash_table_size (vtl->routes) > 0 ) {
2039     trw_layer_add_sublayer_routes ( vtl, vt, layer_iter );
2040
2041     pass_along[0] = &(vtl->routes_iter);
2042     pass_along[4] = GINT_TO_POINTER(VIK_TRW_LAYER_SUBLAYER_ROUTE);
2043
2044     g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_realize_track, pass_along );
2045
2046     vik_treeview_item_set_visible ( (VikTreeview *) vt, &(vtl->routes_iter), vtl->routes_visible );
2047   }
2048
2049   if ( g_hash_table_size (vtl->waypoints) > 0 ) {
2050     trw_layer_add_sublayer_waypoints ( vtl, vt, layer_iter );
2051
2052     pass_along[0] = &(vtl->waypoints_iter);
2053     pass_along[4] = GINT_TO_POINTER(VIK_TRW_LAYER_SUBLAYER_WAYPOINT);
2054
2055     g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_realize_waypoint, pass_along );
2056
2057     vik_treeview_item_set_visible ( (VikTreeview *) vt, &(vtl->waypoints_iter), vtl->waypoints_visible );
2058   }
2059
2060 }
2061
2062 static gboolean trw_layer_sublayer_toggle_visible ( VikTrwLayer *l, gint subtype, gpointer sublayer )
2063 {
2064   switch ( subtype )
2065   {
2066     case VIK_TRW_LAYER_SUBLAYER_TRACKS: return (l->tracks_visible ^= 1);
2067     case VIK_TRW_LAYER_SUBLAYER_WAYPOINTS: return (l->waypoints_visible ^= 1);
2068     case VIK_TRW_LAYER_SUBLAYER_ROUTES: return (l->routes_visible ^= 1);
2069     case VIK_TRW_LAYER_SUBLAYER_TRACK:
2070     {
2071       VikTrack *t = g_hash_table_lookup ( l->tracks, sublayer );
2072       if (t)
2073         return (t->visible ^= 1);
2074       else
2075         return TRUE;
2076     }
2077     case VIK_TRW_LAYER_SUBLAYER_WAYPOINT:
2078     {
2079       VikWaypoint *t = g_hash_table_lookup ( l->waypoints, sublayer );
2080       if (t)
2081         return (t->visible ^= 1);
2082       else
2083         return TRUE;
2084     }
2085     case VIK_TRW_LAYER_SUBLAYER_ROUTE:
2086     {
2087       VikTrack *t = g_hash_table_lookup ( l->routes, sublayer );
2088       if (t)
2089         return (t->visible ^= 1);
2090       else
2091         return TRUE;
2092     }
2093   }
2094   return TRUE;
2095 }
2096
2097 /*
2098  * Return a property about tracks for this layer
2099  */
2100 gint vik_trw_layer_get_property_tracks_line_thickness ( VikTrwLayer *vtl )
2101 {
2102   return vtl->line_thickness;
2103 }
2104
2105 // Structure to hold multiple track information for a layer
2106 typedef struct {
2107   gdouble length;
2108   time_t  start_time;
2109   time_t  end_time;
2110   gint    duration;
2111 } tooltip_tracks;
2112
2113 /*
2114  * Build up layer multiple track information via updating the tooltip_tracks structure
2115  */
2116 static void trw_layer_tracks_tooltip ( const gchar *name, VikTrack *tr, tooltip_tracks *tt )
2117 {
2118   tt->length = tt->length + vik_track_get_length (tr);
2119
2120   // Ensure times are available
2121   if ( tr->trackpoints &&
2122        VIK_TRACKPOINT(tr->trackpoints->data)->has_timestamp &&
2123        VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->has_timestamp ) {
2124
2125     time_t t1, t2;
2126     t1 = VIK_TRACKPOINT(tr->trackpoints->data)->timestamp;
2127     t2 = VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp;
2128
2129     // Assume never actually have a track with a time of 0 (1st Jan 1970)
2130     // Hence initialize to the first 'proper' value
2131     if ( tt->start_time == 0 )
2132         tt->start_time = t1;
2133     if ( tt->end_time == 0 )
2134         tt->end_time = t2;
2135
2136     // Update find the earliest / last times
2137     if ( t1 < tt->start_time )
2138         tt->start_time = t1;
2139     if ( t2 > tt->end_time )
2140         tt->end_time = t2;
2141
2142     // Keep track of total time
2143     //  there maybe gaps within a track (eg segments)
2144     //  but this should be generally good enough for a simple indicator
2145     tt->duration = tt->duration + (int)(t2-t1);
2146   }
2147 }
2148
2149 /*
2150  * Generate tooltip text for the layer.
2151  * This is relatively complicated as it considers information for
2152  *   no tracks, a single track or multiple tracks
2153  *     (which may or may not have timing information)
2154  */
2155 static const gchar* trw_layer_layer_tooltip ( VikTrwLayer *vtl )
2156 {
2157   gchar tbuf1[32];
2158   gchar tbuf2[64];
2159   gchar tbuf3[64];
2160   gchar tbuf4[10];
2161   tbuf1[0] = '\0';
2162   tbuf2[0] = '\0';
2163   tbuf3[0] = '\0';
2164   tbuf4[0] = '\0';
2165
2166   static gchar tmp_buf[128];
2167   tmp_buf[0] = '\0';
2168
2169   // For compact date format I'm using '%x'     [The preferred date representation for the current locale without the time.]
2170
2171   // Safety check - I think these should always be valid
2172   if ( vtl->tracks && vtl->waypoints ) {
2173     tooltip_tracks tt = { 0.0, 0, 0 };
2174     g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_tracks_tooltip, &tt );
2175
2176     GDate* gdate_start = g_date_new ();
2177     g_date_set_time_t (gdate_start, tt.start_time);
2178
2179     GDate* gdate_end = g_date_new ();
2180     g_date_set_time_t (gdate_end, tt.end_time);
2181
2182     if ( g_date_compare (gdate_start, gdate_end) ) {
2183       // Dates differ so print range on separate line
2184       g_date_strftime (tbuf1, sizeof(tbuf1), "%x", gdate_start);
2185       g_date_strftime (tbuf2, sizeof(tbuf2), "%x", gdate_end);
2186       g_snprintf (tbuf3, sizeof(tbuf3), "%s to %s\n", tbuf1, tbuf2);
2187     }
2188     else {
2189       // Same date so just show it and keep rest of text on the same line - provided it's a valid time!
2190       if ( tt.start_time != 0 )
2191         g_date_strftime (tbuf3, sizeof(tbuf3), "%x: ", gdate_start);
2192     }
2193
2194     tbuf2[0] = '\0';
2195     if ( tt.length > 0.0 ) {
2196       gdouble len_in_units;
2197
2198       // Setup info dependent on distance units
2199       if ( a_vik_get_units_distance() == VIK_UNITS_DISTANCE_MILES ) {
2200         g_snprintf (tbuf4, sizeof(tbuf4), "miles");
2201         len_in_units = VIK_METERS_TO_MILES(tt.length);
2202       }
2203       else {
2204         g_snprintf (tbuf4, sizeof(tbuf4), "kms");
2205         len_in_units = tt.length/1000.0;
2206       }
2207
2208       // Timing information if available
2209       tbuf1[0] = '\0';
2210       if ( tt.duration > 0 ) {
2211         g_snprintf (tbuf1, sizeof(tbuf1),
2212                     _(" in %d:%02d hrs:mins"),
2213                     (int)round(tt.duration/3600), (int)round((tt.duration/60)%60));
2214       }
2215       g_snprintf (tbuf2, sizeof(tbuf2),
2216                   _("\n%sTotal Length %.1f %s%s"),
2217                   tbuf3, len_in_units, tbuf4, tbuf1);
2218     }
2219
2220     // Put together all the elements to form compact tooltip text
2221     g_snprintf (tmp_buf, sizeof(tmp_buf),
2222                 _("Tracks: %d - Waypoints: %d - Routes: %d%s"),
2223                 g_hash_table_size (vtl->tracks), g_hash_table_size (vtl->waypoints), g_hash_table_size (vtl->routes), tbuf2);
2224
2225     g_date_free (gdate_start);
2226     g_date_free (gdate_end);
2227
2228   }
2229
2230   return tmp_buf;
2231 }
2232
2233 static const gchar* trw_layer_sublayer_tooltip ( VikTrwLayer *l, gint subtype, gpointer sublayer )
2234 {
2235   switch ( subtype )
2236   {
2237     case VIK_TRW_LAYER_SUBLAYER_TRACKS:
2238     {
2239       // Very simple tooltip - may expand detail in the future...
2240       static gchar tmp_buf[32];
2241       g_snprintf (tmp_buf, sizeof(tmp_buf),
2242                   _("Tracks: %d"),
2243                   g_hash_table_size (l->tracks));
2244       return tmp_buf;
2245     }
2246     break;
2247     case VIK_TRW_LAYER_SUBLAYER_ROUTES:
2248     {
2249       // Very simple tooltip - may expand detail in the future...
2250       static gchar tmp_buf[32];
2251       g_snprintf (tmp_buf, sizeof(tmp_buf),
2252                   _("Routes: %d"),
2253                   g_hash_table_size (l->routes));
2254       return tmp_buf;
2255     }
2256     break;
2257
2258     case VIK_TRW_LAYER_SUBLAYER_ROUTE:
2259       // Same tooltip for a route
2260     case VIK_TRW_LAYER_SUBLAYER_TRACK:
2261     {
2262       VikTrack *tr;
2263       if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
2264         tr = g_hash_table_lookup ( l->tracks, sublayer );
2265       else
2266         tr = g_hash_table_lookup ( l->routes, sublayer );
2267
2268       if ( tr ) {
2269         // Could be a better way of handling strings - but this works...
2270         gchar time_buf1[20];
2271         gchar time_buf2[20];
2272         time_buf1[0] = '\0';
2273         time_buf2[0] = '\0';
2274         static gchar tmp_buf[100];
2275         // Compact info: Short date eg (11/20/99), duration and length
2276         // Hopefully these are the things that are most useful and so promoted into the tooltip
2277         if ( tr->trackpoints && VIK_TRACKPOINT(tr->trackpoints->data)->has_timestamp ) {
2278           // %x     The preferred date representation for the current locale without the time.
2279           strftime (time_buf1, sizeof(time_buf1), "%x: ", gmtime(&(VIK_TRACKPOINT(tr->trackpoints->data)->timestamp)));
2280           if ( VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->has_timestamp ) {
2281             gint dur = ( (VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp) - (VIK_TRACKPOINT(tr->trackpoints->data)->timestamp) );
2282             if ( dur > 0 )
2283               g_snprintf ( time_buf2, sizeof(time_buf2), _("- %d:%02d hrs:mins"), (int)round(dur/3600), (int)round((dur/60)%60) );
2284           }
2285         }
2286         // Get length and consider the appropriate distance units
2287         gdouble tr_len = vik_track_get_length(tr);
2288         vik_units_distance_t dist_units = a_vik_get_units_distance ();
2289         switch (dist_units) {
2290         case VIK_UNITS_DISTANCE_KILOMETRES:
2291           g_snprintf (tmp_buf, sizeof(tmp_buf), _("%s%.1f km %s"), time_buf1, tr_len/1000.0, time_buf2);
2292           break;
2293         case VIK_UNITS_DISTANCE_MILES:
2294           g_snprintf (tmp_buf, sizeof(tmp_buf), _("%s%.1f miles %s"), time_buf1, VIK_METERS_TO_MILES(tr_len), time_buf2);
2295           break;
2296         default:
2297           break;
2298         }
2299         return tmp_buf;
2300       }
2301     }
2302     break;
2303     case VIK_TRW_LAYER_SUBLAYER_WAYPOINTS:
2304     {
2305       // Very simple tooltip - may expand detail in the future...
2306       static gchar tmp_buf[32];
2307       g_snprintf (tmp_buf, sizeof(tmp_buf),
2308                   _("Waypoints: %d"),
2309                   g_hash_table_size (l->waypoints));
2310       return tmp_buf;
2311     }
2312     break;
2313     case VIK_TRW_LAYER_SUBLAYER_WAYPOINT:
2314     {
2315       VikWaypoint *w = g_hash_table_lookup ( l->waypoints, sublayer );
2316       // NB It's OK to return NULL
2317       if ( w ) {
2318         if ( w->comment )
2319           return w->comment;
2320         else
2321           return w->description;
2322       }
2323     }
2324     break;
2325     default: break;
2326   }
2327   return NULL;
2328 }
2329
2330 /*
2331  * Function to show basic track point information on the statusbar
2332  */
2333 static void set_statusbar_msg_info_trkpt ( VikTrwLayer *vtl, VikTrackpoint *trkpt )
2334 {
2335   gchar tmp_buf1[64];
2336   switch (a_vik_get_units_height ()) {
2337   case VIK_UNITS_HEIGHT_FEET:
2338     g_snprintf(tmp_buf1, sizeof(tmp_buf1), _("Trkpt: Alt %dft"), (int)round(VIK_METERS_TO_FEET(trkpt->altitude)));
2339     break;
2340   default:
2341     //VIK_UNITS_HEIGHT_METRES:
2342     g_snprintf(tmp_buf1, sizeof(tmp_buf1), _("Trkpt: Alt %dm"), (int)round(trkpt->altitude));
2343   }
2344   
2345   gchar tmp_buf2[64];
2346   tmp_buf2[0] = '\0';
2347   if ( trkpt->has_timestamp ) {
2348     // Compact date time format
2349     strftime (tmp_buf2, sizeof(tmp_buf2), _(" | Time %x %X"), localtime(&(trkpt->timestamp)));
2350   }
2351
2352   // Position part
2353   // Position is put later on, as this bit may not be seen if the display is not big enough,
2354   //   one can easily use the current pointer position to see this if needed
2355   gchar *lat = NULL, *lon = NULL;
2356   static struct LatLon ll;
2357   vik_coord_to_latlon (&(trkpt->coord), &ll);
2358   a_coords_latlon_to_string ( &ll, &lat, &lon );
2359
2360   // Track name
2361   // Again is put later on, as this bit may not be seen if the display is not big enough
2362   //  trackname can be seen from the treeview (when enabled)
2363   // Also name could be very long to not leave room for anything else
2364   gchar tmp_buf3[64];
2365   tmp_buf3[0] = '\0';
2366   if ( vtl->current_tp_track ) {
2367     g_snprintf(tmp_buf3, sizeof(tmp_buf3),  _(" | Track: %s"), vtl->current_tp_track->name );
2368   }
2369
2370   // Combine parts to make overall message
2371   gchar *msg = g_strdup_printf (_("%s%s | %s %s %s"), tmp_buf1, tmp_buf2, lat, lon, tmp_buf3);
2372   vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO, msg );
2373   g_free ( lat );
2374   g_free ( lon );
2375   g_free ( msg );
2376 }
2377
2378 /*
2379  * Function to show basic waypoint information on the statusbar
2380  */
2381 static void set_statusbar_msg_info_wpt ( VikTrwLayer *vtl, VikWaypoint *wpt )
2382 {
2383   gchar tmp_buf1[64];
2384   switch (a_vik_get_units_height ()) {
2385   case VIK_UNITS_HEIGHT_FEET:
2386     g_snprintf(tmp_buf1, sizeof(tmp_buf1), _("Wpt: Alt %dft"), (int)round(VIK_METERS_TO_FEET(wpt->altitude)));
2387     break;
2388   default:
2389     //VIK_UNITS_HEIGHT_METRES:
2390     g_snprintf(tmp_buf1, sizeof(tmp_buf1), _("Wpt: Alt %dm"), (int)round(wpt->altitude));
2391   }
2392   
2393   // Position part
2394   // Position is put last, as this bit is most likely not to be seen if the display is not big enough,
2395   //   one can easily use the current pointer position to see this if needed
2396   gchar *lat = NULL, *lon = NULL;
2397   static struct LatLon ll;
2398   vik_coord_to_latlon (&(wpt->coord), &ll);
2399   a_coords_latlon_to_string ( &ll, &lat, &lon );
2400
2401   // Combine parts to make overall message
2402   gchar *msg;
2403   if ( wpt->comment )
2404     // Add comment if available
2405     msg = g_strdup_printf ( _("%s | %s %s | Comment: %s"), tmp_buf1, lat, lon, wpt->comment );
2406   else
2407     msg = g_strdup_printf ( _("%s | %s %s"), tmp_buf1, lat, lon );
2408   vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO, msg );
2409   g_free ( lat );
2410   g_free ( lon );
2411   g_free ( msg );
2412 }
2413
2414 /**
2415  * General layer selection function, find out which bit is selected and take appropriate action
2416  */
2417 static gboolean trw_layer_selected ( VikTrwLayer *l, gint subtype, gpointer sublayer, gint type, gpointer vlp )
2418 {
2419   // Reset
2420   l->current_wp    = NULL;
2421   l->current_wp_id = NULL;
2422   trw_layer_cancel_current_tp ( l, FALSE );
2423
2424   // Clear statusbar
2425   vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(l))), VIK_STATUSBAR_INFO, "" );
2426
2427   switch ( type )
2428     {
2429     case VIK_TREEVIEW_TYPE_LAYER:
2430       {
2431         vik_window_set_selected_trw_layer ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), l );
2432         /* Mark for redraw */
2433         return TRUE;
2434       }
2435       break;
2436
2437     case VIK_TREEVIEW_TYPE_SUBLAYER:
2438       {
2439         switch ( subtype )
2440           {
2441           case VIK_TRW_LAYER_SUBLAYER_TRACKS:
2442             {
2443               vik_window_set_selected_tracks ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), l->tracks, l );
2444               /* Mark for redraw */
2445               return TRUE;
2446             }
2447             break;
2448           case VIK_TRW_LAYER_SUBLAYER_TRACK:
2449             {
2450               VikTrack *track = g_hash_table_lookup ( l->tracks, sublayer );
2451               vik_window_set_selected_track ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), (gpointer)track, l );
2452               /* Mark for redraw */
2453               return TRUE;
2454             }
2455             break;
2456           case VIK_TRW_LAYER_SUBLAYER_ROUTES:
2457             {
2458               vik_window_set_selected_tracks ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), l->routes, l );
2459               /* Mark for redraw */
2460               return TRUE;
2461             }
2462             break;
2463           case VIK_TRW_LAYER_SUBLAYER_ROUTE:
2464             {
2465               VikTrack *track = g_hash_table_lookup ( l->routes, sublayer );
2466               vik_window_set_selected_track ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), (gpointer)track, l );
2467               /* Mark for redraw */
2468               return TRUE;
2469             }
2470             break;
2471           case VIK_TRW_LAYER_SUBLAYER_WAYPOINTS:
2472             {
2473               vik_window_set_selected_waypoints ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), l->waypoints, l );
2474               /* Mark for redraw */
2475               return TRUE;
2476             }
2477             break;
2478           case VIK_TRW_LAYER_SUBLAYER_WAYPOINT:
2479             {
2480               VikWaypoint *wpt = g_hash_table_lookup ( l->waypoints, sublayer );
2481               if ( wpt ) {
2482                 vik_window_set_selected_waypoint ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l), (gpointer)wpt, l );
2483                 // Show some waypoint info
2484                 set_statusbar_msg_info_wpt ( l, wpt );
2485                 /* Mark for redraw */
2486                 return TRUE;
2487               }
2488             }
2489             break;
2490           default:
2491             {
2492               return vik_window_clear_highlight ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l) );
2493             }
2494             break;
2495           }
2496         return FALSE;
2497       }
2498       break;
2499
2500     default:
2501       return vik_window_clear_highlight ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(l) );
2502       break;
2503     }
2504 }
2505
2506 GHashTable *vik_trw_layer_get_tracks ( VikTrwLayer *l )
2507 {
2508   return l->tracks;
2509 }
2510
2511 GHashTable *vik_trw_layer_get_routes ( VikTrwLayer *l )
2512 {
2513   return l->routes;
2514 }
2515
2516 GHashTable *vik_trw_layer_get_waypoints ( VikTrwLayer *l )
2517 {
2518   return l->waypoints;
2519 }
2520
2521 gboolean vik_trw_layer_is_empty ( VikTrwLayer *vtl )
2522 {
2523   return ! ( g_hash_table_size ( vtl->tracks ) ||
2524              g_hash_table_size ( vtl->routes ) ||
2525              g_hash_table_size ( vtl->waypoints ) );
2526 }
2527
2528 gboolean vik_trw_layer_get_tracks_visibility ( VikTrwLayer *vtl )
2529 {
2530   return vtl->tracks_visible;
2531 }
2532
2533 gboolean vik_trw_layer_get_routes_visibility ( VikTrwLayer *vtl )
2534 {
2535   return vtl->routes_visible;
2536 }
2537
2538 gboolean vik_trw_layer_get_waypoints_visibility ( VikTrwLayer *vtl )
2539 {
2540   return vtl->waypoints_visible;
2541 }
2542
2543 /*
2544  * ATM use a case sensitive find
2545  * Finds the first one
2546  */
2547 static gboolean trw_layer_waypoint_find ( const gpointer id, const VikWaypoint *wp, const gchar *name )
2548 {
2549   if ( wp && wp->name )
2550     if ( ! strcmp ( wp->name, name ) )
2551       return TRUE;
2552   return FALSE;
2553 }
2554
2555 /*
2556  * Get waypoint by name - not guaranteed to be unique
2557  * Finds the first one
2558  */
2559 VikWaypoint *vik_trw_layer_get_waypoint ( VikTrwLayer *vtl, const gchar *name )
2560 {
2561   return g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find, (gpointer) name );
2562 }
2563
2564 /*
2565  * ATM use a case sensitive find
2566  * Finds the first one
2567  */
2568 static gboolean trw_layer_track_find ( const gpointer id, const VikTrack *trk, const gchar *name )
2569 {
2570   if ( trk && trk->name )
2571     if ( ! strcmp ( trk->name, name ) )
2572       return TRUE;
2573   return FALSE;
2574 }
2575
2576 /*
2577  * Get track by name - not guaranteed to be unique
2578  * Finds the first one
2579  */
2580 VikTrack *vik_trw_layer_get_track ( VikTrwLayer *vtl, const gchar *name )
2581 {
2582   return g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find, (gpointer) name );
2583 }
2584
2585 /*
2586  * Get route by name - not guaranteed to be unique
2587  * Finds the first one
2588  */
2589 VikTrack *vik_trw_layer_get_route ( VikTrwLayer *vtl, const gchar *name )
2590 {
2591   return g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find, (gpointer) name );
2592 }
2593
2594 static void trw_layer_find_maxmin_tracks ( const gpointer id, const VikTrack *trk, struct LatLon maxmin[2] )
2595 {
2596   if ( trk->bbox.north > maxmin[0].lat || maxmin[0].lat == 0.0 )
2597     maxmin[0].lat = trk->bbox.north;
2598   if ( trk->bbox.south < maxmin[1].lat || maxmin[1].lat == 0.0 )
2599     maxmin[1].lat = trk->bbox.south;
2600   if ( trk->bbox.east > maxmin[0].lon || maxmin[0].lon == 0.0 )
2601     maxmin[0].lon = trk->bbox.east;
2602   if ( trk->bbox.west < maxmin[1].lon || maxmin[1].lon == 0.0 )
2603     maxmin[1].lon = trk->bbox.west;
2604 }
2605
2606 static void trw_layer_find_maxmin (VikTrwLayer *vtl, struct LatLon maxmin[2])
2607 {
2608   // Continually reuse maxmin to find the latest maximum and minimum values
2609   // First set to waypoints bounds
2610   maxmin[0].lat = vtl->waypoints_bbox.north;
2611   maxmin[1].lat = vtl->waypoints_bbox.south;
2612   maxmin[0].lon = vtl->waypoints_bbox.east;
2613   maxmin[1].lon = vtl->waypoints_bbox.west;
2614   g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_find_maxmin_tracks, maxmin );
2615   g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_find_maxmin_tracks, maxmin );
2616 }
2617
2618 gboolean vik_trw_layer_find_center ( VikTrwLayer *vtl, VikCoord *dest )
2619 {
2620   /* TODO: what if there's only one waypoint @ 0,0, it will think nothing found. like I don't have more important things to worry about... */
2621   struct LatLon maxmin[2] = { {0.0,0.0}, {0.0,0.0} };
2622   trw_layer_find_maxmin (vtl, maxmin);
2623   if (maxmin[0].lat == 0.0 && maxmin[0].lon == 0.0 && maxmin[1].lat == 0.0 && maxmin[1].lon == 0.0)
2624     return FALSE;
2625   else
2626   {
2627     struct LatLon average = { (maxmin[0].lat+maxmin[1].lat)/2, (maxmin[0].lon+maxmin[1].lon)/2 };
2628     vik_coord_load_from_latlon ( dest, vtl->coord_mode, &average );
2629     return TRUE;
2630   }
2631 }
2632
2633 static void trw_layer_centerize ( gpointer layer_and_vlp[2] )
2634 {
2635   VikCoord coord;
2636   if ( vik_trw_layer_find_center ( VIK_TRW_LAYER(layer_and_vlp[0]), &coord ) )
2637     goto_coord ( layer_and_vlp[1], NULL, NULL, &coord );
2638   else
2639     a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("This layer has no waypoints or trackpoints.") );
2640 }
2641
2642 static void trw_layer_zoom_to_show_latlons ( VikTrwLayer *vtl, VikViewport *vvp, struct LatLon maxmin[2] )
2643 {
2644   /* First set the center [in case previously viewing from elsewhere] */
2645   /* Then loop through zoom levels until provided positions are in view */
2646   /* This method is not particularly fast - but should work well enough */
2647   struct LatLon average = { (maxmin[0].lat+maxmin[1].lat)/2, (maxmin[0].lon+maxmin[1].lon)/2 };
2648   VikCoord coord;
2649   vik_coord_load_from_latlon ( &coord, vtl->coord_mode, &average );
2650   vik_viewport_set_center_coord ( vvp, &coord );
2651
2652   /* Convert into definite 'smallest' and 'largest' positions */
2653   struct LatLon minmin;
2654   if ( maxmin[0].lat < maxmin[1].lat )
2655     minmin.lat = maxmin[0].lat;
2656   else
2657     minmin.lat = maxmin[1].lat;
2658
2659   struct LatLon maxmax;
2660   if ( maxmin[0].lon > maxmin[1].lon )
2661     maxmax.lon = maxmin[0].lon;
2662   else
2663     maxmax.lon = maxmin[1].lon;
2664
2665   /* Never zoom in too far - generally not that useful, as too close ! */
2666   /* Always recalculate the 'best' zoom level */
2667   gdouble zoom = 1.0;
2668   vik_viewport_set_zoom ( vvp, zoom );
2669
2670   gdouble min_lat, max_lat, min_lon, max_lon;
2671   /* Should only be a maximum of about 18 iterations from min to max zoom levels */
2672   while ( zoom <= VIK_VIEWPORT_MAX_ZOOM ) {
2673     vik_viewport_get_min_max_lat_lon ( vvp, &min_lat, &max_lat, &min_lon, &max_lon );
2674     /* NB I think the logic used in this test to determine if the bounds is within view
2675        fails if track goes across 180 degrees longitude.
2676        Hopefully that situation is not too common...
2677        Mind you viking doesn't really do edge locations to well anyway */
2678     if ( min_lat < minmin.lat &&
2679          max_lat > minmin.lat &&
2680          min_lon < maxmax.lon &&
2681          max_lon > maxmax.lon )
2682       /* Found within zoom level */
2683       break;
2684
2685     /* Try next */
2686     zoom = zoom * 2;
2687     vik_viewport_set_zoom ( vvp, zoom );
2688   }
2689 }
2690
2691 gboolean vik_trw_layer_auto_set_view ( VikTrwLayer *vtl, VikViewport *vvp )
2692 {
2693   /* TODO: what if there's only one waypoint @ 0,0, it will think nothing found. */
2694   struct LatLon maxmin[2] = { {0.0,0.0}, {0.0,0.0} };
2695   trw_layer_find_maxmin (vtl, maxmin);
2696   if (maxmin[0].lat == 0.0 && maxmin[0].lon == 0.0 && maxmin[1].lat == 0.0 && maxmin[1].lon == 0.0)
2697     return FALSE;
2698   else {
2699     trw_layer_zoom_to_show_latlons ( vtl, vvp, maxmin );
2700     return TRUE;
2701   }
2702 }
2703
2704 static void trw_layer_auto_view ( gpointer layer_and_vlp[2] )
2705 {
2706   if ( vik_trw_layer_auto_set_view ( VIK_TRW_LAYER(layer_and_vlp[0]), vik_layers_panel_get_viewport (VIK_LAYERS_PANEL(layer_and_vlp[1])) ) ) {
2707     vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(layer_and_vlp[1]) );
2708   }
2709   else
2710     a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("This layer has no waypoints or trackpoints.") );
2711 }
2712
2713 static void trw_layer_export ( gpointer layer_and_vlp[2], const gchar *title, const gchar* default_name, VikTrack* trk, guint file_type )
2714 {
2715   GtkWidget *file_selector;
2716   const gchar *fn;
2717   gboolean failed = FALSE;
2718   file_selector = gtk_file_chooser_dialog_new (title,
2719                                                NULL,
2720                                                GTK_FILE_CHOOSER_ACTION_SAVE,
2721                                                GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
2722                                                GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
2723                                                NULL);
2724   gchar *cwd = g_get_current_dir();
2725   if ( cwd ) {
2726     gtk_file_chooser_set_current_folder ( GTK_FILE_CHOOSER(file_selector), cwd );
2727     g_free ( cwd );
2728   }
2729
2730   gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER(file_selector), default_name);
2731
2732   while ( gtk_dialog_run ( GTK_DIALOG(file_selector) ) == GTK_RESPONSE_ACCEPT )
2733   {
2734     fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(file_selector) );
2735     if ( g_file_test ( fn, G_FILE_TEST_EXISTS ) == FALSE )
2736     {
2737       gtk_widget_hide ( file_selector );
2738       vik_window_set_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0])) );
2739       failed = ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp[0]), fn, file_type, trk, TRUE );
2740       vik_window_clear_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0])) );
2741       break;
2742     }
2743     else
2744     {
2745       if ( a_dialog_yes_or_no ( GTK_WINDOW(file_selector), _("The file \"%s\" exists, do you wish to overwrite it?"), a_file_basename ( fn ) ) )
2746       {
2747         gtk_widget_hide ( file_selector );
2748         vik_window_set_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0])) );
2749         failed = ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp[0]), fn, file_type, trk, TRUE );
2750         vik_window_clear_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0])) );
2751         break;
2752       }
2753     }
2754   }
2755   gtk_widget_destroy ( file_selector );
2756   if ( failed )
2757     a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("The filename you requested could not be opened for writing.") );
2758 }
2759
2760 static void trw_layer_export_gpspoint ( gpointer layer_and_vlp[2] )
2761 {
2762   trw_layer_export ( layer_and_vlp, _("Export Layer"), vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])), NULL, FILE_TYPE_GPSPOINT );
2763 }
2764
2765 static void trw_layer_export_gpsmapper ( gpointer layer_and_vlp[2] )
2766 {
2767   trw_layer_export ( layer_and_vlp, _("Export Layer"), vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])), NULL, FILE_TYPE_GPSMAPPER );
2768 }
2769
2770 static void trw_layer_export_gpx ( gpointer layer_and_vlp[2] )
2771 {
2772   /* Auto append '.gpx' to track name (providing it's not already there) for the default filename */
2773   gchar *auto_save_name = g_strdup ( vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])) );
2774   if ( ! check_file_ext ( auto_save_name, ".gpx" ) )
2775     auto_save_name = g_strconcat ( auto_save_name, ".gpx", NULL );
2776
2777   trw_layer_export ( layer_and_vlp, _("Export Layer"), auto_save_name, NULL, FILE_TYPE_GPX );
2778
2779   g_free ( auto_save_name );
2780 }
2781
2782 static void trw_layer_export_kml ( gpointer layer_and_vlp[2] )
2783 {
2784   /* Auto append '.kml' to the name (providing it's not already there) for the default filename */
2785   gchar *auto_save_name = g_strdup ( vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])) );
2786   if ( ! check_file_ext ( auto_save_name, ".kml" ) )
2787     auto_save_name = g_strconcat ( auto_save_name, ".kml", NULL );
2788
2789   trw_layer_export ( layer_and_vlp, _("Export Layer"), auto_save_name, NULL, FILE_TYPE_KML );
2790
2791   g_free ( auto_save_name );
2792 }
2793
2794 /**
2795  * Convert the given TRW layer into a temporary GPX file and open it with the specified program
2796  *
2797  */
2798 static void trw_layer_export_external_gpx ( gpointer layer_and_vlp[2], const gchar* external_program )
2799 {
2800   gchar *name_used = NULL;
2801   int fd;
2802
2803   if ((fd = g_file_open_tmp("tmp-viking.XXXXXX.gpx", &name_used, NULL)) >= 0) {
2804     vik_window_set_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0])) );
2805     gboolean failed = ! a_file_export ( VIK_TRW_LAYER(layer_and_vlp[0]), name_used, FILE_TYPE_GPX, NULL, TRUE);
2806     vik_window_clear_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0])) );
2807     if (failed) {
2808       a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("Could not create temporary file for export.") );
2809     }
2810     else {
2811       GError *err = NULL;
2812       gchar *quoted_file = g_shell_quote ( name_used );
2813       gchar *cmd = g_strdup_printf ( "%s %s", external_program, quoted_file );
2814       g_free ( quoted_file );
2815       if ( ! g_spawn_command_line_async ( cmd, &err ) )
2816         {
2817           a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_LAYER( layer_and_vlp[0]), _("Could not launch %s."), external_program );
2818           g_error_free ( err );
2819         }
2820       g_free ( cmd );
2821     }
2822     // Note ATM the 'temporary' file is not deleted, as loading via another program is not instantaneous
2823     //g_remove ( name_used );
2824     // Perhaps should be deleted when the program ends?
2825     // For now leave it to the user to delete it / use system temp cleanup methods.
2826     g_free ( name_used );
2827   }
2828 }
2829
2830 static void trw_layer_export_external_gpx_1 ( gpointer layer_and_vlp[2] )
2831 {
2832   trw_layer_export_external_gpx ( layer_and_vlp, a_vik_get_external_gpx_program_1() );
2833 }
2834
2835 static void trw_layer_export_external_gpx_2 ( gpointer layer_and_vlp[2] )
2836 {
2837   trw_layer_export_external_gpx ( layer_and_vlp, a_vik_get_external_gpx_program_2() );
2838 }
2839
2840 static void trw_layer_export_gpx_track ( gpointer pass_along[6] )
2841 {
2842   gpointer layer_and_vlp[2];
2843   layer_and_vlp[0] = pass_along[0];
2844   layer_and_vlp[1] = pass_along[1];
2845
2846   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
2847   VikTrack *trk;
2848   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
2849     trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
2850   else
2851     trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
2852
2853   if ( !trk || !trk->name )
2854     return;
2855
2856   /* Auto append '.gpx' to track name (providing it's not already there) for the default filename */
2857   gchar *auto_save_name = g_strdup ( trk->name );
2858   if ( ! check_file_ext ( auto_save_name, ".gpx" ) )
2859     auto_save_name = g_strconcat ( auto_save_name, ".gpx", NULL );
2860
2861   trw_layer_export ( layer_and_vlp, _("Export Track as GPX"), auto_save_name, trk, FILE_TYPE_GPX );
2862
2863   g_free ( auto_save_name );
2864 }
2865
2866 typedef struct {
2867   VikWaypoint *wp; // input
2868   gpointer uuid;   // output
2869 } wpu_udata;
2870
2871 static gboolean trw_layer_waypoint_find_uuid ( const gpointer id, const VikWaypoint *wp, gpointer udata )
2872 {
2873   wpu_udata *user_data = udata;
2874   if ( wp == user_data->wp ) {
2875     user_data->uuid = id;
2876     return TRUE;
2877   }
2878   return FALSE;
2879 }
2880
2881 static void trw_layer_goto_wp ( gpointer layer_and_vlp[2] )
2882 {
2883   GtkWidget *dia = gtk_dialog_new_with_buttons (_("Find"),
2884                                                  VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]),
2885                                                  GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
2886                                                  GTK_STOCK_CANCEL,
2887                                                  GTK_RESPONSE_REJECT,
2888                                                  GTK_STOCK_OK,
2889                                                  GTK_RESPONSE_ACCEPT,
2890                                                  NULL);
2891
2892   GtkWidget *label, *entry;
2893   label = gtk_label_new(_("Waypoint Name:"));
2894   entry = gtk_entry_new();
2895
2896   gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dia))), label, FALSE, FALSE, 0);
2897   gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dia))), entry, FALSE, FALSE, 0);
2898   gtk_widget_show_all ( label );
2899   gtk_widget_show_all ( entry );
2900
2901   gtk_dialog_set_default_response ( GTK_DIALOG(dia), GTK_RESPONSE_ACCEPT );
2902
2903   while ( gtk_dialog_run ( GTK_DIALOG(dia) ) == GTK_RESPONSE_ACCEPT )
2904   {
2905     gchar *name = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
2906     // Find *first* wp with the given name
2907     VikWaypoint *wp = vik_trw_layer_get_waypoint ( VIK_TRW_LAYER(layer_and_vlp[0]), name );
2908
2909     if ( !wp )
2910       a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(layer_and_vlp[0]), _("Waypoint not found in this layer.") );
2911     else
2912     {
2913       vik_viewport_set_center_coord ( vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(layer_and_vlp[1])), &(wp->coord) );
2914       vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(layer_and_vlp[1]) );
2915
2916       // Find and select on the side panel
2917       wpu_udata udata;
2918       udata.wp   = wp;
2919       udata.uuid = NULL;
2920
2921       // Hmmm, want key of it
2922       gpointer *wpf = g_hash_table_find ( VIK_TRW_LAYER(layer_and_vlp[0])->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata );
2923
2924       if ( wpf && udata.uuid ) {
2925         GtkTreeIter *it = g_hash_table_lookup ( VIK_TRW_LAYER(layer_and_vlp[0])->waypoints_iters, udata.uuid );
2926         vik_treeview_select_iter ( VIK_LAYER(layer_and_vlp[0])->vt, it, TRUE );
2927       }
2928
2929       break;
2930     }
2931
2932     g_free ( name );
2933
2934   }
2935   gtk_widget_destroy ( dia );
2936 }
2937
2938 gboolean vik_trw_layer_new_waypoint ( VikTrwLayer *vtl, GtkWindow *w, const VikCoord *def_coord )
2939 {
2940   gchar *default_name = highest_wp_number_get(vtl);
2941   VikWaypoint *wp = vik_waypoint_new();
2942   gchar *returned_name;
2943   gboolean updated;
2944   wp->coord = *def_coord;
2945   
2946   // Attempt to auto set height if DEM data is available
2947   vik_waypoint_apply_dem_data ( wp, TRUE );
2948
2949   returned_name = a_dialog_waypoint ( w, default_name, vtl, wp, vtl->coord_mode, TRUE, &updated );
2950
2951   if ( returned_name )
2952   {
2953     wp->visible = TRUE;
2954     vik_trw_layer_add_waypoint ( vtl, returned_name, wp );
2955     g_free (default_name);
2956     g_free (returned_name);
2957     return TRUE;
2958   }
2959   g_free (default_name);
2960   vik_waypoint_free(wp);
2961   return FALSE;
2962 }
2963
2964 static void trw_layer_new_wikipedia_wp_viewport ( gpointer lav[2] )
2965 {
2966   struct LatLon maxmin[2] = { {0.0,0.0}, {0.0,0.0} };
2967   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
2968   VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
2969   VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
2970   VikViewport *vvp =  vik_window_viewport(vw);
2971
2972   // Note the order is max part first then min part - thus reverse order of use in min_max function:
2973   vik_viewport_get_min_max_lat_lon ( vvp, &maxmin[1].lat, &maxmin[0].lat, &maxmin[1].lon, &maxmin[0].lon );
2974   a_geonames_wikipedia_box((VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vtl, maxmin);
2975   trw_layer_calculate_bounds_waypoints ( vtl );
2976   vik_layers_panel_emit_update ( vlp );
2977 }
2978
2979 static void trw_layer_new_wikipedia_wp_layer ( gpointer lav[2] )
2980 {
2981   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
2982   VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
2983   struct LatLon maxmin[2] = { {0.0,0.0}, {0.0,0.0} };
2984   
2985   trw_layer_find_maxmin (vtl, maxmin);
2986   a_geonames_wikipedia_box((VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vtl, maxmin);
2987   trw_layer_calculate_bounds_waypoints ( vtl );
2988   vik_layers_panel_emit_update ( vlp );
2989 }
2990
2991 #ifdef VIK_CONFIG_GEOTAG
2992 static void trw_layer_geotagging_waypoint_mtime_keep ( gpointer pass_along[6] )
2993 {
2994   VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->waypoints, pass_along[3] );
2995   if ( wp )
2996     // Update directly - not changing the mtime
2997     a_geotag_write_exif_gps ( wp->image, wp->coord, wp->altitude, TRUE );
2998 }
2999
3000 static void trw_layer_geotagging_waypoint_mtime_update ( gpointer pass_along[6] )
3001 {
3002   VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->waypoints, pass_along[3] );
3003   if ( wp )
3004     // Update directly
3005     a_geotag_write_exif_gps ( wp->image, wp->coord, wp->altitude, FALSE );
3006 }
3007
3008 /*
3009  * Use code in separate file for this feature as reasonably complex
3010  */
3011 static void trw_layer_geotagging_track ( gpointer pass_along[6] )
3012 {
3013   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
3014   VikTrack *track = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
3015   // Unset so can be reverified later if necessary
3016   vtl->has_verified_thumbnails = FALSE;
3017
3018   trw_layer_geotag_dialog ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
3019                             vtl,
3020                             track,
3021                             track->name );
3022 }
3023
3024 static void trw_layer_geotagging ( gpointer lav[2] )
3025 {
3026   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
3027   // Unset so can be reverified later if necessary
3028   vtl->has_verified_thumbnails = FALSE;
3029
3030   trw_layer_geotag_dialog ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
3031                             vtl,
3032                             NULL,
3033                             NULL);
3034 }
3035 #endif
3036
3037 // 'Acquires' - Same as in File Menu -> Acquire - applies into the selected TRW Layer //
3038
3039 /*
3040  * Acquire into this TRW Layer straight from GPS Device
3041  */
3042 static void trw_layer_acquire_gps_cb ( gpointer lav[2] )
3043 {
3044   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
3045   VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
3046   VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
3047   VikViewport *vvp =  vik_window_viewport(vw);
3048
3049   vik_datasource_gps_interface.mode = VIK_DATASOURCE_ADDTOLAYER;
3050   a_acquire ( vw, vlp, vvp, &vik_datasource_gps_interface, NULL, NULL );
3051 }
3052
3053 /*
3054  * Acquire into this TRW Layer from Directions
3055  */
3056 static void trw_layer_acquire_routing_cb ( gpointer lav[2] )
3057 {
3058   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
3059   VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
3060   VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
3061   VikViewport *vvp =  vik_window_viewport(vw);
3062
3063   a_acquire ( vw, vlp, vvp, &vik_datasource_routing_interface, NULL, NULL );
3064 }
3065
3066 #ifdef VIK_CONFIG_OPENSTREETMAP
3067 /*
3068  * Acquire into this TRW Layer from OSM
3069  */
3070 static void trw_layer_acquire_osm_cb ( gpointer lav[2] )
3071 {
3072   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
3073   VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
3074   VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
3075   VikViewport *vvp =  vik_window_viewport(vw);
3076
3077   a_acquire ( vw, vlp, vvp, &vik_datasource_osm_interface, NULL, NULL );
3078 }
3079
3080 /**
3081  * Acquire into this TRW Layer from OSM for 'My' Traces
3082  */
3083 static void trw_layer_acquire_osm_my_traces_cb ( gpointer lav[2] )
3084 {
3085   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
3086   VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
3087   VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
3088   VikViewport *vvp =  vik_window_viewport(vw);
3089
3090   a_acquire ( vw, vlp, vvp, &vik_datasource_osm_my_traces_interface, NULL, NULL );
3091 }
3092 #endif
3093
3094 #ifdef VIK_CONFIG_GEOCACHES
3095 /*
3096  * Acquire into this TRW Layer from Geocaching.com
3097  */
3098 static void trw_layer_acquire_geocache_cb ( gpointer lav[2] )
3099 {
3100   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
3101   VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
3102   VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
3103   VikViewport *vvp =  vik_window_viewport(vw);
3104
3105   a_acquire ( vw, vlp, vvp, &vik_datasource_gc_interface, NULL, NULL );
3106 }
3107 #endif
3108
3109 #ifdef VIK_CONFIG_GEOTAG
3110 /*
3111  * Acquire into this TRW Layer from images
3112  */
3113 static void trw_layer_acquire_geotagged_cb ( gpointer lav[2] )
3114 {
3115   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
3116   VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
3117   VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
3118   VikViewport *vvp =  vik_window_viewport(vw);
3119
3120   vik_datasource_geotag_interface.mode = VIK_DATASOURCE_ADDTOLAYER;
3121   a_acquire ( vw, vlp, vvp, &vik_datasource_geotag_interface, NULL, NULL );
3122
3123   // Reverify thumbnails as they may have changed
3124   vtl->has_verified_thumbnails = FALSE;
3125   trw_layer_verify_thumbnails ( vtl, NULL );
3126 }
3127 #endif
3128
3129 static void trw_layer_gps_upload ( gpointer lav[2] )
3130 {
3131   gpointer pass_along[6];
3132   pass_along[0] = lav[0];
3133   pass_along[1] = lav[1];
3134   pass_along[2] = NULL; // No track - operate on the layer
3135   pass_along[3] = NULL;
3136   pass_along[4] = NULL;
3137   pass_along[5] = NULL;
3138
3139   trw_layer_gps_upload_any ( pass_along );
3140 }
3141
3142 /**
3143  * If pass_along[3] is defined that this will upload just that track
3144  */
3145 static void trw_layer_gps_upload_any ( gpointer pass_along[6] )
3146 {
3147   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
3148   VikLayersPanel *vlp = VIK_LAYERS_PANEL(pass_along[1]);
3149
3150   // May not actually get a track here as pass_along[2&3] can be null
3151   VikTrack *track = NULL;
3152   vik_gps_xfer_type xfer_type = TRK; // VIK_TRW_LAYER_SUBLAYER_TRACKS = 0 so hard to test different from NULL!
3153   gboolean xfer_all = FALSE;
3154
3155   if ( pass_along[2] ) {
3156     xfer_all = FALSE;
3157     if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) {
3158       track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
3159       xfer_type = RTE;
3160     }
3161     else if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
3162       track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
3163       xfer_type = TRK;
3164     }
3165     else if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS ) {
3166       xfer_type = WPT;
3167     }
3168     else if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTES ) {
3169       xfer_type = RTE;
3170     }
3171   }
3172   else if ( !pass_along[4] )
3173     xfer_all = TRUE; // i.e. whole layer
3174
3175   if (track && !track->visible) {
3176     a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Can not upload invisible track.") );
3177     return;
3178   }
3179
3180   GtkWidget *dialog = gtk_dialog_new_with_buttons ( _("GPS Upload"),
3181                                                     VIK_GTK_WINDOW_FROM_LAYER(pass_along[0]),
3182                                                     GTK_DIALOG_DESTROY_WITH_PARENT,
3183                                                     GTK_STOCK_OK,
3184                                                     GTK_RESPONSE_ACCEPT,
3185                                                     GTK_STOCK_CANCEL,
3186                                                     GTK_RESPONSE_REJECT,
3187                                                     NULL );
3188
3189   gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
3190   GtkWidget *response_w = NULL;
3191 #if GTK_CHECK_VERSION (2, 20, 0)
3192   response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
3193 #endif
3194
3195   if ( response_w )
3196     gtk_widget_grab_focus ( response_w );
3197
3198   gpointer dgs = datasource_gps_setup ( dialog, xfer_type, xfer_all );
3199
3200   if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) != GTK_RESPONSE_ACCEPT ) {
3201     datasource_gps_clean_up ( dgs );
3202     gtk_widget_destroy ( dialog );
3203     return;
3204   }
3205
3206   // Get info from reused datasource dialog widgets
3207   gchar* protocol = datasource_gps_get_protocol ( dgs );
3208   gchar* port = datasource_gps_get_descriptor ( dgs );
3209   // NB don't free the above strings as they're references to values held elsewhere
3210   gboolean do_tracks = datasource_gps_get_do_tracks ( dgs );
3211   gboolean do_routes = datasource_gps_get_do_routes ( dgs );
3212   gboolean do_waypoints = datasource_gps_get_do_waypoints ( dgs );
3213   gboolean turn_off = datasource_gps_get_off ( dgs );
3214
3215   gtk_widget_destroy ( dialog );
3216
3217   // When called from the viewport - work the corresponding layerspanel:
3218   if ( !vlp ) {
3219     vlp = vik_window_layers_panel ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) );
3220   }
3221
3222   // Apply settings to transfer to the GPS device
3223   vik_gps_comm ( vtl,
3224                  track,
3225                  GPS_UP,
3226                  protocol,
3227                  port,
3228                  FALSE,
3229                  vik_layers_panel_get_viewport (vlp),
3230                  vlp,
3231                  do_tracks,
3232                  do_routes,
3233                  do_waypoints,
3234                  turn_off );
3235 }
3236
3237 /*
3238  * Acquire into this TRW Layer from any GPS Babel supported file
3239  */
3240 static void trw_layer_acquire_file_cb ( gpointer lav[2] )
3241 {
3242   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
3243   VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
3244   VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
3245   VikViewport *vvp =  vik_window_viewport(vw);
3246
3247   a_acquire ( vw, vlp, vvp, &vik_datasource_file_interface, NULL, NULL );
3248 }
3249
3250 static void trw_layer_new_wp ( gpointer lav[2] )
3251 {
3252   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
3253   VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
3254   /* TODO longone: okay, if layer above (aggregate) is invisible but vtl->visible is true, this redraws for no reason.
3255      instead return true if you want to update. */
3256   if ( vik_trw_layer_new_waypoint ( vtl, VIK_GTK_WINDOW_FROM_LAYER(vtl), vik_viewport_get_center(vik_layers_panel_get_viewport(vlp))) && VIK_LAYER(vtl)->visible ) {
3257     trw_layer_calculate_bounds_waypoints ( vtl );
3258     vik_layers_panel_emit_update ( vlp );
3259   }
3260 }
3261
3262 static void new_track_create_common ( VikTrwLayer *vtl, gchar *name )
3263 {
3264   vtl->current_track = vik_track_new();
3265   vtl->current_track->visible = TRUE;
3266   if ( vtl->drawmode == DRAWMODE_ALL_SAME_COLOR )
3267     // Create track with the preferred colour from the layer properties
3268     vtl->current_track->color = vtl->track_color;
3269   else
3270     gdk_color_parse ( "#000000", &(vtl->current_track->color) );
3271   vtl->current_track->has_color = TRUE;
3272   vik_trw_layer_add_track ( vtl, name, vtl->current_track );
3273 }
3274
3275 static void trw_layer_new_track ( gpointer lav[2] )
3276 {
3277   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
3278
3279   if ( ! vtl->current_track ) {
3280     gchar *name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, _("Track")) ;
3281     new_track_create_common ( vtl, name );
3282     g_free ( name );
3283
3284     vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_CREATE_TRACK );
3285   }
3286 }
3287
3288 static void new_route_create_common ( VikTrwLayer *vtl, gchar *name )
3289 {
3290   vtl->current_track = vik_track_new();
3291   vtl->current_track->visible = TRUE;
3292   vtl->current_track->is_route = TRUE;
3293   // By default make all routes red
3294   vtl->current_track->has_color = TRUE;
3295   gdk_color_parse ( "red", &vtl->current_track->color );
3296   vik_trw_layer_add_route ( vtl, name, vtl->current_track );
3297 }
3298
3299 static void trw_layer_new_route ( gpointer lav[2] )
3300 {
3301   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
3302
3303   if ( ! vtl->current_track ) {
3304     gchar *name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_ROUTE, _("Route")) ;
3305     new_route_create_common ( vtl, name );
3306     g_free ( name );
3307     vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_CREATE_ROUTE );
3308   }
3309 }
3310
3311 static void trw_layer_auto_routes_view ( gpointer lav[2] )
3312 {
3313   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
3314   VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
3315
3316   if ( g_hash_table_size (vtl->routes) > 0 ) {
3317     struct LatLon maxmin[2] = { {0,0}, {0,0} };
3318     g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_find_maxmin_tracks, maxmin );
3319     trw_layer_zoom_to_show_latlons ( vtl, vik_layers_panel_get_viewport (vlp), maxmin );
3320     vik_layers_panel_emit_update ( vlp );
3321   }
3322 }
3323
3324
3325 static void trw_layer_finish_track ( gpointer lav[2] )
3326 {
3327   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
3328   vtl->current_track = NULL;
3329   vik_layer_emit_update ( VIK_LAYER(vtl) );
3330 }
3331
3332 static void trw_layer_auto_tracks_view ( gpointer lav[2] )
3333 {
3334   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
3335   VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
3336
3337   if ( g_hash_table_size (vtl->tracks) > 0 ) {
3338     struct LatLon maxmin[2] = { {0,0}, {0,0} };
3339     g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_find_maxmin_tracks, maxmin );
3340     trw_layer_zoom_to_show_latlons ( vtl, vik_layers_panel_get_viewport (vlp), maxmin );
3341     vik_layers_panel_emit_update ( vlp );
3342   }
3343 }
3344
3345 static void trw_layer_single_waypoint_jump ( const gpointer id, const VikWaypoint *wp, gpointer vvp )
3346 {
3347   /* NB do not care if wp is visible or not */
3348   vik_viewport_set_center_coord ( VIK_VIEWPORT(vvp), &(wp->coord) );
3349 }
3350
3351 static void trw_layer_auto_waypoints_view ( gpointer lav[2] )
3352 {
3353   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
3354   VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
3355
3356   /* Only 1 waypoint - jump straight to it */
3357   if ( g_hash_table_size (vtl->waypoints) == 1 ) {
3358     VikViewport *vvp = vik_layers_panel_get_viewport (vlp);
3359     g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_single_waypoint_jump, (gpointer) vvp );
3360   }
3361   /* If at least 2 waypoints - find center and then zoom to fit */
3362   else if ( g_hash_table_size (vtl->waypoints) > 1 )
3363   {
3364     struct LatLon maxmin[2] = { {0,0}, {0,0} };
3365     maxmin[0].lat = vtl->waypoints_bbox.north;
3366     maxmin[1].lat = vtl->waypoints_bbox.south;
3367     maxmin[0].lon = vtl->waypoints_bbox.east;
3368     maxmin[1].lon = vtl->waypoints_bbox.west;
3369     trw_layer_zoom_to_show_latlons ( vtl, vik_layers_panel_get_viewport (vlp), maxmin );
3370   }
3371
3372   vik_layers_panel_emit_update ( vlp );
3373 }
3374
3375 static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vlp )
3376 {
3377   static gpointer pass_along[2];
3378   GtkWidget *item;
3379   GtkWidget *export_submenu;
3380   pass_along[0] = vtl;
3381   pass_along[1] = vlp;
3382
3383   item = gtk_menu_item_new();
3384   gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3385   gtk_widget_show ( item );
3386
3387   if ( vtl->current_track ) {
3388     if ( vtl->current_track->is_route )
3389       item = gtk_menu_item_new_with_mnemonic ( _("_Finish Route") );
3390     else
3391       item = gtk_menu_item_new_with_mnemonic ( _("_Finish Track") );
3392     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_finish_track), pass_along );
3393     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3394     gtk_widget_show ( item );
3395
3396     // Add separator
3397     item = gtk_menu_item_new ();
3398     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3399     gtk_widget_show ( item );
3400   }
3401
3402   /* Now with icons */
3403   item = gtk_image_menu_item_new_with_mnemonic ( _("_View Layer") );
3404   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
3405   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_view), pass_along );
3406   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3407   gtk_widget_show ( item );
3408
3409   GtkWidget *view_submenu = gtk_menu_new();
3410   item = gtk_image_menu_item_new_with_mnemonic ( _("V_iew") );
3411   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_FIND, GTK_ICON_SIZE_MENU) );
3412   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3413   gtk_widget_show ( item );
3414   gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), view_submenu );
3415
3416   item = gtk_menu_item_new_with_mnemonic ( _("View All _Tracks") );
3417   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_tracks_view), pass_along );
3418   gtk_menu_shell_append (GTK_MENU_SHELL (view_submenu), item);
3419   gtk_widget_show ( item );
3420
3421   item = gtk_menu_item_new_with_mnemonic ( _("View All _Routes") );
3422   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_routes_view), pass_along );
3423   gtk_menu_shell_append (GTK_MENU_SHELL (view_submenu), item);
3424   gtk_widget_show ( item );
3425
3426   item = gtk_menu_item_new_with_mnemonic ( _("View All _Waypoints") );
3427   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_waypoints_view), pass_along );
3428   gtk_menu_shell_append (GTK_MENU_SHELL (view_submenu), item);
3429   gtk_widget_show ( item );
3430
3431   item = gtk_image_menu_item_new_with_mnemonic ( _("_Goto Center of Layer") );
3432   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
3433   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_centerize), pass_along );
3434   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3435   gtk_widget_show ( item );
3436
3437   item = gtk_menu_item_new_with_mnemonic ( _("Goto _Waypoint...") );
3438   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_wp), pass_along );
3439   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3440   gtk_widget_show ( item );
3441
3442   export_submenu = gtk_menu_new ();
3443   item = gtk_image_menu_item_new_with_mnemonic ( _("_Export Layer") );
3444   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_HARDDISK, GTK_ICON_SIZE_MENU) );
3445   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3446   gtk_widget_show ( item );
3447   gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), export_submenu );
3448   
3449   item = gtk_menu_item_new_with_mnemonic ( _("Export as GPS_Point...") );
3450   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpspoint), pass_along );
3451   gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
3452   gtk_widget_show ( item );
3453
3454   item = gtk_menu_item_new_with_mnemonic ( _("Export as GPS_Mapper...") );
3455   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpsmapper), pass_along );
3456   gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
3457   gtk_widget_show ( item );
3458
3459   item = gtk_menu_item_new_with_mnemonic ( _("Export as _GPX...") );
3460   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpx), pass_along );
3461   gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
3462   gtk_widget_show ( item );
3463
3464   item = gtk_menu_item_new_with_mnemonic ( _("Export as _KML...") );
3465   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_kml), pass_along );
3466   gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
3467   gtk_widget_show ( item );
3468
3469   gchar* external1 = g_strconcat ( _("Open with External Program_1: "), a_vik_get_external_gpx_program_1(), NULL );
3470   item = gtk_menu_item_new_with_mnemonic ( external1 );
3471   g_free ( external1 );
3472   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_external_gpx_1), pass_along );
3473   gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
3474   gtk_widget_show ( item );
3475
3476   gchar* external2 = g_strconcat ( _("Open with External Program_2: "), a_vik_get_external_gpx_program_2(), NULL );
3477   item = gtk_menu_item_new_with_mnemonic ( external2 );
3478   g_free ( external2 );
3479   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_external_gpx_2), pass_along );
3480   gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
3481   gtk_widget_show ( item );
3482
3483   GtkWidget *new_submenu = gtk_menu_new();
3484   item = gtk_image_menu_item_new_with_mnemonic ( _("_New") );
3485   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) );
3486   gtk_menu_shell_append(GTK_MENU_SHELL (menu), item);
3487   gtk_widget_show(item);
3488   gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), new_submenu);
3489
3490   item = gtk_image_menu_item_new_with_mnemonic ( _("New _Waypoint...") );
3491   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) );
3492   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wp), pass_along );
3493   gtk_menu_shell_append (GTK_MENU_SHELL (new_submenu), item);
3494   gtk_widget_show ( item );
3495
3496   item = gtk_image_menu_item_new_with_mnemonic ( _("New _Track") );
3497   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) );
3498   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_track), pass_along );
3499   gtk_menu_shell_append (GTK_MENU_SHELL (new_submenu), item);
3500   gtk_widget_show ( item );
3501   // Make it available only when a new track *not* already in progress
3502   gtk_widget_set_sensitive ( item, ! (gboolean)GPOINTER_TO_INT(vtl->current_track) );
3503
3504   item = gtk_image_menu_item_new_with_mnemonic ( _("New _Route") );
3505   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) );
3506   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_route), pass_along );
3507   gtk_menu_shell_append (GTK_MENU_SHELL (new_submenu), item);
3508   gtk_widget_show ( item );
3509   // Make it available only when a new track *not* already in progress
3510   gtk_widget_set_sensitive ( item, ! (gboolean)GPOINTER_TO_INT(vtl->current_track) );
3511
3512 #ifdef VIK_CONFIG_GEOTAG
3513   item = gtk_menu_item_new_with_mnemonic ( _("Geotag _Images...") );
3514   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_geotagging), pass_along );
3515   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3516   gtk_widget_show ( item );
3517 #endif
3518
3519   GtkWidget *acquire_submenu = gtk_menu_new ();
3520   item = gtk_image_menu_item_new_with_mnemonic ( _("_Acquire") );
3521   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_DOWN, GTK_ICON_SIZE_MENU) );
3522   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3523   gtk_widget_show ( item );
3524   gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), acquire_submenu );
3525   
3526   item = gtk_menu_item_new_with_mnemonic ( _("From _GPS...") );
3527   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_gps_cb), pass_along );
3528   gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
3529   gtk_widget_show ( item );
3530
3531   /* FIXME: only add menu when at least a routing engine has support for Directions */
3532   item = gtk_menu_item_new_with_mnemonic ( _("From _Directions...") );
3533   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_routing_cb), pass_along );
3534   gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
3535   gtk_widget_show ( item );
3536
3537 #ifdef VIK_CONFIG_OPENSTREETMAP
3538   item = gtk_menu_item_new_with_mnemonic ( _("From _OSM Traces...") );
3539   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_osm_cb), pass_along );
3540   gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
3541   gtk_widget_show ( item );
3542
3543   item = gtk_menu_item_new_with_mnemonic ( _("From _My OSM Traces...") );
3544   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_osm_my_traces_cb), pass_along );
3545   gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
3546   gtk_widget_show ( item );
3547 #endif
3548
3549 #ifdef VIK_CONFIG_GEONAMES
3550   GtkWidget *wikipedia_submenu = gtk_menu_new();
3551   item = gtk_image_menu_item_new_with_mnemonic ( _("From _Wikipedia Waypoints") );
3552   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
3553   gtk_menu_shell_append(GTK_MENU_SHELL (acquire_submenu), item);
3554   gtk_widget_show(item);
3555   gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), wikipedia_submenu);
3556
3557   item = gtk_image_menu_item_new_with_mnemonic ( _("Within _Layer Bounds") );
3558   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
3559   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wikipedia_wp_layer), pass_along );
3560   gtk_menu_shell_append (GTK_MENU_SHELL (wikipedia_submenu), item);
3561   gtk_widget_show ( item );
3562
3563   item = gtk_image_menu_item_new_with_mnemonic ( _("Within _Current View") );
3564   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_100, GTK_ICON_SIZE_MENU) );
3565   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wikipedia_wp_viewport), pass_along );
3566   gtk_menu_shell_append (GTK_MENU_SHELL (wikipedia_submenu), item);
3567   gtk_widget_show ( item );
3568 #endif
3569
3570 #ifdef VIK_CONFIG_GEOCACHES
3571   item = gtk_menu_item_new_with_mnemonic ( _("From Geo_caching...") );
3572   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_geocache_cb), pass_along );
3573   gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
3574   gtk_widget_show ( item );
3575 #endif
3576
3577 #ifdef VIK_CONFIG_GEOTAG
3578   item = gtk_menu_item_new_with_mnemonic ( _("From Geotagged _Images...") );
3579   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_geotagged_cb), pass_along );
3580   gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
3581   gtk_widget_show ( item );
3582 #endif
3583
3584   item = gtk_menu_item_new_with_mnemonic ( _("From _File...") );
3585   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_file_cb), pass_along );
3586   gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
3587   gtk_widget_show ( item );
3588
3589   vik_ext_tool_datasources_add_menu_items_to_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), GTK_MENU (acquire_submenu) );
3590
3591   GtkWidget *upload_submenu = gtk_menu_new ();
3592   item = gtk_image_menu_item_new_with_mnemonic ( _("_Upload") );
3593   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU) );
3594   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3595   gtk_widget_show ( item );
3596   gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), upload_submenu );
3597
3598   item = gtk_image_menu_item_new_with_mnemonic ( _("Upload to _GPS...") );
3599   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_MENU) );
3600   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_gps_upload), pass_along );
3601   gtk_menu_shell_append (GTK_MENU_SHELL (upload_submenu), item);
3602   gtk_widget_show ( item );
3603
3604 #ifdef VIK_CONFIG_OPENSTREETMAP 
3605   item = gtk_image_menu_item_new_with_mnemonic ( _("Upload to _OSM...") );
3606   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU) );
3607   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(osm_traces_upload_cb), pass_along );
3608   gtk_menu_shell_append (GTK_MENU_SHELL (upload_submenu), item);
3609   gtk_widget_show ( item );
3610 #endif
3611
3612   GtkWidget *delete_submenu = gtk_menu_new ();
3613   item = gtk_image_menu_item_new_with_mnemonic ( _("De_lete") );
3614   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
3615   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3616   gtk_widget_show ( item );
3617   gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), delete_submenu );
3618   
3619   item = gtk_image_menu_item_new_with_mnemonic ( _("Delete All _Tracks") );
3620   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
3621   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_tracks), pass_along );
3622   gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
3623   gtk_widget_show ( item );
3624   
3625   item = gtk_image_menu_item_new_with_mnemonic ( _("Delete Tracks _From Selection...") );
3626   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
3627   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_tracks_from_selection), pass_along );
3628   gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
3629   gtk_widget_show ( item );
3630
3631   item = gtk_image_menu_item_new_with_mnemonic ( _("Delete _All Routes") );
3632   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
3633   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_routes), pass_along );
3634   gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
3635   gtk_widget_show ( item );
3636
3637   item = gtk_image_menu_item_new_with_mnemonic ( _("_Delete Routes From Selection...") );
3638   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
3639   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_routes_from_selection), pass_along );
3640   gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
3641   gtk_widget_show ( item );
3642   
3643   item = gtk_image_menu_item_new_with_mnemonic ( _("Delete All _Waypoints") );
3644   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
3645   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_waypoints), pass_along );
3646   gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
3647   gtk_widget_show ( item );
3648   
3649   item = gtk_image_menu_item_new_with_mnemonic ( _("Delete Waypoints From _Selection...") );
3650   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
3651   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_waypoints_from_selection), pass_along );
3652   gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
3653   gtk_widget_show ( item );
3654   
3655   item = a_acquire_trwlayer_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vlp,
3656                                    vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vlp)), vtl );
3657   if ( item ) {
3658     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3659     gtk_widget_show ( item );
3660   }  
3661
3662   item = a_acquire_trwlayer_track_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vlp,
3663                                          vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vlp)), vtl );
3664   if ( item ) {
3665     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3666     gtk_widget_show ( item );
3667   }  
3668 }
3669
3670 // Fake Waypoint UUIDs vi simple increasing integer
3671 static guint wp_uuid = 0;
3672
3673 void vik_trw_layer_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp )
3674 {
3675   wp_uuid++;
3676
3677   vik_waypoint_set_name (wp, name);
3678
3679   if ( VIK_LAYER(vtl)->realized )
3680   {
3681     // Do we need to create the sublayer:
3682     if ( g_hash_table_size (vtl->waypoints) == 0 ) {
3683       trw_layer_add_sublayer_waypoints ( vtl, VIK_LAYER(vtl)->vt, &(VIK_LAYER(vtl)->iter) );
3684     }
3685
3686     GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter));
3687
3688     // Visibility column always needed for waypoints
3689     vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), iter, name, vtl, GUINT_TO_POINTER(wp_uuid), VIK_TRW_LAYER_SUBLAYER_WAYPOINT, get_wp_sym_small (wp->symbol), TRUE, TRUE );
3690
3691     // Actual setting of visibility dependent on the waypoint
3692     vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, wp->visible );
3693
3694     g_hash_table_insert ( vtl->waypoints_iters, GUINT_TO_POINTER(wp_uuid), iter );
3695
3696     // Sort now as post_read is not called on a realized waypoint
3697     vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), vtl->wp_sort_order );
3698   }
3699
3700   highest_wp_number_add_wp(vtl, name);
3701   g_hash_table_insert ( vtl->waypoints, GUINT_TO_POINTER(wp_uuid), wp );
3702  
3703 }
3704
3705 // Fake Track UUIDs vi simple increasing integer
3706 static guint tr_uuid = 0;
3707
3708 void vik_trw_layer_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *t )
3709 {
3710   tr_uuid++;
3711
3712   vik_track_set_name (t, name);
3713
3714   if ( VIK_LAYER(vtl)->realized )
3715   {
3716     // Do we need to create the sublayer:
3717     if ( g_hash_table_size (vtl->tracks) == 0 ) {
3718       trw_layer_add_sublayer_tracks ( vtl, VIK_LAYER(vtl)->vt, &(VIK_LAYER(vtl)->iter) );
3719     }
3720
3721     GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter));
3722     // Visibility column always needed for tracks
3723     vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), iter, name, vtl, GUINT_TO_POINTER(tr_uuid), VIK_TRW_LAYER_SUBLAYER_TRACK, NULL, TRUE, TRUE );
3724
3725     // Actual setting of visibility dependent on the track
3726     vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, t->visible );
3727
3728     g_hash_table_insert ( vtl->tracks_iters, GUINT_TO_POINTER(tr_uuid), iter );
3729
3730     // Sort now as post_read is not called on a realized track
3731     vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), vtl->track_sort_order );
3732   }
3733
3734   g_hash_table_insert ( vtl->tracks, GUINT_TO_POINTER(tr_uuid), t );
3735
3736   trw_layer_update_treeview ( vtl, t, GUINT_TO_POINTER(tr_uuid) );
3737 }
3738
3739 // Fake Route UUIDs vi simple increasing integer
3740 static guint rt_uuid = 0;
3741
3742 void vik_trw_layer_add_route ( VikTrwLayer *vtl, gchar *name, VikTrack *t )
3743 {
3744   rt_uuid++;
3745
3746   vik_track_set_name (t, name);
3747
3748   if ( VIK_LAYER(vtl)->realized )
3749   {
3750     // Do we need to create the sublayer:
3751     if ( g_hash_table_size (vtl->routes) == 0 ) {
3752       trw_layer_add_sublayer_routes ( vtl, VIK_LAYER(vtl)->vt, &(VIK_LAYER(vtl)->iter) );
3753     }
3754
3755     GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter));
3756     // Visibility column always needed for routes
3757     vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter), iter, name, vtl, GUINT_TO_POINTER(rt_uuid), VIK_TRW_LAYER_SUBLAYER_ROUTE, NULL, TRUE, TRUE );
3758     // Actual setting of visibility dependent on the route
3759     vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, t->visible );
3760
3761     g_hash_table_insert ( vtl->routes_iters, GUINT_TO_POINTER(rt_uuid), iter );
3762
3763     // Sort now as post_read is not called on a realized route
3764     vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter), vtl->track_sort_order );
3765   }
3766
3767   g_hash_table_insert ( vtl->routes, GUINT_TO_POINTER(rt_uuid), t );
3768
3769   trw_layer_update_treeview ( vtl, t, GUINT_TO_POINTER(rt_uuid) );
3770 }
3771
3772 /* to be called whenever a track has been deleted or may have been changed. */
3773 void trw_layer_cancel_tps_of_track ( VikTrwLayer *vtl, VikTrack *trk )
3774 {
3775   if (vtl->current_tp_track == trk )
3776     trw_layer_cancel_current_tp ( vtl, FALSE );
3777 }
3778
3779 /**
3780  * Normally this is done to due the waypoint size preference having changed
3781  */
3782 void vik_trw_layer_reset_waypoints ( VikTrwLayer *vtl )
3783 {
3784   GHashTableIter iter;
3785   gpointer key, value;
3786
3787   // Foreach waypoint
3788   g_hash_table_iter_init ( &iter, vtl->waypoints );
3789   while ( g_hash_table_iter_next ( &iter, &key, &value ) ) {
3790     VikWaypoint *wp = VIK_WAYPOINT(value);
3791     if ( wp->symbol ) {
3792       // Reapply symbol setting to update the pixbuf
3793       gchar *tmp_symbol = g_strdup ( wp->symbol );
3794       vik_waypoint_set_symbol ( wp, tmp_symbol );
3795       g_free ( tmp_symbol );
3796     }
3797   }
3798 }
3799
3800 /**
3801  * trw_layer_new_unique_sublayer_name:
3802  *
3803  * Allocates a unique new name
3804  */
3805 gchar *trw_layer_new_unique_sublayer_name (VikTrwLayer *vtl, gint sublayer_type, const gchar *name)
3806 {
3807   gint i = 2;
3808   gchar *newname = g_strdup(name);
3809
3810   gpointer id = NULL;
3811   do {
3812     id = NULL;
3813     switch ( sublayer_type ) {
3814     case VIK_TRW_LAYER_SUBLAYER_TRACK:
3815       id = (gpointer) vik_trw_layer_get_track ( vtl, newname );
3816       break;
3817     case VIK_TRW_LAYER_SUBLAYER_WAYPOINT:
3818       id = (gpointer) vik_trw_layer_get_waypoint ( vtl, newname );
3819       break;
3820     default:
3821       id = (gpointer) vik_trw_layer_get_route ( vtl, newname );
3822       break;
3823     }
3824     // If found a name already in use try adding 1 to it and we try again
3825     if ( id ) {
3826       gchar *new_newname = g_strdup_printf("%s#%d", name, i);
3827       g_free(newname);
3828       newname = new_newname;
3829       i++;
3830     }
3831   } while ( id != NULL);
3832
3833   return newname;
3834 }
3835
3836 void vik_trw_layer_filein_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp )
3837 {
3838   // No more uniqueness of name forced when loading from a file
3839   // This now makes this function a little redunant as we just flow the parameters through
3840   vik_trw_layer_add_waypoint ( vtl, name, wp );
3841 }
3842
3843 void vik_trw_layer_filein_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *tr )
3844 {
3845   if ( vtl->route_finder_append && vtl->route_finder_current_track ) {
3846     vik_track_remove_dup_points ( tr ); /* make "double point" track work to undo */
3847     vik_track_steal_and_append_trackpoints ( vtl->route_finder_current_track, tr );
3848     vik_track_free ( tr );
3849     vtl->route_finder_append = FALSE; /* this means we have added it */
3850   } else {
3851
3852     // No more uniqueness of name forced when loading from a file
3853     if ( tr->is_route )
3854       vik_trw_layer_add_route ( vtl, name, tr );
3855     else
3856       vik_trw_layer_add_track ( vtl, name, tr );
3857
3858     if ( vtl->route_finder_check_added_track ) {
3859       vik_track_remove_dup_points ( tr ); /* make "double point" track work to undo */
3860       vtl->route_finder_added_track = tr;
3861     }
3862   }
3863 }
3864
3865 static void trw_layer_enum_item ( gpointer id, GList **tr, GList **l )
3866 {
3867   *l = g_list_append(*l, id);
3868 }
3869
3870 /*
3871  * Move an item from one TRW layer to another TRW layer
3872  */
3873 static void trw_layer_move_item ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, gpointer id, gint type )
3874 {
3875   // TODO reconsider strategy when moving within layer (if anything...)
3876   gboolean rename = ( vtl_src != vtl_dest );
3877   if ( ! rename )
3878     return;
3879
3880   if (type == VIK_TRW_LAYER_SUBLAYER_TRACK) {
3881     VikTrack *trk = g_hash_table_lookup ( vtl_src->tracks, id );
3882
3883     gchar *newname;
3884     if ( rename )
3885       newname = trw_layer_new_unique_sublayer_name ( vtl_dest, type, trk->name );
3886     else
3887       newname = g_strdup ( trk->name );
3888
3889     VikTrack *trk2 = vik_track_copy ( trk, TRUE );
3890     vik_trw_layer_add_track ( vtl_dest, newname, trk2 );
3891     g_free ( newname );
3892     vik_trw_layer_delete_track ( vtl_src, trk );
3893   }
3894
3895   if (type == VIK_TRW_LAYER_SUBLAYER_ROUTE) {
3896     VikTrack *trk = g_hash_table_lookup ( vtl_src->routes, id );
3897
3898     gchar *newname;
3899     if ( rename )
3900       newname = trw_layer_new_unique_sublayer_name ( vtl_dest, type, trk->name );
3901     else
3902       newname = g_strdup ( trk->name );
3903
3904     VikTrack *trk2 = vik_track_copy ( trk, TRUE );
3905     vik_trw_layer_add_route ( vtl_dest, newname, trk2 );
3906     g_free ( newname );
3907     vik_trw_layer_delete_route ( vtl_src, trk );
3908   }
3909
3910   if (type == VIK_TRW_LAYER_SUBLAYER_WAYPOINT) {
3911     VikWaypoint *wp = g_hash_table_lookup ( vtl_src->waypoints, id );
3912
3913     gchar *newname;
3914     if ( rename )
3915       newname = trw_layer_new_unique_sublayer_name ( vtl_dest, type, wp->name );
3916     else
3917       newname = g_strdup ( wp->name );
3918
3919     VikWaypoint *wp2 = vik_waypoint_copy ( wp );
3920     vik_trw_layer_add_waypoint ( vtl_dest, newname, wp2 );
3921     g_free ( newname );
3922     trw_layer_delete_waypoint ( vtl_src, wp );
3923
3924     // Recalculate bounds even if not renamed as maybe dragged between layers
3925     trw_layer_calculate_bounds_waypoints ( vtl_dest );
3926     trw_layer_calculate_bounds_waypoints ( vtl_src );
3927   }
3928 }
3929
3930 static void trw_layer_drag_drop_request ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, GtkTreeIter *src_item_iter, GtkTreePath *dest_path )
3931 {
3932   VikTreeview *vt = VIK_LAYER(vtl_src)->vt;
3933   gint type = vik_treeview_item_get_data(vt, src_item_iter);
3934
3935   if (!vik_treeview_item_get_pointer(vt, src_item_iter)) {
3936     GList *items = NULL;
3937     GList *iter;
3938
3939     if (type==VIK_TRW_LAYER_SUBLAYER_TRACKS) {
3940       g_hash_table_foreach ( vtl_src->tracks, (GHFunc)trw_layer_enum_item, &items);
3941     } 
3942     if (type==VIK_TRW_LAYER_SUBLAYER_WAYPOINTS) {
3943       g_hash_table_foreach ( vtl_src->waypoints, (GHFunc)trw_layer_enum_item, &items);
3944     }    
3945     if (type==VIK_TRW_LAYER_SUBLAYER_ROUTES) {
3946       g_hash_table_foreach ( vtl_src->routes, (GHFunc)trw_layer_enum_item, &items);
3947     }
3948
3949     iter = items;
3950     while (iter) {
3951       if (type==VIK_TRW_LAYER_SUBLAYER_TRACKS) {
3952         trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_TRACK);
3953       } else if (type==VIK_TRW_LAYER_SUBLAYER_ROUTES) {
3954         trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_ROUTE);
3955       } else {
3956         trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_WAYPOINT);
3957       }
3958       iter = iter->next;
3959     }
3960     if (items) 
3961       g_list_free(items);
3962   } else {
3963     gchar *name = vik_treeview_item_get_pointer(vt, src_item_iter);
3964     trw_layer_move_item(vtl_src, vtl_dest, name, type);
3965   }
3966 }
3967
3968 typedef struct {
3969   VikTrack *trk; // input
3970   gpointer uuid;   // output
3971 } trku_udata;
3972
3973 static gboolean trw_layer_track_find_uuid ( const gpointer id, const VikTrack *trk, gpointer udata )
3974 {
3975   trku_udata *user_data = udata;
3976   if ( trk == user_data->trk ) {
3977     user_data->uuid = id;
3978     return TRUE;
3979   }
3980   return FALSE;
3981 }
3982
3983 gboolean vik_trw_layer_delete_track ( VikTrwLayer *vtl, VikTrack *trk )
3984 {
3985   gboolean was_visible = FALSE;
3986
3987   if ( trk && trk->name ) {
3988
3989     if ( trk == vtl->current_track ) {
3990       vtl->current_track = NULL;
3991       vtl->current_tp_track = NULL;
3992       vtl->current_tp_id = NULL;
3993       vtl->moving_tp = FALSE;
3994     }
3995
3996     was_visible = trk->visible;
3997
3998     if ( trk == vtl->route_finder_current_track )
3999       vtl->route_finder_current_track = NULL;
4000
4001     if ( trk == vtl->route_finder_added_track )
4002       vtl->route_finder_added_track = NULL;
4003
4004     trku_udata udata;
4005     udata.trk  = trk;
4006     udata.uuid = NULL;
4007
4008     // Hmmm, want key of it
4009     gpointer *trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udata );
4010
4011     if ( trkf && udata.uuid ) {
4012       /* could be current_tp, so we have to check */
4013       trw_layer_cancel_tps_of_track ( vtl, trk );
4014
4015       GtkTreeIter *it = g_hash_table_lookup ( vtl->tracks_iters, udata.uuid );
4016
4017       if ( it ) {
4018         vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, it );
4019         g_hash_table_remove ( vtl->tracks_iters, udata.uuid );
4020         g_hash_table_remove ( vtl->tracks, udata.uuid );
4021
4022         // If last sublayer, then remove sublayer container
4023         if ( g_hash_table_size (vtl->tracks) == 0 ) {
4024           vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter) );
4025         }
4026       }
4027     }
4028   }
4029   return was_visible;
4030 }
4031
4032 gboolean vik_trw_layer_delete_route ( VikTrwLayer *vtl, VikTrack *trk )
4033 {
4034   gboolean was_visible = FALSE;
4035
4036   if ( trk && trk->name ) {
4037
4038     if ( trk == vtl->current_track ) {
4039       vtl->current_track = NULL;
4040       vtl->current_tp_track = NULL;
4041       vtl->current_tp_id = NULL;
4042       vtl->moving_tp = FALSE;
4043     }
4044
4045     was_visible = trk->visible;
4046
4047     if ( trk == vtl->route_finder_current_track )
4048       vtl->route_finder_current_track = NULL;
4049
4050     if ( trk == vtl->route_finder_added_track )
4051       vtl->route_finder_added_track = NULL;
4052
4053     trku_udata udata;
4054     udata.trk  = trk;
4055     udata.uuid = NULL;
4056
4057     // Hmmm, want key of it
4058     gpointer *trkf = g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find_uuid, &udata );
4059
4060     if ( trkf && udata.uuid ) {
4061       /* could be current_tp, so we have to check */
4062       trw_layer_cancel_tps_of_track ( vtl, trk );
4063
4064       GtkTreeIter *it = g_hash_table_lookup ( vtl->routes_iters, udata.uuid );
4065
4066       if ( it ) {
4067         vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, it );
4068         g_hash_table_remove ( vtl->routes_iters, udata.uuid );
4069         g_hash_table_remove ( vtl->routes, udata.uuid );
4070
4071         // If last sublayer, then remove sublayer container
4072         if ( g_hash_table_size (vtl->routes) == 0 ) {
4073           vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter) );
4074         }
4075       }
4076     }
4077   }
4078   return was_visible;
4079 }
4080
4081 static gboolean trw_layer_delete_waypoint ( VikTrwLayer *vtl, VikWaypoint *wp )
4082 {
4083   gboolean was_visible = FALSE;
4084
4085   if ( wp && wp->name ) {
4086
4087     if ( wp == vtl->current_wp ) {
4088       vtl->current_wp = NULL;
4089       vtl->current_wp_id = NULL;
4090       vtl->moving_wp = FALSE;
4091     }
4092
4093     was_visible = wp->visible;
4094     
4095     wpu_udata udata;
4096     udata.wp   = wp;
4097     udata.uuid = NULL;
4098
4099     // Hmmm, want key of it
4100     gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata );
4101
4102     if ( wpf && udata.uuid ) {
4103       GtkTreeIter *it = g_hash_table_lookup ( vtl->waypoints_iters, udata.uuid );
4104     
4105       if ( it ) {
4106         vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, it );
4107         g_hash_table_remove ( vtl->waypoints_iters, udata.uuid );
4108
4109         highest_wp_number_remove_wp(vtl, wp->name);
4110         g_hash_table_remove ( vtl->waypoints, udata.uuid ); // last because this frees the name
4111
4112         // If last sublayer, then remove sublayer container
4113         if ( g_hash_table_size (vtl->waypoints) == 0 ) {
4114           vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter) );
4115         }
4116       }
4117     }
4118
4119   }
4120
4121   return was_visible;
4122 }
4123
4124 // Only for temporary use by trw_layer_delete_waypoint_by_name
4125 static gboolean trw_layer_waypoint_find_uuid_by_name ( const gpointer id, const VikWaypoint *wp, gpointer udata )
4126 {
4127   wpu_udata *user_data = udata;
4128   if ( ! strcmp ( wp->name, user_data->wp->name ) ) {
4129     user_data->uuid = id;
4130     return TRUE;
4131   }
4132   return FALSE;
4133 }
4134
4135 /*
4136  * Delete a waypoint by the given name
4137  * NOTE: ATM this will delete the first encountered Waypoint with the specified name
4138  *   as there be multiple waypoints with the same name
4139  */
4140 static gboolean trw_layer_delete_waypoint_by_name ( VikTrwLayer *vtl, const gchar *name )
4141 {
4142   wpu_udata udata;
4143   // Fake a waypoint with the given name
4144   udata.wp   = vik_waypoint_new ();
4145   vik_waypoint_set_name (udata.wp, name);
4146   // Currently only the name is used in this waypoint find function
4147   udata.uuid = NULL;
4148
4149   // Hmmm, want key of it
4150   gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid_by_name, (gpointer) &udata );
4151
4152   vik_waypoint_free (udata.wp);
4153
4154   if ( wpf && udata.uuid )
4155     return trw_layer_delete_waypoint (vtl, g_hash_table_lookup ( vtl->waypoints, udata.uuid ));
4156   else
4157     return FALSE;
4158 }
4159
4160 typedef struct {
4161   VikTrack *trk; // input
4162   gpointer uuid; // output
4163 } tpu_udata;
4164
4165 // Only for temporary use by trw_layer_delete_track_by_name
4166 static gboolean trw_layer_track_find_uuid_by_name ( const gpointer id, const VikTrack *trk, gpointer udata )
4167 {
4168   tpu_udata *user_data = udata;
4169   if ( ! strcmp ( trk->name, user_data->trk->name ) ) {
4170     user_data->uuid = id;
4171     return TRUE;
4172   }
4173   return FALSE;
4174 }
4175
4176 /*
4177  * Delete a track by the given name
4178  * NOTE: ATM this will delete the first encountered Track with the specified name
4179  *   as there may be multiple tracks with the same name within the specified hash table
4180  */
4181 static gboolean trw_layer_delete_track_by_name ( VikTrwLayer *vtl, const gchar *name, GHashTable *ht_tracks )
4182 {
4183   tpu_udata udata;
4184   // Fake a track with the given name
4185   udata.trk   = vik_track_new ();
4186   vik_track_set_name (udata.trk, name);
4187   // Currently only the name is used in this waypoint find function
4188   udata.uuid = NULL;
4189
4190   // Hmmm, want key of it
4191   gpointer *trkf = g_hash_table_find ( ht_tracks, (GHRFunc) trw_layer_track_find_uuid_by_name, &udata );
4192
4193   vik_track_free (udata.trk);
4194
4195   if ( trkf && udata.uuid ) {
4196     // This could be a little better written...
4197     if ( vtl->tracks == ht_tracks )
4198       return vik_trw_layer_delete_track (vtl, g_hash_table_lookup ( ht_tracks, udata.uuid ));
4199     if ( vtl->routes == ht_tracks )
4200       return vik_trw_layer_delete_route (vtl, g_hash_table_lookup ( ht_tracks, udata.uuid ));
4201     return FALSE;
4202   }
4203   else
4204     return FALSE;
4205 }
4206
4207 static void remove_item_from_treeview ( const gpointer id, GtkTreeIter *it, VikTreeview * vt )
4208 {
4209     vik_treeview_item_delete (vt, it );
4210 }
4211
4212 void vik_trw_layer_delete_all_routes ( VikTrwLayer *vtl )
4213 {
4214
4215   vtl->current_track = NULL;
4216   vtl->route_finder_current_track = NULL;
4217   vtl->route_finder_added_track = NULL;
4218   if (vtl->current_tp_track)
4219     trw_layer_cancel_current_tp(vtl, FALSE);
4220
4221   g_hash_table_foreach(vtl->routes_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt);
4222   g_hash_table_remove_all(vtl->routes_iters);
4223   g_hash_table_remove_all(vtl->routes);
4224
4225   vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter) );
4226
4227   vik_layer_emit_update ( VIK_LAYER(vtl) );
4228 }
4229
4230 void vik_trw_layer_delete_all_tracks ( VikTrwLayer *vtl )
4231 {
4232
4233   vtl->current_track = NULL;
4234   vtl->route_finder_current_track = NULL;
4235   vtl->route_finder_added_track = NULL;
4236   if (vtl->current_tp_track)
4237     trw_layer_cancel_current_tp(vtl, FALSE);
4238
4239   g_hash_table_foreach(vtl->tracks_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt);
4240   g_hash_table_remove_all(vtl->tracks_iters);
4241   g_hash_table_remove_all(vtl->tracks);
4242
4243   vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter) );
4244
4245   vik_layer_emit_update ( VIK_LAYER(vtl) );
4246 }
4247
4248 void vik_trw_layer_delete_all_waypoints ( VikTrwLayer *vtl )
4249 {
4250   vtl->current_wp = NULL;
4251   vtl->current_wp_id = NULL;
4252   vtl->moving_wp = FALSE;
4253
4254   highest_wp_number_reset(vtl);
4255
4256   g_hash_table_foreach(vtl->waypoints_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt);
4257   g_hash_table_remove_all(vtl->waypoints_iters);
4258   g_hash_table_remove_all(vtl->waypoints);
4259
4260   vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter) );
4261
4262   vik_layer_emit_update ( VIK_LAYER(vtl) );
4263 }
4264
4265 static void trw_layer_delete_all_tracks ( gpointer lav[2] )
4266 {
4267   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
4268   // Get confirmation from the user
4269   if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
4270                             _("Are you sure you want to delete all tracks in %s?"),
4271                             vik_layer_get_name ( VIK_LAYER(vtl) ) ) )
4272     vik_trw_layer_delete_all_tracks (vtl);
4273 }
4274
4275 static void trw_layer_delete_all_routes ( gpointer lav[2] )
4276 {
4277   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
4278   // Get confirmation from the user
4279   if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
4280                             _("Are you sure you want to delete all routes in %s?"),
4281                             vik_layer_get_name ( VIK_LAYER(vtl) ) ) )
4282     vik_trw_layer_delete_all_routes (vtl);
4283 }
4284
4285 static void trw_layer_delete_all_waypoints ( gpointer lav[2] )
4286 {
4287   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
4288   // Get confirmation from the user
4289   if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
4290                             _("Are you sure you want to delete all waypoints in %s?"),
4291                             vik_layer_get_name ( VIK_LAYER(vtl) ) ) )
4292     vik_trw_layer_delete_all_waypoints (vtl);
4293 }
4294
4295 static void trw_layer_delete_item ( gpointer pass_along[6] )
4296 {
4297   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
4298   gboolean was_visible = FALSE;
4299   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
4300   {
4301     VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, pass_along[3] );
4302     if ( wp && wp->name ) {
4303       if ( GPOINTER_TO_INT ( pass_along[4]) )
4304         // Get confirmation from the user
4305         // Maybe this Waypoint Delete should be optional as is it could get annoying...
4306         if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
4307             _("Are you sure you want to delete the waypoint \"%s\""),
4308             wp->name ) )
4309           return;
4310       was_visible = trw_layer_delete_waypoint ( vtl, wp );
4311     }
4312   }
4313   else if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_TRACK )
4314   {
4315     VikTrack *trk = g_hash_table_lookup ( vtl->tracks, pass_along[3] );
4316     if ( trk && trk->name ) {
4317       if ( GPOINTER_TO_INT ( pass_along[4]) )
4318         // Get confirmation from the user
4319         if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
4320                                   _("Are you sure you want to delete the track \"%s\""),
4321                                   trk->name ) )
4322           return;
4323       was_visible = vik_trw_layer_delete_track ( vtl, trk );
4324     }
4325   }
4326   else
4327   {
4328     VikTrack *trk = g_hash_table_lookup ( vtl->routes, pass_along[3] );
4329     if ( trk && trk->name ) {
4330       if ( GPOINTER_TO_INT ( pass_along[4]) )
4331         // Get confirmation from the user
4332         if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
4333                                     _("Are you sure you want to delete the route \"%s\""),
4334                                     trk->name ) )
4335           return;
4336       was_visible = vik_trw_layer_delete_route ( vtl, trk );
4337     }
4338   }
4339   if ( was_visible )
4340     vik_layer_emit_update ( VIK_LAYER(vtl) );
4341 }
4342
4343 /**
4344  *  Rename waypoint and maintain corresponding name of waypoint in the treeview
4345  */
4346 static void trw_layer_waypoint_rename ( VikTrwLayer *vtl, VikWaypoint *wp, const gchar *new_name )
4347 {
4348   vik_waypoint_set_name ( wp, new_name );
4349
4350   // Now update the treeview as well
4351   wpu_udata udataU;
4352   udataU.wp   = wp;
4353   udataU.uuid = NULL;
4354
4355   // Need key of it for treeview update
4356   gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, &udataU );
4357
4358   if ( wpf && udataU.uuid ) {
4359     GtkTreeIter *it = g_hash_table_lookup ( vtl->waypoints_iters, udataU.uuid );
4360
4361     if ( it ) {
4362       vik_treeview_item_set_name ( VIK_LAYER(vtl)->vt, it, new_name );
4363       vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), vtl->wp_sort_order );
4364     }
4365   }
4366 }
4367
4368 static void trw_layer_properties_item ( gpointer pass_along[7] )
4369 {
4370   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
4371   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
4372   {
4373     VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, pass_along[3] ); // sublayer
4374
4375     if ( wp && wp->name )
4376     {
4377       gboolean updated = FALSE;
4378       gchar *new_name = a_dialog_waypoint ( VIK_GTK_WINDOW_FROM_LAYER(vtl), wp->name, vtl, wp, vtl->coord_mode, FALSE, &updated );
4379       if ( new_name )
4380         trw_layer_waypoint_rename ( vtl, wp, new_name );
4381
4382       if ( updated && pass_along[6] )
4383         vik_treeview_item_set_icon ( VIK_LAYER(vtl)->vt, pass_along[6], get_wp_sym_small (wp->symbol) );
4384
4385       if ( updated && VIK_LAYER(vtl)->visible )
4386         vik_layer_emit_update ( VIK_LAYER(vtl) );
4387     }
4388   }
4389   else
4390   {
4391     VikTrack *tr;
4392     if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_TRACK )
4393       tr = g_hash_table_lookup ( vtl->tracks, pass_along[3] );
4394     else
4395       tr = g_hash_table_lookup ( vtl->routes, pass_along[3] );
4396
4397     if ( tr && tr->name )
4398     {
4399       vik_trw_layer_propwin_run ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
4400                                   vtl,
4401                                   tr,
4402                                   pass_along[1], /* vlp */
4403                                   pass_along[5], /* vvp */
4404                                   pass_along[6]); /* iter */
4405     }
4406   }
4407 }
4408
4409 /*
4410  * Update the treeview of the track id - primarily to update the icon
4411  */
4412 void trw_layer_update_treeview ( VikTrwLayer *vtl, VikTrack *trk, gpointer *trk_id )
4413 {
4414   trku_udata udata;
4415   udata.trk  = trk;
4416   udata.uuid = NULL;
4417
4418   gpointer *trkf = NULL;
4419   if ( trk->is_route )
4420     trkf = g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find_uuid, &udata );
4421   else
4422     trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udata );
4423
4424   if ( trkf && udata.uuid ) {
4425
4426     GtkTreeIter *iter = NULL;
4427     if ( trk->is_route )
4428       iter = g_hash_table_lookup ( vtl->routes_iters, udata.uuid );
4429     else
4430       iter = g_hash_table_lookup ( vtl->tracks_iters, udata.uuid );
4431
4432     if ( iter ) {
4433       // TODO: Make this a function
4434       GdkPixbuf *pixbuf = gdk_pixbuf_new ( GDK_COLORSPACE_RGB, FALSE, 8, 18, 18);
4435       guint32 pixel = ((trk->color.red & 0xff00) << 16) |
4436         ((trk->color.green & 0xff00) << 8) |
4437         (trk->color.blue & 0xff00);
4438       gdk_pixbuf_fill ( pixbuf, pixel );
4439       vik_treeview_item_set_icon ( VIK_LAYER(vtl)->vt, iter, pixbuf );
4440       g_object_unref (pixbuf);
4441     }
4442
4443   }
4444 }
4445
4446 /*
4447    Parameter 1 -> VikLayersPanel
4448    Parameter 2 -> VikLayer
4449    Parameter 3 -> VikViewport
4450 */
4451 static void goto_coord ( gpointer *vlp, gpointer vl, gpointer vvp, const VikCoord *coord )
4452 {
4453   if ( vlp ) {
4454     vik_viewport_set_center_coord ( vik_layers_panel_get_viewport (VIK_LAYERS_PANEL(vlp)), coord );
4455     vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) );
4456   }
4457   else {
4458     /* since vlp not set, vl & vvp should be valid instead! */
4459     if ( vl && vvp ) {
4460       vik_viewport_set_center_coord ( VIK_VIEWPORT(vvp), coord );
4461       vik_layer_emit_update ( VIK_LAYER(vl) );
4462     }
4463   }
4464 }
4465
4466 static void trw_layer_goto_track_startpoint ( gpointer pass_along[6] )
4467 {
4468   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
4469   VikTrack *track;
4470   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
4471     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
4472   else
4473     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
4474
4475   if ( track && track->trackpoints )
4476     goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(((VikTrackpoint *) track->trackpoints->data)->coord) );
4477 }
4478
4479 static void trw_layer_goto_track_center ( gpointer pass_along[6] )
4480 {
4481   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
4482   VikTrack *track;
4483   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
4484     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
4485   else
4486     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
4487
4488   if ( track && track->trackpoints )
4489   {
4490     struct LatLon average, maxmin[2] = { {0,0}, {0,0} };
4491     VikCoord coord;
4492     trw_layer_find_maxmin_tracks ( NULL, track, maxmin );
4493     average.lat = (maxmin[0].lat+maxmin[1].lat)/2;
4494     average.lon = (maxmin[0].lon+maxmin[1].lon)/2;
4495     vik_coord_load_from_latlon ( &coord, vtl->coord_mode, &average );
4496     goto_coord ( pass_along[1], pass_along[0], pass_along[5], &coord);
4497   }
4498 }
4499
4500 static void trw_layer_convert_track_route ( gpointer pass_along[6] )
4501 {
4502   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
4503   VikTrack *trk;
4504   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
4505     trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
4506   else
4507     trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
4508
4509   if ( !trk )
4510     return;
4511
4512   // Converting a track to a route can be a bit more complicated,
4513   //  so give a chance to change our minds:
4514   if ( !trk->is_route &&
4515        ( ( vik_track_get_segment_count ( trk ) > 1 ) ||
4516          ( vik_track_get_average_speed ( trk ) > 0.0 ) ) ) {
4517
4518     if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
4519                                 _("Converting a track to a route removes extra track data such as segments, timestamps, etc...\nDo you want to continue?"), NULL ) )
4520       return;
4521 }
4522
4523   // Copy it
4524   VikTrack *trk_copy = vik_track_copy ( trk, TRUE );
4525
4526   // Convert
4527   trk_copy->is_route = !trk_copy->is_route;
4528
4529   // ATM can't set name to self - so must create temporary copy
4530   gchar *name = g_strdup ( trk_copy->name );
4531
4532   // Delete old one and then add new one
4533   if ( trk->is_route ) {
4534     vik_trw_layer_delete_route ( vtl, trk );
4535     vik_trw_layer_add_track ( vtl, name, trk_copy );
4536   }
4537   else {
4538     // Extra route conversion bits...
4539     vik_track_merge_segments ( trk_copy );
4540     vik_track_to_routepoints ( trk_copy );
4541
4542     vik_trw_layer_delete_track ( vtl, trk );
4543     vik_trw_layer_add_route ( vtl, name, trk_copy );
4544   }
4545   g_free ( name );
4546
4547   // Update in case color of track / route changes when moving between sublayers
4548   vik_layer_emit_update ( VIK_LAYER(pass_along[0]) );
4549 }
4550
4551 static void trw_layer_anonymize_times ( gpointer pass_along[6] )
4552 {
4553   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
4554   VikTrack *track;
4555   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
4556     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
4557   else
4558     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
4559
4560   if ( track )
4561     vik_track_anonymize_times ( track );
4562 }
4563
4564 static void trw_layer_extend_track_end ( gpointer pass_along[6] )
4565 {
4566   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
4567   VikTrack *track;
4568   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
4569     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
4570   else
4571     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
4572
4573   if ( !track )
4574     return;
4575
4576   vtl->current_track = track;
4577   vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, track->is_route ? TOOL_CREATE_ROUTE : TOOL_CREATE_TRACK);
4578
4579   if ( track->trackpoints )
4580     goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(((VikTrackpoint *)g_list_last(track->trackpoints)->data)->coord) );
4581 }
4582
4583 /**
4584  * extend a track using route finder
4585  */
4586 static void trw_layer_extend_track_end_route_finder ( gpointer pass_along[6] )
4587 {
4588   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
4589   VikTrack *track = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->routes, pass_along[3] );
4590   if ( !track )
4591     return;
4592   VikCoord last_coord = (((VikTrackpoint *)g_list_last(track->trackpoints)->data)->coord);
4593
4594   vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_ROUTE_FINDER );
4595   vtl->route_finder_coord =  last_coord;
4596   vtl->route_finder_current_track = track;
4597   vtl->route_finder_started = TRUE;
4598
4599   if ( track->trackpoints )
4600     goto_coord ( pass_along[1], pass_along[0], pass_along[5], &last_coord) ;
4601
4602 }
4603
4604 /**
4605  *
4606  */
4607 static gboolean trw_layer_dem_test ( VikTrwLayer *vtl, VikLayersPanel *vlp )
4608 {
4609   // If have a vlp then perform a basic test to see if any DEM info available...
4610   if ( vlp ) {
4611     GList *dems = vik_layers_panel_get_all_layers_of_type (vlp, VIK_LAYER_DEM, TRUE); // Includes hidden DEM layer types
4612
4613     if ( !g_list_length(dems) ) {
4614       a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No DEM layers available, thus no DEM values can be applied.") );
4615       return FALSE;
4616     }
4617   }
4618   return TRUE;
4619 }
4620
4621 /**
4622  * apply_dem_data_common:
4623  *
4624  * A common function for applying the DEM values and reporting the results.
4625  */
4626 static void apply_dem_data_common ( VikTrwLayer *vtl, VikLayersPanel *vlp, VikTrack *track, gboolean skip_existing_elevations )
4627 {
4628   if ( !trw_layer_dem_test ( vtl, vlp ) )
4629     return;
4630
4631   gulong changed = vik_track_apply_dem_data ( track, skip_existing_elevations );
4632   // Inform user how much was changed
4633   gchar str[64];
4634   const gchar *tmp_str = ngettext("%ld point adjusted", "%ld points adjusted", changed);
4635   g_snprintf(str, 64, tmp_str, changed);
4636   a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str);
4637 }
4638
4639 static void trw_layer_apply_dem_data_all ( gpointer pass_along[6] )
4640 {
4641   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
4642   VikTrack *track;
4643   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
4644     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
4645   else
4646     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
4647
4648   if ( track )
4649     apply_dem_data_common ( vtl, pass_along[1], track, FALSE );
4650 }
4651
4652 static void trw_layer_apply_dem_data_only_missing ( gpointer pass_along[6] )
4653 {
4654   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
4655   VikTrack *track;
4656   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
4657     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
4658   else
4659     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
4660
4661   if ( track )
4662     apply_dem_data_common ( vtl, pass_along[1], track, TRUE );
4663 }
4664
4665 /**
4666  * smooth_it:
4667  *
4668  * A common function for applying the elevation smoothing and reporting the results.
4669  */
4670 static void smooth_it ( VikTrwLayer *vtl, VikTrack *track, gboolean flat )
4671 {
4672   gulong changed = vik_track_smooth_missing_elevation_data ( track, flat );
4673   // Inform user how much was changed
4674   gchar str[64];
4675   const gchar *tmp_str = ngettext("%ld point adjusted", "%ld points adjusted", changed);
4676   g_snprintf(str, 64, tmp_str, changed);
4677   a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str);
4678 }
4679
4680 /**
4681  *
4682  */
4683 static void trw_layer_missing_elevation_data_interp ( gpointer pass_along[6] )
4684 {
4685   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
4686   VikTrack *track;
4687   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
4688     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
4689   else
4690     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
4691
4692   if ( !track )
4693     return;
4694
4695   smooth_it ( vtl, track, FALSE );
4696 }
4697
4698 static void trw_layer_missing_elevation_data_flat ( gpointer pass_along[6] )
4699 {
4700   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
4701   VikTrack *track;
4702   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
4703     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
4704   else
4705     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
4706
4707   if ( !track )
4708     return;
4709
4710   smooth_it ( vtl, track, TRUE );
4711 }
4712
4713 /**
4714  * Commonal helper function
4715  */
4716 static void wp_changed_message ( VikTrwLayer *vtl, gint changed )
4717 {
4718   gchar str[64];
4719   const gchar *tmp_str = ngettext("%ld waypoint changed", "%ld waypoints changed", changed);
4720   g_snprintf(str, 64, tmp_str, changed);
4721   a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str);
4722 }
4723
4724 static void trw_layer_apply_dem_data_wpt_all ( gpointer pass_along[6] )
4725 {
4726   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
4727   VikLayersPanel *vlp = (VikLayersPanel *)pass_along[1];
4728
4729   if ( !trw_layer_dem_test ( vtl, vlp ) )
4730     return;
4731
4732   gint changed = 0;
4733   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
4734     // Single Waypoint
4735     VikWaypoint *wp = (VikWaypoint *) g_hash_table_lookup ( vtl->waypoints, pass_along[3] );
4736     if ( wp )
4737       changed = (gint)vik_waypoint_apply_dem_data ( wp, FALSE );
4738   }
4739   else {
4740     // All waypoints
4741     GHashTableIter iter;
4742     gpointer key, value;
4743
4744     g_hash_table_iter_init ( &iter, vtl->waypoints );
4745     while ( g_hash_table_iter_next (&iter, &key, &value) ) {
4746       VikWaypoint *wp = VIK_WAYPOINT(value);
4747       changed = changed + (gint)vik_waypoint_apply_dem_data ( wp, FALSE );
4748     }
4749   }
4750   wp_changed_message ( vtl, changed );
4751 }
4752
4753 static void trw_layer_apply_dem_data_wpt_only_missing ( gpointer pass_along[6] )
4754 {
4755   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
4756   VikLayersPanel *vlp = (VikLayersPanel *)pass_along[1];
4757
4758   if ( !trw_layer_dem_test ( vtl, vlp ) )
4759     return;
4760
4761   gint changed = 0;
4762   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
4763     // Single Waypoint
4764     VikWaypoint *wp = (VikWaypoint *) g_hash_table_lookup ( vtl->waypoints, pass_along[3] );
4765     if ( wp )
4766       changed = (gint)vik_waypoint_apply_dem_data ( wp, TRUE );
4767   }
4768   else {
4769     // All waypoints
4770     GHashTableIter iter;
4771     gpointer key, value;
4772
4773     g_hash_table_iter_init ( &iter, vtl->waypoints );
4774     while ( g_hash_table_iter_next (&iter, &key, &value) ) {
4775       VikWaypoint *wp = VIK_WAYPOINT(value);
4776       changed = changed + (gint)vik_waypoint_apply_dem_data ( wp, TRUE );
4777     }
4778   }
4779   wp_changed_message ( vtl, changed );
4780 }
4781
4782 static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] )
4783 {
4784   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
4785   VikTrack *track;
4786   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
4787     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
4788   else
4789     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
4790
4791   if ( !track )
4792     return;
4793
4794   GList *trps = track->trackpoints;
4795   if ( !trps )
4796     return;
4797   trps = g_list_last(trps);
4798   goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(((VikTrackpoint *) trps->data)->coord));
4799 }
4800
4801 static void trw_layer_goto_track_max_speed ( gpointer pass_along[6] )
4802 {
4803   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
4804   VikTrack *track;
4805   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
4806     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
4807   else
4808     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
4809
4810   if ( !track )
4811     return;
4812
4813   VikTrackpoint* vtp = vik_track_get_tp_by_max_speed ( track );
4814   if ( !vtp )
4815     return;
4816   goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(vtp->coord));
4817 }
4818
4819 static void trw_layer_goto_track_max_alt ( gpointer pass_along[6] )
4820 {
4821   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
4822   VikTrack *track;
4823   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
4824     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
4825   else
4826     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
4827
4828   if ( !track )
4829     return;
4830
4831   VikTrackpoint* vtp = vik_track_get_tp_by_max_alt ( track );
4832   if ( !vtp )
4833     return;
4834   goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(vtp->coord));
4835 }
4836
4837 static void trw_layer_goto_track_min_alt ( gpointer pass_along[6] )
4838 {
4839   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
4840   VikTrack *track;
4841   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
4842     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
4843   else
4844     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
4845
4846   if ( !track )
4847     return;
4848
4849   VikTrackpoint* vtp = vik_track_get_tp_by_min_alt ( track );
4850   if ( !vtp )
4851     return;
4852   goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(vtp->coord));
4853 }
4854
4855 /*
4856  * Automatically change the viewport to center on the track and zoom to see the extent of the track
4857  */
4858 static void trw_layer_auto_track_view ( gpointer pass_along[6] )
4859 {
4860   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
4861   VikTrack *trk;
4862   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
4863     trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
4864   else
4865     trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
4866
4867   if ( trk && trk->trackpoints )
4868   {
4869     struct LatLon maxmin[2] = { {0,0}, {0,0} };
4870     trw_layer_find_maxmin_tracks ( NULL, trk, maxmin );
4871     trw_layer_zoom_to_show_latlons ( vtl, pass_along[5], maxmin );
4872     if ( pass_along[1] )
4873       vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(pass_along[1]) );
4874     else
4875       vik_layer_emit_update ( VIK_LAYER(vtl) );
4876   }
4877 }
4878
4879 /*
4880  * Refine the selected track/route with a routing engine.
4881  * The routing engine is selected by the user, when requestiong the job.
4882  */
4883 static void trw_layer_route_refine ( gpointer pass_along[6] )
4884 {
4885   static gint last_engine = 0;
4886   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
4887   VikTrack *trk;
4888
4889   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
4890     trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
4891   else
4892     trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
4893
4894   if ( trk && trk->trackpoints )
4895   {
4896     /* Check size of the route */
4897     int nb = vik_track_get_tp_count(trk);
4898     if (nb > 100) {
4899       GtkWidget *dialog = gtk_message_dialog_new (VIK_GTK_WINDOW_FROM_LAYER (vtl),
4900                                                   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4901                                                   GTK_MESSAGE_WARNING,
4902                                                   GTK_BUTTONS_OK_CANCEL,
4903                                                   _("Refining a track with many points (%d) is unlikely to yield sensible results. Do you want to Continue?"),
4904                                                   nb);
4905       gint response = gtk_dialog_run ( GTK_DIALOG(dialog) );
4906       gtk_widget_destroy ( dialog );
4907       if (response != GTK_RESPONSE_OK )
4908         return;
4909     }
4910     /* Select engine from dialog */
4911     GtkWidget *dialog = gtk_dialog_new_with_buttons (_("Refine Route with Routing Engine..."),
4912                                                   VIK_GTK_WINDOW_FROM_LAYER (vtl),
4913                                                   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4914                                                   GTK_STOCK_CANCEL,
4915                                                   GTK_RESPONSE_REJECT,
4916                                                   GTK_STOCK_OK,
4917                                                   GTK_RESPONSE_ACCEPT,
4918                                                   NULL);
4919     GtkWidget *label = gtk_label_new ( _("Select routing engine") );
4920     gtk_widget_show_all(label);
4921
4922     gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), label, TRUE, TRUE, 0 );
4923
4924     GtkWidget * combo = vik_routing_ui_selector_new ( (Predicate)vik_routing_engine_supports_refine, NULL );
4925     gtk_combo_box_set_active (GTK_COMBO_BOX (combo), last_engine);
4926     gtk_widget_show_all(combo);
4927
4928     gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), combo, TRUE, TRUE, 0 );
4929
4930     gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
4931
4932     if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
4933     {
4934         /* Dialog validated: retrieve selected engine and do the job */
4935         last_engine = gtk_combo_box_get_active ( GTK_COMBO_BOX(combo) );
4936         VikRoutingEngine *routing = vik_routing_ui_selector_get_nth (combo, last_engine);
4937
4938         /* Change cursor */
4939         vik_window_set_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0])) );
4940
4941         /* Force saving track */
4942         /* FIXME: remove or rename this hack */
4943         vtl->route_finder_check_added_track = TRUE;
4944
4945         /* the job */
4946         vik_routing_engine_refine (routing, vtl, trk);
4947
4948         /* FIXME: remove or rename this hack */
4949         if ( vtl->route_finder_added_track )
4950           vik_track_calculate_bounds ( vtl->route_finder_added_track );
4951
4952         vtl->route_finder_added_track = NULL;
4953         vtl->route_finder_check_added_track = FALSE;
4954
4955         vik_layer_emit_update ( VIK_LAYER(vtl) );
4956
4957         /* Restore cursor */
4958         vik_window_clear_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0])) );
4959     }
4960     gtk_widget_destroy ( dialog );
4961   }
4962 }
4963
4964 static void trw_layer_edit_trackpoint ( gpointer pass_along[6] )
4965 {
4966   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
4967   trw_layer_tpwin_init ( vtl );
4968 }
4969
4970 /*************************************
4971  * merge/split by time routines 
4972  *************************************/
4973
4974 /* called for each key in track hash table.
4975  * If the current track has the same time stamp type, add it to the result,
4976  * except the one pointed by "exclude".
4977  * set exclude to NULL if there is no exclude to check.
4978  * Note that the result is in reverse (for performance reasons).
4979  */
4980 typedef struct {
4981   GList **result;
4982   GList  *exclude;
4983   gboolean with_timestamps;
4984 } twt_udata;
4985 static void find_tracks_with_timestamp_type(gpointer key, gpointer value, gpointer udata)
4986 {
4987   twt_udata *user_data = udata;
4988   VikTrackpoint *p1, *p2;
4989
4990   if (VIK_TRACK(value)->trackpoints == user_data->exclude) {
4991     return;
4992   }
4993
4994   if (VIK_TRACK(value)->trackpoints) {
4995     p1 = VIK_TRACKPOINT(VIK_TRACK(value)->trackpoints->data);
4996     p2 = VIK_TRACKPOINT(g_list_last(VIK_TRACK(value)->trackpoints)->data);
4997
4998     if ( user_data->with_timestamps ) {
4999       if (!p1->has_timestamp || !p2->has_timestamp) {
5000         return;
5001       }
5002     }
5003     else {
5004       // Don't add tracks with timestamps when getting non timestamp tracks
5005       if (p1->has_timestamp || p2->has_timestamp) {
5006         return;
5007       }
5008     }
5009   }
5010
5011   *(user_data->result) = g_list_prepend(*(user_data->result), key);
5012 }
5013
5014 /* called for each key in track hash table. if original track user_data[1] is close enough
5015  * to the passed one, add it to list in user_data[0] 
5016  */
5017 static void find_nearby_tracks_by_time (gpointer key, gpointer value, gpointer user_data)
5018 {
5019   time_t t1, t2;
5020   VikTrackpoint *p1, *p2;
5021   VikTrack *trk = VIK_TRACK(value);
5022
5023   GList **nearby_tracks = ((gpointer *)user_data)[0];
5024   GList *tpoints = ((gpointer *)user_data)[1];
5025
5026   /* outline: 
5027    * detect reasons for not merging, and return
5028    * if no reason is found not to merge, then do it.
5029    */
5030
5031   // Exclude the original track from the compiled list
5032   if (trk->trackpoints == tpoints) {
5033     return;
5034   }
5035
5036   t1 = VIK_TRACKPOINT(g_list_first(tpoints)->data)->timestamp;
5037   t2 = VIK_TRACKPOINT(g_list_last(tpoints)->data)->timestamp;
5038
5039   if (trk->trackpoints) {
5040     p1 = VIK_TRACKPOINT(g_list_first(trk->trackpoints)->data);
5041     p2 = VIK_TRACKPOINT(g_list_last(trk->trackpoints)->data);
5042
5043     if (!p1->has_timestamp || !p2->has_timestamp) {
5044       //g_print("no timestamp\n");
5045       return;
5046     }
5047
5048     guint threshold = GPOINTER_TO_UINT (((gpointer *)user_data)[2]);
5049     //g_print("Got track named %s, times %d, %d\n", trk->name, p1->timestamp, p2->timestamp);
5050     if (! (abs(t1 - p2->timestamp) < threshold ||
5051         /*  p1 p2      t1 t2 */
5052            abs(p1->timestamp - t2) < threshold)
5053         /*  t1 t2      p1 p2 */
5054         ) {
5055       return;
5056     }
5057   }
5058
5059   *nearby_tracks = g_list_prepend(*nearby_tracks, value);
5060 }
5061
5062 /* comparison function used to sort tracks; a and b are hash table keys */
5063 /* Not actively used - can be restored if needed
5064 static gint track_compare(gconstpointer a, gconstpointer b, gpointer user_data)
5065 {
5066   GHashTable *tracks = user_data;
5067   time_t t1, t2;
5068
5069   t1 = VIK_TRACKPOINT(VIK_TRACK(g_hash_table_lookup(tracks, a))->trackpoints->data)->timestamp;
5070   t2 = VIK_TRACKPOINT(VIK_TRACK(g_hash_table_lookup(tracks, b))->trackpoints->data)->timestamp;
5071   
5072   if (t1 < t2) return -1;
5073   if (t1 > t2) return 1;
5074   return 0;
5075 }
5076 */
5077
5078 /* comparison function used to sort trackpoints */
5079 static gint trackpoint_compare(gconstpointer a, gconstpointer b)
5080 {
5081   time_t t1 = VIK_TRACKPOINT(a)->timestamp, t2 = VIK_TRACKPOINT(b)->timestamp;
5082   
5083   if (t1 < t2) return -1;
5084   if (t1 > t2) return 1;
5085   return 0;
5086 }
5087
5088 /**
5089  * comparison function which can be used to sort tracks or waypoints by name
5090  */
5091 static gint sort_alphabetically (gconstpointer a, gconstpointer b, gpointer user_data)
5092 {
5093   const gchar* namea = (const gchar*) a;
5094   const gchar* nameb = (const gchar*) b;
5095   if ( namea == NULL || nameb == NULL)
5096     return 0;
5097   else
5098     // Same sort method as used in the vik_treeview_*_alphabetize functions
5099     return strcmp ( namea, nameb );
5100 }
5101
5102 /**
5103  * Attempt to merge selected track with other tracks specified by the user
5104  * Tracks to merge with must be of the same 'type' as the selected track -
5105  *  either all with timestamps, or all without timestamps
5106  */
5107 static void trw_layer_merge_with_other ( gpointer pass_along[6] )
5108 {
5109   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
5110   GList *other_tracks = NULL;
5111   GHashTable *ght_tracks;
5112   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5113     ght_tracks = vtl->routes;
5114   else
5115     ght_tracks = vtl->tracks;
5116
5117   VikTrack *track = (VikTrack *) g_hash_table_lookup ( ght_tracks, pass_along[3] );
5118
5119   if ( !track )
5120     return;
5121
5122   if ( !track->trackpoints )
5123     return;
5124
5125   twt_udata udata;
5126   udata.result = &other_tracks;
5127   udata.exclude = track->trackpoints;
5128   // Allow merging with 'similar' time type time tracks
5129   // i.e. either those times, or those without
5130   udata.with_timestamps = (VIK_TRACKPOINT(track->trackpoints->data)->has_timestamp);
5131
5132   g_hash_table_foreach(ght_tracks, find_tracks_with_timestamp_type, (gpointer)&udata);
5133   other_tracks = g_list_reverse(other_tracks);
5134
5135   if ( !other_tracks ) {
5136     if ( udata.with_timestamps )
5137       a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Failed. No other tracks with timestamps in this layer found"));
5138     else
5139       a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Failed. No other tracks without timestamps in this layer found"));
5140     return;
5141   }
5142
5143   // Sort alphabetically for user presentation
5144   // Convert into list of names for usage with dialog function
5145   // TODO: Need to consider how to work best when we can have multiple tracks the same name...
5146   GList *other_tracks_names = NULL;
5147   GList *iter = g_list_first ( other_tracks );
5148   while ( iter ) {
5149     other_tracks_names = g_list_append ( other_tracks_names, VIK_TRACK(g_hash_table_lookup (ght_tracks, iter->data))->name );
5150     iter = g_list_next ( iter );
5151   }
5152
5153   other_tracks_names = g_list_sort_with_data (other_tracks_names, sort_alphabetically, NULL);
5154
5155   GList *merge_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl),
5156                                                 other_tracks_names,
5157                                                 TRUE,
5158                                                 _("Merge with..."),
5159                                                 track->is_route ? _("Select route to merge with") : _("Select track to merge with"));
5160   g_list_free(other_tracks);
5161   g_list_free(other_tracks_names);
5162
5163   if (merge_list)
5164   {
5165     GList *l;
5166     for (l = merge_list; l != NULL; l = g_list_next(l)) {
5167       VikTrack *merge_track;
5168       if ( track->is_route )
5169         merge_track = vik_trw_layer_get_route ( vtl, l->data );
5170       else
5171         merge_track = vik_trw_layer_get_track ( vtl, l->data );
5172
5173       if (merge_track) {
5174         vik_track_steal_and_append_trackpoints ( track, merge_track );
5175         if ( track->is_route )
5176           vik_trw_layer_delete_route (vtl, merge_track);
5177         else
5178           vik_trw_layer_delete_track (vtl, merge_track);
5179         track->trackpoints = g_list_sort(track->trackpoints, trackpoint_compare);
5180       }
5181     }
5182     for (l = merge_list; l != NULL; l = g_list_next(l))
5183       g_free(l->data);
5184     g_list_free(merge_list);
5185
5186     vik_layer_emit_update( VIK_LAYER(vtl) );
5187   }
5188 }
5189
5190 // c.f. trw_layer_sorted_track_id_by_name_list
5191 //  but don't add the specified track to the list (normally current track)
5192 static void trw_layer_sorted_track_id_by_name_list_exclude_self (const gpointer id, const VikTrack *trk, gpointer udata)
5193 {
5194   twt_udata *user_data = udata;
5195
5196   // Skip self
5197   if (trk->trackpoints == user_data->exclude) {
5198     return;
5199   }
5200
5201   // Sort named list alphabetically
5202   *(user_data->result) = g_list_insert_sorted_with_data (*(user_data->result), trk->name, sort_alphabetically, NULL);
5203 }
5204
5205 /**
5206  * Join - this allows combining 'tracks' and 'track routes'
5207  *  i.e. doesn't care about whether tracks have consistent timestamps
5208  * ATM can only append one track at a time to the currently selected track
5209  */
5210 static void trw_layer_append_track ( gpointer pass_along[6] )
5211 {
5212
5213   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
5214   VikTrack *trk;
5215   GHashTable *ght_tracks;
5216   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5217     ght_tracks = vtl->routes;
5218   else
5219     ght_tracks = vtl->tracks;
5220
5221   trk = (VikTrack *) g_hash_table_lookup ( ght_tracks, pass_along[3] );
5222
5223   if ( !trk )
5224     return;
5225
5226   GList *other_tracks_names = NULL;
5227
5228   // Sort alphabetically for user presentation
5229   // Convert into list of names for usage with dialog function
5230   // TODO: Need to consider how to work best when we can have multiple tracks the same name...
5231   twt_udata udata;
5232   udata.result = &other_tracks_names;
5233   udata.exclude = trk->trackpoints;
5234
5235   g_hash_table_foreach(ght_tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list_exclude_self, (gpointer)&udata);
5236
5237   // Note the limit to selecting one track only
5238   //  this is to control the ordering of appending tracks, i.e. the selected track always goes after the current track
5239   //  (otherwise with multiple select the ordering would not be controllable by the user - automatically being alphabetically)
5240   GList *append_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl),
5241                                                  other_tracks_names,
5242                                                  FALSE,
5243                                                  trk->is_route ? _("Append Route"): _("Append Track"),
5244                                                  trk->is_route ? _("Select the route to append after the current route") :
5245                                                                  _("Select the track to append after the current track") );
5246
5247   g_list_free(other_tracks_names);
5248
5249   // It's a list, but shouldn't contain more than one other track!
5250   if ( append_list ) {
5251     GList *l;
5252     for (l = append_list; l != NULL; l = g_list_next(l)) {
5253       // TODO: at present this uses the first track found by name,
5254       //  which with potential multiple same named tracks may not be the one selected...
5255       VikTrack *append_track;
5256       if ( trk->is_route )
5257         append_track = vik_trw_layer_get_route ( vtl, l->data );
5258       else
5259         append_track = vik_trw_layer_get_track ( vtl, l->data );
5260
5261       if ( append_track ) {
5262         vik_track_steal_and_append_trackpoints ( trk, append_track );
5263         if ( trk->is_route )
5264           vik_trw_layer_delete_route (vtl, append_track);
5265         else
5266           vik_trw_layer_delete_track (vtl, append_track);
5267       }
5268     }
5269     for (l = append_list; l != NULL; l = g_list_next(l))
5270       g_free(l->data);
5271     g_list_free(append_list);
5272
5273     vik_layer_emit_update( VIK_LAYER(vtl) );
5274   }
5275 }
5276
5277 /**
5278  * Very similar to trw_layer_append_track for joining
5279  * but this allows selection from the 'other' list
5280  * If a track is selected, then is shows routes and joins the selected one
5281  * If a route is selected, then is shows tracks and joins the selected one
5282  */
5283 static void trw_layer_append_other ( gpointer pass_along[6] )
5284 {
5285
5286   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
5287   VikTrack *trk;
5288   GHashTable *ght_mykind, *ght_others;
5289   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) {
5290     ght_mykind = vtl->routes;
5291     ght_others = vtl->tracks;
5292   }
5293   else {
5294     ght_mykind = vtl->tracks;
5295     ght_others = vtl->routes;
5296   }
5297
5298   trk = (VikTrack *) g_hash_table_lookup ( ght_mykind, pass_along[3] );
5299
5300   if ( !trk )
5301     return;
5302
5303   GList *other_tracks_names = NULL;
5304
5305   // Sort alphabetically for user presentation
5306   // Convert into list of names for usage with dialog function
5307   // TODO: Need to consider how to work best when we can have multiple tracks the same name...
5308   twt_udata udata;
5309   udata.result = &other_tracks_names;
5310   udata.exclude = trk->trackpoints;
5311
5312   g_hash_table_foreach(ght_others, (GHFunc) trw_layer_sorted_track_id_by_name_list_exclude_self, (gpointer)&udata);
5313
5314   // Note the limit to selecting one track only
5315   //  this is to control the ordering of appending tracks, i.e. the selected track always goes after the current track
5316   //  (otherwise with multiple select the ordering would not be controllable by the user - automatically being alphabetically)
5317   GList *append_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl),
5318                                                  other_tracks_names,
5319                                                  FALSE,
5320                                                  trk->is_route ? _("Append Track"): _("Append Route"),
5321                                                  trk->is_route ? _("Select the track to append after the current route") :
5322                                                                  _("Select the route to append after the current track") );
5323
5324   g_list_free(other_tracks_names);
5325
5326   // It's a list, but shouldn't contain more than one other track!
5327   if ( append_list ) {
5328     GList *l;
5329     for (l = append_list; l != NULL; l = g_list_next(l)) {
5330       // TODO: at present this uses the first track found by name,
5331       //  which with potential multiple same named tracks may not be the one selected...
5332
5333       // Get FROM THE OTHER TYPE list
5334       VikTrack *append_track;
5335       if ( trk->is_route )
5336         append_track = vik_trw_layer_get_track ( vtl, l->data );
5337       else
5338         append_track = vik_trw_layer_get_route ( vtl, l->data );
5339
5340       if ( append_track ) {
5341
5342         if ( !append_track->is_route &&
5343              ( ( vik_track_get_segment_count ( append_track ) > 1 ) ||
5344                ( vik_track_get_average_speed ( append_track ) > 0.0 ) ) ) {
5345
5346           if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
5347                                       _("Converting a track to a route removes extra track data such as segments, timestamps, etc...\nDo you want to continue?"), NULL ) ) {
5348             vik_track_merge_segments ( append_track );
5349             vik_track_to_routepoints ( append_track );
5350           }
5351           else {
5352             break;
5353           }
5354         }
5355
5356         vik_track_steal_and_append_trackpoints ( trk, append_track );
5357
5358         // Delete copied which is FROM THE OTHER TYPE list
5359         if ( trk->is_route )
5360           vik_trw_layer_delete_track (vtl, append_track);
5361         else
5362           vik_trw_layer_delete_route (vtl, append_track);
5363       }
5364     }
5365     for (l = append_list; l != NULL; l = g_list_next(l))
5366       g_free(l->data);
5367     g_list_free(append_list);
5368     vik_layer_emit_update( VIK_LAYER(vtl) );
5369   }
5370 }
5371
5372 /* merge by segments */
5373 static void trw_layer_merge_by_segment ( gpointer pass_along[6] )
5374 {
5375   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
5376   VikTrack *trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
5377   guint segments = vik_track_merge_segments ( trk );
5378   // NB currently no need to redraw as segments not actually shown on the display
5379   // However inform the user of what happened:
5380   gchar str[64];
5381   const gchar *tmp_str = ngettext("%d segment merged", "%d segments merged", segments);
5382   g_snprintf(str, 64, tmp_str, segments);
5383   a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str );
5384 }
5385
5386 /* merge by time routine */
5387 static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] )
5388 {
5389   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
5390
5391   //time_t t1, t2;
5392
5393   GList *tracks_with_timestamp = NULL;
5394   VikTrack *orig_trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
5395   if (orig_trk->trackpoints &&
5396       !VIK_TRACKPOINT(orig_trk->trackpoints->data)->has_timestamp) {
5397     a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Failed. This track does not have timestamp"));
5398     return;
5399   }
5400
5401   twt_udata udata;
5402   udata.result = &tracks_with_timestamp;
5403   udata.exclude = orig_trk->trackpoints;
5404   udata.with_timestamps = TRUE;
5405   g_hash_table_foreach(vtl->tracks, find_tracks_with_timestamp_type, (gpointer)&udata);
5406   tracks_with_timestamp = g_list_reverse(tracks_with_timestamp);
5407
5408   if (!tracks_with_timestamp) {
5409     a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Failed. No other track in this layer has timestamp"));
5410     return;
5411   }
5412   g_list_free(tracks_with_timestamp);
5413
5414   static guint threshold_in_minutes = 1;
5415   if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(vtl),
5416                                _("Merge Threshold..."),
5417                                _("Merge when time between tracks less than:"),
5418                                &threshold_in_minutes)) {
5419     return;
5420   }
5421
5422   // keep attempting to merge all tracks until no merges within the time specified is possible
5423   gboolean attempt_merge = TRUE;
5424   GList *nearby_tracks = NULL;
5425   GList *trps;
5426   static gpointer params[3];
5427
5428   while ( attempt_merge ) {
5429
5430     // Don't try again unless tracks have changed
5431     attempt_merge = FALSE;
5432
5433     trps = orig_trk->trackpoints;
5434     if ( !trps )
5435       return;
5436
5437     if (nearby_tracks) {
5438       g_list_free(nearby_tracks);
5439       nearby_tracks = NULL;
5440     }
5441
5442     //t1 = ((VikTrackpoint *)trps->data)->timestamp;
5443     //t2 = ((VikTrackpoint *)g_list_last(trps)->data)->timestamp;
5444     
5445     /*    g_print("Original track times: %d and %d\n", t1, t2);  */
5446     params[0] = &nearby_tracks;
5447     params[1] = (gpointer)trps;
5448     params[2] = GUINT_TO_POINTER (threshold_in_minutes*60); // In seconds
5449
5450     /* get a list of adjacent-in-time tracks */
5451     g_hash_table_foreach(vtl->tracks, find_nearby_tracks_by_time, params);
5452
5453     /* merge them */
5454     GList *l = nearby_tracks;
5455     while ( l ) {
5456        /*
5457 #define get_first_trackpoint(x) VIK_TRACKPOINT(VIK_TRACK(x)->trackpoints->data)
5458 #define get_last_trackpoint(x) VIK_TRACKPOINT(g_list_last(VIK_TRACK(x)->trackpoints)->data)
5459         time_t t1, t2;
5460         t1 = get_first_trackpoint(l)->timestamp;
5461         t2 = get_last_trackpoint(l)->timestamp;
5462 #undef get_first_trackpoint
5463 #undef get_last_trackpoint
5464         g_print("     %20s: track %d - %d\n", VIK_TRACK(l->data)->name, (int)t1, (int)t2);
5465        */
5466
5467       /* remove trackpoints from merged track, delete track */
5468       vik_track_steal_and_append_trackpoints ( orig_trk, VIK_TRACK(l->data) );
5469       vik_trw_layer_delete_track (vtl, VIK_TRACK(l->data));
5470
5471       // Tracks have changed, therefore retry again against all the remaining tracks
5472       attempt_merge = TRUE;
5473
5474       l = g_list_next(l);
5475     }
5476
5477     orig_trk->trackpoints = g_list_sort(orig_trk->trackpoints, trackpoint_compare);
5478   }
5479
5480   g_list_free(nearby_tracks);
5481
5482   vik_layer_emit_update( VIK_LAYER(vtl) );
5483 }
5484
5485 /**
5486  * Split a track at the currently selected trackpoint
5487  */
5488 static void trw_layer_split_at_selected_trackpoint ( VikTrwLayer *vtl, gint subtype )
5489 {
5490   if ( !vtl->current_tpl )
5491     return;
5492
5493   if ( vtl->current_tpl->next && vtl->current_tpl->prev ) {
5494     gchar *name = trw_layer_new_unique_sublayer_name(vtl, subtype, vtl->current_tp_track->name);
5495     if ( name ) {
5496       VikTrack *tr = vik_track_copy ( vtl->current_tp_track, FALSE );
5497       GList *newglist = g_list_alloc ();
5498       newglist->prev = NULL;
5499       newglist->next = vtl->current_tpl->next;
5500       newglist->data = vik_trackpoint_copy(VIK_TRACKPOINT(vtl->current_tpl->data));
5501       tr->trackpoints = newglist;
5502
5503       vtl->current_tpl->next->prev = newglist; /* end old track here */
5504       vtl->current_tpl->next = NULL;
5505
5506       // Bounds of the selected track changed due to the split
5507       vik_track_calculate_bounds ( vtl->current_tp_track );
5508
5509       vtl->current_tpl = newglist; /* change tp to first of new track. */
5510       vtl->current_tp_track = tr;
5511
5512       if ( tr->is_route )
5513         vik_trw_layer_add_route ( vtl, name, tr );
5514       else
5515         vik_trw_layer_add_track ( vtl, name, tr );
5516
5517       // Bounds of the new track created by the split
5518       vik_track_calculate_bounds ( tr );
5519
5520       trku_udata udata;
5521       udata.trk  = tr;
5522       udata.uuid = NULL;
5523
5524       // Also need id of newly created track
5525       gpointer *trkf;
5526       if ( tr->is_route )
5527          trkf = g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find_uuid, &udata );
5528       else
5529          trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udata );
5530
5531       if ( trkf && udata.uuid )
5532         vtl->current_tp_id = udata.uuid;
5533       else
5534         vtl->current_tp_id = NULL;
5535
5536       vik_layer_emit_update(VIK_LAYER(vtl));
5537     }
5538     g_free ( name );
5539   }
5540 }
5541
5542 /* split by time routine */
5543 static void trw_layer_split_by_timestamp ( gpointer pass_along[6] )
5544 {
5545   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
5546   VikTrack *track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
5547   GList *trps = track->trackpoints;
5548   GList *iter;
5549   GList *newlists = NULL;
5550   GList *newtps = NULL;
5551   static guint thr = 1;
5552
5553   time_t ts, prev_ts;
5554
5555   if ( !trps )
5556     return;
5557
5558   if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0]), 
5559                                _("Split Threshold..."), 
5560                                _("Split when time between trackpoints exceeds:"), 
5561                                &thr)) {
5562     return;
5563   }
5564
5565   /* iterate through trackpoints, and copy them into new lists without touching original list */
5566   prev_ts = VIK_TRACKPOINT(trps->data)->timestamp;
5567   iter = trps;
5568
5569   while (iter) {
5570     ts = VIK_TRACKPOINT(iter->data)->timestamp;
5571
5572     // Check for unordered time points - this is quite a rare occurence - unless one has reversed a track.
5573     if (ts < prev_ts) {
5574       gchar tmp_str[64];
5575       strftime ( tmp_str, sizeof(tmp_str), "%c", localtime(&ts) );
5576       if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
5577                                 _("Can not split track due to trackpoints not ordered in time - such as at %s.\n\nGoto this trackpoint?"),
5578                                 tmp_str ) ) {
5579         goto_coord ( pass_along[1], vtl, pass_along[5], &(VIK_TRACKPOINT(iter->data)->coord) );
5580       }
5581       return;
5582     }
5583
5584     if (ts - prev_ts > thr*60) {
5585       /* flush accumulated trackpoints into new list */
5586       newlists = g_list_append(newlists, g_list_reverse(newtps));
5587       newtps = NULL;
5588     }
5589
5590     /* accumulate trackpoint copies in newtps, in reverse order */
5591     newtps = g_list_prepend(newtps, vik_trackpoint_copy(VIK_TRACKPOINT(iter->data)));
5592     prev_ts = ts;
5593     iter = g_list_next(iter);
5594   }
5595   if (newtps) {
5596       newlists = g_list_append(newlists, g_list_reverse(newtps));
5597   }
5598
5599   /* put lists of trackpoints into tracks */
5600   iter = newlists;
5601   // Only bother updating if the split results in new tracks
5602   if (g_list_length (newlists) > 1) {
5603     while (iter) {
5604       gchar *new_tr_name;
5605       VikTrack *tr;
5606
5607       tr = vik_track_copy ( track, FALSE );
5608       tr->trackpoints = (GList *)(iter->data);
5609
5610       new_tr_name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, track->name);
5611       vik_trw_layer_add_track(vtl, new_tr_name, tr);
5612       /*    g_print("adding track %s, times %d - %d\n", new_tr_name, VIK_TRACKPOINT(tr->trackpoints->data)->timestamp,
5613           VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp);*/
5614       g_free ( new_tr_name );
5615       vik_track_calculate_bounds ( tr );
5616       iter = g_list_next(iter);
5617     }
5618     // Remove original track and then update the display
5619     vik_trw_layer_delete_track (vtl, track);
5620     vik_layer_emit_update(VIK_LAYER(pass_along[0]));
5621   }
5622   g_list_free(newlists);
5623 }
5624
5625 /**
5626  * Split a track by the number of points as specified by the user
5627  */
5628 static void trw_layer_split_by_n_points ( gpointer pass_along[6] )
5629 {
5630   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
5631   VikTrack *track;
5632   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5633     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
5634   else
5635     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
5636
5637   if ( !track )
5638     return;
5639
5640   // Check valid track
5641   GList *trps = track->trackpoints;
5642   if ( !trps )
5643     return;
5644
5645   gint points = a_dialog_get_positive_number(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0]),
5646                                              _("Split Every Nth Point"),
5647                                              _("Split on every Nth point:"),
5648                                              250,   // Default value as per typical limited track capacity of various GPS devices
5649                                              2,     // Min
5650                                              65536, // Max
5651                                              5);    // Step
5652   // Was a valid number returned?
5653   if (!points)
5654     return;
5655
5656   // Now split...
5657   GList *iter;
5658   GList *newlists = NULL;
5659   GList *newtps = NULL;
5660   gint count = 0;
5661   iter = trps;
5662
5663   while (iter) {
5664     /* accumulate trackpoint copies in newtps, in reverse order */
5665     newtps = g_list_prepend(newtps, vik_trackpoint_copy(VIK_TRACKPOINT(iter->data)));
5666     count++;
5667     if (count >= points) {
5668       /* flush accumulated trackpoints into new list */
5669       newlists = g_list_append(newlists, g_list_reverse(newtps));
5670       newtps = NULL;
5671       count = 0;
5672     }
5673     iter = g_list_next(iter);
5674   }
5675
5676   // If there is a remaining chunk put that into the new split list
5677   // This may well be the whole track if no split points were encountered
5678   if (newtps) {
5679       newlists = g_list_append(newlists, g_list_reverse(newtps));
5680   }
5681
5682   /* put lists of trackpoints into tracks */
5683   iter = newlists;
5684   // Only bother updating if the split results in new tracks
5685   if (g_list_length (newlists) > 1) {
5686     while (iter) {
5687       gchar *new_tr_name;
5688       VikTrack *tr;
5689
5690       tr = vik_track_copy ( track, FALSE );
5691       tr->trackpoints = (GList *)(iter->data);
5692
5693       if ( track->is_route ) {
5694         new_tr_name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_ROUTE, track->name);
5695         vik_trw_layer_add_route(vtl, new_tr_name, tr);
5696       }
5697       else {
5698         new_tr_name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, track->name);
5699         vik_trw_layer_add_track(vtl, new_tr_name, tr);
5700       }
5701       g_free ( new_tr_name );
5702       vik_track_calculate_bounds ( tr );
5703
5704       iter = g_list_next(iter);
5705     }
5706     // Remove original track and then update the display
5707     if ( track->is_route )
5708       vik_trw_layer_delete_route (vtl, track);
5709     else
5710       vik_trw_layer_delete_track (vtl, track);
5711     vik_layer_emit_update(VIK_LAYER(pass_along[0]));
5712   }
5713   g_list_free(newlists);
5714 }
5715
5716 /**
5717  * Split a track at the currently selected trackpoint
5718  */
5719 static void trw_layer_split_at_trackpoint ( gpointer pass_along[6] )
5720 {
5721   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
5722   gint subtype = GPOINTER_TO_INT (pass_along[2]);
5723   trw_layer_split_at_selected_trackpoint ( vtl, subtype );
5724 }
5725
5726 /**
5727  * Split a track by its segments
5728  * Routes do not have segments so don't call this for routes
5729  */
5730 static void trw_layer_split_segments ( gpointer pass_along[6] )
5731 {
5732   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
5733   VikTrack *trk = g_hash_table_lookup ( vtl->tracks, pass_along[3] );
5734
5735   if ( !trk )
5736     return;
5737
5738   guint ntracks;
5739
5740   VikTrack **tracks = vik_track_split_into_segments (trk, &ntracks);
5741   gchar *new_tr_name;
5742   guint i;
5743   for ( i = 0; i < ntracks; i++ ) {
5744     if ( tracks[i] ) {
5745       new_tr_name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, trk->name);
5746       vik_trw_layer_add_track ( vtl, new_tr_name, tracks[i] );
5747       g_free ( new_tr_name );
5748     }
5749   }
5750   if ( tracks ) {
5751     g_free ( tracks );
5752     // Remove original track
5753     vik_trw_layer_delete_track ( vtl, trk );
5754     vik_layer_emit_update ( VIK_LAYER(vtl) );
5755   }
5756   else {
5757     a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Can not split track as it has no segments"));
5758   }
5759 }
5760 /* end of split/merge routines */
5761
5762 /**
5763  * Delete adjacent track points at the same position
5764  * AKA Delete Dulplicates on the Properties Window
5765  */
5766 static void trw_layer_delete_points_same_position ( gpointer pass_along[6] )
5767 {
5768   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
5769   VikTrack *trk;
5770   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5771     trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
5772   else
5773     trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
5774
5775   if ( !trk )
5776     return;
5777
5778   gulong removed = vik_track_remove_dup_points ( trk );
5779
5780   // Track has been updated so update tps:
5781   trw_layer_cancel_tps_of_track ( vtl, trk );
5782
5783   // Inform user how much was deleted as it's not obvious from the normal view
5784   gchar str[64];
5785   const gchar *tmp_str = ngettext("Deleted %ld point", "Deleted %ld points", removed);
5786   g_snprintf(str, 64, tmp_str, removed);
5787   a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str);
5788
5789   vik_layer_emit_update ( VIK_LAYER(vtl) );
5790 }
5791
5792 /**
5793  * Delete adjacent track points with the same timestamp
5794  * Normally new tracks that are 'routes' won't have any timestamps so should be OK to clean up the track
5795  */
5796 static void trw_layer_delete_points_same_time ( gpointer pass_along[6] )
5797 {
5798   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
5799   VikTrack *trk;
5800   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5801     trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
5802   else
5803     trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
5804
5805   if ( !trk )
5806     return;
5807
5808   gulong removed = vik_track_remove_same_time_points ( trk );
5809
5810   // Track has been updated so update tps:
5811   trw_layer_cancel_tps_of_track ( vtl, trk );
5812
5813   // Inform user how much was deleted as it's not obvious from the normal view
5814   gchar str[64];
5815   const gchar *tmp_str = ngettext("Deleted %ld point", "Deleted %ld points", removed);
5816   g_snprintf(str, 64, tmp_str, removed);
5817   a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str);
5818
5819   vik_layer_emit_update ( VIK_LAYER(vtl) );
5820 }
5821
5822 /**
5823  * Reverse a track
5824  */
5825 static void trw_layer_reverse ( gpointer pass_along[6] )
5826 {
5827   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
5828   VikTrack *track;
5829   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5830     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
5831   else
5832     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
5833
5834   if ( ! track )
5835     return;
5836
5837   vik_track_reverse ( track );
5838  
5839   vik_layer_emit_update ( VIK_LAYER(pass_along[0]) );
5840 }
5841
5842 /**
5843  * Similar to trw_layer_enum_item, but this uses a sorted method
5844  */
5845 /* Currently unused
5846 static void trw_layer_sorted_name_list(gpointer key, gpointer value, gpointer udata)
5847 {
5848   GList **list = (GList**)udata;
5849   // *list = g_list_prepend(*all, key); //unsorted method
5850   // Sort named list alphabetically
5851   *list = g_list_insert_sorted_with_data (*list, key, sort_alphabetically, NULL);
5852 }
5853 */
5854
5855 /**
5856  * Now Waypoint specific sort
5857  */
5858 static void trw_layer_sorted_wp_id_by_name_list (const gpointer id, const VikWaypoint *wp, gpointer udata)
5859 {
5860   GList **list = (GList**)udata;
5861   // Sort named list alphabetically
5862   *list = g_list_insert_sorted_with_data (*list, wp->name, sort_alphabetically, NULL);
5863 }
5864
5865 /**
5866  * Track specific sort
5867  */
5868 static void trw_layer_sorted_track_id_by_name_list (const gpointer id, const VikTrack *trk, gpointer udata)
5869 {
5870   GList **list = (GList**)udata;
5871   // Sort named list alphabetically
5872   *list = g_list_insert_sorted_with_data (*list, trk->name, sort_alphabetically, NULL);
5873 }
5874
5875
5876 typedef struct {
5877   gboolean    has_same_track_name;
5878   const gchar *same_track_name;
5879 } same_track_name_udata;
5880
5881 static gint check_tracks_for_same_name ( gconstpointer aa, gconstpointer bb, gpointer udata )
5882 {
5883   const gchar* namea = (const gchar*) aa;
5884   const gchar* nameb = (const gchar*) bb;
5885
5886   // the test
5887   gint result = strcmp ( namea, nameb );
5888
5889   if ( result == 0 ) {
5890     // Found two names the same
5891     same_track_name_udata *user_data = udata;
5892     user_data->has_same_track_name = TRUE;
5893     user_data->same_track_name = namea;
5894   }
5895
5896   // Leave ordering the same
5897   return 0;
5898 }
5899
5900 /**
5901  * Find out if any tracks have the same name in this hash table
5902  */
5903 static gboolean trw_layer_has_same_track_names ( GHashTable *ht_tracks )
5904 {
5905   // Sort items by name, then compare if any next to each other are the same
5906
5907   GList *track_names = NULL;
5908   g_hash_table_foreach ( ht_tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list, &track_names );
5909
5910   // No tracks
5911   if ( ! track_names )
5912     return FALSE;
5913
5914   same_track_name_udata udata;
5915   udata.has_same_track_name = FALSE;
5916
5917   // Use sort routine to traverse list comparing items
5918   // Don't care how this list ends up ordered ( doesn't actually change ) - care about the returned status
5919   GList *dummy_list = g_list_sort_with_data ( track_names, check_tracks_for_same_name, &udata );
5920   // Still no tracks...
5921   if ( ! dummy_list )
5922     return FALSE;
5923
5924   return udata.has_same_track_name;
5925 }
5926
5927 /**
5928  * Force unqiue track names for the track table specified
5929  * Note the panel is a required parameter to enable the update of the names displayed
5930  * Specify if on tracks or else on routes
5931  */
5932 static void vik_trw_layer_uniquify_tracks ( VikTrwLayer *vtl, VikLayersPanel *vlp, GHashTable *track_table, gboolean ontrack )
5933 {
5934   // . Search list for an instance of repeated name
5935   // . get track of this name
5936   // . create new name
5937   // . rename track & update equiv. treeview iter
5938   // . repeat until all different
5939
5940   same_track_name_udata udata;
5941
5942   GList *track_names = NULL;
5943   udata.has_same_track_name = FALSE;
5944   udata.same_track_name = NULL;
5945
5946   g_hash_table_foreach ( track_table, (GHFunc) trw_layer_sorted_track_id_by_name_list, &track_names );
5947
5948   // No tracks
5949   if ( ! track_names )
5950     return;
5951
5952   GList *dummy_list1 = g_list_sort_with_data ( track_names, check_tracks_for_same_name, &udata );
5953
5954   // Still no tracks...
5955   if ( ! dummy_list1 )
5956     return;
5957
5958   while ( udata.has_same_track_name ) {
5959
5960     // Find a track with the same name
5961     VikTrack *trk;
5962     if ( ontrack )
5963       trk = vik_trw_layer_get_track ( vtl, (gpointer) udata.same_track_name );
5964     else
5965       trk = vik_trw_layer_get_route ( vtl, (gpointer) udata.same_track_name );
5966
5967     if ( ! trk ) {
5968       // Broken :(
5969       g_critical("Houston, we've had a problem.");
5970       vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO, 
5971                                   _("Internal Error in vik_trw_layer_uniquify_tracks") );
5972       return;
5973     }
5974
5975     // Rename it
5976     gchar *newname = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, udata.same_track_name );
5977     vik_track_set_name ( trk, newname );
5978
5979     trku_udata udataU;
5980     udataU.trk  = trk;
5981     udataU.uuid = NULL;
5982
5983     // Need want key of it for treeview update
5984     gpointer *trkf = g_hash_table_find ( track_table, (GHRFunc) trw_layer_track_find_uuid, &udataU );
5985
5986     if ( trkf && udataU.uuid ) {
5987
5988       GtkTreeIter *it;
5989       if ( ontrack )
5990         it = g_hash_table_lookup ( vtl->tracks_iters, udataU.uuid );
5991       else
5992         it = g_hash_table_lookup ( vtl->routes_iters, udataU.uuid );
5993
5994       if ( it ) {
5995         vik_treeview_item_set_name ( VIK_LAYER(vtl)->vt, it, newname );
5996         if ( ontrack )
5997           vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), vtl->wp_sort_order );
5998         else
5999           vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter), vtl->wp_sort_order );
6000       }
6001     }
6002
6003     // Start trying to find same names again...
6004     track_names = NULL;
6005     g_hash_table_foreach ( track_table, (GHFunc) trw_layer_sorted_track_id_by_name_list, &track_names );
6006     udata.has_same_track_name = FALSE;
6007     GList *dummy_list2 = g_list_sort_with_data ( track_names, check_tracks_for_same_name, &udata );
6008
6009     // No tracks any more - give up searching
6010     if ( ! dummy_list2 )
6011       udata.has_same_track_name = FALSE;
6012   }
6013
6014   // Update
6015   vik_layers_panel_emit_update ( vlp );
6016 }
6017
6018 static void trw_layer_sort_order_a2z ( gpointer pass_along[6] )
6019 {
6020   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
6021   GtkTreeIter *iter;
6022
6023   switch (GPOINTER_TO_INT (pass_along[2])) {
6024   case VIK_TRW_LAYER_SUBLAYER_TRACKS:
6025     iter = &(vtl->tracks_iter);
6026     vtl->track_sort_order = VL_SO_ALPHABETICAL_ASCENDING;
6027     break;
6028   case VIK_TRW_LAYER_SUBLAYER_ROUTES:
6029     iter = &(vtl->routes_iter);
6030     vtl->track_sort_order = VL_SO_ALPHABETICAL_ASCENDING;
6031     break;
6032   default: // VIK_TRW_LAYER_SUBLAYER_WAYPOINTS:
6033     iter = &(vtl->waypoints_iter);
6034     vtl->wp_sort_order = VL_SO_ALPHABETICAL_ASCENDING;
6035     break;
6036   }
6037
6038   vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, iter, VL_SO_ALPHABETICAL_ASCENDING );
6039 }
6040
6041 static void trw_layer_sort_order_z2a ( gpointer pass_along[6] )
6042 {
6043   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
6044   GtkTreeIter *iter;
6045
6046   switch (GPOINTER_TO_INT (pass_along[2])) {
6047   case VIK_TRW_LAYER_SUBLAYER_TRACKS:
6048     iter = &(vtl->tracks_iter);
6049     vtl->track_sort_order = VL_SO_ALPHABETICAL_DESCENDING;
6050     break;
6051   case VIK_TRW_LAYER_SUBLAYER_ROUTES:
6052     iter = &(vtl->routes_iter);
6053     vtl->track_sort_order = VL_SO_ALPHABETICAL_DESCENDING;
6054     break;
6055   default: // VIK_TRW_LAYER_SUBLAYER_WAYPOINTS:
6056     iter = &(vtl->waypoints_iter);
6057     vtl->wp_sort_order = VL_SO_ALPHABETICAL_DESCENDING;
6058     break;
6059   }
6060
6061   vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, iter, VL_SO_ALPHABETICAL_DESCENDING );
6062 }
6063
6064 /**
6065  *
6066  */
6067 static void trw_layer_delete_tracks_from_selection ( gpointer lav[2] )
6068 {
6069   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
6070   GList *all = NULL;
6071
6072   // Ensure list of track names offered is unique
6073   if ( trw_layer_has_same_track_names ( vtl->tracks ) ) {
6074     if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
6075                               _("Multiple entries with the same name exist. This method only works with unique names. Force unique names now?"), NULL ) ) {
6076       vik_trw_layer_uniquify_tracks ( vtl, VIK_LAYERS_PANEL(lav[1]), vtl->tracks, TRUE );
6077     }
6078     else
6079       return;
6080   }
6081
6082   // Sort list alphabetically for better presentation
6083   g_hash_table_foreach(vtl->tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list, &all);
6084
6085   if ( ! all ) {
6086     a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No tracks found"));
6087     return;
6088   }
6089
6090   // Get list of items to delete from the user
6091   GList *delete_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl),
6092                                                  all,
6093                                                  TRUE,
6094                                                  _("Delete Selection"),
6095                                                  _("Select tracks to delete"));
6096   g_list_free(all);
6097
6098   // Delete requested tracks
6099   // since specificly requested, IMHO no need for extra confirmation
6100   if ( delete_list ) {
6101     GList *l;
6102     for (l = delete_list; l != NULL; l = g_list_next(l)) {
6103       // This deletes first trk it finds of that name (but uniqueness is enforced above)
6104       trw_layer_delete_track_by_name (vtl, l->data, vtl->tracks);
6105     }
6106     g_list_free(delete_list);
6107     vik_layer_emit_update( VIK_LAYER(vtl) );
6108   }
6109 }
6110
6111 /**
6112  *
6113  */
6114 static void trw_layer_delete_routes_from_selection ( gpointer lav[2] )
6115 {
6116   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
6117   GList *all = NULL;
6118
6119   // Ensure list of track names offered is unique
6120   if ( trw_layer_has_same_track_names ( vtl->routes ) ) {
6121     if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
6122                               _("Multiple entries with the same name exist. This method only works with unique names. Force unique names now?"), NULL ) ) {
6123       vik_trw_layer_uniquify_tracks ( vtl, VIK_LAYERS_PANEL(lav[1]), vtl->routes, FALSE );
6124     }
6125     else
6126       return;
6127   }
6128
6129   // Sort list alphabetically for better presentation
6130   g_hash_table_foreach(vtl->routes, (GHFunc) trw_layer_sorted_track_id_by_name_list, &all);
6131
6132   if ( ! all ) {
6133     a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No routes found"));
6134     return;
6135   }
6136
6137   // Get list of items to delete from the user
6138   GList *delete_list = a_dialog_select_from_list ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
6139                                                    all,
6140                                                    TRUE,
6141                                                    _("Delete Selection"),
6142                                                    _("Select routes to delete") );
6143   g_list_free(all);
6144
6145   // Delete requested routes
6146   // since specificly requested, IMHO no need for extra confirmation
6147   if ( delete_list ) {
6148     GList *l;
6149     for (l = delete_list; l != NULL; l = g_list_next(l)) {
6150       // This deletes first route it finds of that name (but uniqueness is enforced above)
6151       trw_layer_delete_track_by_name (vtl, l->data, vtl->routes);
6152     }
6153     g_list_free(delete_list);
6154     vik_layer_emit_update( VIK_LAYER(vtl) );
6155   }
6156 }
6157
6158 typedef struct {
6159   gboolean    has_same_waypoint_name;
6160   const gchar *same_waypoint_name;
6161 } same_waypoint_name_udata;
6162
6163 static gint check_waypoints_for_same_name ( gconstpointer aa, gconstpointer bb, gpointer udata )
6164 {
6165   const gchar* namea = (const gchar*) aa;
6166   const gchar* nameb = (const gchar*) bb;
6167
6168   // the test
6169   gint result = strcmp ( namea, nameb );
6170
6171   if ( result == 0 ) {
6172     // Found two names the same
6173     same_waypoint_name_udata *user_data = udata;
6174     user_data->has_same_waypoint_name = TRUE;
6175     user_data->same_waypoint_name = namea;
6176   }
6177
6178   // Leave ordering the same
6179   return 0;
6180 }
6181
6182 /**
6183  * Find out if any waypoints have the same name in this layer
6184  */
6185 gboolean trw_layer_has_same_waypoint_names ( VikTrwLayer *vtl )
6186 {
6187   // Sort items by name, then compare if any next to each other are the same
6188
6189   GList *waypoint_names = NULL;
6190   g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_sorted_wp_id_by_name_list, &waypoint_names );
6191
6192   // No waypoints
6193   if ( ! waypoint_names )
6194     return FALSE;
6195
6196   same_waypoint_name_udata udata;
6197   udata.has_same_waypoint_name = FALSE;
6198
6199   // Use sort routine to traverse list comparing items
6200   // Don't care how this list ends up ordered ( doesn't actually change ) - care about the returned status
6201   GList *dummy_list = g_list_sort_with_data ( waypoint_names, check_waypoints_for_same_name, &udata );
6202   // Still no waypoints...
6203   if ( ! dummy_list )
6204     return FALSE;
6205
6206   return udata.has_same_waypoint_name;
6207 }
6208
6209 /**
6210  * Force unqiue waypoint names for this layer
6211  * Note the panel is a required parameter to enable the update of the names displayed
6212  */
6213 static void vik_trw_layer_uniquify_waypoints ( VikTrwLayer *vtl, VikLayersPanel *vlp )
6214 {
6215   // . Search list for an instance of repeated name
6216   // . get waypoint of this name
6217   // . create new name
6218   // . rename waypoint & update equiv. treeview iter
6219   // . repeat until all different
6220
6221   same_waypoint_name_udata udata;
6222
6223   GList *waypoint_names = NULL;
6224   udata.has_same_waypoint_name = FALSE;
6225   udata.same_waypoint_name = NULL;
6226
6227   g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_sorted_wp_id_by_name_list, &waypoint_names );
6228
6229   // No waypoints
6230   if ( ! waypoint_names )
6231     return;
6232
6233   GList *dummy_list1 = g_list_sort_with_data ( waypoint_names, check_waypoints_for_same_name, &udata );
6234
6235   // Still no waypoints...
6236   if ( ! dummy_list1 )
6237     return;
6238
6239   while ( udata.has_same_waypoint_name ) {
6240
6241     // Find a waypoint with the same name
6242     VikWaypoint *waypoint = vik_trw_layer_get_waypoint ( vtl, (gpointer) udata.same_waypoint_name );
6243
6244     if ( ! waypoint ) {
6245       // Broken :(
6246       g_critical("Houston, we've had a problem.");
6247       vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO, 
6248                                   _("Internal Error in vik_trw_layer_uniquify_waypoints") );
6249       return;
6250     }
6251
6252     // Rename it
6253     gchar *newname = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, udata.same_waypoint_name );
6254
6255     trw_layer_waypoint_rename ( vtl, waypoint, newname );
6256
6257     // Start trying to find same names again...
6258     waypoint_names = NULL;
6259     g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_sorted_wp_id_by_name_list, &waypoint_names );
6260     udata.has_same_waypoint_name = FALSE;
6261     GList *dummy_list2 = g_list_sort_with_data ( waypoint_names, check_waypoints_for_same_name, &udata );
6262
6263     // No waypoints any more - give up searching
6264     if ( ! dummy_list2 )
6265       udata.has_same_waypoint_name = FALSE;
6266   }
6267
6268   // Update
6269   vik_layers_panel_emit_update ( vlp );
6270 }
6271
6272 /**
6273  *
6274  */
6275 static void trw_layer_delete_waypoints_from_selection ( gpointer lav[2] )
6276 {
6277   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
6278   GList *all = NULL;
6279
6280   // Ensure list of waypoint names offered is unique
6281   if ( trw_layer_has_same_waypoint_names ( vtl ) ) {
6282     if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
6283                               _("Multiple entries with the same name exist. This method only works with unique names. Force unique names now?"), NULL ) ) {
6284       vik_trw_layer_uniquify_waypoints ( vtl, VIK_LAYERS_PANEL(lav[1]) );
6285     }
6286     else
6287       return;
6288   }
6289
6290   // Sort list alphabetically for better presentation
6291   g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_sorted_wp_id_by_name_list, &all);
6292   if ( ! all ) {
6293     a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No waypoints found"));
6294     return;
6295   }
6296
6297   all = g_list_sort_with_data(all, sort_alphabetically, NULL);
6298
6299   // Get list of items to delete from the user
6300   GList *delete_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl),
6301                                                  all,
6302                                                  TRUE,
6303                                                  _("Delete Selection"),
6304                                                  _("Select waypoints to delete"));
6305   g_list_free(all);
6306
6307   // Delete requested waypoints
6308   // since specificly requested, IMHO no need for extra confirmation
6309   if ( delete_list ) {
6310     GList *l;
6311     for (l = delete_list; l != NULL; l = g_list_next(l)) {
6312       // This deletes first waypoint it finds of that name (but uniqueness is enforced above)
6313       trw_layer_delete_waypoint_by_name (vtl, l->data);
6314     }
6315     g_list_free(delete_list);
6316
6317     trw_layer_calculate_bounds_waypoints ( vtl );
6318     vik_layer_emit_update( VIK_LAYER(vtl) );
6319   }
6320
6321 }
6322
6323 /**
6324  *
6325  */
6326 static void trw_layer_iter_visibility_toggle ( gpointer id, GtkTreeIter *it, VikTreeview *vt )
6327 {
6328   vik_treeview_item_toggle_visible ( vt, it );
6329 }
6330
6331 /**
6332  *
6333  */
6334 static void trw_layer_iter_visibility ( gpointer id, GtkTreeIter *it, gpointer vis_data[2] )
6335 {
6336   vik_treeview_item_set_visible ( (VikTreeview*)vis_data[0], it, GPOINTER_TO_INT (vis_data[1]) );
6337 }
6338
6339 /**
6340  *
6341  */
6342 static void trw_layer_waypoints_visibility ( gpointer id, VikWaypoint *wp, gpointer on_off )
6343 {
6344   wp->visible = GPOINTER_TO_INT (on_off);
6345 }
6346
6347 /**
6348  *
6349  */
6350 static void trw_layer_waypoints_toggle_visibility ( gpointer id, VikWaypoint *wp )
6351 {
6352   wp->visible = !wp->visible;
6353 }
6354
6355 /**
6356  *
6357  */
6358 static void trw_layer_waypoints_visibility_off ( gpointer lav[2] )
6359 {
6360   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
6361   gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(FALSE) };
6362   g_hash_table_foreach ( vtl->waypoints_iters, (GHFunc) trw_layer_iter_visibility, vis_data );
6363   g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_waypoints_visibility, vis_data[1] );
6364   // Redraw
6365   vik_layer_emit_update ( VIK_LAYER(vtl) );
6366 }
6367
6368 /**
6369  *
6370  */
6371 static void trw_layer_waypoints_visibility_on ( gpointer lav[2] )
6372 {
6373   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
6374   gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(TRUE) };
6375   g_hash_table_foreach ( vtl->waypoints_iters, (GHFunc) trw_layer_iter_visibility, vis_data );
6376   g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_waypoints_visibility, vis_data[1] );
6377   // Redraw
6378   vik_layer_emit_update ( VIK_LAYER(vtl) );
6379 }
6380
6381 /**
6382  *
6383  */
6384 static void trw_layer_waypoints_visibility_toggle ( gpointer lav[2] )
6385 {
6386   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
6387   g_hash_table_foreach ( vtl->waypoints_iters, (GHFunc) trw_layer_iter_visibility_toggle, VIK_LAYER(vtl)->vt );
6388   g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_waypoints_toggle_visibility, NULL );
6389   // Redraw
6390   vik_layer_emit_update ( VIK_LAYER(vtl) );
6391 }
6392
6393 /**
6394  *
6395  */
6396 static void trw_layer_tracks_visibility ( gpointer id, VikTrack *trk, gpointer on_off )
6397 {
6398   trk->visible = GPOINTER_TO_INT (on_off);
6399 }
6400
6401 /**
6402  *
6403  */
6404 static void trw_layer_tracks_toggle_visibility ( gpointer id, VikTrack *trk )
6405 {
6406   trk->visible = !trk->visible;
6407 }
6408
6409 /**
6410  *
6411  */
6412 static void trw_layer_tracks_visibility_off ( gpointer lav[2] )
6413 {
6414   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
6415   gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(FALSE) };
6416   g_hash_table_foreach ( vtl->tracks_iters, (GHFunc) trw_layer_iter_visibility, vis_data );
6417   g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_tracks_visibility, vis_data[1] );
6418   // Redraw
6419   vik_layer_emit_update ( VIK_LAYER(vtl) );
6420 }
6421
6422 /**
6423  *
6424  */
6425 static void trw_layer_tracks_visibility_on ( gpointer lav[2] )
6426 {
6427   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
6428   gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(TRUE) };
6429   g_hash_table_foreach ( vtl->tracks_iters, (GHFunc) trw_layer_iter_visibility, vis_data );
6430   g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_tracks_visibility, vis_data[1] );
6431   // Redraw
6432   vik_layer_emit_update ( VIK_LAYER(vtl) );
6433 }
6434
6435 /**
6436  *
6437  */
6438 static void trw_layer_tracks_visibility_toggle ( gpointer lav[2] )
6439 {
6440   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
6441   g_hash_table_foreach ( vtl->tracks_iters, (GHFunc) trw_layer_iter_visibility_toggle, VIK_LAYER(vtl)->vt );
6442   g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_tracks_toggle_visibility, NULL );
6443   // Redraw
6444   vik_layer_emit_update ( VIK_LAYER(vtl) );
6445 }
6446
6447 /**
6448  *
6449  */
6450 static void trw_layer_routes_visibility_off ( gpointer lav[2] )
6451 {
6452   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
6453   gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(FALSE) };
6454   g_hash_table_foreach ( vtl->routes_iters, (GHFunc) trw_layer_iter_visibility, vis_data );
6455   g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_tracks_visibility, vis_data[1] );
6456   // Redraw
6457   vik_layer_emit_update ( VIK_LAYER(vtl) );
6458 }
6459
6460 /**
6461  *
6462  */
6463 static void trw_layer_routes_visibility_on ( gpointer lav[2] )
6464 {
6465   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
6466   gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(TRUE) };
6467   g_hash_table_foreach ( vtl->routes_iters, (GHFunc) trw_layer_iter_visibility, vis_data );
6468   g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_tracks_visibility, vis_data[1] );
6469   // Redraw
6470   vik_layer_emit_update ( VIK_LAYER(vtl) );
6471 }
6472
6473 /**
6474  *
6475  */
6476 static void trw_layer_routes_visibility_toggle ( gpointer lav[2] )
6477 {
6478   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
6479   g_hash_table_foreach ( vtl->routes_iters, (GHFunc) trw_layer_iter_visibility_toggle, VIK_LAYER(vtl)->vt );
6480   g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_tracks_toggle_visibility, NULL );
6481   // Redraw
6482   vik_layer_emit_update ( VIK_LAYER(vtl) );
6483 }
6484
6485 /**
6486  * trw_layer_analyse_close:
6487  *
6488  * Stuff to do on dialog closure
6489  */
6490 static void trw_layer_analyse_close ( GtkWidget *dialog, gint resp, VikLayer* vl )
6491 {
6492   VikTrwLayer *vtl = VIK_TRW_LAYER(vl);
6493   gtk_widget_destroy ( dialog );
6494   vtl->tracks_analysis_dialog = NULL;
6495 }
6496
6497 /**
6498  * trw_layer_analyse_create_list:
6499  *
6500  * Create the latest list of tracks with the associated layer(s)
6501  *  Although this will always be from a single layer here
6502  */
6503 static GList* trw_layer_analyse_create_list ( VikLayer *vl, gpointer user_data )
6504 {
6505   VikTrwLayer *vtl = VIK_TRW_LAYER(vl);
6506   GList *tracks = NULL;
6507   if ( GPOINTER_TO_INT(user_data) == VIK_TRW_LAYER_SUBLAYER_TRACKS )
6508     tracks = g_hash_table_get_values ( vik_trw_layer_get_tracks(vtl) );
6509   else
6510     tracks = g_hash_table_get_values ( vik_trw_layer_get_routes(vtl) );
6511
6512   GList *tracks_and_layers = NULL;
6513   // build tracks_and_layers list
6514   tracks = g_list_first ( tracks );
6515   while ( tracks ) {
6516     vik_trw_track_list_t *vtdl = g_malloc (sizeof(vik_trw_track_list_t));
6517     vtdl->trk = VIK_TRACK(tracks->data);
6518     vtdl->vtl = vtl;
6519     tracks_and_layers = g_list_prepend ( tracks_and_layers, vtdl );
6520     tracks = g_list_next ( tracks );
6521   }
6522
6523   return tracks_and_layers;
6524 }
6525
6526 static void trw_layer_tracks_stats ( gpointer lav[2] )
6527 {
6528   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
6529   // There can only be one!
6530   if ( vtl->tracks_analysis_dialog )
6531     return;
6532
6533   vtl->tracks_analysis_dialog = vik_trw_layer_analyse_this ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
6534                                                              VIK_LAYER(vtl)->name,
6535                                                              VIK_LAYER(vtl),
6536                                                              GINT_TO_POINTER(VIK_TRW_LAYER_SUBLAYER_TRACKS),
6537                                                              trw_layer_analyse_create_list,
6538                                                              trw_layer_analyse_close );
6539 }
6540
6541 /**
6542  *
6543  */
6544 static void trw_layer_routes_stats ( gpointer lav[2] )
6545 {
6546   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
6547   // There can only be one!
6548   if ( vtl->tracks_analysis_dialog )
6549     return;
6550
6551   vtl->tracks_analysis_dialog = vik_trw_layer_analyse_this ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
6552                                                              VIK_LAYER(vtl)->name,
6553                                                              VIK_LAYER(vtl),
6554                                                              GINT_TO_POINTER(VIK_TRW_LAYER_SUBLAYER_ROUTES),
6555                                                              trw_layer_analyse_create_list,
6556                                                              trw_layer_analyse_close );
6557 }
6558
6559 static void trw_layer_goto_waypoint ( gpointer pass_along[6] )
6560 {
6561   VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->waypoints, pass_along[3] );
6562   if ( wp )
6563     goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(wp->coord) );
6564 }
6565
6566 static void trw_layer_waypoint_gc_webpage ( gpointer pass_along[6] )
6567 {
6568   VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->waypoints, pass_along[3] );
6569   if ( !wp )
6570     return;
6571   gchar *webpage = g_strdup_printf("http://www.geocaching.com/seek/cache_details.aspx?wp=%s", wp->name );
6572   open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), webpage);
6573   g_free ( webpage );
6574 }
6575
6576 static void trw_layer_waypoint_webpage ( gpointer pass_along[6] )
6577 {
6578   VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->waypoints, pass_along[3] );
6579   if ( !wp )
6580     return;
6581   if ( !strncmp(wp->comment, "http", 4) ) {
6582     open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), wp->comment);
6583   } else if ( !strncmp(wp->description, "http", 4) ) {
6584     open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), wp->description);
6585   }
6586 }
6587
6588 static const gchar* trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gchar *newname, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter )
6589 {
6590   if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
6591   {
6592     VikWaypoint *wp = g_hash_table_lookup ( l->waypoints, sublayer );
6593
6594     // No actual change to the name supplied
6595     if ( wp->name )
6596       if (strcmp(newname, wp->name) == 0 )
6597        return NULL;
6598
6599     VikWaypoint *wpf = vik_trw_layer_get_waypoint ( l, newname );
6600
6601     if ( wpf ) {
6602       // An existing waypoint has been found with the requested name
6603       if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(l),
6604            _("A waypoint with the name \"%s\" already exists. Really rename to the same name?"),
6605            newname ) )
6606         return NULL;
6607     }
6608
6609     // Update WP name and refresh the treeview
6610     vik_waypoint_set_name (wp, newname);
6611
6612     vik_treeview_item_set_name ( VIK_LAYER(l)->vt, iter, newname );
6613     vik_treeview_sort_children ( VIK_LAYER(l)->vt, &(l->waypoints_iter), l->wp_sort_order );
6614
6615     vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) );
6616
6617     return newname;
6618   }
6619
6620   if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
6621   {
6622     VikTrack *trk = g_hash_table_lookup ( l->tracks, sublayer );
6623
6624     // No actual change to the name supplied
6625     if ( trk->name )
6626       if (strcmp(newname, trk->name) == 0)
6627         return NULL;
6628
6629     VikTrack *trkf = vik_trw_layer_get_track ( l, (gpointer) newname );
6630
6631     if ( trkf ) {
6632       // An existing track has been found with the requested name
6633       if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(l),
6634           _("A track with the name \"%s\" already exists. Really rename to the same name?"),
6635           newname ) )
6636         return NULL;
6637     }
6638     // Update track name and refresh GUI parts
6639     vik_track_set_name (trk, newname);
6640
6641     // Update any subwindows that could be displaying this track which has changed name
6642     // Only one Track Edit Window
6643     if ( l->current_tp_track == trk && l->tpwin ) {
6644       vik_trw_layer_tpwin_set_track_name ( l->tpwin, newname );
6645     }
6646     // Property Dialog of the track
6647     vik_trw_layer_propwin_update ( trk );
6648
6649     vik_treeview_item_set_name ( VIK_LAYER(l)->vt, iter, newname );
6650     vik_treeview_sort_children ( VIK_LAYER(l)->vt, &(l->tracks_iter), l->track_sort_order );
6651
6652     vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) );
6653
6654     return newname;
6655   }
6656
6657   if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE )
6658   {
6659     VikTrack *trk = g_hash_table_lookup ( l->routes, sublayer );
6660
6661     // No actual change to the name supplied
6662     if ( trk->name )
6663       if (strcmp(newname, trk->name) == 0)
6664         return NULL;
6665
6666     VikTrack *trkf = vik_trw_layer_get_route ( l, (gpointer) newname );
6667
6668     if ( trkf ) {
6669       // An existing track has been found with the requested name
6670       if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(l),
6671           _("A route with the name \"%s\" already exists. Really rename to the same name?"),
6672           newname ) )
6673         return NULL;
6674     }
6675     // Update track name and refresh GUI parts
6676     vik_track_set_name (trk, newname);
6677
6678     // Update any subwindows that could be displaying this track which has changed name
6679     // Only one Track Edit Window
6680     if ( l->current_tp_track == trk && l->tpwin ) {
6681       vik_trw_layer_tpwin_set_track_name ( l->tpwin, newname );
6682     }
6683     // Property Dialog of the track
6684     vik_trw_layer_propwin_update ( trk );
6685
6686     vik_treeview_item_set_name ( VIK_LAYER(l)->vt, iter, newname );
6687     vik_treeview_sort_children ( VIK_LAYER(l)->vt, &(l->tracks_iter), l->track_sort_order );
6688
6689     vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) );
6690
6691     return newname;
6692   }
6693   return NULL;
6694 }
6695
6696 static gboolean is_valid_geocache_name ( gchar *str )
6697 {
6698   gint len = strlen ( str );
6699   return len >= 3 && len <= 7 && str[0] == 'G' && str[1] == 'C' && isalnum(str[2]) && (len < 4 || isalnum(str[3])) && (len < 5 || isalnum(str[4])) && (len < 6 || isalnum(str[5])) && (len < 7 || isalnum(str[6]));
6700 }
6701
6702 static void trw_layer_track_use_with_filter ( gpointer pass_along[6] )
6703 {
6704   VikTrack *trk = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
6705   a_acquire_set_filter_track ( trk );
6706 }
6707
6708 #ifdef VIK_CONFIG_GOOGLE
6709 static gboolean is_valid_google_route ( VikTrwLayer *vtl, const gpointer track_id )
6710 {
6711   VikTrack *tr = g_hash_table_lookup ( vtl->routes, track_id );
6712   return ( tr && tr->comment && strlen(tr->comment) > 7 && !strncmp(tr->comment, "from:", 5) );
6713 }
6714
6715 static void trw_layer_google_route_webpage ( gpointer pass_along[6] )
6716 {
6717   VikTrack *tr = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->routes, pass_along[3] );
6718   if ( tr ) {
6719     gchar *escaped = uri_escape ( tr->comment );
6720     gchar *webpage = g_strdup_printf("http://maps.google.com/maps?f=q&hl=en&q=%s", escaped );
6721     open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), webpage);
6722     g_free ( escaped );
6723     g_free ( webpage );
6724   }
6725 }
6726 #endif
6727
6728 /* vlp can be NULL if necessary - i.e. right-click from a tool */
6729 /* viewpoint is now available instead */
6730 static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter, VikViewport *vvp )
6731 {
6732   static gpointer pass_along[8];
6733   GtkWidget *item;
6734   gboolean rv = FALSE;
6735
6736   pass_along[0] = l;
6737   pass_along[1] = vlp;
6738   pass_along[2] = GINT_TO_POINTER (subtype);
6739   pass_along[3] = sublayer;
6740   pass_along[4] = GINT_TO_POINTER (1); // Confirm delete request
6741   pass_along[5] = vvp;
6742   pass_along[6] = iter;
6743   pass_along[7] = NULL; // For misc purposes - maybe track or waypoint
6744
6745   if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT || subtype == VIK_TRW_LAYER_SUBLAYER_TRACK || subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE )
6746   {
6747     rv = TRUE;
6748
6749     item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_PROPERTIES, NULL );
6750     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_properties_item), pass_along );
6751     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
6752     gtk_widget_show ( item );
6753
6754     if (subtype == VIK_TRW_LAYER_SUBLAYER_TRACK) {
6755       VikTrack *tr = g_hash_table_lookup ( l->tracks, sublayer );
6756       if (tr && tr->property_dialog)
6757         gtk_widget_set_sensitive(GTK_WIDGET(item), FALSE );
6758     }
6759     if (subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE) {
6760       VikTrack *tr = g_hash_table_lookup ( l->routes, sublayer );
6761       if (tr && tr->property_dialog)
6762         gtk_widget_set_sensitive(GTK_WIDGET(item), FALSE );
6763     }
6764
6765     item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_CUT, NULL );
6766     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_cut_item_cb), pass_along );
6767     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
6768     gtk_widget_show ( item );
6769
6770     item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_COPY, NULL );
6771     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_copy_item_cb), pass_along );
6772     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
6773     gtk_widget_show ( item );
6774
6775     item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_DELETE, NULL );
6776     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_item), pass_along );
6777     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
6778     gtk_widget_show ( item );
6779
6780     if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
6781     {
6782       gboolean separator_created = FALSE;
6783
6784       /* could be a right-click using the tool */
6785       if ( vlp != NULL ) {
6786         item = gtk_menu_item_new ();
6787         gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
6788         gtk_widget_show ( item );
6789
6790         separator_created = TRUE;
6791
6792         item = gtk_image_menu_item_new_with_mnemonic ( _("_Goto") );
6793         gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
6794         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_waypoint), pass_along );
6795         gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
6796         gtk_widget_show ( item );
6797       }
6798
6799       VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(l)->waypoints, sublayer );
6800
6801       if ( wp && wp->name ) {
6802         if ( is_valid_geocache_name ( wp->name ) ) {
6803
6804           if ( !separator_created ) {
6805             item = gtk_menu_item_new ();
6806             gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
6807             gtk_widget_show ( item );
6808             separator_created = TRUE;
6809           }
6810
6811           item = gtk_menu_item_new_with_mnemonic ( _("_Visit Geocache Webpage") );
6812           g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoint_gc_webpage), pass_along );
6813           gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
6814           gtk_widget_show ( item );
6815         }
6816       }
6817
6818       if ( wp && wp->image )
6819       {
6820         if ( !separator_created ) {
6821           item = gtk_menu_item_new ();
6822           gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
6823           gtk_widget_show ( item );
6824           separator_created = TRUE;
6825         }
6826
6827         // Set up image paramater
6828         pass_along[5] = wp->image;
6829
6830         item = gtk_image_menu_item_new_with_mnemonic ( _("_Show Picture...") );
6831         gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("vik-icon-Show Picture", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c
6832         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_show_picture), pass_along );
6833         gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
6834         gtk_widget_show ( item );
6835
6836 #ifdef VIK_CONFIG_GEOTAG
6837         GtkWidget *geotag_submenu = gtk_menu_new ();
6838         item = gtk_image_menu_item_new_with_mnemonic ( _("Update Geotag on _Image") );
6839         gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
6840         gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
6841         gtk_widget_show ( item );
6842         gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), geotag_submenu );
6843   
6844         item = gtk_menu_item_new_with_mnemonic ( _("_Update") );
6845         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_geotagging_waypoint_mtime_update), pass_along );
6846         gtk_menu_shell_append (GTK_MENU_SHELL (geotag_submenu), item);
6847         gtk_widget_show ( item );
6848
6849         item = gtk_menu_item_new_with_mnemonic ( _("Update and _Keep File Timestamp") );
6850         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_geotagging_waypoint_mtime_keep), pass_along );
6851         gtk_menu_shell_append (GTK_MENU_SHELL (geotag_submenu), item);
6852         gtk_widget_show ( item );
6853 #endif
6854       }
6855
6856       if ( wp )
6857       {
6858         if ( ( wp->comment && !strncmp(wp->comment, "http", 4) ) ||
6859              ( wp->description && !strncmp(wp->description, "http", 4) )) {
6860           item = gtk_image_menu_item_new_with_mnemonic ( _("Visit _Webpage") );
6861           gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NETWORK, GTK_ICON_SIZE_MENU) );
6862           g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoint_webpage), pass_along );
6863           gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
6864           gtk_widget_show ( item );
6865         }
6866       }
6867
6868     }
6869   }
6870
6871   if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS || subtype == VIK_TRW_LAYER_SUBLAYER_TRACKS || subtype == VIK_TRW_LAYER_SUBLAYER_ROUTES ) {
6872     item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_PASTE, NULL );
6873     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_paste_item_cb), pass_along );
6874     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
6875     gtk_widget_show ( item );
6876     // TODO: only enable if suitable item is in clipboard - want to determine *which* sublayer type
6877     if ( a_clipboard_type ( ) == VIK_CLIPBOARD_DATA_SUBLAYER )
6878       gtk_widget_set_sensitive ( item, TRUE );
6879     else
6880       gtk_widget_set_sensitive ( item, FALSE );
6881
6882     // Add separator
6883     item = gtk_menu_item_new ();
6884     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
6885     gtk_widget_show ( item );
6886   }
6887
6888   if ( vlp && (subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS || subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT) )
6889   {
6890     rv = TRUE;
6891     item = gtk_image_menu_item_new_with_mnemonic ( _("_New Waypoint...") );
6892     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) );
6893     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wp), pass_along );
6894     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
6895     gtk_widget_show ( item );
6896   }
6897
6898   if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS )
6899   {
6900     item = gtk_image_menu_item_new_with_mnemonic ( _("_View All Waypoints") );
6901     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
6902     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_waypoints_view), pass_along );
6903     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
6904     gtk_widget_show ( item );
6905
6906     item = gtk_image_menu_item_new_with_mnemonic ( _("Goto _Waypoint...") );
6907     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
6908     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_wp), pass_along );
6909     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
6910     gtk_widget_show ( item );
6911
6912     item = gtk_image_menu_item_new_with_mnemonic ( _("Delete _All Waypoints") );
6913     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
6914     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_waypoints), pass_along );
6915     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
6916     gtk_widget_show ( item );
6917
6918     item = gtk_image_menu_item_new_with_mnemonic ( _("_Delete Waypoints From Selection...") );
6919     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
6920     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_waypoints_from_selection), pass_along );
6921     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
6922     gtk_widget_show ( item );
6923
6924     GtkWidget *vis_submenu = gtk_menu_new ();
6925     item = gtk_menu_item_new_with_mnemonic ( _("_Visibility") );
6926     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
6927     gtk_widget_show ( item );
6928     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), vis_submenu );
6929
6930     item = gtk_image_menu_item_new_with_mnemonic ( _("_Show All Waypoints") );
6931     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_APPLY, GTK_ICON_SIZE_MENU) );
6932     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoints_visibility_on), pass_along );
6933     gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item );
6934     gtk_widget_show ( item );
6935
6936     item = gtk_image_menu_item_new_with_mnemonic ( _("_Hide All Waypoints") );
6937     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CLEAR, GTK_ICON_SIZE_MENU) );
6938     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoints_visibility_off), pass_along );
6939     gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item );
6940     gtk_widget_show ( item );
6941
6942     item = gtk_image_menu_item_new_with_mnemonic ( _("_Toggle") );
6943     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
6944     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoints_visibility_toggle), pass_along );
6945     gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item );
6946     gtk_widget_show ( item );
6947   }
6948
6949   if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACKS )
6950   {
6951     rv = TRUE;
6952
6953     if ( l->current_track && !l->current_track->is_route ) {
6954       item = gtk_menu_item_new_with_mnemonic ( _("_Finish Track") );
6955       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_finish_track), pass_along );
6956       gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
6957       gtk_widget_show ( item );
6958       // Add separator
6959       item = gtk_menu_item_new ();
6960       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
6961       gtk_widget_show ( item );
6962     }
6963
6964     item = gtk_image_menu_item_new_with_mnemonic ( _("_View All Tracks") );
6965     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
6966     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_tracks_view), pass_along );
6967     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
6968     gtk_widget_show ( item );
6969
6970     item = gtk_image_menu_item_new_with_mnemonic ( _("_New Track") );
6971     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) );
6972     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_track), pass_along );
6973     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
6974     gtk_widget_show ( item );
6975     // Make it available only when a new track *not* already in progress
6976     gtk_widget_set_sensitive ( item, ! (gboolean)GPOINTER_TO_INT(l->current_track) );
6977
6978     item = gtk_image_menu_item_new_with_mnemonic ( _("Delete _All Tracks") );
6979     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
6980     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_tracks), pass_along );
6981     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
6982     gtk_widget_show ( item );
6983
6984     item = gtk_image_menu_item_new_with_mnemonic ( _("_Delete Tracks From Selection...") );
6985     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
6986     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_tracks_from_selection), pass_along );
6987     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
6988     gtk_widget_show ( item );
6989
6990     GtkWidget *vis_submenu = gtk_menu_new ();
6991     item = gtk_menu_item_new_with_mnemonic ( _("_Visibility") );
6992     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
6993     gtk_widget_show ( item );
6994     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), vis_submenu );
6995
6996     item = gtk_image_menu_item_new_with_mnemonic ( _("_Show All Tracks") );
6997     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_APPLY, GTK_ICON_SIZE_MENU) );
6998     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_tracks_visibility_on), pass_along );
6999     gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item );
7000     gtk_widget_show ( item );
7001
7002     item = gtk_image_menu_item_new_with_mnemonic ( _("_Hide All Tracks") );
7003     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CLEAR, GTK_ICON_SIZE_MENU) );
7004     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_tracks_visibility_off), pass_along );
7005     gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item );
7006     gtk_widget_show ( item );
7007
7008     item = gtk_image_menu_item_new_with_mnemonic ( _("_Toggle") );
7009     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
7010     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_tracks_visibility_toggle), pass_along );
7011     gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item );
7012     gtk_widget_show ( item );
7013
7014     item = gtk_menu_item_new_with_mnemonic ( _("_Statistics") );
7015     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_tracks_stats), pass_along );
7016     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7017     gtk_widget_show ( item );
7018   }
7019
7020   if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTES )
7021   {
7022     rv = TRUE;
7023
7024     if ( l->current_track && l->current_track->is_route ) {
7025       item = gtk_menu_item_new_with_mnemonic ( _("_Finish Route") );
7026       // Reuse finish track method
7027       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_finish_track), pass_along );
7028       gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7029       gtk_widget_show ( item );
7030       // Add separator
7031       item = gtk_menu_item_new ();
7032       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7033       gtk_widget_show ( item );
7034     }
7035
7036     item = gtk_image_menu_item_new_with_mnemonic ( _("_View All Routes") );
7037     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
7038     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_routes_view), pass_along );
7039     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7040     gtk_widget_show ( item );
7041
7042     item = gtk_image_menu_item_new_with_mnemonic ( _("_New Route") );
7043     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) );
7044     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_route), pass_along );
7045     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7046     gtk_widget_show ( item );
7047     // Make it available only when a new track *not* already in progress
7048     gtk_widget_set_sensitive ( item, ! (gboolean)GPOINTER_TO_INT(l->current_track) );
7049
7050     item = gtk_image_menu_item_new_with_mnemonic ( _("Delete _All Routes") );
7051     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
7052     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_routes), pass_along );
7053     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7054     gtk_widget_show ( item );
7055
7056     item = gtk_image_menu_item_new_with_mnemonic ( _("_Delete Routes From Selection...") );
7057     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
7058     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_routes_from_selection), pass_along );
7059     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7060     gtk_widget_show ( item );
7061
7062     GtkWidget *vis_submenu = gtk_menu_new ();
7063     item = gtk_menu_item_new_with_mnemonic ( _("_Visibility") );
7064     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7065     gtk_widget_show ( item );
7066     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), vis_submenu );
7067
7068     item = gtk_image_menu_item_new_with_mnemonic ( _("_Show All Routes") );
7069     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_APPLY, GTK_ICON_SIZE_MENU) );
7070     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_routes_visibility_on), pass_along );
7071     gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item );
7072     gtk_widget_show ( item );
7073
7074     item = gtk_image_menu_item_new_with_mnemonic ( _("_Hide All Routes") );
7075     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CLEAR, GTK_ICON_SIZE_MENU) );
7076     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_routes_visibility_off), pass_along );
7077     gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item );
7078     gtk_widget_show ( item );
7079
7080     item = gtk_image_menu_item_new_with_mnemonic ( _("_Toggle") );
7081     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
7082     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_routes_visibility_toggle), pass_along );
7083     gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item );
7084     gtk_widget_show ( item );
7085
7086     item = gtk_menu_item_new_with_mnemonic ( _("_Statistics") );
7087     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_routes_stats), pass_along );
7088     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7089     gtk_widget_show ( item );
7090   }
7091
7092
7093   if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS || subtype == VIK_TRW_LAYER_SUBLAYER_TRACKS || subtype == VIK_TRW_LAYER_SUBLAYER_ROUTES ) {
7094     GtkWidget *submenu_sort = gtk_menu_new ();
7095     item = gtk_image_menu_item_new_with_mnemonic ( _("_Sort") );
7096     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
7097     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7098     gtk_widget_show ( item );
7099     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu_sort );
7100
7101     item = gtk_image_menu_item_new_with_mnemonic ( _("Name _Ascending") );
7102     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_SORT_ASCENDING, GTK_ICON_SIZE_MENU) );
7103     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_sort_order_a2z), pass_along );
7104     gtk_menu_shell_append ( GTK_MENU_SHELL(submenu_sort), item );
7105     gtk_widget_show ( item );
7106
7107     item = gtk_image_menu_item_new_with_mnemonic ( _("Name _Descending") );
7108     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_SORT_DESCENDING, GTK_ICON_SIZE_MENU) );
7109     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_sort_order_z2a), pass_along );
7110     gtk_menu_shell_append ( GTK_MENU_SHELL(submenu_sort), item );
7111     gtk_widget_show ( item );
7112   }
7113
7114   GtkWidget *upload_submenu = gtk_menu_new ();
7115
7116   if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK || subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE )
7117   {
7118     item = gtk_menu_item_new ();
7119     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7120     gtk_widget_show ( item );
7121
7122     if ( l->current_track && subtype == VIK_TRW_LAYER_SUBLAYER_TRACK && !l->current_track->is_route )
7123       item = gtk_menu_item_new_with_mnemonic ( _("_Finish Track") );
7124     if ( l->current_track && subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE && l->current_track->is_route )
7125       item = gtk_menu_item_new_with_mnemonic ( _("_Finish Route") );
7126     if ( l->current_track ) {
7127       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_finish_track), pass_along );
7128       gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7129       gtk_widget_show ( item );
7130
7131       // Add separator
7132       item = gtk_menu_item_new ();
7133       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7134       gtk_widget_show ( item );
7135     }
7136
7137     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
7138       item = gtk_image_menu_item_new_with_mnemonic ( _("_View Track") );
7139     else
7140       item = gtk_image_menu_item_new_with_mnemonic ( _("_View Route") );
7141     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
7142     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_track_view), pass_along );
7143     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7144     gtk_widget_show ( item );
7145
7146     GtkWidget *goto_submenu;
7147     goto_submenu = gtk_menu_new ();
7148     item = gtk_image_menu_item_new_with_mnemonic ( _("_Goto") );
7149     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
7150     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7151     gtk_widget_show ( item );
7152     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), goto_submenu );
7153
7154     item = gtk_image_menu_item_new_with_mnemonic ( _("_Startpoint") );
7155     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GOTO_FIRST, GTK_ICON_SIZE_MENU) );
7156     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_startpoint), pass_along );
7157     gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
7158     gtk_widget_show ( item );
7159
7160     item = gtk_image_menu_item_new_with_mnemonic ( _("\"_Center\"") );
7161     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
7162     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_center), pass_along );
7163     gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
7164     gtk_widget_show ( item );
7165
7166     item = gtk_image_menu_item_new_with_mnemonic ( _("_Endpoint") );
7167     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GOTO_LAST, GTK_ICON_SIZE_MENU) );
7168     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_endpoint), pass_along );
7169     gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
7170     gtk_widget_show ( item );
7171
7172     item = gtk_image_menu_item_new_with_mnemonic ( _("_Highest Altitude") );
7173     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GOTO_TOP, GTK_ICON_SIZE_MENU) );
7174     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_max_alt), pass_along );
7175     gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
7176     gtk_widget_show ( item );
7177
7178     item = gtk_image_menu_item_new_with_mnemonic ( _("_Lowest Altitude") );
7179     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GOTO_BOTTOM, GTK_ICON_SIZE_MENU) );
7180     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_min_alt), pass_along );
7181     gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
7182     gtk_widget_show ( item );
7183
7184     // Routes don't have speeds
7185     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
7186       item = gtk_image_menu_item_new_with_mnemonic ( _("_Maximum Speed") );
7187       gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_MEDIA_FORWARD, GTK_ICON_SIZE_MENU) );
7188       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_max_speed), pass_along );
7189       gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
7190       gtk_widget_show ( item );
7191     }
7192
7193     GtkWidget *combine_submenu;
7194     combine_submenu = gtk_menu_new ();
7195     item = gtk_image_menu_item_new_with_mnemonic ( _("Co_mbine") );
7196     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CONNECT, GTK_ICON_SIZE_MENU) );
7197     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7198     gtk_widget_show ( item );
7199     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), combine_submenu );
7200
7201     // Routes don't have times or segments...
7202     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
7203       item = gtk_menu_item_new_with_mnemonic ( _("_Merge By Time...") );
7204       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_merge_by_timestamp), pass_along );
7205       gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item );
7206       gtk_widget_show ( item );
7207
7208       item = gtk_menu_item_new_with_mnemonic ( _("Merge _Segments") );
7209       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_merge_by_segment), pass_along );
7210       gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item );
7211       gtk_widget_show ( item );
7212     }
7213
7214     item = gtk_menu_item_new_with_mnemonic ( _("Merge _With Other Tracks...") );
7215     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_merge_with_other), pass_along );
7216     gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item );
7217     gtk_widget_show ( item );
7218
7219     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
7220       item = gtk_menu_item_new_with_mnemonic ( _("_Append Track...") );
7221     else
7222       item = gtk_menu_item_new_with_mnemonic ( _("_Append Route...") );
7223     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_append_track), pass_along );
7224     gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item );
7225     gtk_widget_show ( item );
7226
7227     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
7228       item = gtk_menu_item_new_with_mnemonic ( _("Append _Route...") );
7229     else
7230       item = gtk_menu_item_new_with_mnemonic ( _("Append _Track...") );
7231     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_append_other), pass_along );
7232     gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item );
7233     gtk_widget_show ( item );
7234
7235     GtkWidget *split_submenu;
7236     split_submenu = gtk_menu_new ();
7237     item = gtk_image_menu_item_new_with_mnemonic ( _("_Split") );
7238     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_DISCONNECT, GTK_ICON_SIZE_MENU) );
7239     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7240     gtk_widget_show ( item );
7241     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), split_submenu );
7242
7243     // Routes don't have times or segments...
7244     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
7245       item = gtk_menu_item_new_with_mnemonic ( _("_Split By Time...") );
7246       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_by_timestamp), pass_along );
7247       gtk_menu_shell_append ( GTK_MENU_SHELL(split_submenu), item );
7248       gtk_widget_show ( item );
7249
7250       // ATM always enable this entry - don't want to have to analyse the track before displaying the menu - to keep the menu speedy
7251       item = gtk_menu_item_new_with_mnemonic ( _("Split Se_gments") );
7252       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_segments), pass_along );
7253       gtk_menu_shell_append ( GTK_MENU_SHELL(split_submenu), item );
7254       gtk_widget_show ( item );
7255     }
7256
7257     item = gtk_menu_item_new_with_mnemonic ( _("Split By _Number of Points...") );
7258     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_by_n_points), pass_along );
7259     gtk_menu_shell_append ( GTK_MENU_SHELL(split_submenu), item );
7260     gtk_widget_show ( item );
7261
7262     item = gtk_menu_item_new_with_mnemonic ( _("Split at _Trackpoint") );
7263     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_at_trackpoint), pass_along );
7264     gtk_menu_shell_append ( GTK_MENU_SHELL(split_submenu), item );
7265     gtk_widget_show ( item );
7266     // Make it available only when a trackpoint is selected.
7267     gtk_widget_set_sensitive ( item, (gboolean)GPOINTER_TO_INT(l->current_tpl) );
7268
7269     GtkWidget *delete_submenu;
7270     delete_submenu = gtk_menu_new ();
7271     item = gtk_image_menu_item_new_with_mnemonic ( _("Delete Poi_nts") );
7272     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_DELETE, GTK_ICON_SIZE_MENU) );
7273     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7274     gtk_widget_show ( item );
7275     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), delete_submenu );
7276
7277     item = gtk_menu_item_new_with_mnemonic ( _("Delete Points With The Same _Position") );
7278     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_points_same_position), pass_along );
7279     gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
7280     gtk_widget_show ( item );
7281
7282     item = gtk_menu_item_new_with_mnemonic ( _("Delete Points With The Same _Time") );
7283     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_points_same_time), pass_along );
7284     gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
7285     gtk_widget_show ( item );
7286
7287     GtkWidget *transform_submenu;
7288     transform_submenu = gtk_menu_new ();
7289     item = gtk_image_menu_item_new_with_mnemonic ( _("_Transform") );
7290     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CONVERT, GTK_ICON_SIZE_MENU) );
7291     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7292     gtk_widget_show ( item );
7293     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), transform_submenu );
7294
7295     GtkWidget *dem_submenu;
7296     dem_submenu = gtk_menu_new ();
7297     item = gtk_image_menu_item_new_with_mnemonic ( _("_Apply DEM Data") );
7298     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("vik-icon-DEM Download", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c
7299     gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item );
7300     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), dem_submenu );
7301
7302     item = gtk_image_menu_item_new_with_mnemonic ( _("_Overwrite") );
7303     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data_all), pass_along );
7304     gtk_menu_shell_append ( GTK_MENU_SHELL(dem_submenu), item );
7305     gtk_widget_set_tooltip_text (item, _("Overwrite any existing elevation values with DEM values"));
7306     gtk_widget_show ( item );
7307
7308     item = gtk_image_menu_item_new_with_mnemonic ( _("_Keep Existing") );
7309     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data_only_missing), pass_along );
7310     gtk_menu_shell_append ( GTK_MENU_SHELL(dem_submenu), item );
7311     gtk_widget_set_tooltip_text (item, _("Keep existing elevation values, only attempt for missing values"));
7312     gtk_widget_show ( item );
7313
7314     GtkWidget *smooth_submenu;
7315     smooth_submenu = gtk_menu_new ();
7316     item = gtk_menu_item_new_with_mnemonic ( _("_Smooth Missing Elevation Data") );
7317     gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item );
7318     gtk_widget_show ( item );
7319     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), smooth_submenu );
7320
7321     item = gtk_image_menu_item_new_with_mnemonic ( _("_Interpolated") );
7322     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_missing_elevation_data_interp), pass_along );
7323     gtk_menu_shell_append ( GTK_MENU_SHELL(smooth_submenu), item );
7324     gtk_widget_set_tooltip_text (item, _("Interpolate between known elevation values to derive values for the missing elevations"));
7325     gtk_widget_show ( item );
7326
7327     item = gtk_image_menu_item_new_with_mnemonic ( _("_Flat") );
7328     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_missing_elevation_data_flat), pass_along );
7329     gtk_menu_shell_append ( GTK_MENU_SHELL(smooth_submenu), item );
7330     gtk_widget_set_tooltip_text (item, _("Set unknown elevation values to the last known value"));
7331     gtk_widget_show ( item );
7332
7333     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
7334       item = gtk_image_menu_item_new_with_mnemonic ( _("C_onvert to a Route") );
7335     else
7336       item = gtk_image_menu_item_new_with_mnemonic ( _("C_onvert to a Track") );
7337     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CONVERT, GTK_ICON_SIZE_MENU) );
7338     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_convert_track_route), pass_along );
7339     gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item );
7340     gtk_widget_show ( item );
7341
7342     // Routes don't have timestamps - so this is only available for tracks
7343     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
7344       item = gtk_image_menu_item_new_with_mnemonic ( _("_Anonymize Times") );
7345       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_anonymize_times), pass_along );
7346       gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item );
7347       gtk_widget_set_tooltip_text (item, _("Shift timestamps to a relative offset from 1901-01-01"));
7348       gtk_widget_show ( item );
7349     }
7350
7351     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
7352       item = gtk_image_menu_item_new_with_mnemonic ( _("_Reverse Track") );
7353     else
7354       item = gtk_image_menu_item_new_with_mnemonic ( _("_Reverse Route") );
7355     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_BACK, GTK_ICON_SIZE_MENU) );
7356     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_reverse), pass_along );
7357     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7358     gtk_widget_show ( item );
7359
7360     if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE ) {
7361       item = gtk_image_menu_item_new_with_mnemonic ( _("Refine Route...") );
7362       gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_FIND, GTK_ICON_SIZE_MENU) );
7363       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_route_refine), pass_along );
7364       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7365       gtk_widget_show ( item );
7366     }
7367
7368     /* ATM This function is only available via the layers panel, due to the method in finding out the maps in use */
7369     if ( vlp ) {
7370       if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
7371         item = gtk_image_menu_item_new_with_mnemonic ( _("Down_load Maps Along Track...") );
7372       else
7373         item = gtk_image_menu_item_new_with_mnemonic ( _("Down_load Maps Along Route...") );
7374       gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("vik-icon-Maps Download", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c
7375       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_download_map_along_track_cb), pass_along );
7376       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7377       gtk_widget_show ( item );
7378     }
7379
7380     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
7381       item = gtk_image_menu_item_new_with_mnemonic ( _("_Export Track as GPX...") );
7382     else
7383       item = gtk_image_menu_item_new_with_mnemonic ( _("_Export Route as GPX...") );
7384     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_HARDDISK, GTK_ICON_SIZE_MENU) );
7385     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpx_track), pass_along );
7386     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7387     gtk_widget_show ( item );
7388
7389     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
7390       item = gtk_image_menu_item_new_with_mnemonic ( _("E_xtend Track End") );
7391     else
7392       item = gtk_image_menu_item_new_with_mnemonic ( _("E_xtend Route End") );
7393     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
7394     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_extend_track_end), pass_along );
7395     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7396     gtk_widget_show ( item );
7397
7398     if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE ) {
7399       item = gtk_image_menu_item_new_with_mnemonic ( _("Extend _Using Route Finder") );
7400       gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("vik-icon-Route Finder", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c
7401       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_extend_track_end_route_finder), pass_along );
7402       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7403       gtk_widget_show ( item );
7404     }
7405
7406     // ATM can't upload a single waypoint but can do waypoints to a GPS
7407     if ( subtype != VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
7408       item = gtk_image_menu_item_new_with_mnemonic ( _("_Upload") );
7409       gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU) );
7410       gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7411       gtk_widget_show ( item );
7412       gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), upload_submenu );
7413
7414       item = gtk_image_menu_item_new_with_mnemonic ( _("_Upload to GPS...") );
7415       gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_MENU) );
7416       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_gps_upload_any), pass_along );
7417       gtk_menu_shell_append ( GTK_MENU_SHELL(upload_submenu), item );
7418       gtk_widget_show ( item );
7419     }
7420   }
7421
7422 #ifdef VIK_CONFIG_GOOGLE
7423   if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE && is_valid_google_route ( l, sublayer ) )
7424   {
7425     item = gtk_image_menu_item_new_with_mnemonic ( _("_View Google Directions") );
7426     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NETWORK, GTK_ICON_SIZE_MENU) );
7427     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_google_route_webpage), pass_along );
7428     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7429     gtk_widget_show ( item );
7430   }
7431 #endif
7432
7433   // Some things aren't usable with routes
7434   if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
7435 #ifdef VIK_CONFIG_OPENSTREETMAP
7436     item = gtk_image_menu_item_new_with_mnemonic ( _("Upload to _OSM...") );
7437     // Convert internal pointer into actual track for usage outside this file
7438     pass_along[7] = g_hash_table_lookup ( l->tracks, sublayer);
7439     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU) );
7440     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(osm_traces_upload_track_cb), pass_along );
7441     gtk_menu_shell_append ( GTK_MENU_SHELL(upload_submenu), item );
7442     gtk_widget_show ( item );
7443 #endif
7444
7445     item = gtk_image_menu_item_new_with_mnemonic ( _("Use with _Filter") );
7446     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
7447     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_use_with_filter), pass_along );
7448     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7449     gtk_widget_show ( item );
7450
7451     /* ATM This function is only available via the layers panel, due to needing a vlp */
7452     if ( vlp ) {
7453       item = a_acquire_track_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(l)), vlp,
7454                                     vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vlp)),
7455                                     g_hash_table_lookup ( l->tracks, (gchar *) sublayer ) );
7456       if ( item ) {
7457         gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7458         gtk_widget_show ( item );
7459       }
7460     }
7461
7462 #ifdef VIK_CONFIG_GEOTAG
7463     item = gtk_menu_item_new_with_mnemonic ( _("Geotag _Images...") );
7464     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_geotagging_track), pass_along );
7465     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7466     gtk_widget_show ( item );
7467 #endif
7468   }
7469
7470   if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK || subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE ) {
7471     // Only show on viewport popmenu when a trackpoint is selected
7472     if ( ! vlp && l->current_tpl ) {
7473       // Add separator
7474       item = gtk_menu_item_new ();
7475       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7476       gtk_widget_show ( item );
7477
7478       item = gtk_image_menu_item_new_with_mnemonic ( _("_Edit Trackpoint") );
7479       gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_PROPERTIES, GTK_ICON_SIZE_MENU) );
7480       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_edit_trackpoint), pass_along );
7481       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7482       gtk_widget_show ( item );
7483     }
7484   }
7485
7486   if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS || subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
7487     GtkWidget *transform_submenu;
7488     transform_submenu = gtk_menu_new ();
7489     item = gtk_image_menu_item_new_with_mnemonic ( _("_Transform") );
7490     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CONVERT, GTK_ICON_SIZE_MENU) );
7491     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7492     gtk_widget_show ( item );
7493     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), transform_submenu );
7494
7495     GtkWidget *dem_submenu;
7496     dem_submenu = gtk_menu_new ();
7497     item = gtk_image_menu_item_new_with_mnemonic ( _("_Apply DEM Data") );
7498     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock ("vik-icon-DEM Download", GTK_ICON_SIZE_MENU) ); // Own icon - see stock_icons in vikwindow.c
7499     gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item );
7500     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), dem_submenu );
7501
7502     item = gtk_image_menu_item_new_with_mnemonic ( _("_Overwrite") );
7503     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data_wpt_all), pass_along );
7504     gtk_menu_shell_append ( GTK_MENU_SHELL(dem_submenu), item );
7505     gtk_widget_set_tooltip_text (item, _("Overwrite any existing elevation values with DEM values"));
7506     gtk_widget_show ( item );
7507
7508     item = gtk_image_menu_item_new_with_mnemonic ( _("_Keep Existing") );
7509     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data_wpt_only_missing), pass_along );
7510     gtk_menu_shell_append ( GTK_MENU_SHELL(dem_submenu), item );
7511     gtk_widget_set_tooltip_text (item, _("Keep existing elevation values, only attempt for missing values"));
7512     gtk_widget_show ( item );
7513   }
7514
7515   gtk_widget_show_all ( GTK_WIDGET(menu) );
7516
7517   return rv;
7518 }
7519
7520 static void trw_layer_insert_tp_after_current_tp ( VikTrwLayer *vtl )
7521 {
7522   /* sanity checks */
7523   if (!vtl->current_tpl)
7524     return;
7525   if (!vtl->current_tpl->next)
7526     return;
7527
7528   VikTrackpoint *tp_current = VIK_TRACKPOINT(vtl->current_tpl->data);
7529   VikTrackpoint *tp_next = VIK_TRACKPOINT(vtl->current_tpl->next->data);
7530
7531   /* Use current and next trackpoints to form a new track point which is inserted into the tracklist */
7532   if ( tp_next ) {
7533
7534     VikTrackpoint *tp_new = vik_trackpoint_new();
7535     struct LatLon ll_current, ll_next;
7536     vik_coord_to_latlon ( &tp_current->coord, &ll_current );
7537     vik_coord_to_latlon ( &tp_next->coord, &ll_next );
7538
7539     /* main positional interpolation */
7540     struct LatLon ll_new = { (ll_current.lat+ll_next.lat)/2, (ll_current.lon+ll_next.lon)/2 };
7541     vik_coord_load_from_latlon ( &(tp_new->coord), vtl->coord_mode, &ll_new );
7542
7543     /* Now other properties that can be interpolated */
7544     tp_new->altitude = (tp_current->altitude + tp_next->altitude) / 2;
7545
7546     if (tp_current->has_timestamp && tp_next->has_timestamp) {
7547       /* Note here the division is applied to each part, then added
7548          This is to avoid potential overflow issues with a 32 time_t for dates after midpoint of this Unix time on 2004/01/04 */
7549       tp_new->timestamp = (tp_current->timestamp/2) + (tp_next->timestamp/2);
7550       tp_new->has_timestamp = TRUE;
7551     }
7552
7553     if (tp_current->speed != NAN && tp_next->speed != NAN)
7554       tp_new->speed = (tp_current->speed + tp_next->speed)/2;
7555
7556     /* TODO - improve interpolation of course, as it may not be correct.
7557        if courses in degrees are 350 + 020, the mid course more likely to be 005 (not 185)
7558        [similar applies if value is in radians] */
7559     if (tp_current->course != NAN && tp_next->course != NAN)
7560       tp_new->course = (tp_current->course + tp_next->course)/2;
7561
7562     /* DOP / sat values remain at defaults as not they do not seem applicable to a dreamt up point */
7563
7564     /* Insert new point into the trackpoints list after the current TP */
7565     VikTrack *trk = g_hash_table_lookup ( vtl->tracks, vtl->current_tp_id );
7566     if ( !trk )
7567       // Otherwise try routes
7568       trk = g_hash_table_lookup ( vtl->routes, vtl->current_tp_id );
7569     if ( !trk )
7570       return;
7571
7572     gint index =  g_list_index ( trk->trackpoints, tp_current );
7573     if ( index > -1 ) {
7574       // NB no recalculation of bounds since it is inserted between points
7575       trk->trackpoints = g_list_insert ( trk->trackpoints, tp_new, index+1 );
7576     }
7577   }
7578 }
7579
7580 static void trw_layer_cancel_current_tp ( VikTrwLayer *vtl, gboolean destroy )
7581 {
7582   if ( vtl->tpwin )
7583   {
7584     if ( destroy)
7585     {
7586       gtk_widget_destroy ( GTK_WIDGET(vtl->tpwin) );
7587       vtl->tpwin = NULL;
7588     }
7589     else
7590       vik_trw_layer_tpwin_set_empty ( vtl->tpwin );
7591   }
7592   if ( vtl->current_tpl )
7593   {
7594     vtl->current_tpl = NULL;
7595     vtl->current_tp_track = NULL;
7596     vtl->current_tp_id = NULL;
7597     vik_layer_emit_update(VIK_LAYER(vtl));
7598   }
7599 }
7600
7601 static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response )
7602 {
7603   g_assert ( vtl->tpwin != NULL );
7604   if ( response == VIK_TRW_LAYER_TPWIN_CLOSE )
7605     trw_layer_cancel_current_tp ( vtl, TRUE );
7606
7607   if ( vtl->current_tpl == NULL )
7608     return;
7609
7610   if ( response == VIK_TRW_LAYER_TPWIN_SPLIT && vtl->current_tpl->next && vtl->current_tpl->prev )
7611   {
7612     trw_layer_split_at_selected_trackpoint ( vtl, vtl->current_tp_track->is_route ? VIK_TRW_LAYER_SUBLAYER_ROUTE : VIK_TRW_LAYER_SUBLAYER_TRACK );
7613     vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
7614   }
7615   else if ( response == VIK_TRW_LAYER_TPWIN_DELETE )
7616   {
7617     VikTrack *tr = g_hash_table_lookup ( vtl->tracks, vtl->current_tp_id );
7618     if ( tr == NULL )
7619       tr = g_hash_table_lookup ( vtl->routes, vtl->current_tp_id );
7620     if ( tr == NULL )
7621       return;
7622
7623     GList *new_tpl;
7624
7625     // Find available adjacent trackpoint
7626     if ( (new_tpl = vtl->current_tpl->next) || (new_tpl = vtl->current_tpl->prev) )
7627     {
7628       if ( VIK_TRACKPOINT(vtl->current_tpl->data)->newsegment && vtl->current_tpl->next )
7629         VIK_TRACKPOINT(vtl->current_tpl->next->data)->newsegment = TRUE; /* don't concat segments on del */
7630
7631       // Delete current trackpoint
7632       vik_trackpoint_free ( vtl->current_tpl->data );
7633       tr->trackpoints = g_list_delete_link ( tr->trackpoints, vtl->current_tpl );
7634
7635       // Set to current to the available adjacent trackpoint
7636       vtl->current_tpl = new_tpl;
7637
7638       // Reset dialog with the available adjacent trackpoint
7639       if ( vtl->current_tp_track ) {
7640         vik_track_calculate_bounds ( vtl->current_tp_track );
7641         vik_trw_layer_tpwin_set_tp ( vtl->tpwin, new_tpl, vtl->current_tp_track->name );
7642       }
7643
7644       vik_layer_emit_update(VIK_LAYER(vtl));
7645     }
7646     else
7647     {
7648       // Delete current trackpoint
7649       vik_trackpoint_free ( vtl->current_tpl->data );
7650       tr->trackpoints = g_list_delete_link ( tr->trackpoints, vtl->current_tpl );
7651       trw_layer_cancel_current_tp ( vtl, FALSE );
7652     }
7653   }
7654   else if ( response == VIK_TRW_LAYER_TPWIN_FORWARD && vtl->current_tpl->next )
7655   {
7656     if ( vtl->current_tp_track )
7657       vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl = vtl->current_tpl->next, vtl->current_tp_track->name );
7658     vik_layer_emit_update(VIK_LAYER(vtl)); /* TODO longone: either move or only update if tp is inside drawing window */
7659   }
7660   else if ( response == VIK_TRW_LAYER_TPWIN_BACK && vtl->current_tpl->prev )
7661   {
7662     if ( vtl->current_tp_track )
7663       vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl = vtl->current_tpl->prev, vtl->current_tp_track->name );
7664     vik_layer_emit_update(VIK_LAYER(vtl));
7665   }
7666   else if ( response == VIK_TRW_LAYER_TPWIN_INSERT && vtl->current_tpl->next )
7667   {
7668     trw_layer_insert_tp_after_current_tp ( vtl );
7669     vik_layer_emit_update(VIK_LAYER(vtl));
7670   }
7671   else if ( response == VIK_TRW_LAYER_TPWIN_DATA_CHANGED )
7672     vik_layer_emit_update(VIK_LAYER(vtl));
7673 }
7674
7675 /**
7676  * trw_layer_dialog_shift:
7677  * @vertical: The reposition strategy. If Vertical moves dialog vertically, otherwise moves it horizontally
7678  *
7679  * Try to reposition a dialog if it's over the specified coord
7680  *  so to not obscure the item of interest
7681  */
7682 void trw_layer_dialog_shift ( VikTrwLayer *vtl, GtkWindow *dialog, VikCoord *coord, gboolean vertical )
7683 {
7684   GtkWindow *parent = VIK_GTK_WINDOW_FROM_LAYER(vtl); //i.e. the main window
7685
7686   // Attempt force dialog to be shown so we can find out where it is more reliably...
7687   while ( gtk_events_pending() )
7688     gtk_main_iteration ();
7689
7690   // get parent window position & size
7691   gint win_pos_x, win_pos_y;
7692   gtk_window_get_position ( parent, &win_pos_x, &win_pos_y );
7693
7694   gint win_size_x, win_size_y;
7695   gtk_window_get_size ( parent, &win_size_x, &win_size_y );
7696
7697   // get own dialog size
7698   gint dia_size_x, dia_size_y;
7699   gtk_window_get_size ( dialog, &dia_size_x, &dia_size_y );
7700
7701   // get own dialog position
7702   gint dia_pos_x, dia_pos_y;
7703   gtk_window_get_position ( dialog, &dia_pos_x, &dia_pos_y );
7704
7705   // Dialog not 'realized'/positioned - so can't really do any repositioning logic
7706   if ( dia_pos_x > 2 && dia_pos_y > 2 ) {
7707
7708     VikViewport *vvp = vik_window_viewport ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) );
7709
7710     gint vp_xx, vp_yy; // In viewport pixels
7711     vik_viewport_coord_to_screen ( vvp, coord, &vp_xx, &vp_yy );
7712
7713     // Work out the 'bounding box' in pixel terms of the dialog and only move it when over the position
7714
7715     gint dest_x = 0;
7716     gint dest_y = 0;
7717     if ( gtk_widget_translate_coordinates ( GTK_WIDGET(vvp), GTK_WIDGET(parent), 0, 0, &dest_x, &dest_y ) ) {
7718
7719       // Transform Viewport pixels into absolute pixels
7720       gint tmp_xx = vp_xx + dest_x + win_pos_x - 10;
7721       gint tmp_yy = vp_yy + dest_y + win_pos_y - 10;
7722
7723       // Is dialog over the point (to within an  ^^ edge value)
7724       if ( (tmp_xx > dia_pos_x) && (tmp_xx < (dia_pos_x + dia_size_x)) &&
7725            (tmp_yy > dia_pos_y) && (tmp_yy < (dia_pos_y + dia_size_y)) ) {
7726
7727         if ( vertical ) {
7728           // Shift up<->down
7729           gint hh = vik_viewport_get_height ( vvp );
7730
7731           // Consider the difference in viewport to the full window
7732           gint offset_y = dest_y;
7733           // Add difference between dialog and window sizes
7734           offset_y += win_pos_y + (hh/2 - dia_size_y)/2;
7735
7736           if ( vp_yy > hh/2 ) {
7737             // Point in bottom half, move window to top half
7738             gtk_window_move ( dialog, dia_pos_x, offset_y );
7739           }
7740           else {
7741             // Point in top half, move dialog down
7742             gtk_window_move ( dialog, dia_pos_x, hh/2 + offset_y );
7743           }
7744         }
7745         else {
7746           // Shift left<->right
7747           gint ww = vik_viewport_get_width ( vvp );
7748
7749           // Consider the difference in viewport to the full window
7750           gint offset_x = dest_x;
7751           // Add difference between dialog and window sizes
7752           offset_x += win_pos_x + (ww/2 - dia_size_x)/2;
7753
7754           if ( vp_xx > ww/2 ) {
7755             // Point on right, move window to left
7756             gtk_window_move ( dialog, offset_x, dia_pos_y );
7757           }
7758           else {
7759             // Point on left, move right
7760             gtk_window_move ( dialog, ww/2 + offset_x, dia_pos_y );
7761           }
7762         }
7763       }
7764     }
7765   }
7766 }
7767
7768 static void trw_layer_tpwin_init ( VikTrwLayer *vtl )
7769 {
7770   if ( ! vtl->tpwin )
7771   {
7772     vtl->tpwin = vik_trw_layer_tpwin_new ( VIK_GTK_WINDOW_FROM_LAYER(vtl) );
7773     g_signal_connect_swapped ( GTK_DIALOG(vtl->tpwin), "response", G_CALLBACK(trw_layer_tpwin_response), vtl );
7774     /* connect signals -- DELETE SIGNAL VERY IMPORTANT TO SET TO NULL */
7775     g_signal_connect_swapped ( vtl->tpwin, "delete-event", G_CALLBACK(trw_layer_cancel_current_tp), vtl );
7776
7777     gtk_widget_show_all ( GTK_WIDGET(vtl->tpwin) );
7778
7779     if ( vtl->current_tpl ) {
7780       // get tp pixel position
7781       VikTrackpoint *tp = VIK_TRACKPOINT(vtl->current_tpl->data);
7782
7783       // Shift up<->down to try not to obscure the trackpoint.
7784       trw_layer_dialog_shift ( vtl, GTK_WINDOW(vtl->tpwin), &(tp->coord), TRUE );
7785     }
7786   }
7787
7788   if ( vtl->current_tpl )
7789     if ( vtl->current_tp_track )
7790       vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
7791   /* set layer name and TP data */
7792 }
7793
7794 /***************************************************************************
7795  ** Tool code
7796  ***************************************************************************/
7797
7798 /*** Utility data structures and functions ****/
7799
7800 typedef struct {
7801   gint x, y;
7802   gint closest_x, closest_y;
7803   gboolean draw_images;
7804   gpointer *closest_wp_id;
7805   VikWaypoint *closest_wp;
7806   VikViewport *vvp;
7807 } WPSearchParams;
7808
7809 typedef struct {
7810   gint x, y;
7811   gint closest_x, closest_y;
7812   gpointer closest_track_id;
7813   VikTrackpoint *closest_tp;
7814   VikViewport *vvp;
7815   GList *closest_tpl;
7816   LatLonBBox bbox;
7817 } TPSearchParams;
7818
7819 static void waypoint_search_closest_tp ( gpointer id, VikWaypoint *wp, WPSearchParams *params )
7820 {
7821   gint x, y;
7822   if ( !wp->visible )
7823     return;
7824
7825   vik_viewport_coord_to_screen ( params->vvp, &(wp->coord), &x, &y );
7826
7827   // If waypoint has an image then use the image size to select
7828   if ( params->draw_images && wp->image ) {
7829     gint slackx, slacky;
7830     slackx = wp->image_width / 2;
7831     slacky = wp->image_height / 2;
7832
7833     if (    x <= params->x + slackx && x >= params->x - slackx
7834          && y <= params->y + slacky && y >= params->y - slacky ) {
7835       params->closest_wp_id = id;
7836       params->closest_wp = wp;
7837       params->closest_x = x;
7838       params->closest_y = y;
7839     }
7840   }
7841   else if ( abs (x - params->x) <= WAYPOINT_SIZE_APPROX && abs (y - params->y) <= WAYPOINT_SIZE_APPROX &&
7842             ((!params->closest_wp) ||        /* was the old waypoint we already found closer than this one? */
7843              abs(x - params->x)+abs(y - params->y) < abs(x - params->closest_x)+abs(y - params->closest_y)))
7844     {
7845       params->closest_wp_id = id;
7846       params->closest_wp = wp;
7847       params->closest_x = x;
7848       params->closest_y = y;
7849     }
7850 }
7851
7852 static void track_search_closest_tp ( gpointer id, VikTrack *t, TPSearchParams *params )
7853 {
7854   GList *tpl = t->trackpoints;
7855   VikTrackpoint *tp;
7856
7857   if ( !t->visible )
7858     return;
7859
7860   if ( ! BBOX_INTERSECT ( t->bbox, params->bbox ) )
7861     return;
7862
7863   while (tpl)
7864   {
7865     gint x, y;
7866     tp = VIK_TRACKPOINT(tpl->data);
7867
7868     vik_viewport_coord_to_screen ( params->vvp, &(tp->coord), &x, &y );
7869  
7870     if ( abs (x - params->x) <= TRACKPOINT_SIZE_APPROX && abs (y - params->y) <= TRACKPOINT_SIZE_APPROX &&
7871         ((!params->closest_tp) ||        /* was the old trackpoint we already found closer than this one? */
7872           abs(x - params->x)+abs(y - params->y) < abs(x - params->closest_x)+abs(y - params->closest_y)))
7873     {
7874       params->closest_track_id = id;
7875       params->closest_tp = tp;
7876       params->closest_tpl = tpl;
7877       params->closest_x = x;
7878       params->closest_y = y;
7879     }
7880     tpl = tpl->next;
7881   }
7882 }
7883
7884 // ATM: Leave this as 'Track' only.
7885 //  Not overly bothered about having a snap to route trackpoint capability
7886 static VikTrackpoint *closest_tp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y )
7887 {
7888   TPSearchParams params;
7889   params.x = x;
7890   params.y = y;
7891   params.vvp = vvp;
7892   params.closest_track_id = NULL;
7893   params.closest_tp = NULL;
7894   vik_viewport_get_min_max_lat_lon ( params.vvp, &(params.bbox.south), &(params.bbox.north), &(params.bbox.west), &(params.bbox.east) );
7895   g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, &params);
7896   return params.closest_tp;
7897 }
7898
7899 static VikWaypoint *closest_wp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y )
7900 {
7901   WPSearchParams params;
7902   params.x = x;
7903   params.y = y;
7904   params.vvp = vvp;
7905   params.draw_images = vtl->drawimages;
7906   params.closest_wp = NULL;
7907   params.closest_wp_id = NULL;
7908   g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, &params);
7909   return params.closest_wp;
7910 }
7911
7912
7913 // Some forward declarations
7914 static void marker_begin_move ( tool_ed_t *t, gint x, gint y );
7915 static void marker_moveto ( tool_ed_t *t, gint x, gint y );
7916 static void marker_end_move ( tool_ed_t *t );
7917 //
7918
7919 static gboolean trw_layer_select_move ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t* t )
7920 {
7921   if ( t->holding ) {
7922     VikCoord new_coord;
7923     vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
7924
7925     // Here always allow snapping back to the original location
7926     //  this is useful when one decides not to move the thing afterall
7927     // If one wants to move the item only a little bit then don't hold down the 'snap' key!
7928  
7929     // snap to TP
7930     if ( event->state & GDK_CONTROL_MASK )
7931     {
7932       VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
7933       if ( tp )
7934         new_coord = tp->coord;
7935     }
7936
7937     // snap to WP
7938     if ( event->state & GDK_SHIFT_MASK )
7939     {
7940       VikWaypoint *wp = closest_wp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
7941       if ( wp )
7942         new_coord = wp->coord;
7943     }
7944     
7945     gint x, y;
7946     vik_viewport_coord_to_screen ( vvp, &new_coord, &x, &y );
7947
7948     marker_moveto ( t, x, y );
7949
7950     return TRUE;
7951   }
7952   return FALSE;
7953 }
7954
7955 static gboolean trw_layer_select_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t* t )
7956 {
7957   if ( t->holding && event->button == 1 )
7958   {
7959     VikCoord new_coord;
7960     vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
7961
7962     // snap to TP
7963     if ( event->state & GDK_CONTROL_MASK )
7964     {
7965       VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
7966       if ( tp )
7967         new_coord = tp->coord;
7968     }
7969
7970     // snap to WP
7971     if ( event->state & GDK_SHIFT_MASK )
7972     {
7973       VikWaypoint *wp = closest_wp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
7974       if ( wp )
7975         new_coord = wp->coord;
7976     }
7977
7978     marker_end_move ( t );
7979
7980     // Determine if working on a waypoint or a trackpoint
7981     if ( t->is_waypoint ) {
7982       vtl->current_wp->coord = new_coord;
7983       trw_layer_calculate_bounds_waypoints ( vtl );
7984     }
7985     else {
7986       if ( vtl->current_tpl ) {
7987         VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord;
7988
7989         if ( vtl->current_tp_track )
7990           vik_track_calculate_bounds ( vtl->current_tp_track );
7991
7992         if ( vtl->tpwin )
7993           if ( vtl->current_tp_track )
7994             vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
7995       }
7996     }
7997
7998     // Reset
7999     vtl->current_wp    = NULL;
8000     vtl->current_wp_id = NULL;
8001     trw_layer_cancel_current_tp ( vtl, FALSE );
8002
8003     vik_layer_emit_update ( VIK_LAYER(vtl) );
8004     return TRUE;
8005   }
8006   return FALSE;
8007 }
8008
8009 /*
8010   Returns true if a waypoint or track is found near the requested event position for this particular layer
8011   The item found is automatically selected
8012   This is a tool like feature but routed via the layer interface, since it's instigated by a 'global' layer tool in vikwindow.c
8013  */
8014 static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t* tet )
8015 {
8016   if ( event->button != 1 )
8017     return FALSE;
8018
8019   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
8020     return FALSE;
8021
8022   if ( !vtl->tracks_visible && !vtl->waypoints_visible && !vtl->routes_visible )
8023     return FALSE;
8024
8025   LatLonBBox bbox;
8026   vik_viewport_get_min_max_lat_lon ( vvp, &(bbox.south), &(bbox.north), &(bbox.west), &(bbox.east) );
8027
8028   // Go for waypoints first as these often will be near a track, but it's likely the wp is wanted rather then the track
8029
8030   if ( vtl->waypoints_visible && BBOX_INTERSECT (vtl->waypoints_bbox, bbox ) ) {
8031     WPSearchParams wp_params;
8032     wp_params.vvp = vvp;
8033     wp_params.x = event->x;
8034     wp_params.y = event->y;
8035     wp_params.draw_images = vtl->drawimages;
8036     wp_params.closest_wp_id = NULL;
8037     wp_params.closest_wp = NULL;
8038
8039     g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, &wp_params);
8040
8041     if ( wp_params.closest_wp )  {
8042
8043       // Select
8044       vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->waypoints_iters, wp_params.closest_wp_id ), TRUE );
8045
8046       // Too easy to move it so must be holding shift to start immediately moving it
8047       //   or otherwise be previously selected but not have an image (otherwise clicking within image bounds (again) moves it)
8048       if ( event->state & GDK_SHIFT_MASK ||
8049            ( vtl->current_wp == wp_params.closest_wp && !vtl->current_wp->image ) ) {
8050         // Put into 'move buffer'
8051         // NB vvp & vw already set in tet
8052         tet->vtl = (gpointer)vtl;
8053         tet->is_waypoint = TRUE;
8054       
8055         marker_begin_move (tet, event->x, event->y);
8056       }
8057
8058       vtl->current_wp =    wp_params.closest_wp;
8059       vtl->current_wp_id = wp_params.closest_wp_id;
8060
8061       vik_layer_emit_update ( VIK_LAYER(vtl) );
8062
8063       return TRUE;
8064     }
8065   }
8066
8067   // Used for both track and route lists
8068   TPSearchParams tp_params;
8069   tp_params.vvp = vvp;
8070   tp_params.x = event->x;
8071   tp_params.y = event->y;
8072   tp_params.closest_track_id = NULL;
8073   tp_params.closest_tp = NULL;
8074   tp_params.closest_tpl = NULL;
8075   tp_params.bbox = bbox;
8076
8077   if (vtl->tracks_visible) {
8078     g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, &tp_params);
8079
8080     if ( tp_params.closest_tp )  {
8081
8082       // Always select + highlight the track
8083       vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->tracks_iters, tp_params.closest_track_id ), TRUE );
8084
8085       tet->is_waypoint = FALSE;
8086
8087       // Select the Trackpoint
8088       // Can move it immediately when control held or it's the previously selected tp
8089       if ( event->state & GDK_CONTROL_MASK ||
8090            vtl->current_tpl == tp_params.closest_tpl ) {
8091         // Put into 'move buffer'
8092         // NB vvp & vw already set in tet
8093         tet->vtl = (gpointer)vtl;
8094         marker_begin_move (tet, event->x, event->y);
8095       }
8096
8097       vtl->current_tpl = tp_params.closest_tpl;
8098       vtl->current_tp_id = tp_params.closest_track_id;
8099       vtl->current_tp_track = g_hash_table_lookup ( vtl->tracks, tp_params.closest_track_id );
8100
8101       set_statusbar_msg_info_trkpt ( vtl, tp_params.closest_tp );
8102
8103       if ( vtl->tpwin )
8104         vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
8105
8106       vik_layer_emit_update ( VIK_LAYER(vtl) );
8107       return TRUE;
8108     }
8109   }
8110
8111   // Try again for routes
8112   if (vtl->routes_visible) {
8113     g_hash_table_foreach ( vtl->routes, (GHFunc) track_search_closest_tp, &tp_params);
8114
8115     if ( tp_params.closest_tp )  {
8116
8117       // Always select + highlight the track
8118       vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->routes_iters, tp_params.closest_track_id ), TRUE );
8119
8120       tet->is_waypoint = FALSE;
8121
8122       // Select the Trackpoint
8123       // Can move it immediately when control held or it's the previously selected tp
8124       if ( event->state & GDK_CONTROL_MASK ||
8125            vtl->current_tpl == tp_params.closest_tpl ) {
8126         // Put into 'move buffer'
8127         // NB vvp & vw already set in tet
8128         tet->vtl = (gpointer)vtl;
8129         marker_begin_move (tet, event->x, event->y);
8130       }
8131
8132       vtl->current_tpl = tp_params.closest_tpl;
8133       vtl->current_tp_id = tp_params.closest_track_id;
8134       vtl->current_tp_track = g_hash_table_lookup ( vtl->routes, tp_params.closest_track_id );
8135
8136       set_statusbar_msg_info_trkpt ( vtl, tp_params.closest_tp );
8137
8138       if ( vtl->tpwin )
8139         vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
8140
8141       vik_layer_emit_update ( VIK_LAYER(vtl) );
8142       return TRUE;
8143     }
8144   }
8145
8146   /* these aren't the droids you're looking for */
8147   vtl->current_wp    = NULL;
8148   vtl->current_wp_id = NULL;
8149   trw_layer_cancel_current_tp ( vtl, FALSE );
8150
8151   // Blank info
8152   vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO, "" );
8153
8154   return FALSE;
8155 }
8156
8157 static gboolean trw_layer_show_selected_viewport_menu ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
8158 {
8159   if ( event->button != 3 )
8160     return FALSE;
8161
8162   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
8163     return FALSE;
8164
8165   if ( !vtl->tracks_visible && !vtl->waypoints_visible && !vtl->routes_visible )
8166     return FALSE;
8167
8168   /* Post menu for the currently selected item */
8169
8170   /* See if a track is selected */
8171   VikTrack *track = (VikTrack*)vik_window_get_selected_track ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) );
8172   if ( track && track->visible ) {
8173
8174     if ( track->name ) {
8175
8176       if ( vtl->track_right_click_menu )
8177         g_object_ref_sink ( G_OBJECT(vtl->track_right_click_menu) );
8178
8179       vtl->track_right_click_menu = GTK_MENU ( gtk_menu_new () );
8180       
8181       trku_udata udataU;
8182       udataU.trk  = track;
8183       udataU.uuid = NULL;
8184
8185       gpointer *trkf;
8186       if ( track->is_route )
8187         trkf = g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find_uuid, &udataU );
8188       else
8189         trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udataU );
8190
8191       if ( trkf && udataU.uuid ) {
8192
8193         GtkTreeIter *iter;
8194         if ( track->is_route )
8195           iter = g_hash_table_lookup ( vtl->routes_iters, udataU.uuid );
8196         else
8197           iter = g_hash_table_lookup ( vtl->tracks_iters, udataU.uuid );
8198
8199         trw_layer_sublayer_add_menu_items ( vtl,
8200                                             vtl->track_right_click_menu,
8201                                             NULL,
8202                                             track->is_route ? VIK_TRW_LAYER_SUBLAYER_ROUTE : VIK_TRW_LAYER_SUBLAYER_TRACK,
8203                                             udataU.uuid,
8204                                             iter,
8205                                             vvp );
8206       }
8207
8208       gtk_menu_popup ( vtl->track_right_click_menu, NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time() );
8209         
8210       return TRUE;
8211     }
8212   }
8213
8214   /* See if a waypoint is selected */
8215   VikWaypoint *waypoint = (VikWaypoint*)vik_window_get_selected_waypoint ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) );
8216   if ( waypoint && waypoint->visible ) {
8217     if ( waypoint->name ) {
8218
8219       if ( vtl->wp_right_click_menu )
8220         g_object_ref_sink ( G_OBJECT(vtl->wp_right_click_menu) );
8221
8222       vtl->wp_right_click_menu = GTK_MENU ( gtk_menu_new () );
8223
8224       wpu_udata udata;
8225       udata.wp   = waypoint;
8226       udata.uuid = NULL;
8227
8228       gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata );
8229
8230       if ( wpf && udata.uuid ) {
8231         GtkTreeIter *iter = g_hash_table_lookup ( vtl->waypoints_iters, udata.uuid );
8232
8233         trw_layer_sublayer_add_menu_items ( vtl,
8234                                             vtl->wp_right_click_menu,
8235                                             NULL,
8236                                             VIK_TRW_LAYER_SUBLAYER_WAYPOINT,
8237                                             udata.uuid,
8238                                             iter,
8239                                             vvp );
8240       }
8241       gtk_menu_popup ( vtl->wp_right_click_menu, NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time() );
8242
8243       return TRUE;
8244     }
8245   }
8246
8247   return FALSE;
8248 }
8249
8250 /* background drawing hook, to be passed the viewport */
8251 static gboolean tool_sync_done = TRUE;
8252
8253 static gboolean tool_sync(gpointer data)
8254 {
8255   VikViewport *vvp = data;
8256   gdk_threads_enter();
8257   vik_viewport_sync(vvp);
8258   tool_sync_done = TRUE;
8259   gdk_threads_leave();
8260   return FALSE;
8261 }
8262
8263 static void marker_begin_move ( tool_ed_t *t, gint x, gint y )
8264 {
8265   t->holding = TRUE;
8266   t->gc = vik_viewport_new_gc (t->vvp, "black", 2);
8267   gdk_gc_set_function ( t->gc, GDK_INVERT );
8268   vik_viewport_draw_rectangle ( t->vvp, t->gc, FALSE, x-3, y-3, 6, 6 );
8269   vik_viewport_sync(t->vvp);
8270   t->oldx = x;
8271   t->oldy = y;
8272 }
8273
8274 static void marker_moveto ( tool_ed_t *t, gint x, gint y )
8275 {
8276   VikViewport *vvp =  t->vvp;
8277   vik_viewport_draw_rectangle ( vvp, t->gc, FALSE, t->oldx-3, t->oldy-3, 6, 6 );
8278   vik_viewport_draw_rectangle ( vvp, t->gc, FALSE, x-3, y-3, 6, 6 );
8279   t->oldx = x;
8280   t->oldy = y;
8281
8282   if (tool_sync_done) {
8283     g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, tool_sync, vvp, NULL);
8284     tool_sync_done = FALSE;
8285   }
8286 }
8287
8288 static void marker_end_move ( tool_ed_t *t )
8289 {
8290   vik_viewport_draw_rectangle ( t->vvp, t->gc, FALSE, t->oldx-3, t->oldy-3, 6, 6 );
8291   g_object_unref ( t->gc );
8292   t->holding = FALSE;
8293 }
8294
8295 /*** Edit waypoint ****/
8296
8297 static gpointer tool_edit_waypoint_create ( VikWindow *vw, VikViewport *vvp)
8298 {
8299   tool_ed_t *t = g_new(tool_ed_t, 1);
8300   t->vvp = vvp;
8301   t->holding = FALSE;
8302   return t;
8303 }
8304
8305 static void tool_edit_waypoint_destroy ( tool_ed_t *t )
8306 {
8307   g_free ( t );
8308 }
8309
8310 static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data )
8311 {
8312   WPSearchParams params;
8313   tool_ed_t *t = data;
8314   VikViewport *vvp = t->vvp;
8315
8316   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
8317     return FALSE;
8318
8319   if ( t->holding ) {
8320     return TRUE;
8321   }
8322
8323   if ( !vtl->vl.visible || !vtl->waypoints_visible )
8324     return FALSE;
8325
8326   if ( vtl->current_wp && vtl->current_wp->visible )
8327   {
8328     /* first check if current WP is within area (other may be 'closer', but we want to move the current) */
8329     gint x, y;
8330     vik_viewport_coord_to_screen ( vvp, &(vtl->current_wp->coord), &x, &y );
8331
8332     if ( abs(x - event->x) <= WAYPOINT_SIZE_APPROX &&
8333          abs(y - event->y) <= WAYPOINT_SIZE_APPROX )
8334     {
8335       if ( event->button == 3 )
8336         vtl->waypoint_rightclick = TRUE; /* remember that we're clicking; other layers will ignore release signal */
8337       else {
8338         marker_begin_move(t, event->x, event->y);
8339       }
8340       return TRUE;
8341     }
8342   }
8343
8344   params.vvp = vvp;
8345   params.x = event->x;
8346   params.y = event->y;
8347   params.draw_images = vtl->drawimages;
8348   params.closest_wp_id = NULL;
8349   /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */
8350   params.closest_wp = NULL;
8351   g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, &params);
8352   if ( vtl->current_wp == params.closest_wp && vtl->current_wp != NULL )
8353   {
8354     // how do we get here?
8355     marker_begin_move(t, event->x, event->y);
8356     g_critical("shouldn't be here");
8357     return FALSE;
8358   }
8359   else if ( params.closest_wp )
8360   {
8361     if ( event->button == 3 )
8362       vtl->waypoint_rightclick = TRUE; /* remember that we're clicking; other layers will ignore release signal */
8363     else
8364       vtl->waypoint_rightclick = FALSE;
8365
8366     vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->waypoints_iters, params.closest_wp_id ), TRUE );
8367
8368     vtl->current_wp = params.closest_wp;
8369     vtl->current_wp_id = params.closest_wp_id;
8370
8371     /* could make it so don't update if old WP is off screen and new is null but oh well */
8372     vik_layer_emit_update ( VIK_LAYER(vtl) );
8373     return TRUE;
8374   }
8375
8376   vtl->current_wp = NULL;
8377   vtl->current_wp_id = NULL;
8378   vtl->waypoint_rightclick = FALSE;
8379   vik_layer_emit_update ( VIK_LAYER(vtl) );
8380   return FALSE;
8381 }
8382
8383 static gboolean tool_edit_waypoint_move ( VikTrwLayer *vtl, GdkEventMotion *event, gpointer data )
8384 {
8385   tool_ed_t *t = data;
8386   VikViewport *vvp = t->vvp;
8387
8388   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
8389     return FALSE;
8390
8391   if ( t->holding ) {
8392     VikCoord new_coord;
8393     vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
8394
8395     /* snap to TP */
8396     if ( event->state & GDK_CONTROL_MASK )
8397     {
8398       VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
8399       if ( tp )
8400         new_coord = tp->coord;
8401     }
8402
8403     /* snap to WP */
8404     if ( event->state & GDK_SHIFT_MASK )
8405     {
8406       VikWaypoint *wp = closest_wp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
8407       if ( wp && wp != vtl->current_wp )
8408         new_coord = wp->coord;
8409     }
8410     
8411     { 
8412       gint x, y;
8413       vik_viewport_coord_to_screen ( vvp, &new_coord, &x, &y );
8414
8415       marker_moveto ( t, x, y );
8416     } 
8417     return TRUE;
8418   }
8419   return FALSE;
8420 }
8421
8422 static gboolean tool_edit_waypoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data )
8423 {
8424   tool_ed_t *t = data;
8425   VikViewport *vvp = t->vvp;
8426
8427   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
8428     return FALSE;
8429   
8430   if ( t->holding && event->button == 1 )
8431   {
8432     VikCoord new_coord;
8433     vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
8434
8435     /* snap to TP */
8436     if ( event->state & GDK_CONTROL_MASK )
8437     {
8438       VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
8439       if ( tp )
8440         new_coord = tp->coord;
8441     }
8442
8443     /* snap to WP */
8444     if ( event->state & GDK_SHIFT_MASK )
8445     {
8446       VikWaypoint *wp = closest_wp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
8447       if ( wp && wp != vtl->current_wp )
8448         new_coord = wp->coord;
8449     }
8450
8451     marker_end_move ( t );
8452
8453     vtl->current_wp->coord = new_coord;
8454
8455     trw_layer_calculate_bounds_waypoints ( vtl );
8456     vik_layer_emit_update ( VIK_LAYER(vtl) );
8457     return TRUE;
8458   }
8459   /* PUT IN RIGHT PLACE!!! */
8460   if ( event->button == 3 && vtl->waypoint_rightclick )
8461   {
8462     if ( vtl->wp_right_click_menu )
8463       g_object_ref_sink ( G_OBJECT(vtl->wp_right_click_menu) );
8464     if ( vtl->current_wp ) {
8465       vtl->wp_right_click_menu = GTK_MENU ( gtk_menu_new () );
8466       trw_layer_sublayer_add_menu_items ( vtl, vtl->wp_right_click_menu, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, vtl->current_wp_id, g_hash_table_lookup ( vtl->waypoints_iters, vtl->current_wp_id ), vvp );
8467       gtk_menu_popup ( vtl->wp_right_click_menu, NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time() );
8468     }
8469     vtl->waypoint_rightclick = FALSE;
8470   }
8471   return FALSE;
8472 }
8473
8474 /*** New track ****/
8475
8476 static gpointer tool_new_track_create ( VikWindow *vw, VikViewport *vvp)
8477 {
8478   return vvp;
8479 }
8480
8481 typedef struct {
8482   VikTrwLayer *vtl;
8483   GdkDrawable *drawable;
8484   GdkGC *gc;
8485   GdkPixmap *pixmap;
8486 } draw_sync_t;
8487
8488 /*
8489  * Draw specified pixmap
8490  */
8491 static gboolean draw_sync ( gpointer data )
8492 {
8493   draw_sync_t *ds = (draw_sync_t*) data;
8494   // Sometimes don't want to draw
8495   //  normally because another update has taken precedent such as panning the display
8496   //   which means this pixmap is no longer valid
8497   if ( ds->vtl->draw_sync_do ) {
8498     gdk_threads_enter();
8499     gdk_draw_drawable (ds->drawable,
8500                        ds->gc,
8501                        ds->pixmap,
8502                        0, 0, 0, 0, -1, -1);
8503     ds->vtl->draw_sync_done = TRUE;
8504     gdk_threads_leave();
8505   }
8506   g_free ( ds );
8507   return FALSE;
8508 }
8509
8510 static gchar* distance_string (gdouble distance)
8511 {
8512   gchar str[128];
8513
8514   /* draw label with distance */
8515   vik_units_distance_t dist_units = a_vik_get_units_distance ();
8516   switch (dist_units) {
8517   case VIK_UNITS_DISTANCE_MILES:
8518     if (distance >= VIK_MILES_TO_METERS(1) && distance < VIK_MILES_TO_METERS(100)) {
8519       g_sprintf(str, "%3.2f miles", VIK_METERS_TO_MILES(distance));
8520     } else if (distance < 1609.4) {
8521       g_sprintf(str, "%d yards", (int)(distance*1.0936133));
8522     } else {
8523       g_sprintf(str, "%d miles", (int)VIK_METERS_TO_MILES(distance));
8524     }
8525     break;
8526   default:
8527     // VIK_UNITS_DISTANCE_KILOMETRES
8528     if (distance >= 1000 && distance < 100000) {
8529       g_sprintf(str, "%3.2f km", distance/1000.0);
8530     } else if (distance < 1000) {
8531       g_sprintf(str, "%d m", (int)distance);
8532     } else {
8533       g_sprintf(str, "%d km", (int)distance/1000);
8534     }
8535     break;
8536   }
8537   return g_strdup (str);
8538 }
8539
8540 /*
8541  * Actually set the message in statusbar
8542  */
8543 static void statusbar_write (gdouble distance, gdouble elev_gain, gdouble elev_loss, gdouble last_step, gdouble angle, VikTrwLayer *vtl )
8544 {
8545   // Only show elevation data when track has some elevation properties
8546   gchar str_gain_loss[64];
8547   str_gain_loss[0] = '\0';
8548   gchar str_last_step[64];
8549   str_last_step[0] = '\0';
8550   gchar *str_total = distance_string (distance);
8551   
8552   if ( (elev_gain > 0.1) || (elev_loss > 0.1) ) {
8553     if ( a_vik_get_units_height () == VIK_UNITS_HEIGHT_METRES )
8554       g_sprintf(str_gain_loss, _(" - Gain %dm:Loss %dm"), (int)elev_gain, (int)elev_loss);
8555     else
8556       g_sprintf(str_gain_loss, _(" - Gain %dft:Loss %dft"), (int)VIK_METERS_TO_FEET(elev_gain), (int)VIK_METERS_TO_FEET(elev_loss));
8557   }
8558   
8559   if ( last_step > 0 ) {
8560       gchar *tmp = distance_string (last_step);
8561       g_sprintf(str_last_step, _(" - Bearing %3.1f° - Step %s"), RAD2DEG(angle), tmp);
8562       g_free ( tmp );
8563   }
8564   
8565   VikWindow *vw = VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl));
8566
8567   // Write with full gain/loss information
8568   gchar *msg = g_strdup_printf ( "Total %s%s%s", str_total, str_last_step, str_gain_loss);
8569   vik_statusbar_set_message ( vik_window_get_statusbar (vw), VIK_STATUSBAR_INFO, msg );
8570   g_free ( msg );
8571   g_free ( str_total );
8572 }
8573
8574 /*
8575  * Figure out what information should be set in the statusbar and then write it
8576  */
8577 static void update_statusbar ( VikTrwLayer *vtl )
8578 {
8579   // Get elevation data
8580   gdouble elev_gain, elev_loss;
8581   vik_track_get_total_elevation_gain ( vtl->current_track, &elev_gain, &elev_loss);
8582
8583   /* Find out actual distance of current track */
8584   gdouble distance = vik_track_get_length (vtl->current_track);
8585
8586   statusbar_write (distance, elev_gain, elev_loss, 0, 0, vtl);
8587 }
8588
8589
8590 static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMotion *event, VikViewport *vvp )
8591 {
8592   /* if we haven't sync'ed yet, we don't have time to do more. */
8593   if ( vtl->draw_sync_done && vtl->current_track && vtl->current_track->trackpoints ) {
8594     GList *iter = g_list_last ( vtl->current_track->trackpoints );
8595     VikTrackpoint *last_tpt = VIK_TRACKPOINT(iter->data);
8596
8597     static GdkPixmap *pixmap = NULL;
8598     int w1, h1, w2, h2;
8599     // Need to check in case window has been resized
8600     w1 = vik_viewport_get_width(vvp);
8601     h1 = vik_viewport_get_height(vvp);
8602     if (!pixmap) {
8603       pixmap = gdk_pixmap_new ( gtk_widget_get_window(GTK_WIDGET(vvp)), w1, h1, -1 );
8604     }
8605     gdk_drawable_get_size (pixmap, &w2, &h2);
8606     if (w1 != w2 || h1 != h2) {
8607       g_object_unref ( G_OBJECT ( pixmap ) );
8608       pixmap = gdk_pixmap_new ( gtk_widget_get_window(GTK_WIDGET(vvp)), w1, h1, -1 );
8609     }
8610
8611     // Reset to background
8612     gdk_draw_drawable (pixmap,
8613                        vtl->current_track_newpoint_gc,
8614                        vik_viewport_get_pixmap(vvp),
8615                        0, 0, 0, 0, -1, -1);
8616
8617     draw_sync_t *passalong;
8618     gint x1, y1;
8619
8620     vik_viewport_coord_to_screen ( vvp, &(last_tpt->coord), &x1, &y1 );
8621
8622     // FOR SCREEN OVERLAYS WE MUST DRAW INTO THIS PIXMAP (when using the reset method)
8623     //  otherwise using vik_viewport_draw_* functions puts the data into the base pixmap,
8624     //  thus when we come to reset to the background it would include what we have already drawn!!
8625     gdk_draw_line ( pixmap,
8626                     vtl->current_track_newpoint_gc,
8627                     x1, y1, event->x, event->y );
8628     // Using this reset method is more reliable than trying to undraw previous efforts via the GDK_INVERT method
8629
8630     /* Find out actual distance of current track */
8631     gdouble distance = vik_track_get_length (vtl->current_track);
8632
8633     // Now add distance to where the pointer is //
8634     VikCoord coord;
8635     struct LatLon ll;
8636     vik_viewport_screen_to_coord ( vvp, (gint) event->x, (gint) event->y, &coord );
8637     vik_coord_to_latlon ( &coord, &ll );
8638     gdouble last_step = vik_coord_diff( &coord, &(last_tpt->coord));
8639     distance = distance + last_step;
8640
8641     // Get elevation data
8642     gdouble elev_gain, elev_loss;
8643     vik_track_get_total_elevation_gain ( vtl->current_track, &elev_gain, &elev_loss);
8644
8645     // Adjust elevation data (if available) for the current pointer position
8646     gdouble elev_new;
8647     elev_new = (gdouble) a_dems_get_elev_by_coord ( &coord, VIK_DEM_INTERPOL_BEST );
8648     if ( elev_new != VIK_DEM_INVALID_ELEVATION ) {
8649       if ( last_tpt->altitude != VIK_DEFAULT_ALTITUDE ) {
8650         // Adjust elevation of last track point
8651         if ( elev_new > last_tpt->altitude )
8652           // Going up
8653           elev_gain += elev_new - last_tpt->altitude;
8654         else
8655           // Going down
8656           elev_loss += last_tpt->altitude - elev_new;
8657       }
8658     }
8659
8660     //
8661     // Display of the distance 'tooltip' during track creation is controlled by a preference
8662     //
8663     if ( a_vik_get_create_track_tooltip() ) {
8664
8665       gchar *str = distance_string (distance);
8666
8667       PangoLayout *pl = gtk_widget_create_pango_layout (GTK_WIDGET(vvp), NULL);
8668       pango_layout_set_font_description (pl, gtk_widget_get_style(GTK_WIDGET(vvp))->font_desc);
8669       pango_layout_set_text (pl, str, -1);
8670       gint wd, hd;
8671       pango_layout_get_pixel_size ( pl, &wd, &hd );
8672
8673       gint xd,yd;
8674       // offset from cursor a bit depending on font size
8675       xd = event->x + 10;
8676       yd = event->y - hd;
8677
8678       // Create a background block to make the text easier to read over the background map
8679       GdkGC *background_block_gc = vik_viewport_new_gc ( vvp, "#cccccc", 1);
8680       gdk_draw_rectangle (pixmap, background_block_gc, TRUE, xd-2, yd-2, wd+4, hd+2);
8681       gdk_draw_layout (pixmap, vtl->current_track_newpoint_gc, xd, yd, pl);
8682
8683       g_object_unref ( G_OBJECT ( pl ) );
8684       g_object_unref ( G_OBJECT ( background_block_gc ) );
8685       g_free (str);
8686     }
8687
8688     passalong = g_new(draw_sync_t,1); // freed by draw_sync()
8689     passalong->vtl = vtl;
8690     passalong->pixmap = pixmap;
8691     passalong->drawable = gtk_widget_get_window(GTK_WIDGET(vvp));
8692     passalong->gc = vtl->current_track_newpoint_gc;
8693
8694     gdouble angle;
8695     gdouble baseangle;
8696     vik_viewport_compute_bearing ( vvp, x1, y1, event->x, event->y, &angle, &baseangle );
8697
8698     // Update statusbar with full gain/loss information
8699     statusbar_write (distance, elev_gain, elev_loss, last_step, angle, vtl);
8700
8701     // draw pixmap when we have time to
8702     g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, draw_sync, passalong, NULL);
8703     vtl->draw_sync_done = FALSE;
8704     return VIK_LAYER_TOOL_ACK_GRAB_FOCUS;
8705   }
8706   return VIK_LAYER_TOOL_ACK;
8707 }
8708
8709 static gboolean tool_new_track_key_press ( VikTrwLayer *vtl, GdkEventKey *event, VikViewport *vvp )
8710 {
8711   if ( vtl->current_track && event->keyval == GDK_Escape ) {
8712     vtl->current_track = NULL;
8713     vik_layer_emit_update ( VIK_LAYER(vtl) );
8714     return TRUE;
8715   } else if ( vtl->current_track && event->keyval == GDK_BackSpace ) {
8716     /* undo */
8717     if ( vtl->current_track->trackpoints )
8718     {
8719       GList *last = g_list_last(vtl->current_track->trackpoints);
8720       g_free ( last->data );
8721       vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last );
8722     }
8723
8724     update_statusbar ( vtl );
8725
8726     vik_layer_emit_update ( VIK_LAYER(vtl) );
8727     return TRUE;
8728   }
8729   return FALSE;
8730 }
8731
8732 /*
8733  * Common function to handle trackpoint button requests on either a route or a track
8734  *  . enables adding a point via normal click
8735  *  . enables removal of last point via right click
8736  *  . finishing of the track or route via double clicking
8737  */
8738 static gboolean tool_new_track_or_route_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
8739 {
8740   VikTrackpoint *tp;
8741
8742   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
8743     return FALSE;
8744
8745   if ( event->button == 2 ) {
8746     // As the display is panning, the new track pixmap is now invalid so don't draw it
8747     //  otherwise this drawing done results in flickering back to an old image
8748     vtl->draw_sync_do = FALSE;
8749     return FALSE;
8750   }
8751
8752   if ( event->button == 3 )
8753   {
8754     if ( !vtl->current_track )
8755       return FALSE;
8756     /* undo */
8757     if ( vtl->current_track->trackpoints )
8758     {
8759       GList *last = g_list_last(vtl->current_track->trackpoints);
8760       g_free ( last->data );
8761       vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last );
8762     }
8763     vik_track_calculate_bounds ( vtl->current_track );
8764     update_statusbar ( vtl );
8765
8766     vik_layer_emit_update ( VIK_LAYER(vtl) );
8767     return TRUE;
8768   }
8769
8770   if ( event->type == GDK_2BUTTON_PRESS )
8771   {
8772     /* subtract last (duplicate from double click) tp then end */
8773     if ( vtl->current_track && vtl->current_track->trackpoints && vtl->ct_x1 == vtl->ct_x2 && vtl->ct_y1 == vtl->ct_y2 )
8774     {
8775       GList *last = g_list_last(vtl->current_track->trackpoints);
8776       g_free ( last->data );
8777       vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last );
8778       /* undo last, then end */
8779       vtl->current_track = NULL;
8780     }
8781     vik_layer_emit_update ( VIK_LAYER(vtl) );
8782     return TRUE;
8783   }
8784
8785   tp = vik_trackpoint_new();
8786   vik_viewport_screen_to_coord ( vvp, event->x, event->y, &(tp->coord) );
8787
8788   /* snap to other TP */
8789   if ( event->state & GDK_CONTROL_MASK )
8790   {
8791     VikTrackpoint *other_tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
8792     if ( other_tp )
8793       tp->coord = other_tp->coord;
8794   }
8795
8796   tp->newsegment = FALSE;
8797   tp->has_timestamp = FALSE;
8798   tp->timestamp = 0;
8799
8800   if ( vtl->current_track ) {
8801     vik_track_add_trackpoint ( vtl->current_track, tp, TRUE ); // Ensure bounds is updated
8802     /* Auto attempt to get elevation from DEM data (if it's available) */
8803     vik_track_apply_dem_data_last_trackpoint ( vtl->current_track );
8804   }
8805
8806   vtl->ct_x1 = vtl->ct_x2;
8807   vtl->ct_y1 = vtl->ct_y2;
8808   vtl->ct_x2 = event->x;
8809   vtl->ct_y2 = event->y;
8810
8811   vik_layer_emit_update ( VIK_LAYER(vtl) );
8812   return TRUE;
8813 }
8814
8815 static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
8816 {
8817   // ----------------------------------------------------- if current is a route - switch to new track
8818   if ( event->button == 1 && ( ! vtl->current_track || (vtl->current_track && vtl->current_track->is_route ) ))
8819   {
8820     gchar *name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, _("Track"));
8821     if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), vtl->tracks, name, FALSE ) ) )
8822     {
8823       new_track_create_common ( vtl, name );
8824       g_free ( name );
8825     }
8826     else
8827       return TRUE;
8828   }
8829   return tool_new_track_or_route_click ( vtl, event, vvp );
8830 }
8831
8832 static void tool_new_track_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
8833 {
8834   if ( event->button == 2 ) {
8835     // Pan moving ended - enable potential point drawing again
8836     vtl->draw_sync_do = TRUE;
8837     vtl->draw_sync_done = TRUE;
8838   }
8839 }
8840
8841 /*** New route ****/
8842
8843 static gpointer tool_new_route_create ( VikWindow *vw, VikViewport *vvp)
8844 {
8845   return vvp;
8846 }
8847
8848 static gboolean tool_new_route_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
8849 {
8850   // -------------------------- if current is a track - switch to new route
8851   if ( event->button == 1 && ( ! vtl->current_track || (vtl->current_track && !vtl->current_track->is_route ) ) )
8852   {
8853     gchar *name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_ROUTE, _("Route"));
8854     if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), vtl->routes, name, TRUE ) ) ) {
8855       new_route_create_common ( vtl, name );
8856       g_free ( name );
8857     }
8858     else
8859       return TRUE;
8860   }
8861   return tool_new_track_or_route_click ( vtl, event, vvp );
8862 }
8863
8864 /*** New waypoint ****/
8865
8866 static gpointer tool_new_waypoint_create ( VikWindow *vw, VikViewport *vvp)
8867 {
8868   return vvp;
8869 }
8870
8871 static gboolean tool_new_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
8872 {
8873   VikCoord coord;
8874   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
8875     return FALSE;
8876   vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
8877   if (vik_trw_layer_new_waypoint ( vtl, VIK_GTK_WINDOW_FROM_LAYER(vtl), &coord ) && VIK_LAYER(vtl)->visible) {
8878     trw_layer_calculate_bounds_waypoints ( vtl );
8879     vik_layer_emit_update ( VIK_LAYER(vtl) );
8880   }
8881   return TRUE;
8882 }
8883
8884
8885 /*** Edit trackpoint ****/
8886
8887 static gpointer tool_edit_trackpoint_create ( VikWindow *vw, VikViewport *vvp)
8888 {
8889   tool_ed_t *t = g_new(tool_ed_t, 1);
8890   t->vvp = vvp;
8891   t->holding = FALSE;
8892   return t;
8893 }
8894
8895 static void tool_edit_trackpoint_destroy ( tool_ed_t *t )
8896 {
8897   g_free ( t );
8898 }
8899
8900 static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data )
8901 {
8902   tool_ed_t *t = data;
8903   VikViewport *vvp = t->vvp;
8904   TPSearchParams params;
8905   /* OUTDATED DOCUMENTATION:
8906    find 5 pixel range on each side. then put these UTM, and a pointer
8907    to the winning track name (and maybe the winning track itself), and a
8908    pointer to the winning trackpoint, inside an array or struct. pass 
8909    this along, do a foreach on the tracks which will do a foreach on the 
8910    trackpoints. */
8911   params.vvp = vvp;
8912   params.x = event->x;
8913   params.y = event->y;
8914   params.closest_track_id = NULL;
8915   /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */
8916   params.closest_tp = NULL;
8917   params.closest_tpl = NULL;
8918   vik_viewport_get_min_max_lat_lon ( vvp, &(params.bbox.south), &(params.bbox.north), &(params.bbox.west), &(params.bbox.east) );
8919
8920   if ( event->button != 1 ) 
8921     return FALSE;
8922
8923   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
8924     return FALSE;
8925
8926   if ( !vtl->vl.visible || !vtl->tracks_visible || !vtl->routes_visible )
8927     return FALSE;
8928
8929   if ( vtl->current_tpl )
8930   {
8931     /* first check if it is within range of prev. tp. and if current_tp track is shown. (if it is, we are moving that trackpoint.) */
8932     VikTrackpoint *tp = VIK_TRACKPOINT(vtl->current_tpl->data);
8933     VikTrack *current_tr = VIK_TRACK(g_hash_table_lookup(vtl->tracks, vtl->current_tp_id));
8934     if ( !current_tr )
8935       return FALSE;
8936
8937     gint x, y;
8938     vik_viewport_coord_to_screen ( vvp, &(tp->coord), &x, &y );
8939
8940     if ( current_tr->visible && 
8941          abs(x - event->x) < TRACKPOINT_SIZE_APPROX &&
8942          abs(y - event->y) < TRACKPOINT_SIZE_APPROX ) {
8943       marker_begin_move ( t, event->x, event->y );
8944       return TRUE;
8945     }
8946
8947   }
8948
8949   if ( vtl->tracks_visible )
8950     g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, &params);
8951
8952   if ( params.closest_tp )
8953   {
8954     vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->tracks_iters, params.closest_track_id ), TRUE );
8955     vtl->current_tpl = params.closest_tpl;
8956     vtl->current_tp_id = params.closest_track_id;
8957     vtl->current_tp_track = g_hash_table_lookup ( vtl->tracks, params.closest_track_id );
8958     trw_layer_tpwin_init ( vtl );
8959     set_statusbar_msg_info_trkpt ( vtl, params.closest_tp );
8960     vik_layer_emit_update ( VIK_LAYER(vtl) );
8961     return TRUE;
8962   }
8963
8964   if ( vtl->routes_visible )
8965     g_hash_table_foreach ( vtl->routes, (GHFunc) track_search_closest_tp, &params);
8966
8967   if ( params.closest_tp )
8968   {
8969     vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->routes_iters, params.closest_track_id ), TRUE );
8970     vtl->current_tpl = params.closest_tpl;
8971     vtl->current_tp_id = params.closest_track_id;
8972     vtl->current_tp_track = g_hash_table_lookup ( vtl->routes, params.closest_track_id );
8973     trw_layer_tpwin_init ( vtl );
8974     set_statusbar_msg_info_trkpt ( vtl, params.closest_tp );
8975     vik_layer_emit_update ( VIK_LAYER(vtl) );
8976     return TRUE;
8977   }
8978
8979   /* these aren't the droids you're looking for */
8980   return FALSE;
8981 }
8982
8983 static gboolean tool_edit_trackpoint_move ( VikTrwLayer *vtl, GdkEventMotion *event, gpointer data )
8984 {
8985   tool_ed_t *t = data;
8986   VikViewport *vvp = t->vvp;
8987
8988   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
8989     return FALSE;
8990
8991   if ( t->holding )
8992   {
8993     VikCoord new_coord;
8994     vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
8995
8996     /* snap to TP */
8997     if ( event->state & GDK_CONTROL_MASK )
8998     {
8999       VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
9000       if ( tp && tp != vtl->current_tpl->data )
9001         new_coord = tp->coord;
9002     }
9003     //    VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord;
9004     { 
9005       gint x, y;
9006       vik_viewport_coord_to_screen ( vvp, &new_coord, &x, &y );
9007       marker_moveto ( t, x, y );
9008     } 
9009
9010     return TRUE;
9011   }
9012   return FALSE;
9013 }
9014
9015 static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data )
9016 {
9017   tool_ed_t *t = data;
9018   VikViewport *vvp = t->vvp;
9019
9020   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
9021     return FALSE;
9022   if ( event->button != 1) 
9023     return FALSE;
9024
9025   if ( t->holding ) {
9026     VikCoord new_coord;
9027     vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
9028
9029     /* snap to TP */
9030     if ( event->state & GDK_CONTROL_MASK )
9031     {
9032       VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
9033       if ( tp && tp != vtl->current_tpl->data )
9034         new_coord = tp->coord;
9035     }
9036
9037     VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord;
9038     if ( vtl->current_tp_track )
9039       vik_track_calculate_bounds ( vtl->current_tp_track );
9040
9041     marker_end_move ( t );
9042
9043     /* diff dist is diff from orig */
9044     if ( vtl->tpwin )
9045       vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
9046
9047     vik_layer_emit_update ( VIK_LAYER(vtl) );
9048     return TRUE;
9049   }
9050   return FALSE;
9051 }
9052
9053
9054 /*** Route Finder ***/
9055 static gpointer tool_route_finder_create ( VikWindow *vw, VikViewport *vvp)
9056 {
9057   return vvp;
9058 }
9059
9060 static gboolean tool_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
9061 {
9062   VikCoord tmp;
9063   if ( !vtl ) return FALSE;
9064   vik_viewport_screen_to_coord ( vvp, event->x, event->y, &tmp );
9065   if ( event->button == 3 && vtl->route_finder_current_track ) {
9066     VikCoord *new_end;
9067     new_end = vik_track_cut_back_to_double_point ( vtl->route_finder_current_track );
9068     if ( new_end ) {
9069       vtl->route_finder_coord = *new_end;
9070       g_free ( new_end );
9071       vik_layer_emit_update ( VIK_LAYER(vtl) );
9072       /* remove last ' to:...' */
9073       if ( vtl->route_finder_current_track->comment ) {
9074         gchar *last_to = strrchr ( vtl->route_finder_current_track->comment, 't' );
9075         if ( last_to && (last_to - vtl->route_finder_current_track->comment > 1) ) {
9076           gchar *new_comment = g_strndup ( vtl->route_finder_current_track->comment,
9077                                            last_to - vtl->route_finder_current_track->comment - 1);
9078           vik_track_set_comment_no_copy ( vtl->route_finder_current_track, new_comment );
9079         }
9080       }
9081     }
9082   }
9083   else if ( vtl->route_finder_started || (event->state & GDK_CONTROL_MASK && vtl->route_finder_current_track) ) {
9084     struct LatLon start, end;
9085
9086     vik_coord_to_latlon ( &(vtl->route_finder_coord), &start );
9087     vik_coord_to_latlon ( &(tmp), &end );
9088     vtl->route_finder_coord = tmp; /* for continuations */
9089
9090     /* these are checked when adding a track from a file (vik_trw_layer_filein_add_track) */
9091     if ( event->state & GDK_CONTROL_MASK && vtl->route_finder_current_track ) {
9092       vtl->route_finder_append = TRUE;  // merge tracks. keep started true.
9093     } else {
9094       vtl->route_finder_check_added_track = TRUE;
9095       vtl->route_finder_started = FALSE;
9096     }
9097
9098     vik_routing_default_find ( vtl, start, end);
9099
9100     /* see if anything was done -- a track was added or appended to */
9101     if ( vtl->route_finder_check_added_track && vtl->route_finder_added_track ) {
9102       vik_track_set_comment_no_copy ( vtl->route_finder_added_track, g_strdup_printf("from: %f,%f to: %f,%f", start.lat, start.lon, end.lat, end.lon ) );
9103     } else if ( vtl->route_finder_append == FALSE && vtl->route_finder_current_track ) {
9104       /* route_finder_append was originally TRUE but set to FALSE by filein_add_track */
9105       gchar *new_comment = g_strdup_printf("%s to: %f,%f", vtl->route_finder_current_track->comment, end.lat, end.lon );
9106       vik_track_set_comment_no_copy ( vtl->route_finder_current_track, new_comment );
9107     }
9108
9109     if ( vtl->route_finder_added_track )
9110       vik_track_calculate_bounds ( vtl->route_finder_added_track );
9111
9112     vtl->route_finder_added_track = NULL;
9113     vtl->route_finder_check_added_track = FALSE;
9114     vtl->route_finder_append = FALSE;
9115
9116     vik_layer_emit_update ( VIK_LAYER(vtl) );
9117   } else {
9118     vtl->route_finder_started = TRUE;
9119     vtl->route_finder_coord = tmp;
9120     vtl->route_finder_current_track = NULL;
9121   }
9122   return TRUE;
9123 }
9124
9125 /*** Show picture ****/
9126
9127 static gpointer tool_show_picture_create ( VikWindow *vw, VikViewport *vvp)
9128 {
9129   return vvp;
9130 }
9131
9132 /* Params are: vvp, event, last match found or NULL */
9133 static void tool_show_picture_wp ( const gpointer id, VikWaypoint *wp, gpointer params[3] )
9134 {
9135   if ( wp->image && wp->visible )
9136   {
9137     gint x, y, slackx, slacky;
9138     GdkEventButton *event = (GdkEventButton *) params[1];
9139
9140     vik_viewport_coord_to_screen ( VIK_VIEWPORT(params[0]), &(wp->coord), &x, &y );
9141     slackx = wp->image_width / 2;
9142     slacky = wp->image_height / 2;
9143     if (    x <= event->x + slackx && x >= event->x - slackx
9144          && y <= event->y + slacky && y >= event->y - slacky )
9145     {
9146       params[2] = wp->image; /* we've found a match. however continue searching
9147                               * since we want to find the last match -- that
9148                               * is, the match that was drawn last. */
9149     }
9150   }
9151 }
9152
9153 static void trw_layer_show_picture ( gpointer pass_along[6] )
9154 {
9155   /* thanks to the Gaim people for showing me ShellExecute and g_spawn_command_line_async */
9156 #ifdef WINDOWS
9157   ShellExecute(NULL, "open", (char *) pass_along[5], NULL, NULL, SW_SHOWNORMAL);
9158 #else /* WINDOWS */
9159   GError *err = NULL;
9160   gchar *quoted_file = g_shell_quote ( (gchar *) pass_along[5] );
9161   gchar *cmd = g_strdup_printf ( "%s %s", a_vik_get_image_viewer(), quoted_file );
9162   g_free ( quoted_file );
9163   if ( ! g_spawn_command_line_async ( cmd, &err ) )
9164     {
9165       a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_LAYER( pass_along[0]), _("Could not launch %s to open file."), a_vik_get_image_viewer() );
9166       g_error_free ( err );
9167     }
9168   g_free ( cmd );
9169 #endif /* WINDOWS */
9170 }
9171
9172 static gboolean tool_show_picture_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
9173 {
9174   gpointer params[3] = { vvp, event, NULL };
9175   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
9176     return FALSE;
9177   g_hash_table_foreach ( vtl->waypoints, (GHFunc) tool_show_picture_wp, params );
9178   if ( params[2] )
9179   {
9180     static gpointer pass_along[6];
9181     pass_along[0] = vtl;
9182     pass_along[5] = params[2];
9183     trw_layer_show_picture ( pass_along );
9184     return TRUE; /* found a match */
9185   }
9186   else
9187     return FALSE; /* go through other layers, searching for a match */
9188 }
9189
9190 /***************************************************************************
9191  ** End tool code 
9192  ***************************************************************************/
9193
9194
9195 static void image_wp_make_list ( const gpointer id, VikWaypoint *wp, GSList **pics )
9196 {
9197   if ( wp->image && ( ! a_thumbnails_exists ( wp->image ) ) )
9198     *pics = g_slist_append ( *pics, (gpointer) g_strdup ( wp->image ) );
9199 }
9200
9201 /* Structure for thumbnail creating data used in the background thread */
9202 typedef struct {
9203   VikTrwLayer *vtl; // Layer needed for redrawing
9204   GSList *pics;     // Image list
9205 } thumbnail_create_thread_data;
9206
9207 static int create_thumbnails_thread ( thumbnail_create_thread_data *tctd, gpointer threaddata )
9208 {
9209   guint total = g_slist_length(tctd->pics), done = 0;
9210   while ( tctd->pics )
9211   {
9212     a_thumbnails_create ( (gchar *) tctd->pics->data );
9213     int result = a_background_thread_progress ( threaddata, ((gdouble) ++done) / total );
9214     if ( result != 0 )
9215       return -1; /* Abort thread */
9216
9217     tctd->pics = tctd->pics->next;
9218   }
9219
9220   // Redraw to show the thumbnails as they are now created
9221   if ( IS_VIK_LAYER(tctd->vtl) )
9222     vik_layer_emit_update ( VIK_LAYER(tctd->vtl) ); // NB update from background thread
9223
9224   return 0;
9225 }
9226
9227 static void thumbnail_create_thread_free ( thumbnail_create_thread_data *tctd )
9228 {
9229   while ( tctd->pics )
9230   {
9231     g_free ( tctd->pics->data );
9232     tctd->pics = g_slist_delete_link ( tctd->pics, tctd->pics );
9233   }
9234   g_free ( tctd );
9235 }
9236
9237 void trw_layer_verify_thumbnails ( VikTrwLayer *vtl, GtkWidget *vp )
9238 {
9239   if ( ! vtl->has_verified_thumbnails )
9240   {
9241     GSList *pics = NULL;
9242     g_hash_table_foreach ( vtl->waypoints, (GHFunc) image_wp_make_list, &pics );
9243     if ( pics )
9244     {
9245       gint len = g_slist_length ( pics );
9246       gchar *tmp = g_strdup_printf ( _("Creating %d Image Thumbnails..."), len );
9247       thumbnail_create_thread_data *tctd = g_malloc ( sizeof(thumbnail_create_thread_data) );
9248       tctd->vtl = vtl;
9249       tctd->pics = pics;
9250       a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
9251                             tmp,
9252                             (vik_thr_func) create_thumbnails_thread,
9253                             tctd,
9254                             (vik_thr_free_func) thumbnail_create_thread_free,
9255                             NULL,
9256                             len );
9257       g_free ( tmp );
9258     }
9259   }
9260 }
9261
9262 static const gchar* my_track_colors ( gint ii )
9263 {
9264   static const gchar* colors[VIK_TRW_LAYER_TRACK_GCS] = {
9265     "#2d870a",
9266     "#135D34",
9267     "#0a8783",
9268     "#0e4d87",
9269     "#05469f",
9270     "#695CBB",
9271     "#2d059f",
9272     "#4a059f",
9273     "#5A171A",
9274     "#96059f"
9275   };
9276   // Fast and reliable way of returning a colour
9277   return colors[(ii % VIK_TRW_LAYER_TRACK_GCS)];
9278 }
9279
9280 static void trw_layer_track_alloc_colors ( VikTrwLayer *vtl )
9281 {
9282   GHashTableIter iter;
9283   gpointer key, value;
9284
9285   gint ii = 0;
9286   // Tracks
9287   g_hash_table_iter_init ( &iter, vtl->tracks );
9288
9289   while ( g_hash_table_iter_next (&iter, &key, &value) ) {
9290
9291     // Tracks get a random spread of colours if not already assigned
9292     if ( ! VIK_TRACK(value)->has_color ) {
9293       if ( vtl->drawmode == DRAWMODE_ALL_SAME_COLOR )
9294         VIK_TRACK(value)->color = vtl->track_color;
9295       else {
9296         gdk_color_parse ( my_track_colors (ii), &(VIK_TRACK(value)->color) );
9297       }
9298       VIK_TRACK(value)->has_color = TRUE;
9299     }
9300
9301     trw_layer_update_treeview ( vtl, VIK_TRACK(value), key );
9302
9303     ii++;
9304     if (ii > VIK_TRW_LAYER_TRACK_GCS)
9305       ii = 0;
9306   }
9307
9308   // Routes
9309   ii = 0;
9310   g_hash_table_iter_init ( &iter, vtl->routes );
9311
9312   while ( g_hash_table_iter_next (&iter, &key, &value) ) {
9313
9314     // Routes get an intermix of reds
9315     if ( ! VIK_TRACK(value)->has_color ) {
9316       if ( ii )
9317         gdk_color_parse ( "#FF0000" , &(VIK_TRACK(value)->color) ); // Red
9318       else
9319         gdk_color_parse ( "#B40916" , &(VIK_TRACK(value)->color) ); // Dark Red
9320       VIK_TRACK(value)->has_color = TRUE;
9321     }
9322
9323     trw_layer_update_treeview ( vtl, VIK_TRACK(value), key );
9324
9325     ii = !ii;
9326   }
9327 }
9328
9329 /*
9330  * (Re)Calculate the bounds of the waypoints in this layer,
9331  * This should be called whenever waypoints are changed
9332  */
9333 static void trw_layer_calculate_bounds_waypoints ( VikTrwLayer *vtl )
9334 {
9335   struct LatLon topleft = { 0.0, 0.0 };
9336   struct LatLon bottomright = { 0.0, 0.0 };
9337   struct LatLon ll;
9338
9339   GHashTableIter iter;
9340   gpointer key, value;
9341
9342   g_hash_table_iter_init ( &iter, vtl->waypoints );
9343
9344   // Set bounds to first point
9345   if ( g_hash_table_iter_next (&iter, &key, &value) ) {
9346     vik_coord_to_latlon ( &(VIK_WAYPOINT(value)->coord), &topleft );
9347     vik_coord_to_latlon ( &(VIK_WAYPOINT(value)->coord), &bottomright );
9348   }
9349
9350   // Ensure there is another point...
9351   if ( g_hash_table_size ( vtl->waypoints ) > 1 ) {
9352
9353     while ( g_hash_table_iter_next (&iter, &key, &value) ) {
9354
9355       // See if this point increases the bounds.
9356       vik_coord_to_latlon ( &(VIK_WAYPOINT(value)->coord), &ll );
9357
9358       if ( ll.lat > topleft.lat) topleft.lat = ll.lat;
9359       if ( ll.lon < topleft.lon) topleft.lon = ll.lon;
9360       if ( ll.lat < bottomright.lat) bottomright.lat = ll.lat;
9361       if ( ll.lon > bottomright.lon) bottomright.lon = ll.lon;
9362     }
9363   }
9364
9365   vtl->waypoints_bbox.north = topleft.lat;
9366   vtl->waypoints_bbox.east = bottomright.lon;
9367   vtl->waypoints_bbox.south = bottomright.lat;
9368   vtl->waypoints_bbox.west = topleft.lon;
9369 }
9370
9371 static void trw_layer_calculate_bounds_track ( gpointer id, VikTrack *trk )
9372 {
9373   vik_track_calculate_bounds ( trk );
9374 }
9375
9376 static void trw_layer_calculate_bounds_tracks ( VikTrwLayer *vtl )
9377 {
9378   g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_calculate_bounds_track, NULL );
9379   g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_calculate_bounds_track, NULL );
9380 }
9381
9382 static void trw_layer_sort_all ( VikTrwLayer *vtl )
9383 {
9384   if ( ! VIK_LAYER(vtl)->vt )
9385     return;
9386
9387   // Obviously need 2 to tango - sorting with only 1 (or less) is a lonely activity!
9388   if ( g_hash_table_size (vtl->tracks) > 1 )
9389     vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), vtl->track_sort_order );
9390
9391   if ( g_hash_table_size (vtl->routes) > 1 )
9392     vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter), vtl->track_sort_order );
9393
9394   if ( g_hash_table_size (vtl->waypoints) > 1 )
9395     vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), vtl->wp_sort_order );
9396 }
9397
9398 static void trw_layer_post_read ( VikTrwLayer *vtl, GtkWidget *vvp, gboolean from_file )
9399 {
9400   trw_layer_verify_thumbnails ( vtl, vvp );
9401   trw_layer_track_alloc_colors ( vtl );
9402
9403   trw_layer_calculate_bounds_waypoints ( vtl );
9404   trw_layer_calculate_bounds_tracks ( vtl );
9405
9406   // Apply treeview sort after loading all the tracks for this layer
9407   //  (rather than sorted insert on each individual track additional)
9408   //  and after subsequent changes to the properties as the specified order may have changed.
9409   //  since the sorting of a treeview section is now very quick
9410   // NB sorting is also performed after every name change as well to maintain the list order
9411   trw_layer_sort_all ( vtl );
9412 }
9413
9414 VikCoordMode vik_trw_layer_get_coord_mode ( VikTrwLayer *vtl )
9415 {
9416   return vtl->coord_mode;
9417 }
9418
9419 /**
9420  * Uniquify the whole layer
9421  * Also requires the layers panel as the names shown there need updating too
9422  * Returns whether the operation was successful or not
9423  */
9424 gboolean vik_trw_layer_uniquify ( VikTrwLayer *vtl, VikLayersPanel *vlp )
9425 {
9426   if ( vtl && vlp ) {
9427     vik_trw_layer_uniquify_tracks ( vtl, vlp, vtl->tracks, TRUE );
9428     vik_trw_layer_uniquify_tracks ( vtl, vlp, vtl->routes, FALSE );
9429     vik_trw_layer_uniquify_waypoints ( vtl, vlp );
9430     return TRUE;
9431   }
9432   return FALSE;
9433 }
9434
9435 static void waypoint_convert ( const gpointer id, VikWaypoint *wp, VikCoordMode *dest_mode )
9436 {
9437   vik_coord_convert ( &(wp->coord), *dest_mode );
9438 }
9439
9440 static void track_convert ( const gpointer id, VikTrack *tr, VikCoordMode *dest_mode )
9441 {
9442   vik_track_convert ( tr, *dest_mode );
9443 }
9444
9445 static void trw_layer_change_coord_mode ( VikTrwLayer *vtl, VikCoordMode dest_mode )
9446 {
9447   if ( vtl->coord_mode != dest_mode )
9448   {
9449     vtl->coord_mode = dest_mode;
9450     g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_convert, &dest_mode );
9451     g_hash_table_foreach ( vtl->tracks, (GHFunc) track_convert, &dest_mode );
9452     g_hash_table_foreach ( vtl->routes, (GHFunc) track_convert, &dest_mode );
9453   }
9454 }
9455
9456 static void trw_layer_set_menu_selection ( VikTrwLayer *vtl, guint16 selection )
9457 {
9458   vtl->menu_selection = selection;
9459 }
9460
9461 static guint16 trw_layer_get_menu_selection ( VikTrwLayer *vtl )
9462 {
9463   return (vtl->menu_selection);
9464 }
9465
9466 /* ----------- Downloading maps along tracks --------------- */
9467
9468 static int get_download_area_width(VikViewport *vvp, gdouble zoom_level, struct LatLon *wh)
9469 {
9470   /* TODO: calculating based on current size of viewport */
9471   const gdouble w_at_zoom_0_125 = 0.0013;
9472   const gdouble h_at_zoom_0_125 = 0.0011;
9473   gdouble zoom_factor = zoom_level/0.125;
9474
9475   wh->lat = h_at_zoom_0_125 * zoom_factor;
9476   wh->lon = w_at_zoom_0_125 * zoom_factor;
9477
9478   return 0;   /* all OK */
9479 }
9480
9481 static VikCoord *get_next_coord(VikCoord *from, VikCoord *to, struct LatLon *dist, gdouble gradient)
9482 {
9483   if ((dist->lon >= ABS(to->east_west - from->east_west)) &&
9484       (dist->lat >= ABS(to->north_south - from->north_south)))
9485     return NULL;
9486
9487   VikCoord *coord = g_malloc(sizeof(VikCoord));
9488   coord->mode = VIK_COORD_LATLON;
9489
9490   if (ABS(gradient) < 1) {
9491     if (from->east_west > to->east_west)
9492       coord->east_west = from->east_west - dist->lon;
9493     else
9494       coord->east_west = from->east_west + dist->lon;
9495     coord->north_south = gradient * (coord->east_west - from->east_west) + from->north_south;
9496   } else {
9497     if (from->north_south > to->north_south)
9498       coord->north_south = from->north_south - dist->lat;
9499     else
9500       coord->north_south = from->north_south + dist->lat;
9501     coord->east_west = (1/gradient) * (coord->north_south - from->north_south) + from->north_south;
9502   }
9503
9504   return coord;
9505 }
9506
9507 static GList *add_fillins(GList *list, VikCoord *from, VikCoord *to, struct LatLon *dist)
9508 {
9509   /* TODO: handle virtical track (to->east_west - from->east_west == 0) */
9510   gdouble gradient = (to->north_south - from->north_south)/(to->east_west - from->east_west);
9511
9512   VikCoord *next = from;
9513   while (TRUE) {
9514     if ((next = get_next_coord(next, to, dist, gradient)) == NULL)
9515         break;
9516     list = g_list_prepend(list, next);
9517   }
9518
9519   return list;
9520 }
9521
9522 void vik_track_download_map(VikTrack *tr, VikMapsLayer *vml, VikViewport *vvp, gdouble zoom_level)
9523 {
9524   typedef struct _Rect {
9525     VikCoord tl;
9526     VikCoord br;
9527     VikCoord center;
9528   } Rect;
9529 #define GLRECT(iter) ((Rect *)((iter)->data))
9530
9531   struct LatLon wh;
9532   GList *rects_to_download = NULL;
9533   GList *rect_iter;
9534
9535   if (get_download_area_width(vvp, zoom_level, &wh))
9536     return;
9537
9538   GList *iter = tr->trackpoints;
9539   if (!iter)
9540     return;
9541
9542   gboolean new_map = TRUE;
9543   VikCoord *cur_coord, tl, br;
9544   Rect *rect;
9545   while (iter) {
9546     cur_coord = &(VIK_TRACKPOINT(iter->data))->coord;
9547     if (new_map) {
9548       vik_coord_set_area(cur_coord, &wh, &tl, &br);
9549       rect = g_malloc(sizeof(Rect));
9550       rect->tl = tl;
9551       rect->br = br;
9552       rect->center = *cur_coord;
9553       rects_to_download = g_list_prepend(rects_to_download, rect);
9554       new_map = FALSE;
9555       iter = iter->next;
9556       continue;
9557     }
9558     gboolean found = FALSE;
9559     for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next) {
9560       if (vik_coord_inside(cur_coord, &GLRECT(rect_iter)->tl, &GLRECT(rect_iter)->br)) {
9561         found = TRUE;
9562         break;
9563       }
9564     }
9565     if (found)
9566         iter = iter->next;
9567     else
9568       new_map = TRUE;
9569   }
9570
9571   GList *fillins = NULL;
9572   /* 'fillin' doesn't work in UTM mode - potentially ending up in massive loop continually allocating memory - hence don't do it */
9573   /* seems that ATM the function get_next_coord works only for LATLON */
9574   if ( cur_coord->mode == VIK_COORD_LATLON ) {
9575     /* fill-ins for far apart points */
9576     GList *cur_rect, *next_rect;
9577     for (cur_rect = rects_to_download;
9578          (next_rect = cur_rect->next) != NULL;
9579          cur_rect = cur_rect->next) {
9580       if ((wh.lon < ABS(GLRECT(cur_rect)->center.east_west - GLRECT(next_rect)->center.east_west)) ||
9581           (wh.lat < ABS(GLRECT(cur_rect)->center.north_south - GLRECT(next_rect)->center.north_south))) {
9582         fillins = add_fillins(fillins, &GLRECT(cur_rect)->center, &GLRECT(next_rect)->center, &wh);
9583       }
9584     }
9585   } else
9586     g_message("%s: this feature works only in Mercator mode", __FUNCTION__);
9587
9588   if (fillins) {
9589     GList *iter = fillins;
9590     while (iter) {
9591       cur_coord = (VikCoord *)(iter->data);
9592       vik_coord_set_area(cur_coord, &wh, &tl, &br);
9593       rect = g_malloc(sizeof(Rect));
9594       rect->tl = tl;
9595       rect->br = br;
9596       rect->center = *cur_coord;
9597       rects_to_download = g_list_prepend(rects_to_download, rect);
9598       iter = iter->next;
9599     }
9600   }
9601
9602   for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next) {
9603     vik_maps_layer_download_section (vml, vvp, &(((Rect *)(rect_iter->data))->tl), &(((Rect *)(rect_iter->data))->br), zoom_level);
9604   }
9605
9606   if (fillins) {
9607     for (iter = fillins; iter; iter = iter->next)
9608       g_free(iter->data);
9609     g_list_free(fillins);
9610   }
9611   if (rects_to_download) {
9612     for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next)
9613       g_free(rect_iter->data);
9614     g_list_free(rects_to_download);
9615   }
9616 }
9617
9618 static void trw_layer_download_map_along_track_cb ( gpointer pass_along[6] )
9619 {
9620   VikMapsLayer *vml;
9621   gint selected_map, default_map;
9622   gchar *zoomlist[] = {"0.125", "0.25", "0.5", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", NULL };
9623   gdouble zoom_vals[] = {0.125, 0.25, 0.5, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
9624   gint selected_zoom, default_zoom;
9625   int i,j;
9626
9627
9628   VikTrwLayer *vtl = pass_along[0];
9629   VikLayersPanel *vlp = pass_along[1];
9630   VikTrack *trk;
9631   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
9632     trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
9633   else
9634     trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
9635   if ( !trk )
9636     return;
9637
9638   VikViewport *vvp = vik_window_viewport((VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)));
9639
9640   GList *vmls = vik_layers_panel_get_all_layers_of_type(vlp, VIK_LAYER_MAPS, TRUE); // Includes hidden map layer types
9641   int num_maps = g_list_length(vmls);
9642
9643   if (!num_maps) {
9644     a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No map layer in use. Create one first") );
9645     return;
9646   }
9647
9648   gchar **map_names = g_malloc(1 + num_maps * sizeof(gpointer));
9649   VikMapsLayer **map_layers = g_malloc(1 + num_maps * sizeof(gpointer));
9650
9651   gchar **np = map_names;
9652   VikMapsLayer **lp = map_layers;
9653   for (i = 0; i < num_maps; i++) {
9654     gboolean dup = FALSE;
9655     vml = (VikMapsLayer *)(vmls->data);
9656     for (j = 0; j < i; j++) { /* no duplicate allowed */
9657       if (vik_maps_layer_get_map_type(vml) == vik_maps_layer_get_map_type(map_layers[j])) {
9658         dup = TRUE;
9659         break;
9660       }
9661     }
9662     if (!dup) {
9663       *lp++ = vml;
9664       *np++ = vik_maps_layer_get_map_label(vml);
9665     }
9666     vmls = vmls->next;
9667   }
9668   *lp = NULL;
9669   *np = NULL;
9670   num_maps = lp - map_layers;
9671
9672   for (default_map = 0; default_map < num_maps; default_map++) {
9673     /* TODO: check for parent layer's visibility */
9674     if (VIK_LAYER(map_layers[default_map])->visible)
9675       break;
9676   }
9677   default_map = (default_map == num_maps) ? 0 : default_map;
9678
9679   gdouble cur_zoom = vik_viewport_get_zoom(vvp);
9680   for (default_zoom = 0; default_zoom < sizeof(zoom_vals)/sizeof(gdouble); default_zoom++) {
9681     if (cur_zoom == zoom_vals[default_zoom])
9682       break;
9683   }
9684   default_zoom = (default_zoom == sizeof(zoom_vals)/sizeof(gdouble)) ? sizeof(zoom_vals)/sizeof(gdouble) - 1 : default_zoom;
9685
9686   if (!a_dialog_map_n_zoom(VIK_GTK_WINDOW_FROM_LAYER(vtl), map_names, default_map, zoomlist, default_zoom, &selected_map, &selected_zoom))
9687     goto done;
9688
9689   vik_track_download_map(trk, map_layers[selected_map], vvp, zoom_vals[selected_zoom]);
9690
9691 done:
9692   for (i = 0; i < num_maps; i++)
9693     g_free(map_names[i]);
9694   g_free(map_names);
9695   g_free(map_layers);
9696
9697   g_list_free(vmls);
9698
9699 }
9700
9701 /**** lowest waypoint number calculation ***/
9702 static gint highest_wp_number_name_to_number(const gchar *name) {
9703   if ( strlen(name) == 3 ) {
9704     int n = atoi(name);
9705     if ( n < 100 && name[0] != '0' )
9706       return -1;
9707     if ( n < 10 && name[0] != '0' )
9708       return -1;
9709     return n;
9710   }
9711   return -1;
9712 }
9713
9714
9715 static void highest_wp_number_reset(VikTrwLayer *vtl)
9716 {
9717   vtl->highest_wp_number = -1;
9718 }
9719
9720 static void highest_wp_number_add_wp(VikTrwLayer *vtl, const gchar *new_wp_name)
9721 {
9722   /* if is bigger that top, add it */
9723   gint new_wp_num = highest_wp_number_name_to_number(new_wp_name);
9724   if ( new_wp_num > vtl->highest_wp_number )
9725     vtl->highest_wp_number = new_wp_num;
9726 }
9727
9728 static void highest_wp_number_remove_wp(VikTrwLayer *vtl, const gchar *old_wp_name)
9729 {
9730   /* if wasn't top, do nothing. if was top, count backwards until we find one used */
9731   gint old_wp_num = highest_wp_number_name_to_number(old_wp_name);
9732   if ( vtl->highest_wp_number == old_wp_num ) {
9733     gchar buf[4];
9734     vtl->highest_wp_number--;
9735
9736     g_snprintf(buf,4,"%03d", vtl->highest_wp_number );
9737     /* search down until we find something that *does* exist */
9738
9739     while ( vtl->highest_wp_number > 0 && ! vik_trw_layer_get_waypoint ( vtl, buf )) {
9740       vtl->highest_wp_number--;
9741       g_snprintf(buf,4,"%03d", vtl->highest_wp_number );
9742     }
9743   }
9744 }
9745
9746 /* get lowest unused number */
9747 static gchar *highest_wp_number_get(VikTrwLayer *vtl)
9748 {
9749   gchar buf[4];
9750   if ( vtl->highest_wp_number < 0 || vtl->highest_wp_number >= 999 )
9751     return NULL;
9752   g_snprintf(buf,4,"%03d", vtl->highest_wp_number+1 );
9753   return g_strdup(buf);
9754 }