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