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