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