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