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