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