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