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