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