]> git.street.me.uk Git - andy/viking.git/blob - src/viktrwlayer.c
Tidy update signal handler in VikAggregate Layer.
[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 static void trw_layer_acquire ( gpointer lav[2], VikDataSourceInterface *datasource )
3413 {
3414   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
3415   VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
3416   VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
3417   VikViewport *vvp =  vik_window_viewport(vw);
3418
3419   a_acquire ( vw, vlp, vvp, datasource, NULL, NULL );
3420 }
3421
3422 /*
3423  * Acquire into this TRW Layer straight from GPS Device
3424  */
3425 static void trw_layer_acquire_gps_cb ( gpointer lav[2] )
3426 {
3427   vik_datasource_gps_interface.mode = VIK_DATASOURCE_ADDTOLAYER;
3428   trw_layer_acquire ( lav, &vik_datasource_gps_interface );
3429 }
3430
3431 /*
3432  * Acquire into this TRW Layer from Directions
3433  */
3434 static void trw_layer_acquire_routing_cb ( gpointer lav[2] )
3435 {
3436   trw_layer_acquire ( lav, &vik_datasource_routing_interface );
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   vik_datasource_url_interface.mode = VIK_DATASOURCE_ADDTOLAYER;
3445   trw_layer_acquire ( lav, &vik_datasource_url_interface );
3446 }
3447
3448 #ifdef VIK_CONFIG_OPENSTREETMAP
3449 /*
3450  * Acquire into this TRW Layer from OSM
3451  */
3452 static void trw_layer_acquire_osm_cb ( gpointer lav[2] )
3453 {
3454   trw_layer_acquire ( lav, &vik_datasource_osm_interface );
3455 }
3456
3457 /**
3458  * Acquire into this TRW Layer from OSM for 'My' Traces
3459  */
3460 static void trw_layer_acquire_osm_my_traces_cb ( gpointer lav[2] )
3461 {
3462   trw_layer_acquire ( lav, &vik_datasource_osm_my_traces_interface );
3463 }
3464 #endif
3465
3466 #ifdef VIK_CONFIG_GEOCACHES
3467 /*
3468  * Acquire into this TRW Layer from Geocaching.com
3469  */
3470 static void trw_layer_acquire_geocache_cb ( gpointer lav[2] )
3471 {
3472   trw_layer_acquire ( lav, &vik_datasource_gc_interface );
3473 }
3474 #endif
3475
3476 #ifdef VIK_CONFIG_GEOTAG
3477 /*
3478  * Acquire into this TRW Layer from images
3479  */
3480 static void trw_layer_acquire_geotagged_cb ( gpointer lav[2] )
3481 {
3482   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
3483
3484   vik_datasource_geotag_interface.mode = VIK_DATASOURCE_ADDTOLAYER;
3485   trw_layer_acquire ( lav, &vik_datasource_geotag_interface );
3486
3487   // Reverify thumbnails as they may have changed
3488   vtl->has_verified_thumbnails = FALSE;
3489   trw_layer_verify_thumbnails ( vtl, NULL );
3490 }
3491 #endif
3492
3493 static void trw_layer_gps_upload ( gpointer lav[2] )
3494 {
3495   gpointer pass_along[6];
3496   pass_along[0] = lav[0];
3497   pass_along[1] = lav[1];
3498   pass_along[2] = NULL; // No track - operate on the layer
3499   pass_along[3] = NULL;
3500   pass_along[4] = NULL;
3501   pass_along[5] = NULL;
3502
3503   trw_layer_gps_upload_any ( pass_along );
3504 }
3505
3506 /**
3507  * If pass_along[3] is defined that this will upload just that track
3508  */
3509 static void trw_layer_gps_upload_any ( gpointer pass_along[6] )
3510 {
3511   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
3512   VikLayersPanel *vlp = VIK_LAYERS_PANEL(pass_along[1]);
3513
3514   // May not actually get a track here as pass_along[2&3] can be null
3515   VikTrack *track = NULL;
3516   vik_gps_xfer_type xfer_type = TRK; // VIK_TRW_LAYER_SUBLAYER_TRACKS = 0 so hard to test different from NULL!
3517   gboolean xfer_all = FALSE;
3518
3519   if ( pass_along[2] ) {
3520     xfer_all = FALSE;
3521     if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) {
3522       track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
3523       xfer_type = RTE;
3524     }
3525     else if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
3526       track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
3527       xfer_type = TRK;
3528     }
3529     else if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS ) {
3530       xfer_type = WPT;
3531     }
3532     else if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTES ) {
3533       xfer_type = RTE;
3534     }
3535   }
3536   else if ( !pass_along[4] )
3537     xfer_all = TRUE; // i.e. whole layer
3538
3539   if (track && !track->visible) {
3540     a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Can not upload invisible track.") );
3541     return;
3542   }
3543
3544   GtkWidget *dialog = gtk_dialog_new_with_buttons ( _("GPS Upload"),
3545                                                     VIK_GTK_WINDOW_FROM_LAYER(pass_along[0]),
3546                                                     GTK_DIALOG_DESTROY_WITH_PARENT,
3547                                                     GTK_STOCK_OK,
3548                                                     GTK_RESPONSE_ACCEPT,
3549                                                     GTK_STOCK_CANCEL,
3550                                                     GTK_RESPONSE_REJECT,
3551                                                     NULL );
3552
3553   gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
3554   GtkWidget *response_w = NULL;
3555 #if GTK_CHECK_VERSION (2, 20, 0)
3556   response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
3557 #endif
3558
3559   if ( response_w )
3560     gtk_widget_grab_focus ( response_w );
3561
3562   gpointer dgs = datasource_gps_setup ( dialog, xfer_type, xfer_all );
3563
3564   if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) != GTK_RESPONSE_ACCEPT ) {
3565     datasource_gps_clean_up ( dgs );
3566     gtk_widget_destroy ( dialog );
3567     return;
3568   }
3569
3570   // Get info from reused datasource dialog widgets
3571   gchar* protocol = datasource_gps_get_protocol ( dgs );
3572   gchar* port = datasource_gps_get_descriptor ( dgs );
3573   // NB don't free the above strings as they're references to values held elsewhere
3574   gboolean do_tracks = datasource_gps_get_do_tracks ( dgs );
3575   gboolean do_routes = datasource_gps_get_do_routes ( dgs );
3576   gboolean do_waypoints = datasource_gps_get_do_waypoints ( dgs );
3577   gboolean turn_off = datasource_gps_get_off ( dgs );
3578
3579   gtk_widget_destroy ( dialog );
3580
3581   // When called from the viewport - work the corresponding layerspanel:
3582   if ( !vlp ) {
3583     vlp = vik_window_layers_panel ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) );
3584   }
3585
3586   // Apply settings to transfer to the GPS device
3587   vik_gps_comm ( vtl,
3588                  track,
3589                  GPS_UP,
3590                  protocol,
3591                  port,
3592                  FALSE,
3593                  vik_layers_panel_get_viewport (vlp),
3594                  vlp,
3595                  do_tracks,
3596                  do_routes,
3597                  do_waypoints,
3598                  turn_off );
3599 }
3600
3601 /*
3602  * Acquire into this TRW Layer from any GPS Babel supported file
3603  */
3604 static void trw_layer_acquire_file_cb ( gpointer lav[2] )
3605 {
3606   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
3607   VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
3608   VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
3609   VikViewport *vvp =  vik_window_viewport(vw);
3610
3611   a_acquire ( vw, vlp, vvp, &vik_datasource_file_interface, NULL, NULL );
3612 }
3613
3614 static void trw_layer_new_wp ( gpointer lav[2] )
3615 {
3616   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
3617   VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
3618   /* TODO longone: okay, if layer above (aggregate) is invisible but vtl->visible is true, this redraws for no reason.
3619      instead return true if you want to update. */
3620   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 ) {
3621     trw_layer_calculate_bounds_waypoints ( vtl );
3622     vik_layers_panel_emit_update ( vlp );
3623   }
3624 }
3625
3626 static void new_track_create_common ( VikTrwLayer *vtl, gchar *name )
3627 {
3628   vtl->current_track = vik_track_new();
3629   vik_track_set_defaults ( vtl->current_track );
3630   vtl->current_track->visible = TRUE;
3631   if ( vtl->drawmode == DRAWMODE_ALL_SAME_COLOR )
3632     // Create track with the preferred colour from the layer properties
3633     vtl->current_track->color = vtl->track_color;
3634   else
3635     gdk_color_parse ( "#000000", &(vtl->current_track->color) );
3636   vtl->current_track->has_color = TRUE;
3637   vik_trw_layer_add_track ( vtl, name, vtl->current_track );
3638 }
3639
3640 static void trw_layer_new_track ( gpointer lav[2] )
3641 {
3642   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
3643
3644   if ( ! vtl->current_track ) {
3645     gchar *name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, _("Track")) ;
3646     new_track_create_common ( vtl, name );
3647     g_free ( name );
3648
3649     vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_CREATE_TRACK );
3650   }
3651 }
3652
3653 static void new_route_create_common ( VikTrwLayer *vtl, gchar *name )
3654 {
3655   vtl->current_track = vik_track_new();
3656   vik_track_set_defaults ( vtl->current_track );
3657   vtl->current_track->visible = TRUE;
3658   vtl->current_track->is_route = TRUE;
3659   // By default make all routes red
3660   vtl->current_track->has_color = TRUE;
3661   gdk_color_parse ( "red", &vtl->current_track->color );
3662   vik_trw_layer_add_route ( vtl, name, vtl->current_track );
3663 }
3664
3665 static void trw_layer_new_route ( gpointer lav[2] )
3666 {
3667   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
3668
3669   if ( ! vtl->current_track ) {
3670     gchar *name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_ROUTE, _("Route")) ;
3671     new_route_create_common ( vtl, name );
3672     g_free ( name );
3673     vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_CREATE_ROUTE );
3674   }
3675 }
3676
3677 static void trw_layer_auto_routes_view ( gpointer lav[2] )
3678 {
3679   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
3680   VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
3681
3682   if ( g_hash_table_size (vtl->routes) > 0 ) {
3683     struct LatLon maxmin[2] = { {0,0}, {0,0} };
3684     g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_find_maxmin_tracks, maxmin );
3685     trw_layer_zoom_to_show_latlons ( vtl, vik_layers_panel_get_viewport (vlp), maxmin );
3686     vik_layers_panel_emit_update ( vlp );
3687   }
3688 }
3689
3690
3691 static void trw_layer_finish_track ( gpointer lav[2] )
3692 {
3693   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
3694   vtl->current_track = NULL;
3695   vik_layer_emit_update ( VIK_LAYER(vtl) );
3696 }
3697
3698 static void trw_layer_auto_tracks_view ( gpointer lav[2] )
3699 {
3700   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
3701   VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
3702
3703   if ( g_hash_table_size (vtl->tracks) > 0 ) {
3704     struct LatLon maxmin[2] = { {0,0}, {0,0} };
3705     g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_find_maxmin_tracks, maxmin );
3706     trw_layer_zoom_to_show_latlons ( vtl, vik_layers_panel_get_viewport (vlp), maxmin );
3707     vik_layers_panel_emit_update ( vlp );
3708   }
3709 }
3710
3711 static void trw_layer_single_waypoint_jump ( const gpointer id, const VikWaypoint *wp, gpointer vvp )
3712 {
3713   /* NB do not care if wp is visible or not */
3714   vik_viewport_set_center_coord ( VIK_VIEWPORT(vvp), &(wp->coord) );
3715 }
3716
3717 static void trw_layer_auto_waypoints_view ( gpointer lav[2] )
3718 {
3719   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
3720   VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
3721
3722   /* Only 1 waypoint - jump straight to it */
3723   if ( g_hash_table_size (vtl->waypoints) == 1 ) {
3724     VikViewport *vvp = vik_layers_panel_get_viewport (vlp);
3725     g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_single_waypoint_jump, (gpointer) vvp );
3726   }
3727   /* If at least 2 waypoints - find center and then zoom to fit */
3728   else if ( g_hash_table_size (vtl->waypoints) > 1 )
3729   {
3730     struct LatLon maxmin[2] = { {0,0}, {0,0} };
3731     maxmin[0].lat = vtl->waypoints_bbox.north;
3732     maxmin[1].lat = vtl->waypoints_bbox.south;
3733     maxmin[0].lon = vtl->waypoints_bbox.east;
3734     maxmin[1].lon = vtl->waypoints_bbox.west;
3735     trw_layer_zoom_to_show_latlons ( vtl, vik_layers_panel_get_viewport (vlp), maxmin );
3736   }
3737
3738   vik_layers_panel_emit_update ( vlp );
3739 }
3740
3741 void trw_layer_osm_traces_upload_cb ( gpointer layer_and_vlp[2] )
3742 {
3743   osm_traces_upload_viktrwlayer(VIK_TRW_LAYER(layer_and_vlp[0]), NULL);
3744 }
3745
3746 void trw_layer_osm_traces_upload_track_cb ( gpointer pass_along[8] )
3747 {
3748   if ( pass_along[7] ) {
3749     VikTrack *trk = VIK_TRACK(pass_along[7]);
3750     osm_traces_upload_viktrwlayer(VIK_TRW_LAYER(pass_along[0]), trk);
3751   }
3752 }
3753
3754 static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vlp )
3755 {
3756   static gpointer pass_along[2];
3757   GtkWidget *item;
3758   GtkWidget *export_submenu;
3759   pass_along[0] = vtl;
3760   pass_along[1] = vlp;
3761
3762   item = gtk_menu_item_new();
3763   gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3764   gtk_widget_show ( item );
3765
3766   if ( vtl->current_track ) {
3767     if ( vtl->current_track->is_route )
3768       item = gtk_menu_item_new_with_mnemonic ( _("_Finish Route") );
3769     else
3770       item = gtk_menu_item_new_with_mnemonic ( _("_Finish Track") );
3771     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_finish_track), pass_along );
3772     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3773     gtk_widget_show ( item );
3774
3775     // Add separator
3776     item = gtk_menu_item_new ();
3777     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
3778     gtk_widget_show ( item );
3779   }
3780
3781   /* Now with icons */
3782   item = gtk_image_menu_item_new_with_mnemonic ( _("_View Layer") );
3783   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
3784   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_view), pass_along );
3785   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3786   gtk_widget_show ( item );
3787
3788   GtkWidget *view_submenu = gtk_menu_new();
3789   item = gtk_image_menu_item_new_with_mnemonic ( _("V_iew") );
3790   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_FIND, GTK_ICON_SIZE_MENU) );
3791   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3792   gtk_widget_show ( item );
3793   gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), view_submenu );
3794
3795   item = gtk_menu_item_new_with_mnemonic ( _("View All _Tracks") );
3796   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_tracks_view), pass_along );
3797   gtk_menu_shell_append (GTK_MENU_SHELL (view_submenu), item);
3798   gtk_widget_show ( item );
3799
3800   item = gtk_menu_item_new_with_mnemonic ( _("View All _Routes") );
3801   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_routes_view), pass_along );
3802   gtk_menu_shell_append (GTK_MENU_SHELL (view_submenu), item);
3803   gtk_widget_show ( item );
3804
3805   item = gtk_menu_item_new_with_mnemonic ( _("View All _Waypoints") );
3806   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_waypoints_view), pass_along );
3807   gtk_menu_shell_append (GTK_MENU_SHELL (view_submenu), item);
3808   gtk_widget_show ( item );
3809
3810   item = gtk_image_menu_item_new_with_mnemonic ( _("_Goto Center of Layer") );
3811   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
3812   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_centerize), pass_along );
3813   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3814   gtk_widget_show ( item );
3815
3816   item = gtk_menu_item_new_with_mnemonic ( _("Goto _Waypoint...") );
3817   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_wp), pass_along );
3818   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3819   gtk_widget_show ( item );
3820
3821   export_submenu = gtk_menu_new ();
3822   item = gtk_image_menu_item_new_with_mnemonic ( _("_Export Layer") );
3823   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_HARDDISK, GTK_ICON_SIZE_MENU) );
3824   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3825   gtk_widget_show ( item );
3826   gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), export_submenu );
3827   
3828   item = gtk_menu_item_new_with_mnemonic ( _("Export as GPS_Point...") );
3829   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpspoint), pass_along );
3830   gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
3831   gtk_widget_show ( item );
3832
3833   item = gtk_menu_item_new_with_mnemonic ( _("Export as GPS_Mapper...") );
3834   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpsmapper), pass_along );
3835   gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
3836   gtk_widget_show ( item );
3837
3838   item = gtk_menu_item_new_with_mnemonic ( _("Export as _GPX...") );
3839   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpx), 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 _KML...") );
3844   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_kml), pass_along );
3845   gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
3846   gtk_widget_show ( item );
3847
3848   gchar* external1 = g_strdup_printf ( _("Open with External Program_1: %s"), a_vik_get_external_gpx_program_1() );
3849   item = gtk_menu_item_new_with_mnemonic ( external1 );
3850   g_free ( external1 );
3851   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_external_gpx_1), pass_along );
3852   gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
3853   gtk_widget_show ( item );
3854
3855   gchar* external2 = g_strdup_printf ( _("Open with External Program_2: %s"), a_vik_get_external_gpx_program_2() );
3856   item = gtk_menu_item_new_with_mnemonic ( external2 );
3857   g_free ( external2 );
3858   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_external_gpx_2), pass_along );
3859   gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
3860   gtk_widget_show ( item );
3861
3862   GtkWidget *new_submenu = gtk_menu_new();
3863   item = gtk_image_menu_item_new_with_mnemonic ( _("_New") );
3864   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) );
3865   gtk_menu_shell_append(GTK_MENU_SHELL (menu), item);
3866   gtk_widget_show(item);
3867   gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), new_submenu);
3868
3869   item = gtk_image_menu_item_new_with_mnemonic ( _("New _Waypoint...") );
3870   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) );
3871   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wp), pass_along );
3872   gtk_menu_shell_append (GTK_MENU_SHELL (new_submenu), item);
3873   gtk_widget_show ( item );
3874
3875   item = gtk_image_menu_item_new_with_mnemonic ( _("New _Track") );
3876   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) );
3877   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_track), pass_along );
3878   gtk_menu_shell_append (GTK_MENU_SHELL (new_submenu), item);
3879   gtk_widget_show ( item );
3880   // Make it available only when a new track *not* already in progress
3881   gtk_widget_set_sensitive ( item, ! (gboolean)GPOINTER_TO_INT(vtl->current_track) );
3882
3883   item = gtk_image_menu_item_new_with_mnemonic ( _("New _Route") );
3884   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) );
3885   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_route), pass_along );
3886   gtk_menu_shell_append (GTK_MENU_SHELL (new_submenu), item);
3887   gtk_widget_show ( item );
3888   // Make it available only when a new track *not* already in progress
3889   gtk_widget_set_sensitive ( item, ! (gboolean)GPOINTER_TO_INT(vtl->current_track) );
3890
3891 #ifdef VIK_CONFIG_GEOTAG
3892   item = gtk_menu_item_new_with_mnemonic ( _("Geotag _Images...") );
3893   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_geotagging), pass_along );
3894   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3895   gtk_widget_show ( item );
3896 #endif
3897
3898   GtkWidget *acquire_submenu = gtk_menu_new ();
3899   item = gtk_image_menu_item_new_with_mnemonic ( _("_Acquire") );
3900   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_DOWN, GTK_ICON_SIZE_MENU) );
3901   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3902   gtk_widget_show ( item );
3903   gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), acquire_submenu );
3904   
3905   item = gtk_menu_item_new_with_mnemonic ( _("From _GPS...") );
3906   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_gps_cb), pass_along );
3907   gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
3908   gtk_widget_show ( item );
3909
3910   /* FIXME: only add menu when at least a routing engine has support for Directions */
3911   item = gtk_menu_item_new_with_mnemonic ( _("From _Directions...") );
3912   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_routing_cb), pass_along );
3913   gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
3914   gtk_widget_show ( item );
3915
3916 #ifdef VIK_CONFIG_OPENSTREETMAP
3917   item = gtk_menu_item_new_with_mnemonic ( _("From _OSM Traces...") );
3918   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_osm_cb), pass_along );
3919   gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
3920   gtk_widget_show ( item );
3921
3922   item = gtk_menu_item_new_with_mnemonic ( _("From _My OSM Traces...") );
3923   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_osm_my_traces_cb), pass_along );
3924   gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
3925   gtk_widget_show ( item );
3926 #endif
3927
3928   item = gtk_menu_item_new_with_mnemonic ( _("From _URL...") );
3929   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_url_cb), pass_along );
3930   gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
3931   gtk_widget_show ( item );
3932
3933 #ifdef VIK_CONFIG_GEONAMES
3934   GtkWidget *wikipedia_submenu = gtk_menu_new();
3935   item = gtk_image_menu_item_new_with_mnemonic ( _("From _Wikipedia Waypoints") );
3936   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
3937   gtk_menu_shell_append(GTK_MENU_SHELL (acquire_submenu), item);
3938   gtk_widget_show(item);
3939   gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), wikipedia_submenu);
3940
3941   item = gtk_image_menu_item_new_with_mnemonic ( _("Within _Layer Bounds") );
3942   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
3943   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wikipedia_wp_layer), pass_along );
3944   gtk_menu_shell_append (GTK_MENU_SHELL (wikipedia_submenu), item);
3945   gtk_widget_show ( item );
3946
3947   item = gtk_image_menu_item_new_with_mnemonic ( _("Within _Current View") );
3948   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_100, GTK_ICON_SIZE_MENU) );
3949   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wikipedia_wp_viewport), pass_along );
3950   gtk_menu_shell_append (GTK_MENU_SHELL (wikipedia_submenu), item);
3951   gtk_widget_show ( item );
3952 #endif
3953
3954 #ifdef VIK_CONFIG_GEOCACHES
3955   item = gtk_menu_item_new_with_mnemonic ( _("From Geo_caching...") );
3956   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_geocache_cb), pass_along );
3957   gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
3958   gtk_widget_show ( item );
3959 #endif
3960
3961 #ifdef VIK_CONFIG_GEOTAG
3962   item = gtk_menu_item_new_with_mnemonic ( _("From Geotagged _Images...") );
3963   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_geotagged_cb), pass_along );
3964   gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
3965   gtk_widget_show ( item );
3966 #endif
3967
3968   item = gtk_menu_item_new_with_mnemonic ( _("From _File...") );
3969   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_file_cb), pass_along );
3970   gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
3971   gtk_widget_set_tooltip_text (item, _("Import File With GPS_Babel..."));
3972   gtk_widget_show ( item );
3973
3974   vik_ext_tool_datasources_add_menu_items_to_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), GTK_MENU (acquire_submenu) );
3975
3976   GtkWidget *upload_submenu = gtk_menu_new ();
3977   item = gtk_image_menu_item_new_with_mnemonic ( _("_Upload") );
3978   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU) );
3979   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3980   gtk_widget_show ( item );
3981   gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), upload_submenu );
3982
3983   item = gtk_image_menu_item_new_with_mnemonic ( _("Upload to _GPS...") );
3984   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_MENU) );
3985   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_gps_upload), pass_along );
3986   gtk_menu_shell_append (GTK_MENU_SHELL (upload_submenu), item);
3987   gtk_widget_show ( item );
3988
3989 #ifdef VIK_CONFIG_OPENSTREETMAP 
3990   item = gtk_image_menu_item_new_with_mnemonic ( _("Upload to _OSM...") );
3991   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU) );
3992   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_osm_traces_upload_cb), pass_along );
3993   gtk_menu_shell_append (GTK_MENU_SHELL (upload_submenu), item);
3994   gtk_widget_show ( item );
3995 #endif
3996
3997   GtkWidget *delete_submenu = gtk_menu_new ();
3998   item = gtk_image_menu_item_new_with_mnemonic ( _("De_lete") );
3999   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
4000   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
4001   gtk_widget_show ( item );
4002   gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), delete_submenu );
4003   
4004   item = gtk_image_menu_item_new_with_mnemonic ( _("Delete All _Tracks") );
4005   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
4006   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_tracks), pass_along );
4007   gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
4008   gtk_widget_show ( item );
4009   
4010   item = gtk_image_menu_item_new_with_mnemonic ( _("Delete Tracks _From Selection...") );
4011   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
4012   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_tracks_from_selection), pass_along );
4013   gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
4014   gtk_widget_show ( item );
4015
4016   item = gtk_image_menu_item_new_with_mnemonic ( _("Delete _All Routes") );
4017   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
4018   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_routes), pass_along );
4019   gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
4020   gtk_widget_show ( item );
4021
4022   item = gtk_image_menu_item_new_with_mnemonic ( _("_Delete Routes From Selection...") );
4023   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
4024   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_routes_from_selection), pass_along );
4025   gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
4026   gtk_widget_show ( item );
4027   
4028   item = gtk_image_menu_item_new_with_mnemonic ( _("Delete All _Waypoints") );
4029   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
4030   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_waypoints), pass_along );
4031   gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
4032   gtk_widget_show ( item );
4033   
4034   item = gtk_image_menu_item_new_with_mnemonic ( _("Delete Waypoints From _Selection...") );
4035   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
4036   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_waypoints_from_selection), pass_along );
4037   gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
4038   gtk_widget_show ( item );
4039   
4040   item = a_acquire_trwlayer_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vlp,
4041                                    vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vlp)), vtl );
4042   if ( item ) {
4043     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
4044     gtk_widget_show ( item );
4045   }  
4046
4047   item = a_acquire_trwlayer_track_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), vlp,
4048                                          vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vlp)), vtl );
4049   if ( item ) {
4050     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
4051     gtk_widget_show ( item );
4052   }
4053
4054   item = gtk_image_menu_item_new_with_mnemonic ( _("Track _List...") );
4055   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
4056   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_list_dialog), pass_along );
4057   gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
4058   gtk_widget_show ( item );
4059   gtk_widget_set_sensitive ( item, (gboolean)(g_hash_table_size (vtl->tracks)+g_hash_table_size (vtl->routes)) );
4060
4061   item = gtk_image_menu_item_new_with_mnemonic ( _("_Waypoint List...") );
4062   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
4063   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoint_list_dialog), pass_along );
4064   gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
4065   gtk_widget_show ( item );
4066   gtk_widget_set_sensitive ( item, (gboolean)(g_hash_table_size (vtl->waypoints)) );
4067 }
4068
4069 // Fake Waypoint UUIDs vi simple increasing integer
4070 static guint wp_uuid = 0;
4071
4072 void vik_trw_layer_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp )
4073 {
4074   wp_uuid++;
4075
4076   vik_waypoint_set_name (wp, name);
4077
4078   if ( VIK_LAYER(vtl)->realized )
4079   {
4080     // Do we need to create the sublayer:
4081     if ( g_hash_table_size (vtl->waypoints) == 0 ) {
4082       trw_layer_add_sublayer_waypoints ( vtl, VIK_LAYER(vtl)->vt, &(VIK_LAYER(vtl)->iter) );
4083     }
4084
4085     GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter));
4086
4087     // Visibility column always needed for waypoints
4088     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 );
4089
4090     // Actual setting of visibility dependent on the waypoint
4091     vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, wp->visible );
4092
4093     g_hash_table_insert ( vtl->waypoints_iters, GUINT_TO_POINTER(wp_uuid), iter );
4094
4095     // Sort now as post_read is not called on a realized waypoint
4096     vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), vtl->wp_sort_order );
4097   }
4098
4099   highest_wp_number_add_wp(vtl, name);
4100   g_hash_table_insert ( vtl->waypoints, GUINT_TO_POINTER(wp_uuid), wp );
4101  
4102 }
4103
4104 // Fake Track UUIDs vi simple increasing integer
4105 static guint tr_uuid = 0;
4106
4107 void vik_trw_layer_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *t )
4108 {
4109   tr_uuid++;
4110
4111   vik_track_set_name (t, name);
4112
4113   if ( VIK_LAYER(vtl)->realized )
4114   {
4115     // Do we need to create the sublayer:
4116     if ( g_hash_table_size (vtl->tracks) == 0 ) {
4117       trw_layer_add_sublayer_tracks ( vtl, VIK_LAYER(vtl)->vt, &(VIK_LAYER(vtl)->iter) );
4118     }
4119
4120     GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter));
4121     // Visibility column always needed for tracks
4122     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 );
4123
4124     // Actual setting of visibility dependent on the track
4125     vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, t->visible );
4126
4127     g_hash_table_insert ( vtl->tracks_iters, GUINT_TO_POINTER(tr_uuid), iter );
4128
4129     // Sort now as post_read is not called on a realized track
4130     vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), vtl->track_sort_order );
4131   }
4132
4133   g_hash_table_insert ( vtl->tracks, GUINT_TO_POINTER(tr_uuid), t );
4134
4135   trw_layer_update_treeview ( vtl, t );
4136 }
4137
4138 // Fake Route UUIDs vi simple increasing integer
4139 static guint rt_uuid = 0;
4140
4141 void vik_trw_layer_add_route ( VikTrwLayer *vtl, gchar *name, VikTrack *t )
4142 {
4143   rt_uuid++;
4144
4145   vik_track_set_name (t, name);
4146
4147   if ( VIK_LAYER(vtl)->realized )
4148   {
4149     // Do we need to create the sublayer:
4150     if ( g_hash_table_size (vtl->routes) == 0 ) {
4151       trw_layer_add_sublayer_routes ( vtl, VIK_LAYER(vtl)->vt, &(VIK_LAYER(vtl)->iter) );
4152     }
4153
4154     GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter));
4155     // Visibility column always needed for routes
4156     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 );
4157     // Actual setting of visibility dependent on the route
4158     vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, t->visible );
4159
4160     g_hash_table_insert ( vtl->routes_iters, GUINT_TO_POINTER(rt_uuid), iter );
4161
4162     // Sort now as post_read is not called on a realized route
4163     vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter), vtl->track_sort_order );
4164   }
4165
4166   g_hash_table_insert ( vtl->routes, GUINT_TO_POINTER(rt_uuid), t );
4167
4168   trw_layer_update_treeview ( vtl, t );
4169 }
4170
4171 /* to be called whenever a track has been deleted or may have been changed. */
4172 void trw_layer_cancel_tps_of_track ( VikTrwLayer *vtl, VikTrack *trk )
4173 {
4174   if (vtl->current_tp_track == trk )
4175     trw_layer_cancel_current_tp ( vtl, FALSE );
4176 }
4177
4178 /**
4179  * Normally this is done to due the waypoint size preference having changed
4180  */
4181 void vik_trw_layer_reset_waypoints ( VikTrwLayer *vtl )
4182 {
4183   GHashTableIter iter;
4184   gpointer key, value;
4185
4186   // Foreach waypoint
4187   g_hash_table_iter_init ( &iter, vtl->waypoints );
4188   while ( g_hash_table_iter_next ( &iter, &key, &value ) ) {
4189     VikWaypoint *wp = VIK_WAYPOINT(value);
4190     if ( wp->symbol ) {
4191       // Reapply symbol setting to update the pixbuf
4192       gchar *tmp_symbol = g_strdup ( wp->symbol );
4193       vik_waypoint_set_symbol ( wp, tmp_symbol );
4194       g_free ( tmp_symbol );
4195     }
4196   }
4197 }
4198
4199 /**
4200  * trw_layer_new_unique_sublayer_name:
4201  *
4202  * Allocates a unique new name
4203  */
4204 gchar *trw_layer_new_unique_sublayer_name (VikTrwLayer *vtl, gint sublayer_type, const gchar *name)
4205 {
4206   gint i = 2;
4207   gchar *newname = g_strdup(name);
4208
4209   gpointer id = NULL;
4210   do {
4211     id = NULL;
4212     switch ( sublayer_type ) {
4213     case VIK_TRW_LAYER_SUBLAYER_TRACK:
4214       id = (gpointer) vik_trw_layer_get_track ( vtl, newname );
4215       break;
4216     case VIK_TRW_LAYER_SUBLAYER_WAYPOINT:
4217       id = (gpointer) vik_trw_layer_get_waypoint ( vtl, newname );
4218       break;
4219     default:
4220       id = (gpointer) vik_trw_layer_get_route ( vtl, newname );
4221       break;
4222     }
4223     // If found a name already in use try adding 1 to it and we try again
4224     if ( id ) {
4225       gchar *new_newname = g_strdup_printf("%s#%d", name, i);
4226       g_free(newname);
4227       newname = new_newname;
4228       i++;
4229     }
4230   } while ( id != NULL);
4231
4232   return newname;
4233 }
4234
4235 void vik_trw_layer_filein_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp )
4236 {
4237   // No more uniqueness of name forced when loading from a file
4238   // This now makes this function a little redunant as we just flow the parameters through
4239   vik_trw_layer_add_waypoint ( vtl, name, wp );
4240 }
4241
4242 void vik_trw_layer_filein_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *tr )
4243 {
4244   if ( vtl->route_finder_append && vtl->route_finder_current_track ) {
4245     vik_track_remove_dup_points ( tr ); /* make "double point" track work to undo */
4246     vik_track_steal_and_append_trackpoints ( vtl->route_finder_current_track, tr );
4247     vik_track_free ( tr );
4248     vtl->route_finder_append = FALSE; /* this means we have added it */
4249   } else {
4250
4251     // No more uniqueness of name forced when loading from a file
4252     if ( tr->is_route )
4253       vik_trw_layer_add_route ( vtl, name, tr );
4254     else
4255       vik_trw_layer_add_track ( vtl, name, tr );
4256
4257     if ( vtl->route_finder_check_added_track ) {
4258       vik_track_remove_dup_points ( tr ); /* make "double point" track work to undo */
4259       vtl->route_finder_added_track = tr;
4260     }
4261   }
4262 }
4263
4264 static void trw_layer_enum_item ( gpointer id, GList **tr, GList **l )
4265 {
4266   *l = g_list_append(*l, id);
4267 }
4268
4269 /*
4270  * Move an item from one TRW layer to another TRW layer
4271  */
4272 static void trw_layer_move_item ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, gpointer id, gint type )
4273 {
4274   // TODO reconsider strategy when moving within layer (if anything...)
4275   gboolean rename = ( vtl_src != vtl_dest );
4276   if ( ! rename )
4277     return;
4278
4279   if (type == VIK_TRW_LAYER_SUBLAYER_TRACK) {
4280     VikTrack *trk = g_hash_table_lookup ( vtl_src->tracks, id );
4281
4282     gchar *newname;
4283     if ( rename )
4284       newname = trw_layer_new_unique_sublayer_name ( vtl_dest, type, trk->name );
4285     else
4286       newname = g_strdup ( trk->name );
4287
4288     VikTrack *trk2 = vik_track_copy ( trk, TRUE );
4289     vik_trw_layer_add_track ( vtl_dest, newname, trk2 );
4290     g_free ( newname );
4291     vik_trw_layer_delete_track ( vtl_src, trk );
4292   }
4293
4294   if (type == VIK_TRW_LAYER_SUBLAYER_ROUTE) {
4295     VikTrack *trk = g_hash_table_lookup ( vtl_src->routes, id );
4296
4297     gchar *newname;
4298     if ( rename )
4299       newname = trw_layer_new_unique_sublayer_name ( vtl_dest, type, trk->name );
4300     else
4301       newname = g_strdup ( trk->name );
4302
4303     VikTrack *trk2 = vik_track_copy ( trk, TRUE );
4304     vik_trw_layer_add_route ( vtl_dest, newname, trk2 );
4305     g_free ( newname );
4306     vik_trw_layer_delete_route ( vtl_src, trk );
4307   }
4308
4309   if (type == VIK_TRW_LAYER_SUBLAYER_WAYPOINT) {
4310     VikWaypoint *wp = g_hash_table_lookup ( vtl_src->waypoints, id );
4311
4312     gchar *newname;
4313     if ( rename )
4314       newname = trw_layer_new_unique_sublayer_name ( vtl_dest, type, wp->name );
4315     else
4316       newname = g_strdup ( wp->name );
4317
4318     VikWaypoint *wp2 = vik_waypoint_copy ( wp );
4319     vik_trw_layer_add_waypoint ( vtl_dest, newname, wp2 );
4320     g_free ( newname );
4321     trw_layer_delete_waypoint ( vtl_src, wp );
4322
4323     // Recalculate bounds even if not renamed as maybe dragged between layers
4324     trw_layer_calculate_bounds_waypoints ( vtl_dest );
4325     trw_layer_calculate_bounds_waypoints ( vtl_src );
4326   }
4327 }
4328
4329 static void trw_layer_drag_drop_request ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, GtkTreeIter *src_item_iter, GtkTreePath *dest_path )
4330 {
4331   VikTreeview *vt = VIK_LAYER(vtl_src)->vt;
4332   gint type = vik_treeview_item_get_data(vt, src_item_iter);
4333
4334   if (!vik_treeview_item_get_pointer(vt, src_item_iter)) {
4335     GList *items = NULL;
4336     GList *iter;
4337
4338     if (type==VIK_TRW_LAYER_SUBLAYER_TRACKS) {
4339       g_hash_table_foreach ( vtl_src->tracks, (GHFunc)trw_layer_enum_item, &items);
4340     } 
4341     if (type==VIK_TRW_LAYER_SUBLAYER_WAYPOINTS) {
4342       g_hash_table_foreach ( vtl_src->waypoints, (GHFunc)trw_layer_enum_item, &items);
4343     }    
4344     if (type==VIK_TRW_LAYER_SUBLAYER_ROUTES) {
4345       g_hash_table_foreach ( vtl_src->routes, (GHFunc)trw_layer_enum_item, &items);
4346     }
4347
4348     iter = items;
4349     while (iter) {
4350       if (type==VIK_TRW_LAYER_SUBLAYER_TRACKS) {
4351         trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_TRACK);
4352       } else if (type==VIK_TRW_LAYER_SUBLAYER_ROUTES) {
4353         trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_ROUTE);
4354       } else {
4355         trw_layer_move_item ( vtl_src, vtl_dest, iter->data, VIK_TRW_LAYER_SUBLAYER_WAYPOINT);
4356       }
4357       iter = iter->next;
4358     }
4359     if (items) 
4360       g_list_free(items);
4361   } else {
4362     gchar *name = vik_treeview_item_get_pointer(vt, src_item_iter);
4363     trw_layer_move_item(vtl_src, vtl_dest, name, type);
4364   }
4365 }
4366
4367 gboolean trw_layer_track_find_uuid ( const gpointer id, const VikTrack *trk, gpointer udata )
4368 {
4369   trku_udata *user_data = udata;
4370   if ( trk == user_data->trk ) {
4371     user_data->uuid = id;
4372     return TRUE;
4373   }
4374   return FALSE;
4375 }
4376
4377 gboolean vik_trw_layer_delete_track ( VikTrwLayer *vtl, VikTrack *trk )
4378 {
4379   gboolean was_visible = FALSE;
4380
4381   if ( trk && trk->name ) {
4382
4383     if ( trk == vtl->current_track ) {
4384       vtl->current_track = NULL;
4385       vtl->current_tp_track = NULL;
4386       vtl->current_tp_id = NULL;
4387       vtl->moving_tp = FALSE;
4388     }
4389
4390     was_visible = trk->visible;
4391
4392     if ( trk == vtl->route_finder_current_track )
4393       vtl->route_finder_current_track = NULL;
4394
4395     if ( trk == vtl->route_finder_added_track )
4396       vtl->route_finder_added_track = NULL;
4397
4398     trku_udata udata;
4399     udata.trk  = trk;
4400     udata.uuid = NULL;
4401
4402     // Hmmm, want key of it
4403     gpointer *trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udata );
4404
4405     if ( trkf && udata.uuid ) {
4406       /* could be current_tp, so we have to check */
4407       trw_layer_cancel_tps_of_track ( vtl, trk );
4408
4409       GtkTreeIter *it = g_hash_table_lookup ( vtl->tracks_iters, udata.uuid );
4410
4411       if ( it ) {
4412         vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, it );
4413         g_hash_table_remove ( vtl->tracks_iters, udata.uuid );
4414         g_hash_table_remove ( vtl->tracks, udata.uuid );
4415
4416         // If last sublayer, then remove sublayer container
4417         if ( g_hash_table_size (vtl->tracks) == 0 ) {
4418           vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter) );
4419         }
4420       }
4421     }
4422   }
4423   return was_visible;
4424 }
4425
4426 gboolean vik_trw_layer_delete_route ( VikTrwLayer *vtl, VikTrack *trk )
4427 {
4428   gboolean was_visible = FALSE;
4429
4430   if ( trk && trk->name ) {
4431
4432     if ( trk == vtl->current_track ) {
4433       vtl->current_track = NULL;
4434       vtl->current_tp_track = NULL;
4435       vtl->current_tp_id = NULL;
4436       vtl->moving_tp = FALSE;
4437     }
4438
4439     was_visible = trk->visible;
4440
4441     if ( trk == vtl->route_finder_current_track )
4442       vtl->route_finder_current_track = NULL;
4443
4444     if ( trk == vtl->route_finder_added_track )
4445       vtl->route_finder_added_track = NULL;
4446
4447     trku_udata udata;
4448     udata.trk  = trk;
4449     udata.uuid = NULL;
4450
4451     // Hmmm, want key of it
4452     gpointer *trkf = g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find_uuid, &udata );
4453
4454     if ( trkf && udata.uuid ) {
4455       /* could be current_tp, so we have to check */
4456       trw_layer_cancel_tps_of_track ( vtl, trk );
4457
4458       GtkTreeIter *it = g_hash_table_lookup ( vtl->routes_iters, udata.uuid );
4459
4460       if ( it ) {
4461         vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, it );
4462         g_hash_table_remove ( vtl->routes_iters, udata.uuid );
4463         g_hash_table_remove ( vtl->routes, udata.uuid );
4464
4465         // If last sublayer, then remove sublayer container
4466         if ( g_hash_table_size (vtl->routes) == 0 ) {
4467           vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter) );
4468         }
4469       }
4470     }
4471   }
4472   return was_visible;
4473 }
4474
4475 static gboolean trw_layer_delete_waypoint ( VikTrwLayer *vtl, VikWaypoint *wp )
4476 {
4477   gboolean was_visible = FALSE;
4478
4479   if ( wp && wp->name ) {
4480
4481     if ( wp == vtl->current_wp ) {
4482       vtl->current_wp = NULL;
4483       vtl->current_wp_id = NULL;
4484       vtl->moving_wp = FALSE;
4485     }
4486
4487     was_visible = wp->visible;
4488     
4489     wpu_udata udata;
4490     udata.wp   = wp;
4491     udata.uuid = NULL;
4492
4493     // Hmmm, want key of it
4494     gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata );
4495
4496     if ( wpf && udata.uuid ) {
4497       GtkTreeIter *it = g_hash_table_lookup ( vtl->waypoints_iters, udata.uuid );
4498     
4499       if ( it ) {
4500         vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, it );
4501         g_hash_table_remove ( vtl->waypoints_iters, udata.uuid );
4502
4503         highest_wp_number_remove_wp(vtl, wp->name);
4504         g_hash_table_remove ( vtl->waypoints, udata.uuid ); // last because this frees the name
4505
4506         // If last sublayer, then remove sublayer container
4507         if ( g_hash_table_size (vtl->waypoints) == 0 ) {
4508           vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter) );
4509         }
4510       }
4511     }
4512
4513   }
4514
4515   return was_visible;
4516 }
4517
4518 // Only for temporary use by trw_layer_delete_waypoint_by_name
4519 static gboolean trw_layer_waypoint_find_uuid_by_name ( const gpointer id, const VikWaypoint *wp, gpointer udata )
4520 {
4521   wpu_udata *user_data = udata;
4522   if ( ! strcmp ( wp->name, user_data->wp->name ) ) {
4523     user_data->uuid = id;
4524     return TRUE;
4525   }
4526   return FALSE;
4527 }
4528
4529 /*
4530  * Delete a waypoint by the given name
4531  * NOTE: ATM this will delete the first encountered Waypoint with the specified name
4532  *   as there be multiple waypoints with the same name
4533  */
4534 static gboolean trw_layer_delete_waypoint_by_name ( VikTrwLayer *vtl, const gchar *name )
4535 {
4536   wpu_udata udata;
4537   // Fake a waypoint with the given name
4538   udata.wp   = vik_waypoint_new ();
4539   vik_waypoint_set_name (udata.wp, name);
4540   // Currently only the name is used in this waypoint find function
4541   udata.uuid = NULL;
4542
4543   // Hmmm, want key of it
4544   gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid_by_name, (gpointer) &udata );
4545
4546   vik_waypoint_free (udata.wp);
4547
4548   if ( wpf && udata.uuid )
4549     return trw_layer_delete_waypoint (vtl, g_hash_table_lookup ( vtl->waypoints, udata.uuid ));
4550   else
4551     return FALSE;
4552 }
4553
4554 typedef struct {
4555   VikTrack *trk; // input
4556   gpointer uuid; // output
4557 } tpu_udata;
4558
4559 // Only for temporary use by trw_layer_delete_track_by_name
4560 static gboolean trw_layer_track_find_uuid_by_name ( const gpointer id, const VikTrack *trk, gpointer udata )
4561 {
4562   tpu_udata *user_data = udata;
4563   if ( ! strcmp ( trk->name, user_data->trk->name ) ) {
4564     user_data->uuid = id;
4565     return TRUE;
4566   }
4567   return FALSE;
4568 }
4569
4570 /*
4571  * Delete a track by the given name
4572  * NOTE: ATM this will delete the first encountered Track with the specified name
4573  *   as there may be multiple tracks with the same name within the specified hash table
4574  */
4575 static gboolean trw_layer_delete_track_by_name ( VikTrwLayer *vtl, const gchar *name, GHashTable *ht_tracks )
4576 {
4577   tpu_udata udata;
4578   // Fake a track with the given name
4579   udata.trk   = vik_track_new ();
4580   vik_track_set_name (udata.trk, name);
4581   // Currently only the name is used in this waypoint find function
4582   udata.uuid = NULL;
4583
4584   // Hmmm, want key of it
4585   gpointer *trkf = g_hash_table_find ( ht_tracks, (GHRFunc) trw_layer_track_find_uuid_by_name, &udata );
4586
4587   vik_track_free (udata.trk);
4588
4589   if ( trkf && udata.uuid ) {
4590     // This could be a little better written...
4591     if ( vtl->tracks == ht_tracks )
4592       return vik_trw_layer_delete_track (vtl, g_hash_table_lookup ( ht_tracks, udata.uuid ));
4593     if ( vtl->routes == ht_tracks )
4594       return vik_trw_layer_delete_route (vtl, g_hash_table_lookup ( ht_tracks, udata.uuid ));
4595     return FALSE;
4596   }
4597   else
4598     return FALSE;
4599 }
4600
4601 static void remove_item_from_treeview ( const gpointer id, GtkTreeIter *it, VikTreeview * vt )
4602 {
4603     vik_treeview_item_delete (vt, it );
4604 }
4605
4606 void vik_trw_layer_delete_all_routes ( VikTrwLayer *vtl )
4607 {
4608
4609   vtl->current_track = NULL;
4610   vtl->route_finder_current_track = NULL;
4611   vtl->route_finder_added_track = NULL;
4612   if (vtl->current_tp_track)
4613     trw_layer_cancel_current_tp(vtl, FALSE);
4614
4615   g_hash_table_foreach(vtl->routes_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt);
4616   g_hash_table_remove_all(vtl->routes_iters);
4617   g_hash_table_remove_all(vtl->routes);
4618
4619   vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter) );
4620
4621   vik_layer_emit_update ( VIK_LAYER(vtl) );
4622 }
4623
4624 void vik_trw_layer_delete_all_tracks ( VikTrwLayer *vtl )
4625 {
4626
4627   vtl->current_track = NULL;
4628   vtl->route_finder_current_track = NULL;
4629   vtl->route_finder_added_track = NULL;
4630   if (vtl->current_tp_track)
4631     trw_layer_cancel_current_tp(vtl, FALSE);
4632
4633   g_hash_table_foreach(vtl->tracks_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt);
4634   g_hash_table_remove_all(vtl->tracks_iters);
4635   g_hash_table_remove_all(vtl->tracks);
4636
4637   vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter) );
4638
4639   vik_layer_emit_update ( VIK_LAYER(vtl) );
4640 }
4641
4642 void vik_trw_layer_delete_all_waypoints ( VikTrwLayer *vtl )
4643 {
4644   vtl->current_wp = NULL;
4645   vtl->current_wp_id = NULL;
4646   vtl->moving_wp = FALSE;
4647
4648   highest_wp_number_reset(vtl);
4649
4650   g_hash_table_foreach(vtl->waypoints_iters, (GHFunc) remove_item_from_treeview, VIK_LAYER(vtl)->vt);
4651   g_hash_table_remove_all(vtl->waypoints_iters);
4652   g_hash_table_remove_all(vtl->waypoints);
4653
4654   vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter) );
4655
4656   vik_layer_emit_update ( VIK_LAYER(vtl) );
4657 }
4658
4659 static void trw_layer_delete_all_tracks ( gpointer lav[2] )
4660 {
4661   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
4662   // Get confirmation from the user
4663   if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
4664                             _("Are you sure you want to delete all tracks in %s?"),
4665                             vik_layer_get_name ( VIK_LAYER(vtl) ) ) )
4666     vik_trw_layer_delete_all_tracks (vtl);
4667 }
4668
4669 static void trw_layer_delete_all_routes ( 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 routes in %s?"),
4675                             vik_layer_get_name ( VIK_LAYER(vtl) ) ) )
4676     vik_trw_layer_delete_all_routes (vtl);
4677 }
4678
4679 static void trw_layer_delete_all_waypoints ( 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 waypoints in %s?"),
4685                             vik_layer_get_name ( VIK_LAYER(vtl) ) ) )
4686     vik_trw_layer_delete_all_waypoints (vtl);
4687 }
4688
4689 static void trw_layer_delete_item ( gpointer pass_along[6] )
4690 {
4691   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
4692   gboolean was_visible = FALSE;
4693   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
4694   {
4695     VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, pass_along[3] );
4696     if ( wp && wp->name ) {
4697       if ( GPOINTER_TO_INT ( pass_along[4]) )
4698         // Get confirmation from the user
4699         // Maybe this Waypoint Delete should be optional as is it could get annoying...
4700         if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
4701             _("Are you sure you want to delete the waypoint \"%s\"?"),
4702             wp->name ) )
4703           return;
4704       was_visible = trw_layer_delete_waypoint ( vtl, wp );
4705     }
4706   }
4707   else if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_TRACK )
4708   {
4709     VikTrack *trk = g_hash_table_lookup ( vtl->tracks, pass_along[3] );
4710     if ( trk && trk->name ) {
4711       if ( GPOINTER_TO_INT ( pass_along[4]) )
4712         // Get confirmation from the user
4713         if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
4714                                   _("Are you sure you want to delete the track \"%s\"?"),
4715                                   trk->name ) )
4716           return;
4717       was_visible = vik_trw_layer_delete_track ( vtl, trk );
4718     }
4719   }
4720   else
4721   {
4722     VikTrack *trk = g_hash_table_lookup ( vtl->routes, pass_along[3] );
4723     if ( trk && trk->name ) {
4724       if ( GPOINTER_TO_INT ( pass_along[4]) )
4725         // Get confirmation from the user
4726         if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
4727                                     _("Are you sure you want to delete the route \"%s\"?"),
4728                                     trk->name ) )
4729           return;
4730       was_visible = vik_trw_layer_delete_route ( vtl, trk );
4731     }
4732   }
4733   if ( was_visible )
4734     vik_layer_emit_update ( VIK_LAYER(vtl) );
4735 }
4736
4737 /**
4738  *  Rename waypoint and maintain corresponding name of waypoint in the treeview
4739  */
4740 void trw_layer_waypoint_rename ( VikTrwLayer *vtl, VikWaypoint *wp, const gchar *new_name )
4741 {
4742   vik_waypoint_set_name ( wp, new_name );
4743
4744   // Now update the treeview as well
4745   wpu_udata udataU;
4746   udataU.wp   = wp;
4747   udataU.uuid = NULL;
4748
4749   // Need key of it for treeview update
4750   gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, &udataU );
4751
4752   if ( wpf && udataU.uuid ) {
4753     GtkTreeIter *it = g_hash_table_lookup ( vtl->waypoints_iters, udataU.uuid );
4754
4755     if ( it ) {
4756       vik_treeview_item_set_name ( VIK_LAYER(vtl)->vt, it, new_name );
4757       vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), vtl->wp_sort_order );
4758     }
4759   }
4760 }
4761
4762 /**
4763  *  Maintain icon of waypoint in the treeview
4764  */
4765 void trw_layer_waypoint_reset_icon ( VikTrwLayer *vtl, VikWaypoint *wp )
4766 {
4767   // update the treeview
4768   wpu_udata udataU;
4769   udataU.wp   = wp;
4770   udataU.uuid = NULL;
4771
4772   // Need key of it for treeview update
4773   gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, &udataU );
4774
4775   if ( wpf && udataU.uuid ) {
4776     GtkTreeIter *it = g_hash_table_lookup ( vtl->waypoints_iters, udataU.uuid );
4777
4778     if ( it ) {
4779       vik_treeview_item_set_icon ( VIK_LAYER(vtl)->vt, it, get_wp_sym_small (wp->symbol) );
4780     }
4781   }
4782 }
4783
4784 static void trw_layer_properties_item ( gpointer pass_along[7] )
4785 {
4786   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
4787   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
4788   {
4789     VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, pass_along[3] ); // sublayer
4790
4791     if ( wp && wp->name )
4792     {
4793       gboolean updated = FALSE;
4794       gchar *new_name = a_dialog_waypoint ( VIK_GTK_WINDOW_FROM_LAYER(vtl), wp->name, vtl, wp, vtl->coord_mode, FALSE, &updated );
4795       if ( new_name )
4796         trw_layer_waypoint_rename ( vtl, wp, new_name );
4797
4798       if ( updated && pass_along[6] )
4799         vik_treeview_item_set_icon ( VIK_LAYER(vtl)->vt, pass_along[6], get_wp_sym_small (wp->symbol) );
4800
4801       if ( updated && VIK_LAYER(vtl)->visible )
4802         vik_layer_emit_update ( VIK_LAYER(vtl) );
4803     }
4804   }
4805   else
4806   {
4807     VikTrack *tr;
4808     if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_TRACK )
4809       tr = g_hash_table_lookup ( vtl->tracks, pass_along[3] );
4810     else
4811       tr = g_hash_table_lookup ( vtl->routes, pass_along[3] );
4812
4813     if ( tr && tr->name )
4814     {
4815       vik_trw_layer_propwin_run ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
4816                                   vtl,
4817                                   tr,
4818                                   pass_along[1], /* vlp */
4819                                   pass_along[5], /* vvp */
4820                                   FALSE );
4821     }
4822   }
4823 }
4824
4825 /**
4826  * trw_layer_track_statistics:
4827  *
4828  * Show track statistics.
4829  * ATM jump to the stats page in the properties
4830  * TODO: consider separating the stats into an individual dialog?
4831  */
4832 static void trw_layer_track_statistics ( gpointer pass_along[7] )
4833 {
4834   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
4835   VikTrack *trk;
4836   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_TRACK )
4837     trk = g_hash_table_lookup ( vtl->tracks, pass_along[3] );
4838   else
4839     trk = g_hash_table_lookup ( vtl->routes, pass_along[3] );
4840
4841   if ( trk && trk->name ) {
4842     vik_trw_layer_propwin_run ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
4843                                 vtl,
4844                                 trk,
4845                                 pass_along[1], // vlp
4846                                 pass_along[5], // vvp
4847                                 TRUE );
4848   }
4849 }
4850
4851 /*
4852  * Update the treeview of the track id - primarily to update the icon
4853  */
4854 void trw_layer_update_treeview ( VikTrwLayer *vtl, VikTrack *trk )
4855 {
4856   trku_udata udata;
4857   udata.trk  = trk;
4858   udata.uuid = NULL;
4859
4860   gpointer *trkf = NULL;
4861   if ( trk->is_route )
4862     trkf = g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find_uuid, &udata );
4863   else
4864     trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udata );
4865
4866   if ( trkf && udata.uuid ) {
4867
4868     GtkTreeIter *iter = NULL;
4869     if ( trk->is_route )
4870       iter = g_hash_table_lookup ( vtl->routes_iters, udata.uuid );
4871     else
4872       iter = g_hash_table_lookup ( vtl->tracks_iters, udata.uuid );
4873
4874     if ( iter ) {
4875       // TODO: Make this a function
4876       GdkPixbuf *pixbuf = gdk_pixbuf_new ( GDK_COLORSPACE_RGB, FALSE, 8, 18, 18);
4877       guint32 pixel = ((trk->color.red & 0xff00) << 16) |
4878         ((trk->color.green & 0xff00) << 8) |
4879         (trk->color.blue & 0xff00);
4880       gdk_pixbuf_fill ( pixbuf, pixel );
4881       vik_treeview_item_set_icon ( VIK_LAYER(vtl)->vt, iter, pixbuf );
4882       g_object_unref (pixbuf);
4883     }
4884
4885   }
4886 }
4887
4888 /*
4889    Parameter 1 -> VikLayersPanel
4890    Parameter 2 -> VikLayer
4891    Parameter 3 -> VikViewport
4892 */
4893 static void goto_coord ( gpointer *vlp, gpointer vl, gpointer vvp, const VikCoord *coord )
4894 {
4895   if ( vlp ) {
4896     vik_viewport_set_center_coord ( vik_layers_panel_get_viewport (VIK_LAYERS_PANEL(vlp)), coord );
4897     vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) );
4898   }
4899   else {
4900     /* since vlp not set, vl & vvp should be valid instead! */
4901     if ( vl && vvp ) {
4902       vik_viewport_set_center_coord ( VIK_VIEWPORT(vvp), coord );
4903       vik_layer_emit_update ( VIK_LAYER(vl) );
4904     }
4905   }
4906 }
4907
4908 static void trw_layer_goto_track_startpoint ( gpointer pass_along[6] )
4909 {
4910   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
4911   VikTrack *track;
4912   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
4913     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
4914   else
4915     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
4916
4917   if ( track && track->trackpoints )
4918     goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(((VikTrackpoint *) track->trackpoints->data)->coord) );
4919 }
4920
4921 static void trw_layer_goto_track_center ( gpointer pass_along[6] )
4922 {
4923   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
4924   VikTrack *track;
4925   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
4926     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
4927   else
4928     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
4929
4930   if ( track && track->trackpoints )
4931   {
4932     struct LatLon average, maxmin[2] = { {0,0}, {0,0} };
4933     VikCoord coord;
4934     trw_layer_find_maxmin_tracks ( NULL, track, maxmin );
4935     average.lat = (maxmin[0].lat+maxmin[1].lat)/2;
4936     average.lon = (maxmin[0].lon+maxmin[1].lon)/2;
4937     vik_coord_load_from_latlon ( &coord, vtl->coord_mode, &average );
4938     goto_coord ( pass_along[1], pass_along[0], pass_along[5], &coord);
4939   }
4940 }
4941
4942 static void trw_layer_convert_track_route ( gpointer pass_along[6] )
4943 {
4944   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
4945   VikTrack *trk;
4946   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
4947     trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
4948   else
4949     trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
4950
4951   if ( !trk )
4952     return;
4953
4954   // Converting a track to a route can be a bit more complicated,
4955   //  so give a chance to change our minds:
4956   if ( !trk->is_route &&
4957        ( ( vik_track_get_segment_count ( trk ) > 1 ) ||
4958          ( vik_track_get_average_speed ( trk ) > 0.0 ) ) ) {
4959
4960     if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
4961                                 _("Converting a track to a route removes extra track data such as segments, timestamps, etc...\nDo you want to continue?"), NULL ) )
4962       return;
4963 }
4964
4965   // Copy it
4966   VikTrack *trk_copy = vik_track_copy ( trk, TRUE );
4967
4968   // Convert
4969   trk_copy->is_route = !trk_copy->is_route;
4970
4971   // ATM can't set name to self - so must create temporary copy
4972   gchar *name = g_strdup ( trk_copy->name );
4973
4974   // Delete old one and then add new one
4975   if ( trk->is_route ) {
4976     vik_trw_layer_delete_route ( vtl, trk );
4977     vik_trw_layer_add_track ( vtl, name, trk_copy );
4978   }
4979   else {
4980     // Extra route conversion bits...
4981     vik_track_merge_segments ( trk_copy );
4982     vik_track_to_routepoints ( trk_copy );
4983
4984     vik_trw_layer_delete_track ( vtl, trk );
4985     vik_trw_layer_add_route ( vtl, name, trk_copy );
4986   }
4987   g_free ( name );
4988
4989   // Update in case color of track / route changes when moving between sublayers
4990   vik_layer_emit_update ( VIK_LAYER(pass_along[0]) );
4991 }
4992
4993 static void trw_layer_anonymize_times ( gpointer pass_along[6] )
4994 {
4995   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
4996   VikTrack *track;
4997   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
4998     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
4999   else
5000     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
5001
5002   if ( track )
5003     vik_track_anonymize_times ( track );
5004 }
5005
5006 static void trw_layer_extend_track_end ( gpointer pass_along[6] )
5007 {
5008   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
5009   VikTrack *track;
5010   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5011     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
5012   else
5013     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
5014
5015   if ( !track )
5016     return;
5017
5018   vtl->current_track = track;
5019   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);
5020
5021   if ( track->trackpoints )
5022     goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(((VikTrackpoint *)g_list_last(track->trackpoints)->data)->coord) );
5023 }
5024
5025 /**
5026  * extend a track using route finder
5027  */
5028 static void trw_layer_extend_track_end_route_finder ( gpointer pass_along[6] )
5029 {
5030   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
5031   VikTrack *track = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->routes, pass_along[3] );
5032   if ( !track )
5033     return;
5034   if ( !track->trackpoints )
5035     return;
5036   VikCoord last_coord = (((VikTrackpoint *)g_list_last(track->trackpoints)->data)->coord);
5037
5038   vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_ROUTE_FINDER );
5039   vtl->route_finder_coord =  last_coord;
5040   vtl->route_finder_current_track = track;
5041   vtl->route_finder_started = TRUE;
5042
5043   if ( track->trackpoints )
5044     goto_coord ( pass_along[1], pass_along[0], pass_along[5], &last_coord) ;
5045
5046 }
5047
5048 /**
5049  *
5050  */
5051 static gboolean trw_layer_dem_test ( VikTrwLayer *vtl, VikLayersPanel *vlp )
5052 {
5053   // If have a vlp then perform a basic test to see if any DEM info available...
5054   if ( vlp ) {
5055     GList *dems = vik_layers_panel_get_all_layers_of_type (vlp, VIK_LAYER_DEM, TRUE); // Includes hidden DEM layer types
5056
5057     if ( !g_list_length(dems) ) {
5058       a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No DEM layers available, thus no DEM values can be applied.") );
5059       return FALSE;
5060     }
5061   }
5062   return TRUE;
5063 }
5064
5065 /**
5066  * apply_dem_data_common:
5067  *
5068  * A common function for applying the DEM values and reporting the results.
5069  */
5070 static void apply_dem_data_common ( VikTrwLayer *vtl, VikLayersPanel *vlp, VikTrack *track, gboolean skip_existing_elevations )
5071 {
5072   if ( !trw_layer_dem_test ( vtl, vlp ) )
5073     return;
5074
5075   gulong changed = vik_track_apply_dem_data ( track, skip_existing_elevations );
5076   // Inform user how much was changed
5077   gchar str[64];
5078   const gchar *tmp_str = ngettext("%ld point adjusted", "%ld points adjusted", changed);
5079   g_snprintf(str, 64, tmp_str, changed);
5080   a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str);
5081 }
5082
5083 static void trw_layer_apply_dem_data_all ( gpointer pass_along[6] )
5084 {
5085   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
5086   VikTrack *track;
5087   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5088     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
5089   else
5090     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
5091
5092   if ( track )
5093     apply_dem_data_common ( vtl, pass_along[1], track, FALSE );
5094 }
5095
5096 static void trw_layer_apply_dem_data_only_missing ( gpointer pass_along[6] )
5097 {
5098   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
5099   VikTrack *track;
5100   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5101     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
5102   else
5103     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
5104
5105   if ( track )
5106     apply_dem_data_common ( vtl, pass_along[1], track, TRUE );
5107 }
5108
5109 /**
5110  * smooth_it:
5111  *
5112  * A common function for applying the elevation smoothing and reporting the results.
5113  */
5114 static void smooth_it ( VikTrwLayer *vtl, VikTrack *track, gboolean flat )
5115 {
5116   gulong changed = vik_track_smooth_missing_elevation_data ( track, flat );
5117   // Inform user how much was changed
5118   gchar str[64];
5119   const gchar *tmp_str = ngettext("%ld point adjusted", "%ld points adjusted", changed);
5120   g_snprintf(str, 64, tmp_str, changed);
5121   a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str);
5122 }
5123
5124 /**
5125  *
5126  */
5127 static void trw_layer_missing_elevation_data_interp ( gpointer pass_along[6] )
5128 {
5129   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
5130   VikTrack *track;
5131   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5132     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
5133   else
5134     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
5135
5136   if ( !track )
5137     return;
5138
5139   smooth_it ( vtl, track, FALSE );
5140 }
5141
5142 static void trw_layer_missing_elevation_data_flat ( gpointer pass_along[6] )
5143 {
5144   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
5145   VikTrack *track;
5146   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5147     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
5148   else
5149     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
5150
5151   if ( !track )
5152     return;
5153
5154   smooth_it ( vtl, track, TRUE );
5155 }
5156
5157 /**
5158  * Commonal helper function
5159  */
5160 static void wp_changed_message ( VikTrwLayer *vtl, gint changed )
5161 {
5162   gchar str[64];
5163   const gchar *tmp_str = ngettext("%ld waypoint changed", "%ld waypoints changed", changed);
5164   g_snprintf(str, 64, tmp_str, changed);
5165   a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str);
5166 }
5167
5168 static void trw_layer_apply_dem_data_wpt_all ( gpointer pass_along[6] )
5169 {
5170   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
5171   VikLayersPanel *vlp = (VikLayersPanel *)pass_along[1];
5172
5173   if ( !trw_layer_dem_test ( vtl, vlp ) )
5174     return;
5175
5176   gint changed = 0;
5177   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
5178     // Single Waypoint
5179     VikWaypoint *wp = (VikWaypoint *) g_hash_table_lookup ( vtl->waypoints, pass_along[3] );
5180     if ( wp )
5181       changed = (gint)vik_waypoint_apply_dem_data ( wp, FALSE );
5182   }
5183   else {
5184     // All waypoints
5185     GHashTableIter iter;
5186     gpointer key, value;
5187
5188     g_hash_table_iter_init ( &iter, vtl->waypoints );
5189     while ( g_hash_table_iter_next (&iter, &key, &value) ) {
5190       VikWaypoint *wp = VIK_WAYPOINT(value);
5191       changed = changed + (gint)vik_waypoint_apply_dem_data ( wp, FALSE );
5192     }
5193   }
5194   wp_changed_message ( vtl, changed );
5195 }
5196
5197 static void trw_layer_apply_dem_data_wpt_only_missing ( gpointer pass_along[6] )
5198 {
5199   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
5200   VikLayersPanel *vlp = (VikLayersPanel *)pass_along[1];
5201
5202   if ( !trw_layer_dem_test ( vtl, vlp ) )
5203     return;
5204
5205   gint changed = 0;
5206   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
5207     // Single Waypoint
5208     VikWaypoint *wp = (VikWaypoint *) g_hash_table_lookup ( vtl->waypoints, pass_along[3] );
5209     if ( wp )
5210       changed = (gint)vik_waypoint_apply_dem_data ( wp, TRUE );
5211   }
5212   else {
5213     // All waypoints
5214     GHashTableIter iter;
5215     gpointer key, value;
5216
5217     g_hash_table_iter_init ( &iter, vtl->waypoints );
5218     while ( g_hash_table_iter_next (&iter, &key, &value) ) {
5219       VikWaypoint *wp = VIK_WAYPOINT(value);
5220       changed = changed + (gint)vik_waypoint_apply_dem_data ( wp, TRUE );
5221     }
5222   }
5223   wp_changed_message ( vtl, changed );
5224 }
5225
5226 static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] )
5227 {
5228   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
5229   VikTrack *track;
5230   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5231     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
5232   else
5233     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
5234
5235   if ( !track )
5236     return;
5237
5238   GList *trps = track->trackpoints;
5239   if ( !trps )
5240     return;
5241   trps = g_list_last(trps);
5242   goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(((VikTrackpoint *) trps->data)->coord));
5243 }
5244
5245 static void trw_layer_goto_track_max_speed ( gpointer pass_along[6] )
5246 {
5247   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
5248   VikTrack *track;
5249   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5250     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
5251   else
5252     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
5253
5254   if ( !track )
5255     return;
5256
5257   VikTrackpoint* vtp = vik_track_get_tp_by_max_speed ( track );
5258   if ( !vtp )
5259     return;
5260   goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(vtp->coord));
5261 }
5262
5263 static void trw_layer_goto_track_max_alt ( gpointer pass_along[6] )
5264 {
5265   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
5266   VikTrack *track;
5267   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5268     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
5269   else
5270     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
5271
5272   if ( !track )
5273     return;
5274
5275   VikTrackpoint* vtp = vik_track_get_tp_by_max_alt ( track );
5276   if ( !vtp )
5277     return;
5278   goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(vtp->coord));
5279 }
5280
5281 static void trw_layer_goto_track_min_alt ( gpointer pass_along[6] )
5282 {
5283   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
5284   VikTrack *track;
5285   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5286     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
5287   else
5288     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
5289
5290   if ( !track )
5291     return;
5292
5293   VikTrackpoint* vtp = vik_track_get_tp_by_min_alt ( track );
5294   if ( !vtp )
5295     return;
5296   goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(vtp->coord));
5297 }
5298
5299 /*
5300  * Automatically change the viewport to center on the track and zoom to see the extent of the track
5301  */
5302 static void trw_layer_auto_track_view ( gpointer pass_along[6] )
5303 {
5304   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
5305   VikTrack *trk;
5306   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5307     trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
5308   else
5309     trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
5310
5311   if ( trk && trk->trackpoints )
5312   {
5313     struct LatLon maxmin[2] = { {0,0}, {0,0} };
5314     trw_layer_find_maxmin_tracks ( NULL, trk, maxmin );
5315     trw_layer_zoom_to_show_latlons ( vtl, pass_along[5], maxmin );
5316     if ( pass_along[1] )
5317       vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(pass_along[1]) );
5318     else
5319       vik_layer_emit_update ( VIK_LAYER(vtl) );
5320   }
5321 }
5322
5323 /*
5324  * Refine the selected track/route with a routing engine.
5325  * The routing engine is selected by the user, when requestiong the job.
5326  */
5327 static void trw_layer_route_refine ( gpointer pass_along[6] )
5328 {
5329   static gint last_engine = 0;
5330   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
5331   VikTrack *trk;
5332
5333   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5334     trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
5335   else
5336     trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
5337
5338   if ( trk && trk->trackpoints )
5339   {
5340     /* Check size of the route */
5341     int nb = vik_track_get_tp_count(trk);
5342     if (nb > 100) {
5343       GtkWidget *dialog = gtk_message_dialog_new (VIK_GTK_WINDOW_FROM_LAYER (vtl),
5344                                                   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
5345                                                   GTK_MESSAGE_WARNING,
5346                                                   GTK_BUTTONS_OK_CANCEL,
5347                                                   _("Refining a track with many points (%d) is unlikely to yield sensible results. Do you want to Continue?"),
5348                                                   nb);
5349       gint response = gtk_dialog_run ( GTK_DIALOG(dialog) );
5350       gtk_widget_destroy ( dialog );
5351       if (response != GTK_RESPONSE_OK )
5352         return;
5353     }
5354     /* Select engine from dialog */
5355     GtkWidget *dialog = gtk_dialog_new_with_buttons (_("Refine Route with Routing Engine..."),
5356                                                   VIK_GTK_WINDOW_FROM_LAYER (vtl),
5357                                                   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
5358                                                   GTK_STOCK_CANCEL,
5359                                                   GTK_RESPONSE_REJECT,
5360                                                   GTK_STOCK_OK,
5361                                                   GTK_RESPONSE_ACCEPT,
5362                                                   NULL);
5363     GtkWidget *label = gtk_label_new ( _("Select routing engine") );
5364     gtk_widget_show_all(label);
5365
5366     gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), label, TRUE, TRUE, 0 );
5367
5368     GtkWidget * combo = vik_routing_ui_selector_new ( (Predicate)vik_routing_engine_supports_refine, NULL );
5369     gtk_combo_box_set_active (GTK_COMBO_BOX (combo), last_engine);
5370     gtk_widget_show_all(combo);
5371
5372     gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), combo, TRUE, TRUE, 0 );
5373
5374     gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
5375
5376     if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
5377     {
5378         /* Dialog validated: retrieve selected engine and do the job */
5379         last_engine = gtk_combo_box_get_active ( GTK_COMBO_BOX(combo) );
5380         VikRoutingEngine *routing = vik_routing_ui_selector_get_nth (combo, last_engine);
5381
5382         /* Change cursor */
5383         vik_window_set_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0])) );
5384
5385         /* Force saving track */
5386         /* FIXME: remove or rename this hack */
5387         vtl->route_finder_check_added_track = TRUE;
5388
5389         /* the job */
5390         vik_routing_engine_refine (routing, vtl, trk);
5391
5392         /* FIXME: remove or rename this hack */
5393         if ( vtl->route_finder_added_track )
5394           vik_track_calculate_bounds ( vtl->route_finder_added_track );
5395
5396         vtl->route_finder_added_track = NULL;
5397         vtl->route_finder_check_added_track = FALSE;
5398
5399         vik_layer_emit_update ( VIK_LAYER(vtl) );
5400
5401         /* Restore cursor */
5402         vik_window_clear_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0])) );
5403     }
5404     gtk_widget_destroy ( dialog );
5405   }
5406 }
5407
5408 static void trw_layer_edit_trackpoint ( gpointer pass_along[6] )
5409 {
5410   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
5411   trw_layer_tpwin_init ( vtl );
5412 }
5413
5414 /*************************************
5415  * merge/split by time routines 
5416  *************************************/
5417
5418 /* called for each key in track hash table.
5419  * If the current track has the same time stamp type, add it to the result,
5420  * except the one pointed by "exclude".
5421  * set exclude to NULL if there is no exclude to check.
5422  * Note that the result is in reverse (for performance reasons).
5423  */
5424 typedef struct {
5425   GList **result;
5426   GList  *exclude;
5427   gboolean with_timestamps;
5428 } twt_udata;
5429 static void find_tracks_with_timestamp_type(gpointer key, gpointer value, gpointer udata)
5430 {
5431   twt_udata *user_data = udata;
5432   VikTrackpoint *p1, *p2;
5433
5434   if (VIK_TRACK(value)->trackpoints == user_data->exclude) {
5435     return;
5436   }
5437
5438   if (VIK_TRACK(value)->trackpoints) {
5439     p1 = VIK_TRACKPOINT(VIK_TRACK(value)->trackpoints->data);
5440     p2 = VIK_TRACKPOINT(g_list_last(VIK_TRACK(value)->trackpoints)->data);
5441
5442     if ( user_data->with_timestamps ) {
5443       if (!p1->has_timestamp || !p2->has_timestamp) {
5444         return;
5445       }
5446     }
5447     else {
5448       // Don't add tracks with timestamps when getting non timestamp tracks
5449       if (p1->has_timestamp || p2->has_timestamp) {
5450         return;
5451       }
5452     }
5453   }
5454
5455   *(user_data->result) = g_list_prepend(*(user_data->result), key);
5456 }
5457
5458 /* called for each key in track hash table. if original track user_data[1] is close enough
5459  * to the passed one, add it to list in user_data[0] 
5460  */
5461 static void find_nearby_tracks_by_time (gpointer key, gpointer value, gpointer user_data)
5462 {
5463   time_t t1, t2;
5464   VikTrackpoint *p1, *p2;
5465   VikTrack *trk = VIK_TRACK(value);
5466
5467   GList **nearby_tracks = ((gpointer *)user_data)[0];
5468   GList *tpoints = ((gpointer *)user_data)[1];
5469
5470   /* outline: 
5471    * detect reasons for not merging, and return
5472    * if no reason is found not to merge, then do it.
5473    */
5474
5475   // Exclude the original track from the compiled list
5476   if (trk->trackpoints == tpoints) {
5477     return;
5478   }
5479
5480   t1 = VIK_TRACKPOINT(g_list_first(tpoints)->data)->timestamp;
5481   t2 = VIK_TRACKPOINT(g_list_last(tpoints)->data)->timestamp;
5482
5483   if (trk->trackpoints) {
5484     p1 = VIK_TRACKPOINT(g_list_first(trk->trackpoints)->data);
5485     p2 = VIK_TRACKPOINT(g_list_last(trk->trackpoints)->data);
5486
5487     if (!p1->has_timestamp || !p2->has_timestamp) {
5488       //g_print("no timestamp\n");
5489       return;
5490     }
5491
5492     guint threshold = GPOINTER_TO_UINT (((gpointer *)user_data)[2]);
5493     //g_print("Got track named %s, times %d, %d\n", trk->name, p1->timestamp, p2->timestamp);
5494     if (! (abs(t1 - p2->timestamp) < threshold ||
5495         /*  p1 p2      t1 t2 */
5496            abs(p1->timestamp - t2) < threshold)
5497         /*  t1 t2      p1 p2 */
5498         ) {
5499       return;
5500     }
5501   }
5502
5503   *nearby_tracks = g_list_prepend(*nearby_tracks, value);
5504 }
5505
5506 /* comparison function used to sort tracks; a and b are hash table keys */
5507 /* Not actively used - can be restored if needed
5508 static gint track_compare(gconstpointer a, gconstpointer b, gpointer user_data)
5509 {
5510   GHashTable *tracks = user_data;
5511   time_t t1, t2;
5512
5513   t1 = VIK_TRACKPOINT(VIK_TRACK(g_hash_table_lookup(tracks, a))->trackpoints->data)->timestamp;
5514   t2 = VIK_TRACKPOINT(VIK_TRACK(g_hash_table_lookup(tracks, b))->trackpoints->data)->timestamp;
5515   
5516   if (t1 < t2) return -1;
5517   if (t1 > t2) return 1;
5518   return 0;
5519 }
5520 */
5521
5522 /* comparison function used to sort trackpoints */
5523 static gint trackpoint_compare(gconstpointer a, gconstpointer b)
5524 {
5525   time_t t1 = VIK_TRACKPOINT(a)->timestamp, t2 = VIK_TRACKPOINT(b)->timestamp;
5526   
5527   if (t1 < t2) return -1;
5528   if (t1 > t2) return 1;
5529   return 0;
5530 }
5531
5532 /**
5533  * comparison function which can be used to sort tracks or waypoints by name
5534  */
5535 static gint sort_alphabetically (gconstpointer a, gconstpointer b, gpointer user_data)
5536 {
5537   const gchar* namea = (const gchar*) a;
5538   const gchar* nameb = (const gchar*) b;
5539   if ( namea == NULL || nameb == NULL)
5540     return 0;
5541   else
5542     // Same sort method as used in the vik_treeview_*_alphabetize functions
5543     return strcmp ( namea, nameb );
5544 }
5545
5546 /**
5547  * Attempt to merge selected track with other tracks specified by the user
5548  * Tracks to merge with must be of the same 'type' as the selected track -
5549  *  either all with timestamps, or all without timestamps
5550  */
5551 static void trw_layer_merge_with_other ( gpointer pass_along[6] )
5552 {
5553   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
5554   GList *other_tracks = NULL;
5555   GHashTable *ght_tracks;
5556   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5557     ght_tracks = vtl->routes;
5558   else
5559     ght_tracks = vtl->tracks;
5560
5561   VikTrack *track = (VikTrack *) g_hash_table_lookup ( ght_tracks, pass_along[3] );
5562
5563   if ( !track )
5564     return;
5565
5566   if ( !track->trackpoints )
5567     return;
5568
5569   twt_udata udata;
5570   udata.result = &other_tracks;
5571   udata.exclude = track->trackpoints;
5572   // Allow merging with 'similar' time type time tracks
5573   // i.e. either those times, or those without
5574   udata.with_timestamps = (VIK_TRACKPOINT(track->trackpoints->data)->has_timestamp);
5575
5576   g_hash_table_foreach(ght_tracks, find_tracks_with_timestamp_type, (gpointer)&udata);
5577   other_tracks = g_list_reverse(other_tracks);
5578
5579   if ( !other_tracks ) {
5580     if ( udata.with_timestamps )
5581       a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Failed. No other tracks with timestamps in this layer found"));
5582     else
5583       a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Failed. No other tracks without timestamps in this layer found"));
5584     return;
5585   }
5586
5587   // Sort alphabetically for user presentation
5588   // Convert into list of names for usage with dialog function
5589   // TODO: Need to consider how to work best when we can have multiple tracks the same name...
5590   GList *other_tracks_names = NULL;
5591   GList *iter = g_list_first ( other_tracks );
5592   while ( iter ) {
5593     other_tracks_names = g_list_append ( other_tracks_names, VIK_TRACK(g_hash_table_lookup (ght_tracks, iter->data))->name );
5594     iter = g_list_next ( iter );
5595   }
5596
5597   other_tracks_names = g_list_sort_with_data (other_tracks_names, sort_alphabetically, NULL);
5598
5599   GList *merge_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl),
5600                                                 other_tracks_names,
5601                                                 TRUE,
5602                                                 _("Merge with..."),
5603                                                 track->is_route ? _("Select route to merge with") : _("Select track to merge with"));
5604   g_list_free(other_tracks);
5605   g_list_free(other_tracks_names);
5606
5607   if (merge_list)
5608   {
5609     GList *l;
5610     for (l = merge_list; l != NULL; l = g_list_next(l)) {
5611       VikTrack *merge_track;
5612       if ( track->is_route )
5613         merge_track = vik_trw_layer_get_route ( vtl, l->data );
5614       else
5615         merge_track = vik_trw_layer_get_track ( vtl, l->data );
5616
5617       if (merge_track) {
5618         vik_track_steal_and_append_trackpoints ( track, merge_track );
5619         if ( track->is_route )
5620           vik_trw_layer_delete_route (vtl, merge_track);
5621         else
5622           vik_trw_layer_delete_track (vtl, merge_track);
5623         track->trackpoints = g_list_sort(track->trackpoints, trackpoint_compare);
5624       }
5625     }
5626     for (l = merge_list; l != NULL; l = g_list_next(l))
5627       g_free(l->data);
5628     g_list_free(merge_list);
5629
5630     vik_layer_emit_update( VIK_LAYER(vtl) );
5631   }
5632 }
5633
5634 // c.f. trw_layer_sorted_track_id_by_name_list
5635 //  but don't add the specified track to the list (normally current track)
5636 static void trw_layer_sorted_track_id_by_name_list_exclude_self (const gpointer id, const VikTrack *trk, gpointer udata)
5637 {
5638   twt_udata *user_data = udata;
5639
5640   // Skip self
5641   if (trk->trackpoints == user_data->exclude) {
5642     return;
5643   }
5644
5645   // Sort named list alphabetically
5646   *(user_data->result) = g_list_insert_sorted_with_data (*(user_data->result), trk->name, sort_alphabetically, NULL);
5647 }
5648
5649 /**
5650  * Join - this allows combining 'tracks' and 'track routes'
5651  *  i.e. doesn't care about whether tracks have consistent timestamps
5652  * ATM can only append one track at a time to the currently selected track
5653  */
5654 static void trw_layer_append_track ( gpointer pass_along[6] )
5655 {
5656
5657   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
5658   VikTrack *trk;
5659   GHashTable *ght_tracks;
5660   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
5661     ght_tracks = vtl->routes;
5662   else
5663     ght_tracks = vtl->tracks;
5664
5665   trk = (VikTrack *) g_hash_table_lookup ( ght_tracks, pass_along[3] );
5666
5667   if ( !trk )
5668     return;
5669
5670   GList *other_tracks_names = NULL;
5671
5672   // Sort alphabetically for user presentation
5673   // Convert into list of names for usage with dialog function
5674   // TODO: Need to consider how to work best when we can have multiple tracks the same name...
5675   twt_udata udata;
5676   udata.result = &other_tracks_names;
5677   udata.exclude = trk->trackpoints;
5678
5679   g_hash_table_foreach(ght_tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list_exclude_self, (gpointer)&udata);
5680
5681   // Note the limit to selecting one track only
5682   //  this is to control the ordering of appending tracks, i.e. the selected track always goes after the current track
5683   //  (otherwise with multiple select the ordering would not be controllable by the user - automatically being alphabetically)
5684   GList *append_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl),
5685                                                  other_tracks_names,
5686                                                  FALSE,
5687                                                  trk->is_route ? _("Append Route"): _("Append Track"),
5688                                                  trk->is_route ? _("Select the route to append after the current route") :
5689                                                                  _("Select the track to append after the current track") );
5690
5691   g_list_free(other_tracks_names);
5692
5693   // It's a list, but shouldn't contain more than one other track!
5694   if ( append_list ) {
5695     GList *l;
5696     for (l = append_list; l != NULL; l = g_list_next(l)) {
5697       // TODO: at present this uses the first track found by name,
5698       //  which with potential multiple same named tracks may not be the one selected...
5699       VikTrack *append_track;
5700       if ( trk->is_route )
5701         append_track = vik_trw_layer_get_route ( vtl, l->data );
5702       else
5703         append_track = vik_trw_layer_get_track ( vtl, l->data );
5704
5705       if ( append_track ) {
5706         vik_track_steal_and_append_trackpoints ( trk, append_track );
5707         if ( trk->is_route )
5708           vik_trw_layer_delete_route (vtl, append_track);
5709         else
5710           vik_trw_layer_delete_track (vtl, append_track);
5711       }
5712     }
5713     for (l = append_list; l != NULL; l = g_list_next(l))
5714       g_free(l->data);
5715     g_list_free(append_list);
5716
5717     vik_layer_emit_update( VIK_LAYER(vtl) );
5718   }
5719 }
5720
5721 /**
5722  * Very similar to trw_layer_append_track for joining
5723  * but this allows selection from the 'other' list
5724  * If a track is selected, then is shows routes and joins the selected one
5725  * If a route is selected, then is shows tracks and joins the selected one
5726  */
5727 static void trw_layer_append_other ( gpointer pass_along[6] )
5728 {
5729
5730   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
5731   VikTrack *trk;
5732   GHashTable *ght_mykind, *ght_others;
5733   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE ) {
5734     ght_mykind = vtl->routes;
5735     ght_others = vtl->tracks;
5736   }
5737   else {
5738     ght_mykind = vtl->tracks;
5739     ght_others = vtl->routes;
5740   }
5741
5742   trk = (VikTrack *) g_hash_table_lookup ( ght_mykind, pass_along[3] );
5743
5744   if ( !trk )
5745     return;
5746
5747   GList *other_tracks_names = NULL;
5748
5749   // Sort alphabetically for user presentation
5750   // Convert into list of names for usage with dialog function
5751   // TODO: Need to consider how to work best when we can have multiple tracks the same name...
5752   twt_udata udata;
5753   udata.result = &other_tracks_names;
5754   udata.exclude = trk->trackpoints;
5755
5756   g_hash_table_foreach(ght_others, (GHFunc) trw_layer_sorted_track_id_by_name_list_exclude_self, (gpointer)&udata);
5757
5758   // Note the limit to selecting one track only
5759   //  this is to control the ordering of appending tracks, i.e. the selected track always goes after the current track
5760   //  (otherwise with multiple select the ordering would not be controllable by the user - automatically being alphabetically)
5761   GList *append_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl),
5762                                                  other_tracks_names,
5763                                                  FALSE,
5764                                                  trk->is_route ? _("Append Track"): _("Append Route"),
5765                                                  trk->is_route ? _("Select the track to append after the current route") :
5766                                                                  _("Select the route to append after the current track") );
5767
5768   g_list_free(other_tracks_names);
5769
5770   // It's a list, but shouldn't contain more than one other track!
5771   if ( append_list ) {
5772     GList *l;
5773     for (l = append_list; l != NULL; l = g_list_next(l)) {
5774       // TODO: at present this uses the first track found by name,
5775       //  which with potential multiple same named tracks may not be the one selected...
5776
5777       // Get FROM THE OTHER TYPE list
5778       VikTrack *append_track;
5779       if ( trk->is_route )
5780         append_track = vik_trw_layer_get_track ( vtl, l->data );
5781       else
5782         append_track = vik_trw_layer_get_route ( vtl, l->data );
5783
5784       if ( append_track ) {
5785
5786         if ( !append_track->is_route &&
5787              ( ( vik_track_get_segment_count ( append_track ) > 1 ) ||
5788                ( vik_track_get_average_speed ( append_track ) > 0.0 ) ) ) {
5789
5790           if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
5791                                       _("Converting a track to a route removes extra track data such as segments, timestamps, etc...\nDo you want to continue?"), NULL ) ) {
5792             vik_track_merge_segments ( append_track );
5793             vik_track_to_routepoints ( append_track );
5794           }
5795           else {
5796             break;
5797           }
5798         }
5799
5800         vik_track_steal_and_append_trackpoints ( trk, append_track );
5801
5802         // Delete copied which is FROM THE OTHER TYPE list
5803         if ( trk->is_route )
5804           vik_trw_layer_delete_track (vtl, append_track);
5805         else
5806           vik_trw_layer_delete_route (vtl, append_track);
5807       }
5808     }
5809     for (l = append_list; l != NULL; l = g_list_next(l))
5810       g_free(l->data);
5811     g_list_free(append_list);
5812     vik_layer_emit_update( VIK_LAYER(vtl) );
5813   }
5814 }
5815
5816 /* merge by segments */
5817 static void trw_layer_merge_by_segment ( gpointer pass_along[6] )
5818 {
5819   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
5820   VikTrack *trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
5821   guint segments = vik_track_merge_segments ( trk );
5822   // NB currently no need to redraw as segments not actually shown on the display
5823   // However inform the user of what happened:
5824   gchar str[64];
5825   const gchar *tmp_str = ngettext("%d segment merged", "%d segments merged", segments);
5826   g_snprintf(str, 64, tmp_str, segments);
5827   a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str );
5828 }
5829
5830 /* merge by time routine */
5831 static void trw_layer_merge_by_timestamp ( gpointer pass_along[6] )
5832 {
5833   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
5834
5835   //time_t t1, t2;
5836
5837   GList *tracks_with_timestamp = NULL;
5838   VikTrack *orig_trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
5839   if (orig_trk->trackpoints &&
5840       !VIK_TRACKPOINT(orig_trk->trackpoints->data)->has_timestamp) {
5841     a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Failed. This track does not have timestamp"));
5842     return;
5843   }
5844
5845   twt_udata udata;
5846   udata.result = &tracks_with_timestamp;
5847   udata.exclude = orig_trk->trackpoints;
5848   udata.with_timestamps = TRUE;
5849   g_hash_table_foreach(vtl->tracks, find_tracks_with_timestamp_type, (gpointer)&udata);
5850   tracks_with_timestamp = g_list_reverse(tracks_with_timestamp);
5851
5852   if (!tracks_with_timestamp) {
5853     a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Failed. No other track in this layer has timestamp"));
5854     return;
5855   }
5856   g_list_free(tracks_with_timestamp);
5857
5858   static guint threshold_in_minutes = 1;
5859   if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(vtl),
5860                                _("Merge Threshold..."),
5861                                _("Merge when time between tracks less than:"),
5862                                &threshold_in_minutes)) {
5863     return;
5864   }
5865
5866   // keep attempting to merge all tracks until no merges within the time specified is possible
5867   gboolean attempt_merge = TRUE;
5868   GList *nearby_tracks = NULL;
5869   GList *trps;
5870   static gpointer params[3];
5871
5872   while ( attempt_merge ) {
5873
5874     // Don't try again unless tracks have changed
5875     attempt_merge = FALSE;
5876
5877     trps = orig_trk->trackpoints;
5878     if ( !trps )
5879       return;
5880
5881     if (nearby_tracks) {
5882       g_list_free(nearby_tracks);
5883       nearby_tracks = NULL;
5884     }
5885
5886     //t1 = ((VikTrackpoint *)trps->data)->timestamp;
5887     //t2 = ((VikTrackpoint *)g_list_last(trps)->data)->timestamp;
5888     
5889     /*    g_print("Original track times: %d and %d\n", t1, t2);  */
5890     params[0] = &nearby_tracks;
5891     params[1] = (gpointer)trps;
5892     params[2] = GUINT_TO_POINTER (threshold_in_minutes*60); // In seconds
5893
5894     /* get a list of adjacent-in-time tracks */
5895     g_hash_table_foreach(vtl->tracks, find_nearby_tracks_by_time, params);
5896
5897     /* merge them */
5898     GList *l = nearby_tracks;
5899     while ( l ) {
5900        /*
5901 #define get_first_trackpoint(x) VIK_TRACKPOINT(VIK_TRACK(x)->trackpoints->data)
5902 #define get_last_trackpoint(x) VIK_TRACKPOINT(g_list_last(VIK_TRACK(x)->trackpoints)->data)
5903         time_t t1, t2;
5904         t1 = get_first_trackpoint(l)->timestamp;
5905         t2 = get_last_trackpoint(l)->timestamp;
5906 #undef get_first_trackpoint
5907 #undef get_last_trackpoint
5908         g_print("     %20s: track %d - %d\n", VIK_TRACK(l->data)->name, (int)t1, (int)t2);
5909        */
5910
5911       /* remove trackpoints from merged track, delete track */
5912       vik_track_steal_and_append_trackpoints ( orig_trk, VIK_TRACK(l->data) );
5913       vik_trw_layer_delete_track (vtl, VIK_TRACK(l->data));
5914
5915       // Tracks have changed, therefore retry again against all the remaining tracks
5916       attempt_merge = TRUE;
5917
5918       l = g_list_next(l);
5919     }
5920
5921     orig_trk->trackpoints = g_list_sort(orig_trk->trackpoints, trackpoint_compare);
5922   }
5923
5924   g_list_free(nearby_tracks);
5925
5926   vik_layer_emit_update( VIK_LAYER(vtl) );
5927 }
5928
5929 /**
5930  * Split a track at the currently selected trackpoint
5931  */
5932 static void trw_layer_split_at_selected_trackpoint ( VikTrwLayer *vtl, gint subtype )
5933 {
5934   if ( !vtl->current_tpl )
5935     return;
5936
5937   if ( vtl->current_tpl->next && vtl->current_tpl->prev ) {
5938     gchar *name = trw_layer_new_unique_sublayer_name(vtl, subtype, vtl->current_tp_track->name);
5939     if ( name ) {
5940       VikTrack *tr = vik_track_copy ( vtl->current_tp_track, FALSE );
5941       GList *newglist = g_list_alloc ();
5942       newglist->prev = NULL;
5943       newglist->next = vtl->current_tpl->next;
5944       newglist->data = vik_trackpoint_copy(VIK_TRACKPOINT(vtl->current_tpl->data));
5945       tr->trackpoints = newglist;
5946
5947       vtl->current_tpl->next->prev = newglist; /* end old track here */
5948       vtl->current_tpl->next = NULL;
5949
5950       // Bounds of the selected track changed due to the split
5951       vik_track_calculate_bounds ( vtl->current_tp_track );
5952
5953       vtl->current_tpl = newglist; /* change tp to first of new track. */
5954       vtl->current_tp_track = tr;
5955
5956       if ( tr->is_route )
5957         vik_trw_layer_add_route ( vtl, name, tr );
5958       else
5959         vik_trw_layer_add_track ( vtl, name, tr );
5960
5961       // Bounds of the new track created by the split
5962       vik_track_calculate_bounds ( tr );
5963
5964       trku_udata udata;
5965       udata.trk  = tr;
5966       udata.uuid = NULL;
5967
5968       // Also need id of newly created track
5969       gpointer *trkf;
5970       if ( tr->is_route )
5971          trkf = g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find_uuid, &udata );
5972       else
5973          trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udata );
5974
5975       if ( trkf && udata.uuid )
5976         vtl->current_tp_id = udata.uuid;
5977       else
5978         vtl->current_tp_id = NULL;
5979
5980       vik_layer_emit_update(VIK_LAYER(vtl));
5981     }
5982     g_free ( name );
5983   }
5984 }
5985
5986 /* split by time routine */
5987 static void trw_layer_split_by_timestamp ( gpointer pass_along[6] )
5988 {
5989   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
5990   VikTrack *track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
5991   GList *trps = track->trackpoints;
5992   GList *iter;
5993   GList *newlists = NULL;
5994   GList *newtps = NULL;
5995   static guint thr = 1;
5996
5997   time_t ts, prev_ts;
5998
5999   if ( !trps )
6000     return;
6001
6002   if (!a_dialog_time_threshold(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0]), 
6003                                _("Split Threshold..."), 
6004                                _("Split when time between trackpoints exceeds:"), 
6005                                &thr)) {
6006     return;
6007   }
6008
6009   /* iterate through trackpoints, and copy them into new lists without touching original list */
6010   prev_ts = VIK_TRACKPOINT(trps->data)->timestamp;
6011   iter = trps;
6012
6013   while (iter) {
6014     ts = VIK_TRACKPOINT(iter->data)->timestamp;
6015
6016     // Check for unordered time points - this is quite a rare occurence - unless one has reversed a track.
6017     if (ts < prev_ts) {
6018       gchar tmp_str[64];
6019       strftime ( tmp_str, sizeof(tmp_str), "%c", localtime(&ts) );
6020       if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
6021                                 _("Can not split track due to trackpoints not ordered in time - such as at %s.\n\nGoto this trackpoint?"),
6022                                 tmp_str ) ) {
6023         goto_coord ( pass_along[1], vtl, pass_along[5], &(VIK_TRACKPOINT(iter->data)->coord) );
6024       }
6025       return;
6026     }
6027
6028     if (ts - prev_ts > thr*60) {
6029       /* flush accumulated trackpoints into new list */
6030       newlists = g_list_append(newlists, g_list_reverse(newtps));
6031       newtps = NULL;
6032     }
6033
6034     /* accumulate trackpoint copies in newtps, in reverse order */
6035     newtps = g_list_prepend(newtps, vik_trackpoint_copy(VIK_TRACKPOINT(iter->data)));
6036     prev_ts = ts;
6037     iter = g_list_next(iter);
6038   }
6039   if (newtps) {
6040       newlists = g_list_append(newlists, g_list_reverse(newtps));
6041   }
6042
6043   /* put lists of trackpoints into tracks */
6044   iter = newlists;
6045   // Only bother updating if the split results in new tracks
6046   if (g_list_length (newlists) > 1) {
6047     while (iter) {
6048       gchar *new_tr_name;
6049       VikTrack *tr;
6050
6051       tr = vik_track_copy ( track, FALSE );
6052       tr->trackpoints = (GList *)(iter->data);
6053
6054       new_tr_name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, track->name);
6055       vik_trw_layer_add_track(vtl, new_tr_name, tr);
6056       /*    g_print("adding track %s, times %d - %d\n", new_tr_name, VIK_TRACKPOINT(tr->trackpoints->data)->timestamp,
6057           VIK_TRACKPOINT(g_list_last(tr->trackpoints)->data)->timestamp);*/
6058       g_free ( new_tr_name );
6059       vik_track_calculate_bounds ( tr );
6060       iter = g_list_next(iter);
6061     }
6062     // Remove original track and then update the display
6063     vik_trw_layer_delete_track (vtl, track);
6064     vik_layer_emit_update(VIK_LAYER(pass_along[0]));
6065   }
6066   g_list_free(newlists);
6067 }
6068
6069 /**
6070  * Split a track by the number of points as specified by the user
6071  */
6072 static void trw_layer_split_by_n_points ( gpointer pass_along[6] )
6073 {
6074   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
6075   VikTrack *track;
6076   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
6077     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
6078   else
6079     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
6080
6081   if ( !track )
6082     return;
6083
6084   // Check valid track
6085   GList *trps = track->trackpoints;
6086   if ( !trps )
6087     return;
6088
6089   gint points = a_dialog_get_positive_number(VIK_GTK_WINDOW_FROM_LAYER(pass_along[0]),
6090                                              _("Split Every Nth Point"),
6091                                              _("Split on every Nth point:"),
6092                                              250,   // Default value as per typical limited track capacity of various GPS devices
6093                                              2,     // Min
6094                                              65536, // Max
6095                                              5);    // Step
6096   // Was a valid number returned?
6097   if (!points)
6098     return;
6099
6100   // Now split...
6101   GList *iter;
6102   GList *newlists = NULL;
6103   GList *newtps = NULL;
6104   gint count = 0;
6105   iter = trps;
6106
6107   while (iter) {
6108     /* accumulate trackpoint copies in newtps, in reverse order */
6109     newtps = g_list_prepend(newtps, vik_trackpoint_copy(VIK_TRACKPOINT(iter->data)));
6110     count++;
6111     if (count >= points) {
6112       /* flush accumulated trackpoints into new list */
6113       newlists = g_list_append(newlists, g_list_reverse(newtps));
6114       newtps = NULL;
6115       count = 0;
6116     }
6117     iter = g_list_next(iter);
6118   }
6119
6120   // If there is a remaining chunk put that into the new split list
6121   // This may well be the whole track if no split points were encountered
6122   if (newtps) {
6123       newlists = g_list_append(newlists, g_list_reverse(newtps));
6124   }
6125
6126   /* put lists of trackpoints into tracks */
6127   iter = newlists;
6128   // Only bother updating if the split results in new tracks
6129   if (g_list_length (newlists) > 1) {
6130     while (iter) {
6131       gchar *new_tr_name;
6132       VikTrack *tr;
6133
6134       tr = vik_track_copy ( track, FALSE );
6135       tr->trackpoints = (GList *)(iter->data);
6136
6137       if ( track->is_route ) {
6138         new_tr_name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_ROUTE, track->name);
6139         vik_trw_layer_add_route(vtl, new_tr_name, tr);
6140       }
6141       else {
6142         new_tr_name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, track->name);
6143         vik_trw_layer_add_track(vtl, new_tr_name, tr);
6144       }
6145       g_free ( new_tr_name );
6146       vik_track_calculate_bounds ( tr );
6147
6148       iter = g_list_next(iter);
6149     }
6150     // Remove original track and then update the display
6151     if ( track->is_route )
6152       vik_trw_layer_delete_route (vtl, track);
6153     else
6154       vik_trw_layer_delete_track (vtl, track);
6155     vik_layer_emit_update(VIK_LAYER(pass_along[0]));
6156   }
6157   g_list_free(newlists);
6158 }
6159
6160 /**
6161  * Split a track at the currently selected trackpoint
6162  */
6163 static void trw_layer_split_at_trackpoint ( gpointer pass_along[6] )
6164 {
6165   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
6166   gint subtype = GPOINTER_TO_INT (pass_along[2]);
6167   trw_layer_split_at_selected_trackpoint ( vtl, subtype );
6168 }
6169
6170 /**
6171  * Split a track by its segments
6172  * Routes do not have segments so don't call this for routes
6173  */
6174 static void trw_layer_split_segments ( gpointer pass_along[6] )
6175 {
6176   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
6177   VikTrack *trk = g_hash_table_lookup ( vtl->tracks, pass_along[3] );
6178
6179   if ( !trk )
6180     return;
6181
6182   guint ntracks;
6183
6184   VikTrack **tracks = vik_track_split_into_segments (trk, &ntracks);
6185   gchar *new_tr_name;
6186   guint i;
6187   for ( i = 0; i < ntracks; i++ ) {
6188     if ( tracks[i] ) {
6189       new_tr_name = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, trk->name);
6190       vik_trw_layer_add_track ( vtl, new_tr_name, tracks[i] );
6191       g_free ( new_tr_name );
6192     }
6193   }
6194   if ( tracks ) {
6195     g_free ( tracks );
6196     // Remove original track
6197     vik_trw_layer_delete_track ( vtl, trk );
6198     vik_layer_emit_update ( VIK_LAYER(vtl) );
6199   }
6200   else {
6201     a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Can not split track as it has no segments"));
6202   }
6203 }
6204 /* end of split/merge routines */
6205
6206 static void trw_layer_trackpoint_selected_delete ( VikTrwLayer *vtl, VikTrack *trk )
6207 {
6208   GList *new_tpl;
6209
6210   // Find available adjacent trackpoint
6211   if ( (new_tpl = vtl->current_tpl->next) || (new_tpl = vtl->current_tpl->prev) ) {
6212     if ( VIK_TRACKPOINT(vtl->current_tpl->data)->newsegment && vtl->current_tpl->next )
6213       VIK_TRACKPOINT(vtl->current_tpl->next->data)->newsegment = TRUE; /* don't concat segments on del */
6214
6215     // Delete current trackpoint
6216     vik_trackpoint_free ( vtl->current_tpl->data );
6217     trk->trackpoints = g_list_delete_link ( trk->trackpoints, vtl->current_tpl );
6218
6219     // Set to current to the available adjacent trackpoint
6220     vtl->current_tpl = new_tpl;
6221
6222     if ( vtl->current_tp_track ) {
6223       vik_track_calculate_bounds ( vtl->current_tp_track );
6224     }
6225   }
6226   else {
6227     // Delete current trackpoint
6228     vik_trackpoint_free ( vtl->current_tpl->data );
6229     trk->trackpoints = g_list_delete_link ( trk->trackpoints, vtl->current_tpl );
6230     trw_layer_cancel_current_tp ( vtl, FALSE );
6231   }
6232 }
6233
6234 /**
6235  * Delete the selected point
6236  */
6237 static void trw_layer_delete_point_selected ( gpointer pass_along[6] )
6238 {
6239   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
6240   VikTrack *trk;
6241   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
6242     trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
6243   else
6244     trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
6245
6246   if ( !trk )
6247     return;
6248
6249   if ( !vtl->current_tpl )
6250     return;
6251
6252   trw_layer_trackpoint_selected_delete ( vtl, trk );
6253
6254   // Track has been updated so update tps:
6255   trw_layer_cancel_tps_of_track ( vtl, trk );
6256
6257   vik_layer_emit_update ( VIK_LAYER(vtl) );
6258 }
6259
6260 /**
6261  * Delete adjacent track points at the same position
6262  * AKA Delete Dulplicates on the Properties Window
6263  */
6264 static void trw_layer_delete_points_same_position ( gpointer pass_along[6] )
6265 {
6266   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
6267   VikTrack *trk;
6268   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
6269     trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
6270   else
6271     trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
6272
6273   if ( !trk )
6274     return;
6275
6276   gulong removed = vik_track_remove_dup_points ( trk );
6277
6278   // Track has been updated so update tps:
6279   trw_layer_cancel_tps_of_track ( vtl, trk );
6280
6281   // Inform user how much was deleted as it's not obvious from the normal view
6282   gchar str[64];
6283   const gchar *tmp_str = ngettext("Deleted %ld point", "Deleted %ld points", removed);
6284   g_snprintf(str, 64, tmp_str, removed);
6285   a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str);
6286
6287   vik_layer_emit_update ( VIK_LAYER(vtl) );
6288 }
6289
6290 /**
6291  * Delete adjacent track points with the same timestamp
6292  * Normally new tracks that are 'routes' won't have any timestamps so should be OK to clean up the track
6293  */
6294 static void trw_layer_delete_points_same_time ( gpointer pass_along[6] )
6295 {
6296   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
6297   VikTrack *trk;
6298   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
6299     trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
6300   else
6301     trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
6302
6303   if ( !trk )
6304     return;
6305
6306   gulong removed = vik_track_remove_same_time_points ( trk );
6307
6308   // Track has been updated so update tps:
6309   trw_layer_cancel_tps_of_track ( vtl, trk );
6310
6311   // Inform user how much was deleted as it's not obvious from the normal view
6312   gchar str[64];
6313   const gchar *tmp_str = ngettext("Deleted %ld point", "Deleted %ld points", removed);
6314   g_snprintf(str, 64, tmp_str, removed);
6315   a_dialog_info_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), str);
6316
6317   vik_layer_emit_update ( VIK_LAYER(vtl) );
6318 }
6319
6320 /**
6321  * Insert a point
6322  */
6323 static void trw_layer_insert_point_after ( gpointer pass_along[6] )
6324 {
6325   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
6326   VikTrack *track;
6327   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
6328     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
6329   else
6330     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
6331
6332   if ( ! track )
6333     return;
6334
6335   trw_layer_insert_tp_beside_current_tp ( vtl, FALSE );
6336
6337   vik_layer_emit_update ( VIK_LAYER(vtl) );
6338 }
6339
6340 static void trw_layer_insert_point_before ( gpointer pass_along[6] )
6341 {
6342   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
6343   VikTrack *track;
6344   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
6345     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
6346   else
6347     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
6348
6349   if ( ! track )
6350     return;
6351
6352   trw_layer_insert_tp_beside_current_tp ( vtl, TRUE );
6353
6354   vik_layer_emit_update ( VIK_LAYER(vtl) );
6355 }
6356
6357 /**
6358  * Reverse a track
6359  */
6360 static void trw_layer_reverse ( gpointer pass_along[6] )
6361 {
6362   VikTrwLayer *vtl = (VikTrwLayer *)pass_along[0];
6363   VikTrack *track;
6364   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
6365     track = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
6366   else
6367     track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
6368
6369   if ( ! track )
6370     return;
6371
6372   vik_track_reverse ( track );
6373  
6374   vik_layer_emit_update ( VIK_LAYER(pass_along[0]) );
6375 }
6376
6377 /**
6378  * Similar to trw_layer_enum_item, but this uses a sorted method
6379  */
6380 /* Currently unused
6381 static void trw_layer_sorted_name_list(gpointer key, gpointer value, gpointer udata)
6382 {
6383   GList **list = (GList**)udata;
6384   // *list = g_list_prepend(*all, key); //unsorted method
6385   // Sort named list alphabetically
6386   *list = g_list_insert_sorted_with_data (*list, key, sort_alphabetically, NULL);
6387 }
6388 */
6389
6390 /**
6391  * Now Waypoint specific sort
6392  */
6393 static void trw_layer_sorted_wp_id_by_name_list (const gpointer id, const VikWaypoint *wp, gpointer udata)
6394 {
6395   GList **list = (GList**)udata;
6396   // Sort named list alphabetically
6397   *list = g_list_insert_sorted_with_data (*list, wp->name, sort_alphabetically, NULL);
6398 }
6399
6400 /**
6401  * Track specific sort
6402  */
6403 static void trw_layer_sorted_track_id_by_name_list (const gpointer id, const VikTrack *trk, gpointer udata)
6404 {
6405   GList **list = (GList**)udata;
6406   // Sort named list alphabetically
6407   *list = g_list_insert_sorted_with_data (*list, trk->name, sort_alphabetically, NULL);
6408 }
6409
6410
6411 typedef struct {
6412   gboolean    has_same_track_name;
6413   const gchar *same_track_name;
6414 } same_track_name_udata;
6415
6416 static gint check_tracks_for_same_name ( gconstpointer aa, gconstpointer bb, gpointer udata )
6417 {
6418   const gchar* namea = (const gchar*) aa;
6419   const gchar* nameb = (const gchar*) bb;
6420
6421   // the test
6422   gint result = strcmp ( namea, nameb );
6423
6424   if ( result == 0 ) {
6425     // Found two names the same
6426     same_track_name_udata *user_data = udata;
6427     user_data->has_same_track_name = TRUE;
6428     user_data->same_track_name = namea;
6429   }
6430
6431   // Leave ordering the same
6432   return 0;
6433 }
6434
6435 /**
6436  * Find out if any tracks have the same name in this hash table
6437  */
6438 static gboolean trw_layer_has_same_track_names ( GHashTable *ht_tracks )
6439 {
6440   // Sort items by name, then compare if any next to each other are the same
6441
6442   GList *track_names = NULL;
6443   g_hash_table_foreach ( ht_tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list, &track_names );
6444
6445   // No tracks
6446   if ( ! track_names )
6447     return FALSE;
6448
6449   same_track_name_udata udata;
6450   udata.has_same_track_name = FALSE;
6451
6452   // Use sort routine to traverse list comparing items
6453   // Don't care how this list ends up ordered ( doesn't actually change ) - care about the returned status
6454   GList *dummy_list = g_list_sort_with_data ( track_names, check_tracks_for_same_name, &udata );
6455   // Still no tracks...
6456   if ( ! dummy_list )
6457     return FALSE;
6458
6459   return udata.has_same_track_name;
6460 }
6461
6462 /**
6463  * Force unqiue track names for the track table specified
6464  * Note the panel is a required parameter to enable the update of the names displayed
6465  * Specify if on tracks or else on routes
6466  */
6467 static void vik_trw_layer_uniquify_tracks ( VikTrwLayer *vtl, VikLayersPanel *vlp, GHashTable *track_table, gboolean ontrack )
6468 {
6469   // . Search list for an instance of repeated name
6470   // . get track of this name
6471   // . create new name
6472   // . rename track & update equiv. treeview iter
6473   // . repeat until all different
6474
6475   same_track_name_udata udata;
6476
6477   GList *track_names = NULL;
6478   udata.has_same_track_name = FALSE;
6479   udata.same_track_name = NULL;
6480
6481   g_hash_table_foreach ( track_table, (GHFunc) trw_layer_sorted_track_id_by_name_list, &track_names );
6482
6483   // No tracks
6484   if ( ! track_names )
6485     return;
6486
6487   GList *dummy_list1 = g_list_sort_with_data ( track_names, check_tracks_for_same_name, &udata );
6488
6489   // Still no tracks...
6490   if ( ! dummy_list1 )
6491     return;
6492
6493   while ( udata.has_same_track_name ) {
6494
6495     // Find a track with the same name
6496     VikTrack *trk;
6497     if ( ontrack )
6498       trk = vik_trw_layer_get_track ( vtl, (gpointer) udata.same_track_name );
6499     else
6500       trk = vik_trw_layer_get_route ( vtl, (gpointer) udata.same_track_name );
6501
6502     if ( ! trk ) {
6503       // Broken :(
6504       g_critical("Houston, we've had a problem.");
6505       vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO, 
6506                                   _("Internal Error in vik_trw_layer_uniquify_tracks") );
6507       return;
6508     }
6509
6510     // Rename it
6511     gchar *newname = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, udata.same_track_name );
6512     vik_track_set_name ( trk, newname );
6513
6514     trku_udata udataU;
6515     udataU.trk  = trk;
6516     udataU.uuid = NULL;
6517
6518     // Need want key of it for treeview update
6519     gpointer *trkf = g_hash_table_find ( track_table, (GHRFunc) trw_layer_track_find_uuid, &udataU );
6520
6521     if ( trkf && udataU.uuid ) {
6522
6523       GtkTreeIter *it;
6524       if ( ontrack )
6525         it = g_hash_table_lookup ( vtl->tracks_iters, udataU.uuid );
6526       else
6527         it = g_hash_table_lookup ( vtl->routes_iters, udataU.uuid );
6528
6529       if ( it ) {
6530         vik_treeview_item_set_name ( VIK_LAYER(vtl)->vt, it, newname );
6531         if ( ontrack )
6532           vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), vtl->wp_sort_order );
6533         else
6534           vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter), vtl->wp_sort_order );
6535       }
6536     }
6537
6538     // Start trying to find same names again...
6539     track_names = NULL;
6540     g_hash_table_foreach ( track_table, (GHFunc) trw_layer_sorted_track_id_by_name_list, &track_names );
6541     udata.has_same_track_name = FALSE;
6542     GList *dummy_list2 = g_list_sort_with_data ( track_names, check_tracks_for_same_name, &udata );
6543
6544     // No tracks any more - give up searching
6545     if ( ! dummy_list2 )
6546       udata.has_same_track_name = FALSE;
6547   }
6548
6549   // Update
6550   vik_layers_panel_emit_update ( vlp );
6551 }
6552
6553 static void trw_layer_sort_order_a2z ( gpointer pass_along[6] )
6554 {
6555   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
6556   GtkTreeIter *iter;
6557
6558   switch (GPOINTER_TO_INT (pass_along[2])) {
6559   case VIK_TRW_LAYER_SUBLAYER_TRACKS:
6560     iter = &(vtl->tracks_iter);
6561     vtl->track_sort_order = VL_SO_ALPHABETICAL_ASCENDING;
6562     break;
6563   case VIK_TRW_LAYER_SUBLAYER_ROUTES:
6564     iter = &(vtl->routes_iter);
6565     vtl->track_sort_order = VL_SO_ALPHABETICAL_ASCENDING;
6566     break;
6567   default: // VIK_TRW_LAYER_SUBLAYER_WAYPOINTS:
6568     iter = &(vtl->waypoints_iter);
6569     vtl->wp_sort_order = VL_SO_ALPHABETICAL_ASCENDING;
6570     break;
6571   }
6572
6573   vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, iter, VL_SO_ALPHABETICAL_ASCENDING );
6574 }
6575
6576 static void trw_layer_sort_order_z2a ( gpointer pass_along[6] )
6577 {
6578   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
6579   GtkTreeIter *iter;
6580
6581   switch (GPOINTER_TO_INT (pass_along[2])) {
6582   case VIK_TRW_LAYER_SUBLAYER_TRACKS:
6583     iter = &(vtl->tracks_iter);
6584     vtl->track_sort_order = VL_SO_ALPHABETICAL_DESCENDING;
6585     break;
6586   case VIK_TRW_LAYER_SUBLAYER_ROUTES:
6587     iter = &(vtl->routes_iter);
6588     vtl->track_sort_order = VL_SO_ALPHABETICAL_DESCENDING;
6589     break;
6590   default: // VIK_TRW_LAYER_SUBLAYER_WAYPOINTS:
6591     iter = &(vtl->waypoints_iter);
6592     vtl->wp_sort_order = VL_SO_ALPHABETICAL_DESCENDING;
6593     break;
6594   }
6595
6596   vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, iter, VL_SO_ALPHABETICAL_DESCENDING );
6597 }
6598
6599 /**
6600  *
6601  */
6602 static void trw_layer_delete_tracks_from_selection ( gpointer lav[2] )
6603 {
6604   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
6605   GList *all = NULL;
6606
6607   // Ensure list of track names offered is unique
6608   if ( trw_layer_has_same_track_names ( vtl->tracks ) ) {
6609     if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
6610                               _("Multiple entries with the same name exist. This method only works with unique names. Force unique names now?"), NULL ) ) {
6611       vik_trw_layer_uniquify_tracks ( vtl, VIK_LAYERS_PANEL(lav[1]), vtl->tracks, TRUE );
6612     }
6613     else
6614       return;
6615   }
6616
6617   // Sort list alphabetically for better presentation
6618   g_hash_table_foreach(vtl->tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list, &all);
6619
6620   if ( ! all ) {
6621     a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No tracks found"));
6622     return;
6623   }
6624
6625   // Get list of items to delete from the user
6626   GList *delete_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl),
6627                                                  all,
6628                                                  TRUE,
6629                                                  _("Delete Selection"),
6630                                                  _("Select tracks to delete"));
6631   g_list_free(all);
6632
6633   // Delete requested tracks
6634   // since specificly requested, IMHO no need for extra confirmation
6635   if ( delete_list ) {
6636     GList *l;
6637     for (l = delete_list; l != NULL; l = g_list_next(l)) {
6638       // This deletes first trk it finds of that name (but uniqueness is enforced above)
6639       trw_layer_delete_track_by_name (vtl, l->data, vtl->tracks);
6640     }
6641     g_list_free(delete_list);
6642     vik_layer_emit_update( VIK_LAYER(vtl) );
6643   }
6644 }
6645
6646 /**
6647  *
6648  */
6649 static void trw_layer_delete_routes_from_selection ( gpointer lav[2] )
6650 {
6651   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
6652   GList *all = NULL;
6653
6654   // Ensure list of track names offered is unique
6655   if ( trw_layer_has_same_track_names ( vtl->routes ) ) {
6656     if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
6657                               _("Multiple entries with the same name exist. This method only works with unique names. Force unique names now?"), NULL ) ) {
6658       vik_trw_layer_uniquify_tracks ( vtl, VIK_LAYERS_PANEL(lav[1]), vtl->routes, FALSE );
6659     }
6660     else
6661       return;
6662   }
6663
6664   // Sort list alphabetically for better presentation
6665   g_hash_table_foreach(vtl->routes, (GHFunc) trw_layer_sorted_track_id_by_name_list, &all);
6666
6667   if ( ! all ) {
6668     a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No routes found"));
6669     return;
6670   }
6671
6672   // Get list of items to delete from the user
6673   GList *delete_list = a_dialog_select_from_list ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
6674                                                    all,
6675                                                    TRUE,
6676                                                    _("Delete Selection"),
6677                                                    _("Select routes to delete") );
6678   g_list_free(all);
6679
6680   // Delete requested routes
6681   // since specificly requested, IMHO no need for extra confirmation
6682   if ( delete_list ) {
6683     GList *l;
6684     for (l = delete_list; l != NULL; l = g_list_next(l)) {
6685       // This deletes first route it finds of that name (but uniqueness is enforced above)
6686       trw_layer_delete_track_by_name (vtl, l->data, vtl->routes);
6687     }
6688     g_list_free(delete_list);
6689     vik_layer_emit_update( VIK_LAYER(vtl) );
6690   }
6691 }
6692
6693 typedef struct {
6694   gboolean    has_same_waypoint_name;
6695   const gchar *same_waypoint_name;
6696 } same_waypoint_name_udata;
6697
6698 static gint check_waypoints_for_same_name ( gconstpointer aa, gconstpointer bb, gpointer udata )
6699 {
6700   const gchar* namea = (const gchar*) aa;
6701   const gchar* nameb = (const gchar*) bb;
6702
6703   // the test
6704   gint result = strcmp ( namea, nameb );
6705
6706   if ( result == 0 ) {
6707     // Found two names the same
6708     same_waypoint_name_udata *user_data = udata;
6709     user_data->has_same_waypoint_name = TRUE;
6710     user_data->same_waypoint_name = namea;
6711   }
6712
6713   // Leave ordering the same
6714   return 0;
6715 }
6716
6717 /**
6718  * Find out if any waypoints have the same name in this layer
6719  */
6720 gboolean trw_layer_has_same_waypoint_names ( VikTrwLayer *vtl )
6721 {
6722   // Sort items by name, then compare if any next to each other are the same
6723
6724   GList *waypoint_names = NULL;
6725   g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_sorted_wp_id_by_name_list, &waypoint_names );
6726
6727   // No waypoints
6728   if ( ! waypoint_names )
6729     return FALSE;
6730
6731   same_waypoint_name_udata udata;
6732   udata.has_same_waypoint_name = FALSE;
6733
6734   // Use sort routine to traverse list comparing items
6735   // Don't care how this list ends up ordered ( doesn't actually change ) - care about the returned status
6736   GList *dummy_list = g_list_sort_with_data ( waypoint_names, check_waypoints_for_same_name, &udata );
6737   // Still no waypoints...
6738   if ( ! dummy_list )
6739     return FALSE;
6740
6741   return udata.has_same_waypoint_name;
6742 }
6743
6744 /**
6745  * Force unqiue waypoint names for this layer
6746  * Note the panel is a required parameter to enable the update of the names displayed
6747  */
6748 static void vik_trw_layer_uniquify_waypoints ( VikTrwLayer *vtl, VikLayersPanel *vlp )
6749 {
6750   // . Search list for an instance of repeated name
6751   // . get waypoint of this name
6752   // . create new name
6753   // . rename waypoint & update equiv. treeview iter
6754   // . repeat until all different
6755
6756   same_waypoint_name_udata udata;
6757
6758   GList *waypoint_names = NULL;
6759   udata.has_same_waypoint_name = FALSE;
6760   udata.same_waypoint_name = NULL;
6761
6762   g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_sorted_wp_id_by_name_list, &waypoint_names );
6763
6764   // No waypoints
6765   if ( ! waypoint_names )
6766     return;
6767
6768   GList *dummy_list1 = g_list_sort_with_data ( waypoint_names, check_waypoints_for_same_name, &udata );
6769
6770   // Still no waypoints...
6771   if ( ! dummy_list1 )
6772     return;
6773
6774   while ( udata.has_same_waypoint_name ) {
6775
6776     // Find a waypoint with the same name
6777     VikWaypoint *waypoint = vik_trw_layer_get_waypoint ( vtl, (gpointer) udata.same_waypoint_name );
6778
6779     if ( ! waypoint ) {
6780       // Broken :(
6781       g_critical("Houston, we've had a problem.");
6782       vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO, 
6783                                   _("Internal Error in vik_trw_layer_uniquify_waypoints") );
6784       return;
6785     }
6786
6787     // Rename it
6788     gchar *newname = trw_layer_new_unique_sublayer_name ( vtl, VIK_TRW_LAYER_SUBLAYER_WAYPOINT, udata.same_waypoint_name );
6789
6790     trw_layer_waypoint_rename ( vtl, waypoint, newname );
6791
6792     // Start trying to find same names again...
6793     waypoint_names = NULL;
6794     g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_sorted_wp_id_by_name_list, &waypoint_names );
6795     udata.has_same_waypoint_name = FALSE;
6796     GList *dummy_list2 = g_list_sort_with_data ( waypoint_names, check_waypoints_for_same_name, &udata );
6797
6798     // No waypoints any more - give up searching
6799     if ( ! dummy_list2 )
6800       udata.has_same_waypoint_name = FALSE;
6801   }
6802
6803   // Update
6804   vik_layers_panel_emit_update ( vlp );
6805 }
6806
6807 /**
6808  *
6809  */
6810 static void trw_layer_delete_waypoints_from_selection ( gpointer lav[2] )
6811 {
6812   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
6813   GList *all = NULL;
6814
6815   // Ensure list of waypoint names offered is unique
6816   if ( trw_layer_has_same_waypoint_names ( vtl ) ) {
6817     if ( a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
6818                               _("Multiple entries with the same name exist. This method only works with unique names. Force unique names now?"), NULL ) ) {
6819       vik_trw_layer_uniquify_waypoints ( vtl, VIK_LAYERS_PANEL(lav[1]) );
6820     }
6821     else
6822       return;
6823   }
6824
6825   // Sort list alphabetically for better presentation
6826   g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_sorted_wp_id_by_name_list, &all);
6827   if ( ! all ) {
6828     a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No waypoints found"));
6829     return;
6830   }
6831
6832   all = g_list_sort_with_data(all, sort_alphabetically, NULL);
6833
6834   // Get list of items to delete from the user
6835   GList *delete_list = a_dialog_select_from_list(VIK_GTK_WINDOW_FROM_LAYER(vtl),
6836                                                  all,
6837                                                  TRUE,
6838                                                  _("Delete Selection"),
6839                                                  _("Select waypoints to delete"));
6840   g_list_free(all);
6841
6842   // Delete requested waypoints
6843   // since specificly requested, IMHO no need for extra confirmation
6844   if ( delete_list ) {
6845     GList *l;
6846     for (l = delete_list; l != NULL; l = g_list_next(l)) {
6847       // This deletes first waypoint it finds of that name (but uniqueness is enforced above)
6848       trw_layer_delete_waypoint_by_name (vtl, l->data);
6849     }
6850     g_list_free(delete_list);
6851
6852     trw_layer_calculate_bounds_waypoints ( vtl );
6853     vik_layer_emit_update( VIK_LAYER(vtl) );
6854   }
6855
6856 }
6857
6858 /**
6859  *
6860  */
6861 static void trw_layer_iter_visibility_toggle ( gpointer id, GtkTreeIter *it, VikTreeview *vt )
6862 {
6863   vik_treeview_item_toggle_visible ( vt, it );
6864 }
6865
6866 /**
6867  *
6868  */
6869 static void trw_layer_iter_visibility ( gpointer id, GtkTreeIter *it, gpointer vis_data[2] )
6870 {
6871   vik_treeview_item_set_visible ( (VikTreeview*)vis_data[0], it, GPOINTER_TO_INT (vis_data[1]) );
6872 }
6873
6874 /**
6875  *
6876  */
6877 static void trw_layer_waypoints_visibility ( gpointer id, VikWaypoint *wp, gpointer on_off )
6878 {
6879   wp->visible = GPOINTER_TO_INT (on_off);
6880 }
6881
6882 /**
6883  *
6884  */
6885 static void trw_layer_waypoints_toggle_visibility ( gpointer id, VikWaypoint *wp )
6886 {
6887   wp->visible = !wp->visible;
6888 }
6889
6890 /**
6891  *
6892  */
6893 static void trw_layer_waypoints_visibility_off ( gpointer lav[2] )
6894 {
6895   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
6896   gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(FALSE) };
6897   g_hash_table_foreach ( vtl->waypoints_iters, (GHFunc) trw_layer_iter_visibility, vis_data );
6898   g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_waypoints_visibility, vis_data[1] );
6899   // Redraw
6900   vik_layer_emit_update ( VIK_LAYER(vtl) );
6901 }
6902
6903 /**
6904  *
6905  */
6906 static void trw_layer_waypoints_visibility_on ( gpointer lav[2] )
6907 {
6908   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
6909   gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(TRUE) };
6910   g_hash_table_foreach ( vtl->waypoints_iters, (GHFunc) trw_layer_iter_visibility, vis_data );
6911   g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_waypoints_visibility, vis_data[1] );
6912   // Redraw
6913   vik_layer_emit_update ( VIK_LAYER(vtl) );
6914 }
6915
6916 /**
6917  *
6918  */
6919 static void trw_layer_waypoints_visibility_toggle ( gpointer lav[2] )
6920 {
6921   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
6922   g_hash_table_foreach ( vtl->waypoints_iters, (GHFunc) trw_layer_iter_visibility_toggle, VIK_LAYER(vtl)->vt );
6923   g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_waypoints_toggle_visibility, NULL );
6924   // Redraw
6925   vik_layer_emit_update ( VIK_LAYER(vtl) );
6926 }
6927
6928 /**
6929  *
6930  */
6931 static void trw_layer_tracks_visibility ( gpointer id, VikTrack *trk, gpointer on_off )
6932 {
6933   trk->visible = GPOINTER_TO_INT (on_off);
6934 }
6935
6936 /**
6937  *
6938  */
6939 static void trw_layer_tracks_toggle_visibility ( gpointer id, VikTrack *trk )
6940 {
6941   trk->visible = !trk->visible;
6942 }
6943
6944 /**
6945  *
6946  */
6947 static void trw_layer_tracks_visibility_off ( gpointer lav[2] )
6948 {
6949   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
6950   gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(FALSE) };
6951   g_hash_table_foreach ( vtl->tracks_iters, (GHFunc) trw_layer_iter_visibility, vis_data );
6952   g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_tracks_visibility, vis_data[1] );
6953   // Redraw
6954   vik_layer_emit_update ( VIK_LAYER(vtl) );
6955 }
6956
6957 /**
6958  *
6959  */
6960 static void trw_layer_tracks_visibility_on ( gpointer lav[2] )
6961 {
6962   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
6963   gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(TRUE) };
6964   g_hash_table_foreach ( vtl->tracks_iters, (GHFunc) trw_layer_iter_visibility, vis_data );
6965   g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_tracks_visibility, vis_data[1] );
6966   // Redraw
6967   vik_layer_emit_update ( VIK_LAYER(vtl) );
6968 }
6969
6970 /**
6971  *
6972  */
6973 static void trw_layer_tracks_visibility_toggle ( gpointer lav[2] )
6974 {
6975   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
6976   g_hash_table_foreach ( vtl->tracks_iters, (GHFunc) trw_layer_iter_visibility_toggle, VIK_LAYER(vtl)->vt );
6977   g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_tracks_toggle_visibility, NULL );
6978   // Redraw
6979   vik_layer_emit_update ( VIK_LAYER(vtl) );
6980 }
6981
6982 /**
6983  *
6984  */
6985 static void trw_layer_routes_visibility_off ( gpointer lav[2] )
6986 {
6987   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
6988   gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(FALSE) };
6989   g_hash_table_foreach ( vtl->routes_iters, (GHFunc) trw_layer_iter_visibility, vis_data );
6990   g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_tracks_visibility, vis_data[1] );
6991   // Redraw
6992   vik_layer_emit_update ( VIK_LAYER(vtl) );
6993 }
6994
6995 /**
6996  *
6997  */
6998 static void trw_layer_routes_visibility_on ( gpointer lav[2] )
6999 {
7000   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
7001   gpointer vis_data[2] = { VIK_LAYER(vtl)->vt, GINT_TO_POINTER(TRUE) };
7002   g_hash_table_foreach ( vtl->routes_iters, (GHFunc) trw_layer_iter_visibility, vis_data );
7003   g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_tracks_visibility, vis_data[1] );
7004   // Redraw
7005   vik_layer_emit_update ( VIK_LAYER(vtl) );
7006 }
7007
7008 /**
7009  *
7010  */
7011 static void trw_layer_routes_visibility_toggle ( gpointer lav[2] )
7012 {
7013   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
7014   g_hash_table_foreach ( vtl->routes_iters, (GHFunc) trw_layer_iter_visibility_toggle, VIK_LAYER(vtl)->vt );
7015   g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_tracks_toggle_visibility, NULL );
7016   // Redraw
7017   vik_layer_emit_update ( VIK_LAYER(vtl) );
7018 }
7019
7020 /**
7021  * vik_trw_layer_build_waypoint_list_t:
7022  *
7023  * Helper function to construct a list of #vik_trw_waypoint_list_t
7024  */
7025 GList *vik_trw_layer_build_waypoint_list_t ( VikTrwLayer *vtl, GList *waypoints )
7026 {
7027   GList *waypoints_and_layers = NULL;
7028   // build waypoints_and_layers list
7029   while ( waypoints ) {
7030     vik_trw_waypoint_list_t *vtdl = g_malloc (sizeof(vik_trw_waypoint_list_t));
7031     vtdl->wpt = VIK_WAYPOINT(waypoints->data);
7032     vtdl->vtl = vtl;
7033     waypoints_and_layers = g_list_prepend ( waypoints_and_layers, vtdl );
7034     waypoints = g_list_next ( waypoints );
7035   }
7036   return waypoints_and_layers;
7037 }
7038
7039 /**
7040  * trw_layer_create_waypoint_list:
7041  *
7042  * Create the latest list of waypoints with the associated layer(s)
7043  *  Although this will always be from a single layer here
7044  */
7045 static GList* trw_layer_create_waypoint_list ( VikLayer *vl, gpointer user_data )
7046 {
7047   VikTrwLayer *vtl = VIK_TRW_LAYER(vl);
7048   GList *waypoints = g_hash_table_get_values ( vik_trw_layer_get_waypoints(vtl) );
7049
7050   return vik_trw_layer_build_waypoint_list_t ( vtl, waypoints );
7051 }
7052
7053 /**
7054  * trw_layer_analyse_close:
7055  *
7056  * Stuff to do on dialog closure
7057  */
7058 static void trw_layer_analyse_close ( GtkWidget *dialog, gint resp, VikLayer* vl )
7059 {
7060   VikTrwLayer *vtl = VIK_TRW_LAYER(vl);
7061   gtk_widget_destroy ( dialog );
7062   vtl->tracks_analysis_dialog = NULL;
7063 }
7064
7065 /**
7066  * vik_trw_layer_build_track_list_t:
7067  *
7068  * Helper function to construct a list of #vik_trw_track_list_t
7069  */
7070 GList *vik_trw_layer_build_track_list_t ( VikTrwLayer *vtl, GList *tracks )
7071 {
7072   GList *tracks_and_layers = NULL;
7073   // build tracks_and_layers list
7074   while ( tracks ) {
7075     vik_trw_track_list_t *vtdl = g_malloc (sizeof(vik_trw_track_list_t));
7076     vtdl->trk = VIK_TRACK(tracks->data);
7077     vtdl->vtl = vtl;
7078     tracks_and_layers = g_list_prepend ( tracks_and_layers, vtdl );
7079     tracks = g_list_next ( tracks );
7080   }
7081   return tracks_and_layers;
7082 }
7083
7084 /**
7085  * trw_layer_create_track_list:
7086  *
7087  * Create the latest list of tracks with the associated layer(s)
7088  *  Although this will always be from a single layer here
7089  */
7090 static GList* trw_layer_create_track_list ( VikLayer *vl, gpointer user_data )
7091 {
7092   VikTrwLayer *vtl = VIK_TRW_LAYER(vl);
7093   GList *tracks = NULL;
7094   if ( GPOINTER_TO_INT(user_data) == VIK_TRW_LAYER_SUBLAYER_TRACKS )
7095     tracks = g_hash_table_get_values ( vik_trw_layer_get_tracks(vtl) );
7096   else
7097     tracks = g_hash_table_get_values ( vik_trw_layer_get_routes(vtl) );
7098
7099   return vik_trw_layer_build_track_list_t ( vtl, tracks );
7100 }
7101
7102 static void trw_layer_tracks_stats ( gpointer lav[2] )
7103 {
7104   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
7105   // There can only be one!
7106   if ( vtl->tracks_analysis_dialog )
7107     return;
7108
7109   vtl->tracks_analysis_dialog = vik_trw_layer_analyse_this ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
7110                                                              VIK_LAYER(vtl)->name,
7111                                                              VIK_LAYER(vtl),
7112                                                              GINT_TO_POINTER(VIK_TRW_LAYER_SUBLAYER_TRACKS),
7113                                                              trw_layer_create_track_list,
7114                                                              trw_layer_analyse_close );
7115 }
7116
7117 /**
7118  *
7119  */
7120 static void trw_layer_routes_stats ( gpointer lav[2] )
7121 {
7122   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
7123   // There can only be one!
7124   if ( vtl->tracks_analysis_dialog )
7125     return;
7126
7127   vtl->tracks_analysis_dialog = vik_trw_layer_analyse_this ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
7128                                                              VIK_LAYER(vtl)->name,
7129                                                              VIK_LAYER(vtl),
7130                                                              GINT_TO_POINTER(VIK_TRW_LAYER_SUBLAYER_ROUTES),
7131                                                              trw_layer_create_track_list,
7132                                                              trw_layer_analyse_close );
7133 }
7134
7135 static void trw_layer_goto_waypoint ( gpointer pass_along[6] )
7136 {
7137   VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->waypoints, pass_along[3] );
7138   if ( wp )
7139     goto_coord ( pass_along[1], pass_along[0], pass_along[5], &(wp->coord) );
7140 }
7141
7142 static void trw_layer_waypoint_gc_webpage ( gpointer pass_along[6] )
7143 {
7144   VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->waypoints, pass_along[3] );
7145   if ( !wp )
7146     return;
7147   gchar *webpage = g_strdup_printf("http://www.geocaching.com/seek/cache_details.aspx?wp=%s", wp->name );
7148   open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), webpage);
7149   g_free ( webpage );
7150 }
7151
7152 static void trw_layer_waypoint_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   if ( !strncmp(wp->comment, "http", 4) ) {
7158     open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), wp->comment);
7159   } else if ( !strncmp(wp->description, "http", 4) ) {
7160     open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), wp->description);
7161   }
7162 }
7163
7164 static const gchar* trw_layer_sublayer_rename_request ( VikTrwLayer *l, const gchar *newname, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter )
7165 {
7166   if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
7167   {
7168     VikWaypoint *wp = g_hash_table_lookup ( l->waypoints, sublayer );
7169
7170     // No actual change to the name supplied
7171     if ( wp->name )
7172       if (strcmp(newname, wp->name) == 0 )
7173        return NULL;
7174
7175     VikWaypoint *wpf = vik_trw_layer_get_waypoint ( l, newname );
7176
7177     if ( wpf ) {
7178       // An existing waypoint has been found with the requested name
7179       if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(l),
7180            _("A waypoint with the name \"%s\" already exists. Really rename to the same name?"),
7181            newname ) )
7182         return NULL;
7183     }
7184
7185     // Update WP name and refresh the treeview
7186     vik_waypoint_set_name (wp, newname);
7187
7188     vik_treeview_item_set_name ( VIK_LAYER(l)->vt, iter, newname );
7189     vik_treeview_sort_children ( VIK_LAYER(l)->vt, &(l->waypoints_iter), l->wp_sort_order );
7190
7191     vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) );
7192
7193     return newname;
7194   }
7195
7196   if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
7197   {
7198     VikTrack *trk = g_hash_table_lookup ( l->tracks, sublayer );
7199
7200     // No actual change to the name supplied
7201     if ( trk->name )
7202       if (strcmp(newname, trk->name) == 0)
7203         return NULL;
7204
7205     VikTrack *trkf = vik_trw_layer_get_track ( l, (gpointer) newname );
7206
7207     if ( trkf ) {
7208       // An existing track has been found with the requested name
7209       if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(l),
7210           _("A track with the name \"%s\" already exists. Really rename to the same name?"),
7211           newname ) )
7212         return NULL;
7213     }
7214     // Update track name and refresh GUI parts
7215     vik_track_set_name (trk, newname);
7216
7217     // Update any subwindows that could be displaying this track which has changed name
7218     // Only one Track Edit Window
7219     if ( l->current_tp_track == trk && l->tpwin ) {
7220       vik_trw_layer_tpwin_set_track_name ( l->tpwin, newname );
7221     }
7222     // Property Dialog of the track
7223     vik_trw_layer_propwin_update ( trk );
7224
7225     vik_treeview_item_set_name ( VIK_LAYER(l)->vt, iter, newname );
7226     vik_treeview_sort_children ( VIK_LAYER(l)->vt, &(l->tracks_iter), l->track_sort_order );
7227
7228     vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) );
7229
7230     return newname;
7231   }
7232
7233   if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE )
7234   {
7235     VikTrack *trk = g_hash_table_lookup ( l->routes, sublayer );
7236
7237     // No actual change to the name supplied
7238     if ( trk->name )
7239       if (strcmp(newname, trk->name) == 0)
7240         return NULL;
7241
7242     VikTrack *trkf = vik_trw_layer_get_route ( l, (gpointer) newname );
7243
7244     if ( trkf ) {
7245       // An existing track has been found with the requested name
7246       if ( ! a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(l),
7247           _("A route with the name \"%s\" already exists. Really rename to the same name?"),
7248           newname ) )
7249         return NULL;
7250     }
7251     // Update track name and refresh GUI parts
7252     vik_track_set_name (trk, newname);
7253
7254     // Update any subwindows that could be displaying this track which has changed name
7255     // Only one Track Edit Window
7256     if ( l->current_tp_track == trk && l->tpwin ) {
7257       vik_trw_layer_tpwin_set_track_name ( l->tpwin, newname );
7258     }
7259     // Property Dialog of the track
7260     vik_trw_layer_propwin_update ( trk );
7261
7262     vik_treeview_item_set_name ( VIK_LAYER(l)->vt, iter, newname );
7263     vik_treeview_sort_children ( VIK_LAYER(l)->vt, &(l->tracks_iter), l->track_sort_order );
7264
7265     vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) );
7266
7267     return newname;
7268   }
7269   return NULL;
7270 }
7271
7272 static gboolean is_valid_geocache_name ( gchar *str )
7273 {
7274   gint len = strlen ( str );
7275   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]));
7276 }
7277
7278 static void trw_layer_track_use_with_filter ( gpointer pass_along[6] )
7279 {
7280   VikTrack *trk = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
7281   a_acquire_set_filter_track ( trk );
7282 }
7283
7284 #ifdef VIK_CONFIG_GOOGLE
7285 static gboolean is_valid_google_route ( VikTrwLayer *vtl, const gpointer track_id )
7286 {
7287   VikTrack *tr = g_hash_table_lookup ( vtl->routes, track_id );
7288   return ( tr && tr->comment && strlen(tr->comment) > 7 && !strncmp(tr->comment, "from:", 5) );
7289 }
7290
7291 static void trw_layer_google_route_webpage ( gpointer pass_along[6] )
7292 {
7293   VikTrack *tr = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->routes, pass_along[3] );
7294   if ( tr ) {
7295     gchar *escaped = uri_escape ( tr->comment );
7296     gchar *webpage = g_strdup_printf("http://maps.google.com/maps?f=q&hl=en&q=%s", escaped );
7297     open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(pass_along[0])), webpage);
7298     g_free ( escaped );
7299     g_free ( webpage );
7300   }
7301 }
7302 #endif
7303
7304 /* vlp can be NULL if necessary - i.e. right-click from a tool */
7305 /* viewpoint is now available instead */
7306 static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu, gpointer vlp, gint subtype, gpointer sublayer, GtkTreeIter *iter, VikViewport *vvp )
7307 {
7308   static gpointer pass_along[8];
7309   GtkWidget *item;
7310   gboolean rv = FALSE;
7311
7312   pass_along[0] = l;
7313   pass_along[1] = vlp;
7314   pass_along[2] = GINT_TO_POINTER (subtype);
7315   pass_along[3] = sublayer;
7316   pass_along[4] = GINT_TO_POINTER (1); // Confirm delete request
7317   pass_along[5] = vvp;
7318   pass_along[6] = iter;
7319   pass_along[7] = NULL; // For misc purposes - maybe track or waypoint
7320
7321   if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT || subtype == VIK_TRW_LAYER_SUBLAYER_TRACK || subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE )
7322   {
7323     rv = TRUE;
7324
7325     item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_PROPERTIES, NULL );
7326     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_properties_item), pass_along );
7327     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7328     gtk_widget_show ( item );
7329
7330     if (subtype == VIK_TRW_LAYER_SUBLAYER_TRACK) {
7331       VikTrack *tr = g_hash_table_lookup ( l->tracks, sublayer );
7332       if (tr && tr->property_dialog)
7333         gtk_widget_set_sensitive(GTK_WIDGET(item), FALSE );
7334     }
7335     if (subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE) {
7336       VikTrack *tr = g_hash_table_lookup ( l->routes, sublayer );
7337       if (tr && tr->property_dialog)
7338         gtk_widget_set_sensitive(GTK_WIDGET(item), FALSE );
7339     }
7340
7341     item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_CUT, NULL );
7342     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_cut_item_cb), pass_along );
7343     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7344     gtk_widget_show ( item );
7345
7346     item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_COPY, NULL );
7347     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_copy_item_cb), pass_along );
7348     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7349     gtk_widget_show ( item );
7350
7351     item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_DELETE, NULL );
7352     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_item), pass_along );
7353     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7354     gtk_widget_show ( item );
7355
7356     if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT )
7357     {
7358       // Always create separator as now there is always at least the transform menu option
7359       item = gtk_menu_item_new ();
7360       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7361       gtk_widget_show ( item );
7362
7363       /* could be a right-click using the tool */
7364       if ( vlp != NULL ) {
7365         item = gtk_image_menu_item_new_with_mnemonic ( _("_Goto") );
7366         gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
7367         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_waypoint), pass_along );
7368         gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7369         gtk_widget_show ( item );
7370       }
7371
7372       VikWaypoint *wp = g_hash_table_lookup ( VIK_TRW_LAYER(l)->waypoints, sublayer );
7373
7374       if ( wp && wp->name ) {
7375         if ( is_valid_geocache_name ( wp->name ) ) {
7376           item = gtk_menu_item_new_with_mnemonic ( _("_Visit Geocache Webpage") );
7377           g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoint_gc_webpage), pass_along );
7378           gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7379           gtk_widget_show ( item );
7380         }
7381 #ifdef VIK_CONFIG_GEOTAG
7382         item = gtk_menu_item_new_with_mnemonic ( _("Geotag _Images...") );
7383         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_geotagging_waypoint), pass_along );
7384         gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7385         gtk_widget_set_tooltip_text (item, _("Geotag multiple images against this waypoint"));
7386         gtk_widget_show ( item );
7387 #endif
7388       }
7389
7390       if ( wp && wp->image )
7391       {
7392         // Set up image paramater
7393         pass_along[5] = wp->image;
7394
7395         item = gtk_image_menu_item_new_with_mnemonic ( _("_Show Picture...") );
7396         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
7397         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_show_picture), pass_along );
7398         gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7399         gtk_widget_show ( item );
7400
7401 #ifdef VIK_CONFIG_GEOTAG
7402         GtkWidget *geotag_submenu = gtk_menu_new ();
7403         item = gtk_image_menu_item_new_with_mnemonic ( _("Update Geotag on _Image") );
7404         gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
7405         gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7406         gtk_widget_show ( item );
7407         gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), geotag_submenu );
7408   
7409         item = gtk_menu_item_new_with_mnemonic ( _("_Update") );
7410         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_geotagging_waypoint_mtime_update), pass_along );
7411         gtk_menu_shell_append (GTK_MENU_SHELL (geotag_submenu), item);
7412         gtk_widget_show ( item );
7413
7414         item = gtk_menu_item_new_with_mnemonic ( _("Update and _Keep File Timestamp") );
7415         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_geotagging_waypoint_mtime_keep), pass_along );
7416         gtk_menu_shell_append (GTK_MENU_SHELL (geotag_submenu), item);
7417         gtk_widget_show ( item );
7418 #endif
7419       }
7420
7421       if ( wp )
7422       {
7423         if ( ( wp->comment && !strncmp(wp->comment, "http", 4) ) ||
7424              ( wp->description && !strncmp(wp->description, "http", 4) )) {
7425           item = gtk_image_menu_item_new_with_mnemonic ( _("Visit _Webpage") );
7426           gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NETWORK, GTK_ICON_SIZE_MENU) );
7427           g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoint_webpage), pass_along );
7428           gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7429           gtk_widget_show ( item );
7430         }
7431       }
7432     }
7433   }
7434
7435   if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS || subtype == VIK_TRW_LAYER_SUBLAYER_TRACKS || subtype == VIK_TRW_LAYER_SUBLAYER_ROUTES ) {
7436     item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_PASTE, NULL );
7437     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_paste_item_cb), pass_along );
7438     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7439     gtk_widget_show ( item );
7440     // TODO: only enable if suitable item is in clipboard - want to determine *which* sublayer type
7441     if ( a_clipboard_type ( ) == VIK_CLIPBOARD_DATA_SUBLAYER )
7442       gtk_widget_set_sensitive ( item, TRUE );
7443     else
7444       gtk_widget_set_sensitive ( item, FALSE );
7445
7446     // Add separator
7447     item = gtk_menu_item_new ();
7448     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7449     gtk_widget_show ( item );
7450   }
7451
7452   if ( vlp && (subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS || subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT) )
7453   {
7454     rv = TRUE;
7455     item = gtk_image_menu_item_new_with_mnemonic ( _("_New Waypoint...") );
7456     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) );
7457     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_wp), pass_along );
7458     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7459     gtk_widget_show ( item );
7460   }
7461
7462   if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS )
7463   {
7464     item = gtk_image_menu_item_new_with_mnemonic ( _("_View All Waypoints") );
7465     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
7466     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_waypoints_view), pass_along );
7467     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7468     gtk_widget_show ( item );
7469
7470     item = gtk_image_menu_item_new_with_mnemonic ( _("Goto _Waypoint...") );
7471     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
7472     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_wp), pass_along );
7473     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7474     gtk_widget_show ( item );
7475
7476     item = gtk_image_menu_item_new_with_mnemonic ( _("Delete _All Waypoints") );
7477     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
7478     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_waypoints), pass_along );
7479     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7480     gtk_widget_show ( item );
7481
7482     item = gtk_image_menu_item_new_with_mnemonic ( _("_Delete Waypoints From Selection...") );
7483     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
7484     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_waypoints_from_selection), pass_along );
7485     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7486     gtk_widget_show ( item );
7487
7488     GtkWidget *vis_submenu = gtk_menu_new ();
7489     item = gtk_menu_item_new_with_mnemonic ( _("_Visibility") );
7490     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7491     gtk_widget_show ( item );
7492     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), vis_submenu );
7493
7494     item = gtk_image_menu_item_new_with_mnemonic ( _("_Show All Waypoints") );
7495     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_APPLY, GTK_ICON_SIZE_MENU) );
7496     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoints_visibility_on), pass_along );
7497     gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item );
7498     gtk_widget_show ( item );
7499
7500     item = gtk_image_menu_item_new_with_mnemonic ( _("_Hide All Waypoints") );
7501     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CLEAR, GTK_ICON_SIZE_MENU) );
7502     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoints_visibility_off), pass_along );
7503     gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item );
7504     gtk_widget_show ( item );
7505
7506     item = gtk_image_menu_item_new_with_mnemonic ( _("_Toggle") );
7507     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
7508     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoints_visibility_toggle), pass_along );
7509     gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item );
7510     gtk_widget_show ( item );
7511
7512     item = gtk_image_menu_item_new_with_mnemonic ( _("_List Waypoints...") );
7513     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
7514     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_waypoint_list_dialog), pass_along );
7515     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7516   }
7517
7518   if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACKS )
7519   {
7520     rv = TRUE;
7521
7522     if ( l->current_track && !l->current_track->is_route ) {
7523       item = gtk_menu_item_new_with_mnemonic ( _("_Finish Track") );
7524       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_finish_track), pass_along );
7525       gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7526       gtk_widget_show ( item );
7527       // Add separator
7528       item = gtk_menu_item_new ();
7529       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7530       gtk_widget_show ( item );
7531     }
7532
7533     item = gtk_image_menu_item_new_with_mnemonic ( _("_View All Tracks") );
7534     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
7535     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_tracks_view), pass_along );
7536     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7537     gtk_widget_show ( item );
7538
7539     item = gtk_image_menu_item_new_with_mnemonic ( _("_New Track") );
7540     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) );
7541     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_track), pass_along );
7542     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7543     gtk_widget_show ( item );
7544     // Make it available only when a new track *not* already in progress
7545     gtk_widget_set_sensitive ( item, ! (gboolean)GPOINTER_TO_INT(l->current_track) );
7546
7547     item = gtk_image_menu_item_new_with_mnemonic ( _("Delete _All Tracks") );
7548     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
7549     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_tracks), pass_along );
7550     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7551     gtk_widget_show ( item );
7552
7553     item = gtk_image_menu_item_new_with_mnemonic ( _("_Delete Tracks From Selection...") );
7554     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
7555     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_tracks_from_selection), pass_along );
7556     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7557     gtk_widget_show ( item );
7558
7559     GtkWidget *vis_submenu = gtk_menu_new ();
7560     item = gtk_menu_item_new_with_mnemonic ( _("_Visibility") );
7561     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7562     gtk_widget_show ( item );
7563     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), vis_submenu );
7564
7565     item = gtk_image_menu_item_new_with_mnemonic ( _("_Show All Tracks") );
7566     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_APPLY, GTK_ICON_SIZE_MENU) );
7567     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_tracks_visibility_on), pass_along );
7568     gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item );
7569     gtk_widget_show ( item );
7570
7571     item = gtk_image_menu_item_new_with_mnemonic ( _("_Hide All Tracks") );
7572     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CLEAR, GTK_ICON_SIZE_MENU) );
7573     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_tracks_visibility_off), pass_along );
7574     gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item );
7575     gtk_widget_show ( item );
7576
7577     item = gtk_image_menu_item_new_with_mnemonic ( _("_Toggle") );
7578     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
7579     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_tracks_visibility_toggle), pass_along );
7580     gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item );
7581
7582     item = gtk_image_menu_item_new_with_mnemonic ( _("_List Tracks...") );
7583     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
7584     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_list_dialog_single), pass_along );
7585     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7586     gtk_widget_show ( item );
7587
7588     item = gtk_menu_item_new_with_mnemonic ( _("_Statistics") );
7589     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_tracks_stats), pass_along );
7590     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7591     gtk_widget_show ( item );
7592   }
7593
7594   if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTES )
7595   {
7596     rv = TRUE;
7597
7598     if ( l->current_track && l->current_track->is_route ) {
7599       item = gtk_menu_item_new_with_mnemonic ( _("_Finish Route") );
7600       // Reuse finish track method
7601       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_finish_track), pass_along );
7602       gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7603       gtk_widget_show ( item );
7604       // Add separator
7605       item = gtk_menu_item_new ();
7606       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7607       gtk_widget_show ( item );
7608     }
7609
7610     item = gtk_image_menu_item_new_with_mnemonic ( _("_View All Routes") );
7611     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
7612     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_routes_view), pass_along );
7613     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7614     gtk_widget_show ( item );
7615
7616     item = gtk_image_menu_item_new_with_mnemonic ( _("_New Route") );
7617     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU) );
7618     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_new_route), pass_along );
7619     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7620     gtk_widget_show ( item );
7621     // Make it available only when a new track *not* already in progress
7622     gtk_widget_set_sensitive ( item, ! (gboolean)GPOINTER_TO_INT(l->current_track) );
7623
7624     item = gtk_image_menu_item_new_with_mnemonic ( _("Delete _All Routes") );
7625     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
7626     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_all_routes), pass_along );
7627     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7628     gtk_widget_show ( item );
7629
7630     item = gtk_image_menu_item_new_with_mnemonic ( _("_Delete Routes From Selection...") );
7631     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
7632     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_routes_from_selection), pass_along );
7633     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7634     gtk_widget_show ( item );
7635
7636     GtkWidget *vis_submenu = gtk_menu_new ();
7637     item = gtk_menu_item_new_with_mnemonic ( _("_Visibility") );
7638     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7639     gtk_widget_show ( item );
7640     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), vis_submenu );
7641
7642     item = gtk_image_menu_item_new_with_mnemonic ( _("_Show All Routes") );
7643     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_APPLY, GTK_ICON_SIZE_MENU) );
7644     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_routes_visibility_on), pass_along );
7645     gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item );
7646     gtk_widget_show ( item );
7647
7648     item = gtk_image_menu_item_new_with_mnemonic ( _("_Hide All Routes") );
7649     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CLEAR, GTK_ICON_SIZE_MENU) );
7650     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_routes_visibility_off), pass_along );
7651     gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item );
7652     gtk_widget_show ( item );
7653
7654     item = gtk_image_menu_item_new_with_mnemonic ( _("_Toggle") );
7655     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
7656     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_routes_visibility_toggle), pass_along );
7657     gtk_menu_shell_append ( GTK_MENU_SHELL(vis_submenu), item );
7658
7659     item = gtk_image_menu_item_new_with_mnemonic ( _("_List Routes...") );
7660     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
7661     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_list_dialog_single), pass_along );
7662     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7663
7664     gtk_widget_show ( item );
7665
7666     item = gtk_menu_item_new_with_mnemonic ( _("_Statistics") );
7667     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_routes_stats), pass_along );
7668     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7669     gtk_widget_show ( item );
7670   }
7671
7672
7673   if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS || subtype == VIK_TRW_LAYER_SUBLAYER_TRACKS || subtype == VIK_TRW_LAYER_SUBLAYER_ROUTES ) {
7674     GtkWidget *submenu_sort = gtk_menu_new ();
7675     item = gtk_image_menu_item_new_with_mnemonic ( _("_Sort") );
7676     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
7677     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7678     gtk_widget_show ( item );
7679     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu_sort );
7680
7681     item = gtk_image_menu_item_new_with_mnemonic ( _("Name _Ascending") );
7682     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_SORT_ASCENDING, GTK_ICON_SIZE_MENU) );
7683     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_sort_order_a2z), pass_along );
7684     gtk_menu_shell_append ( GTK_MENU_SHELL(submenu_sort), item );
7685     gtk_widget_show ( item );
7686
7687     item = gtk_image_menu_item_new_with_mnemonic ( _("Name _Descending") );
7688     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_SORT_DESCENDING, GTK_ICON_SIZE_MENU) );
7689     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_sort_order_z2a), pass_along );
7690     gtk_menu_shell_append ( GTK_MENU_SHELL(submenu_sort), item );
7691     gtk_widget_show ( item );
7692   }
7693
7694   GtkWidget *upload_submenu = gtk_menu_new ();
7695
7696   if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK || subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE )
7697   {
7698     item = gtk_menu_item_new ();
7699     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7700     gtk_widget_show ( item );
7701
7702     if ( l->current_track && subtype == VIK_TRW_LAYER_SUBLAYER_TRACK && !l->current_track->is_route )
7703       item = gtk_menu_item_new_with_mnemonic ( _("_Finish Track") );
7704     if ( l->current_track && subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE && l->current_track->is_route )
7705       item = gtk_menu_item_new_with_mnemonic ( _("_Finish Route") );
7706     if ( l->current_track ) {
7707       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_finish_track), pass_along );
7708       gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7709       gtk_widget_show ( item );
7710
7711       // Add separator
7712       item = gtk_menu_item_new ();
7713       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7714       gtk_widget_show ( item );
7715     }
7716
7717     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
7718       item = gtk_image_menu_item_new_with_mnemonic ( _("_View Track") );
7719     else
7720       item = gtk_image_menu_item_new_with_mnemonic ( _("_View Route") );
7721     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ZOOM_FIT, GTK_ICON_SIZE_MENU) );
7722     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_auto_track_view), pass_along );
7723     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7724     gtk_widget_show ( item );
7725
7726     item = gtk_menu_item_new_with_mnemonic ( _("_Statistics") );
7727     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_statistics), pass_along );
7728     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7729     gtk_widget_show ( item );
7730
7731     GtkWidget *goto_submenu;
7732     goto_submenu = gtk_menu_new ();
7733     item = gtk_image_menu_item_new_with_mnemonic ( _("_Goto") );
7734     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
7735     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7736     gtk_widget_show ( item );
7737     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), goto_submenu );
7738
7739     item = gtk_image_menu_item_new_with_mnemonic ( _("_Startpoint") );
7740     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GOTO_FIRST, GTK_ICON_SIZE_MENU) );
7741     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_startpoint), pass_along );
7742     gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
7743     gtk_widget_show ( item );
7744
7745     item = gtk_image_menu_item_new_with_mnemonic ( _("\"_Center\"") );
7746     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU) );
7747     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_center), pass_along );
7748     gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
7749     gtk_widget_show ( item );
7750
7751     item = gtk_image_menu_item_new_with_mnemonic ( _("_Endpoint") );
7752     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GOTO_LAST, GTK_ICON_SIZE_MENU) );
7753     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_endpoint), pass_along );
7754     gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
7755     gtk_widget_show ( item );
7756
7757     item = gtk_image_menu_item_new_with_mnemonic ( _("_Highest Altitude") );
7758     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GOTO_TOP, GTK_ICON_SIZE_MENU) );
7759     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_max_alt), pass_along );
7760     gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
7761     gtk_widget_show ( item );
7762
7763     item = gtk_image_menu_item_new_with_mnemonic ( _("_Lowest Altitude") );
7764     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GOTO_BOTTOM, GTK_ICON_SIZE_MENU) );
7765     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_min_alt), pass_along );
7766     gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
7767     gtk_widget_show ( item );
7768
7769     // Routes don't have speeds
7770     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
7771       item = gtk_image_menu_item_new_with_mnemonic ( _("_Maximum Speed") );
7772       gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_MEDIA_FORWARD, GTK_ICON_SIZE_MENU) );
7773       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_goto_track_max_speed), pass_along );
7774       gtk_menu_shell_append ( GTK_MENU_SHELL(goto_submenu), item );
7775       gtk_widget_show ( item );
7776     }
7777
7778     GtkWidget *combine_submenu;
7779     combine_submenu = gtk_menu_new ();
7780     item = gtk_image_menu_item_new_with_mnemonic ( _("Co_mbine") );
7781     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CONNECT, GTK_ICON_SIZE_MENU) );
7782     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7783     gtk_widget_show ( item );
7784     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), combine_submenu );
7785
7786     // Routes don't have times or segments...
7787     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
7788       item = gtk_menu_item_new_with_mnemonic ( _("_Merge By Time...") );
7789       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_merge_by_timestamp), pass_along );
7790       gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item );
7791       gtk_widget_show ( item );
7792
7793       item = gtk_menu_item_new_with_mnemonic ( _("Merge _Segments") );
7794       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_merge_by_segment), pass_along );
7795       gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item );
7796       gtk_widget_show ( item );
7797     }
7798
7799     item = gtk_menu_item_new_with_mnemonic ( _("Merge _With Other Tracks...") );
7800     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_merge_with_other), pass_along );
7801     gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item );
7802     gtk_widget_show ( item );
7803
7804     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
7805       item = gtk_menu_item_new_with_mnemonic ( _("_Append Track...") );
7806     else
7807       item = gtk_menu_item_new_with_mnemonic ( _("_Append Route...") );
7808     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_append_track), pass_along );
7809     gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item );
7810     gtk_widget_show ( item );
7811
7812     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
7813       item = gtk_menu_item_new_with_mnemonic ( _("Append _Route...") );
7814     else
7815       item = gtk_menu_item_new_with_mnemonic ( _("Append _Track...") );
7816     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_append_other), pass_along );
7817     gtk_menu_shell_append ( GTK_MENU_SHELL(combine_submenu), item );
7818     gtk_widget_show ( item );
7819
7820     GtkWidget *split_submenu;
7821     split_submenu = gtk_menu_new ();
7822     item = gtk_image_menu_item_new_with_mnemonic ( _("_Split") );
7823     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_DISCONNECT, GTK_ICON_SIZE_MENU) );
7824     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7825     gtk_widget_show ( item );
7826     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), split_submenu );
7827
7828     // Routes don't have times or segments...
7829     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
7830       item = gtk_menu_item_new_with_mnemonic ( _("_Split By Time...") );
7831       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_by_timestamp), pass_along );
7832       gtk_menu_shell_append ( GTK_MENU_SHELL(split_submenu), item );
7833       gtk_widget_show ( item );
7834
7835       // ATM always enable this entry - don't want to have to analyse the track before displaying the menu - to keep the menu speedy
7836       item = gtk_menu_item_new_with_mnemonic ( _("Split Se_gments") );
7837       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_segments), pass_along );
7838       gtk_menu_shell_append ( GTK_MENU_SHELL(split_submenu), item );
7839       gtk_widget_show ( item );
7840     }
7841
7842     item = gtk_menu_item_new_with_mnemonic ( _("Split By _Number of Points...") );
7843     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_by_n_points), pass_along );
7844     gtk_menu_shell_append ( GTK_MENU_SHELL(split_submenu), item );
7845     gtk_widget_show ( item );
7846
7847     item = gtk_menu_item_new_with_mnemonic ( _("Split at _Trackpoint") );
7848     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_split_at_trackpoint), pass_along );
7849     gtk_menu_shell_append ( GTK_MENU_SHELL(split_submenu), item );
7850     gtk_widget_show ( item );
7851     // Make it available only when a trackpoint is selected.
7852     gtk_widget_set_sensitive ( item, (gboolean)GPOINTER_TO_INT(l->current_tpl) );
7853
7854     GtkWidget *insert_submenu = gtk_menu_new ();
7855     item = gtk_image_menu_item_new_with_mnemonic ( _("_Insert Points") );
7856     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
7857     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7858     gtk_widget_show ( item );
7859     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), insert_submenu );
7860
7861     item = gtk_menu_item_new_with_mnemonic ( _("Insert Point _Before Selected Point") );
7862     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_insert_point_before), pass_along );
7863     gtk_menu_shell_append ( GTK_MENU_SHELL(insert_submenu), item );
7864     gtk_widget_show ( item );
7865     // Make it available only when a point is selected
7866     gtk_widget_set_sensitive ( item, (gboolean)GPOINTER_TO_INT(l->current_tpl) );
7867
7868     item = gtk_menu_item_new_with_mnemonic ( _("Insert Point _After Selected Point") );
7869     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_insert_point_after), pass_along );
7870     gtk_menu_shell_append ( GTK_MENU_SHELL(insert_submenu), item );
7871     gtk_widget_show ( item );
7872     // Make it available only when a point is selected
7873     gtk_widget_set_sensitive ( item, (gboolean)GPOINTER_TO_INT(l->current_tpl) );
7874
7875     GtkWidget *delete_submenu;
7876     delete_submenu = gtk_menu_new ();
7877     item = gtk_image_menu_item_new_with_mnemonic ( _("Delete Poi_nts") );
7878     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_DELETE, GTK_ICON_SIZE_MENU) );
7879     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7880     gtk_widget_show ( item );
7881     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), delete_submenu );
7882
7883     item = gtk_image_menu_item_new_with_mnemonic ( _("Delete _Selected Point") );
7884     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_DELETE, GTK_ICON_SIZE_MENU) );
7885     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_point_selected), pass_along );
7886     gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
7887     gtk_widget_show ( item );
7888     // Make it available only when a point is selected
7889     gtk_widget_set_sensitive ( item, (gboolean)GPOINTER_TO_INT(l->current_tpl) );
7890
7891     item = gtk_menu_item_new_with_mnemonic ( _("Delete Points With The Same _Position") );
7892     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_points_same_position), pass_along );
7893     gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
7894     gtk_widget_show ( item );
7895
7896     item = gtk_menu_item_new_with_mnemonic ( _("Delete Points With The Same _Time") );
7897     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_delete_points_same_time), pass_along );
7898     gtk_menu_shell_append ( GTK_MENU_SHELL(delete_submenu), item );
7899     gtk_widget_show ( item );
7900
7901     GtkWidget *transform_submenu;
7902     transform_submenu = gtk_menu_new ();
7903     item = gtk_image_menu_item_new_with_mnemonic ( _("_Transform") );
7904     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CONVERT, GTK_ICON_SIZE_MENU) );
7905     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
7906     gtk_widget_show ( item );
7907     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), transform_submenu );
7908
7909     GtkWidget *dem_submenu;
7910     dem_submenu = gtk_menu_new ();
7911     item = gtk_image_menu_item_new_with_mnemonic ( _("_Apply DEM Data") );
7912     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
7913     gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item );
7914     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), dem_submenu );
7915
7916     item = gtk_image_menu_item_new_with_mnemonic ( _("_Overwrite") );
7917     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data_all), pass_along );
7918     gtk_menu_shell_append ( GTK_MENU_SHELL(dem_submenu), item );
7919     gtk_widget_set_tooltip_text (item, _("Overwrite any existing elevation values with DEM values"));
7920     gtk_widget_show ( item );
7921
7922     item = gtk_image_menu_item_new_with_mnemonic ( _("_Keep Existing") );
7923     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data_only_missing), pass_along );
7924     gtk_menu_shell_append ( GTK_MENU_SHELL(dem_submenu), item );
7925     gtk_widget_set_tooltip_text (item, _("Keep existing elevation values, only attempt for missing values"));
7926     gtk_widget_show ( item );
7927
7928     GtkWidget *smooth_submenu;
7929     smooth_submenu = gtk_menu_new ();
7930     item = gtk_menu_item_new_with_mnemonic ( _("_Smooth Missing Elevation Data") );
7931     gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item );
7932     gtk_widget_show ( item );
7933     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), smooth_submenu );
7934
7935     item = gtk_image_menu_item_new_with_mnemonic ( _("_Interpolated") );
7936     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_missing_elevation_data_interp), pass_along );
7937     gtk_menu_shell_append ( GTK_MENU_SHELL(smooth_submenu), item );
7938     gtk_widget_set_tooltip_text (item, _("Interpolate between known elevation values to derive values for the missing elevations"));
7939     gtk_widget_show ( item );
7940
7941     item = gtk_image_menu_item_new_with_mnemonic ( _("_Flat") );
7942     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_missing_elevation_data_flat), pass_along );
7943     gtk_menu_shell_append ( GTK_MENU_SHELL(smooth_submenu), item );
7944     gtk_widget_set_tooltip_text (item, _("Set unknown elevation values to the last known value"));
7945     gtk_widget_show ( item );
7946
7947     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
7948       item = gtk_image_menu_item_new_with_mnemonic ( _("C_onvert to a Route") );
7949     else
7950       item = gtk_image_menu_item_new_with_mnemonic ( _("C_onvert to a Track") );
7951     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CONVERT, GTK_ICON_SIZE_MENU) );
7952     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_convert_track_route), pass_along );
7953     gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item );
7954     gtk_widget_show ( item );
7955
7956     // Routes don't have timestamps - so this is only available for tracks
7957     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
7958       item = gtk_image_menu_item_new_with_mnemonic ( _("_Anonymize Times") );
7959       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_anonymize_times), pass_along );
7960       gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item );
7961       gtk_widget_set_tooltip_text (item, _("Shift timestamps to a relative offset from 1901-01-01"));
7962       gtk_widget_show ( item );
7963     }
7964
7965     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
7966       item = gtk_image_menu_item_new_with_mnemonic ( _("_Reverse Track") );
7967     else
7968       item = gtk_image_menu_item_new_with_mnemonic ( _("_Reverse Route") );
7969     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_BACK, GTK_ICON_SIZE_MENU) );
7970     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_reverse), pass_along );
7971     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7972     gtk_widget_show ( item );
7973
7974     if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE ) {
7975       item = gtk_image_menu_item_new_with_mnemonic ( _("Refine Route...") );
7976       gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_FIND, GTK_ICON_SIZE_MENU) );
7977       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_route_refine), pass_along );
7978       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7979       gtk_widget_show ( item );
7980     }
7981
7982     /* ATM This function is only available via the layers panel, due to the method in finding out the maps in use */
7983     if ( vlp ) {
7984       if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
7985         item = gtk_image_menu_item_new_with_mnemonic ( _("Down_load Maps Along Track...") );
7986       else
7987         item = gtk_image_menu_item_new_with_mnemonic ( _("Down_load Maps Along Route...") );
7988       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
7989       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_download_map_along_track_cb), pass_along );
7990       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
7991       gtk_widget_show ( item );
7992     }
7993
7994     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
7995       item = gtk_image_menu_item_new_with_mnemonic ( _("_Export Track as GPX...") );
7996     else
7997       item = gtk_image_menu_item_new_with_mnemonic ( _("_Export Route as GPX...") );
7998     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_HARDDISK, GTK_ICON_SIZE_MENU) );
7999     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_gpx_track), pass_along );
8000     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
8001     gtk_widget_show ( item );
8002
8003     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
8004       item = gtk_image_menu_item_new_with_mnemonic ( _("E_xtend Track End") );
8005     else
8006       item = gtk_image_menu_item_new_with_mnemonic ( _("E_xtend Route End") );
8007     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
8008     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_extend_track_end), pass_along );
8009     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
8010     gtk_widget_show ( item );
8011
8012     if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE ) {
8013       item = gtk_image_menu_item_new_with_mnemonic ( _("Extend _Using Route Finder") );
8014       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
8015       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_extend_track_end_route_finder), pass_along );
8016       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
8017       gtk_widget_show ( item );
8018     }
8019
8020     // ATM can't upload a single waypoint but can do waypoints to a GPS
8021     if ( subtype != VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
8022       item = gtk_image_menu_item_new_with_mnemonic ( _("_Upload") );
8023       gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU) );
8024       gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
8025       gtk_widget_show ( item );
8026       gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), upload_submenu );
8027
8028       item = gtk_image_menu_item_new_with_mnemonic ( _("_Upload to GPS...") );
8029       gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_MENU) );
8030       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_gps_upload_any), pass_along );
8031       gtk_menu_shell_append ( GTK_MENU_SHELL(upload_submenu), item );
8032       gtk_widget_show ( item );
8033     }
8034   }
8035
8036 #ifdef VIK_CONFIG_GOOGLE
8037   if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE && is_valid_google_route ( l, sublayer ) )
8038   {
8039     item = gtk_image_menu_item_new_with_mnemonic ( _("_View Google Directions") );
8040     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NETWORK, GTK_ICON_SIZE_MENU) );
8041     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_google_route_webpage), pass_along );
8042     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
8043     gtk_widget_show ( item );
8044   }
8045 #endif
8046
8047   // Some things aren't usable with routes
8048   if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
8049 #ifdef VIK_CONFIG_OPENSTREETMAP
8050     item = gtk_image_menu_item_new_with_mnemonic ( _("Upload to _OSM...") );
8051     // Convert internal pointer into actual track for usage outside this file
8052     pass_along[7] = g_hash_table_lookup ( l->tracks, sublayer);
8053     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU) );
8054     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_osm_traces_upload_track_cb), pass_along );
8055     gtk_menu_shell_append ( GTK_MENU_SHELL(upload_submenu), item );
8056     gtk_widget_show ( item );
8057 #endif
8058
8059     item = gtk_image_menu_item_new_with_mnemonic ( _("Use with _Filter") );
8060     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
8061     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_use_with_filter), pass_along );
8062     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
8063     gtk_widget_show ( item );
8064
8065     /* ATM This function is only available via the layers panel, due to needing a vlp */
8066     if ( vlp ) {
8067       item = a_acquire_track_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(l)), vlp,
8068                                     vik_layers_panel_get_viewport(VIK_LAYERS_PANEL(vlp)),
8069                                     g_hash_table_lookup ( l->tracks, (gchar *) sublayer ) );
8070       if ( item ) {
8071         gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
8072         gtk_widget_show ( item );
8073       }
8074     }
8075
8076 #ifdef VIK_CONFIG_GEOTAG
8077     item = gtk_menu_item_new_with_mnemonic ( _("Geotag _Images...") );
8078     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_geotagging_track), pass_along );
8079     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
8080     gtk_widget_show ( item );
8081 #endif
8082   }
8083
8084   if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK || subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE ) {
8085     // Only show on viewport popmenu when a trackpoint is selected
8086     if ( ! vlp && l->current_tpl ) {
8087       // Add separator
8088       item = gtk_menu_item_new ();
8089       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
8090       gtk_widget_show ( item );
8091
8092       item = gtk_image_menu_item_new_with_mnemonic ( _("_Edit Trackpoint") );
8093       gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_PROPERTIES, GTK_ICON_SIZE_MENU) );
8094       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_edit_trackpoint), pass_along );
8095       gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
8096       gtk_widget_show ( item );
8097     }
8098   }
8099
8100   if ( subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS || subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
8101     GtkWidget *transform_submenu;
8102     transform_submenu = gtk_menu_new ();
8103     item = gtk_image_menu_item_new_with_mnemonic ( _("_Transform") );
8104     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_CONVERT, GTK_ICON_SIZE_MENU) );
8105     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
8106     gtk_widget_show ( item );
8107     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), transform_submenu );
8108
8109     GtkWidget *dem_submenu;
8110     dem_submenu = gtk_menu_new ();
8111     item = gtk_image_menu_item_new_with_mnemonic ( _("_Apply DEM Data") );
8112     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
8113     gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item );
8114     gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), dem_submenu );
8115
8116     item = gtk_image_menu_item_new_with_mnemonic ( _("_Overwrite") );
8117     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data_wpt_all), pass_along );
8118     gtk_menu_shell_append ( GTK_MENU_SHELL(dem_submenu), item );
8119     gtk_widget_set_tooltip_text (item, _("Overwrite any existing elevation values with DEM values"));
8120     gtk_widget_show ( item );
8121
8122     item = gtk_image_menu_item_new_with_mnemonic ( _("_Keep Existing") );
8123     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data_wpt_only_missing), pass_along );
8124     gtk_menu_shell_append ( GTK_MENU_SHELL(dem_submenu), item );
8125     gtk_widget_set_tooltip_text (item, _("Keep existing elevation values, only attempt for missing values"));
8126     gtk_widget_show ( item );
8127   }
8128
8129   gtk_widget_show_all ( GTK_WIDGET(menu) );
8130
8131   return rv;
8132 }
8133
8134 // TODO: Probably better to rework this track manipulation in viktrack.c
8135 static void trw_layer_insert_tp_beside_current_tp ( VikTrwLayer *vtl, gboolean before )
8136 {
8137   // sanity check
8138   if (!vtl->current_tpl)
8139     return;
8140
8141   VikTrackpoint *tp_current = VIK_TRACKPOINT(vtl->current_tpl->data);
8142   VikTrackpoint *tp_other = NULL;
8143
8144   if ( before ) {
8145     if (!vtl->current_tpl->prev)
8146       return;
8147     tp_other = VIK_TRACKPOINT(vtl->current_tpl->prev->data);
8148   } else {
8149     if (!vtl->current_tpl->next)
8150       return;
8151     tp_other = VIK_TRACKPOINT(vtl->current_tpl->next->data);
8152   }
8153
8154   // Use current and other trackpoints to form a new track point which is inserted into the tracklist
8155   if ( tp_other ) {
8156
8157     VikTrackpoint *tp_new = vik_trackpoint_new();
8158     struct LatLon ll_current, ll_other;
8159     vik_coord_to_latlon ( &tp_current->coord, &ll_current );
8160     vik_coord_to_latlon ( &tp_other->coord, &ll_other );
8161
8162     /* main positional interpolation */
8163     struct LatLon ll_new = { (ll_current.lat+ll_other.lat)/2, (ll_current.lon+ll_other.lon)/2 };
8164     vik_coord_load_from_latlon ( &(tp_new->coord), vtl->coord_mode, &ll_new );
8165
8166     /* Now other properties that can be interpolated */
8167     tp_new->altitude = (tp_current->altitude + tp_other->altitude) / 2;
8168
8169     if (tp_current->has_timestamp && tp_other->has_timestamp) {
8170       /* Note here the division is applied to each part, then added
8171          This is to avoid potential overflow issues with a 32 time_t for dates after midpoint of this Unix time on 2004/01/04 */
8172       tp_new->timestamp = (tp_current->timestamp/2) + (tp_other->timestamp/2);
8173       tp_new->has_timestamp = TRUE;
8174     }
8175
8176     if (tp_current->speed != NAN && tp_other->speed != NAN)
8177       tp_new->speed = (tp_current->speed + tp_other->speed)/2;
8178
8179     /* TODO - improve interpolation of course, as it may not be correct.
8180        if courses in degrees are 350 + 020, the mid course more likely to be 005 (not 185)
8181        [similar applies if value is in radians] */
8182     if (tp_current->course != NAN && tp_other->course != NAN)
8183       tp_new->course = (tp_current->course + tp_other->course)/2;
8184
8185     /* DOP / sat values remain at defaults as not they do not seem applicable to a dreamt up point */
8186
8187     // Insert new point into the appropriate trackpoint list, either before or after the current trackpoint as directed
8188     VikTrack *trk = g_hash_table_lookup ( vtl->tracks, vtl->current_tp_id );
8189     if ( !trk )
8190       // Otherwise try routes
8191       trk = g_hash_table_lookup ( vtl->routes, vtl->current_tp_id );
8192     if ( !trk )
8193       return;
8194
8195     gint index =  g_list_index ( trk->trackpoints, tp_current );
8196     if ( index > -1 ) {
8197       if ( !before )
8198         index = index + 1;
8199       // NB no recalculation of bounds since it is inserted between points
8200       trk->trackpoints = g_list_insert ( trk->trackpoints, tp_new, index );
8201     }
8202   }
8203 }
8204
8205 static void trw_layer_cancel_current_tp ( VikTrwLayer *vtl, gboolean destroy )
8206 {
8207   if ( vtl->tpwin )
8208   {
8209     if ( destroy)
8210     {
8211       gtk_widget_destroy ( GTK_WIDGET(vtl->tpwin) );
8212       vtl->tpwin = NULL;
8213     }
8214     else
8215       vik_trw_layer_tpwin_set_empty ( vtl->tpwin );
8216   }
8217   if ( vtl->current_tpl )
8218   {
8219     vtl->current_tpl = NULL;
8220     vtl->current_tp_track = NULL;
8221     vtl->current_tp_id = NULL;
8222     vik_layer_emit_update(VIK_LAYER(vtl));
8223   }
8224 }
8225
8226 static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response )
8227 {
8228   g_assert ( vtl->tpwin != NULL );
8229   if ( response == VIK_TRW_LAYER_TPWIN_CLOSE )
8230     trw_layer_cancel_current_tp ( vtl, TRUE );
8231
8232   if ( vtl->current_tpl == NULL )
8233     return;
8234
8235   if ( response == VIK_TRW_LAYER_TPWIN_SPLIT && vtl->current_tpl->next && vtl->current_tpl->prev )
8236   {
8237     trw_layer_split_at_selected_trackpoint ( vtl, vtl->current_tp_track->is_route ? VIK_TRW_LAYER_SUBLAYER_ROUTE : VIK_TRW_LAYER_SUBLAYER_TRACK );
8238     vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
8239   }
8240   else if ( response == VIK_TRW_LAYER_TPWIN_DELETE )
8241   {
8242     VikTrack *tr = g_hash_table_lookup ( vtl->tracks, vtl->current_tp_id );
8243     if ( tr == NULL )
8244       tr = g_hash_table_lookup ( vtl->routes, vtl->current_tp_id );
8245     if ( tr == NULL )
8246       return;
8247
8248     trw_layer_trackpoint_selected_delete ( vtl, tr );
8249
8250     if ( vtl->current_tpl )
8251       // Reset dialog with the available adjacent trackpoint
8252       vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
8253
8254     vik_layer_emit_update(VIK_LAYER(vtl));
8255   }
8256   else if ( response == VIK_TRW_LAYER_TPWIN_FORWARD && vtl->current_tpl->next )
8257   {
8258     if ( vtl->current_tp_track )
8259       vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl = vtl->current_tpl->next, vtl->current_tp_track->name );
8260     vik_layer_emit_update(VIK_LAYER(vtl)); /* TODO longone: either move or only update if tp is inside drawing window */
8261   }
8262   else if ( response == VIK_TRW_LAYER_TPWIN_BACK && vtl->current_tpl->prev )
8263   {
8264     if ( vtl->current_tp_track )
8265       vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl = vtl->current_tpl->prev, vtl->current_tp_track->name );
8266     vik_layer_emit_update(VIK_LAYER(vtl));
8267   }
8268   else if ( response == VIK_TRW_LAYER_TPWIN_INSERT && vtl->current_tpl->next )
8269   {
8270     trw_layer_insert_tp_beside_current_tp ( vtl, FALSE );
8271     vik_layer_emit_update(VIK_LAYER(vtl));
8272   }
8273   else if ( response == VIK_TRW_LAYER_TPWIN_DATA_CHANGED )
8274     vik_layer_emit_update(VIK_LAYER(vtl));
8275 }
8276
8277 /**
8278  * trw_layer_dialog_shift:
8279  * @vertical: The reposition strategy. If Vertical moves dialog vertically, otherwise moves it horizontally
8280  *
8281  * Try to reposition a dialog if it's over the specified coord
8282  *  so to not obscure the item of interest
8283  */
8284 void trw_layer_dialog_shift ( VikTrwLayer *vtl, GtkWindow *dialog, VikCoord *coord, gboolean vertical )
8285 {
8286   GtkWindow *parent = VIK_GTK_WINDOW_FROM_LAYER(vtl); //i.e. the main window
8287
8288   // Attempt force dialog to be shown so we can find out where it is more reliably...
8289   while ( gtk_events_pending() )
8290     gtk_main_iteration ();
8291
8292   // get parent window position & size
8293   gint win_pos_x, win_pos_y;
8294   gtk_window_get_position ( parent, &win_pos_x, &win_pos_y );
8295
8296   gint win_size_x, win_size_y;
8297   gtk_window_get_size ( parent, &win_size_x, &win_size_y );
8298
8299   // get own dialog size
8300   gint dia_size_x, dia_size_y;
8301   gtk_window_get_size ( dialog, &dia_size_x, &dia_size_y );
8302
8303   // get own dialog position
8304   gint dia_pos_x, dia_pos_y;
8305   gtk_window_get_position ( dialog, &dia_pos_x, &dia_pos_y );
8306
8307   // Dialog not 'realized'/positioned - so can't really do any repositioning logic
8308   if ( dia_pos_x > 2 && dia_pos_y > 2 ) {
8309
8310     VikViewport *vvp = vik_window_viewport ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) );
8311
8312     gint vp_xx, vp_yy; // In viewport pixels
8313     vik_viewport_coord_to_screen ( vvp, coord, &vp_xx, &vp_yy );
8314
8315     // Work out the 'bounding box' in pixel terms of the dialog and only move it when over the position
8316
8317     gint dest_x = 0;
8318     gint dest_y = 0;
8319     if ( gtk_widget_translate_coordinates ( GTK_WIDGET(vvp), GTK_WIDGET(parent), 0, 0, &dest_x, &dest_y ) ) {
8320
8321       // Transform Viewport pixels into absolute pixels
8322       gint tmp_xx = vp_xx + dest_x + win_pos_x - 10;
8323       gint tmp_yy = vp_yy + dest_y + win_pos_y - 10;
8324
8325       // Is dialog over the point (to within an  ^^ edge value)
8326       if ( (tmp_xx > dia_pos_x) && (tmp_xx < (dia_pos_x + dia_size_x)) &&
8327            (tmp_yy > dia_pos_y) && (tmp_yy < (dia_pos_y + dia_size_y)) ) {
8328
8329         if ( vertical ) {
8330           // Shift up<->down
8331           gint hh = vik_viewport_get_height ( vvp );
8332
8333           // Consider the difference in viewport to the full window
8334           gint offset_y = dest_y;
8335           // Add difference between dialog and window sizes
8336           offset_y += win_pos_y + (hh/2 - dia_size_y)/2;
8337
8338           if ( vp_yy > hh/2 ) {
8339             // Point in bottom half, move window to top half
8340             gtk_window_move ( dialog, dia_pos_x, offset_y );
8341           }
8342           else {
8343             // Point in top half, move dialog down
8344             gtk_window_move ( dialog, dia_pos_x, hh/2 + offset_y );
8345           }
8346         }
8347         else {
8348           // Shift left<->right
8349           gint ww = vik_viewport_get_width ( vvp );
8350
8351           // Consider the difference in viewport to the full window
8352           gint offset_x = dest_x;
8353           // Add difference between dialog and window sizes
8354           offset_x += win_pos_x + (ww/2 - dia_size_x)/2;
8355
8356           if ( vp_xx > ww/2 ) {
8357             // Point on right, move window to left
8358             gtk_window_move ( dialog, offset_x, dia_pos_y );
8359           }
8360           else {
8361             // Point on left, move right
8362             gtk_window_move ( dialog, ww/2 + offset_x, dia_pos_y );
8363           }
8364         }
8365       }
8366     }
8367   }
8368 }
8369
8370 static void trw_layer_tpwin_init ( VikTrwLayer *vtl )
8371 {
8372   if ( ! vtl->tpwin )
8373   {
8374     vtl->tpwin = vik_trw_layer_tpwin_new ( VIK_GTK_WINDOW_FROM_LAYER(vtl) );
8375     g_signal_connect_swapped ( GTK_DIALOG(vtl->tpwin), "response", G_CALLBACK(trw_layer_tpwin_response), vtl );
8376     /* connect signals -- DELETE SIGNAL VERY IMPORTANT TO SET TO NULL */
8377     g_signal_connect_swapped ( vtl->tpwin, "delete-event", G_CALLBACK(trw_layer_cancel_current_tp), vtl );
8378
8379     gtk_widget_show_all ( GTK_WIDGET(vtl->tpwin) );
8380
8381     if ( vtl->current_tpl ) {
8382       // get tp pixel position
8383       VikTrackpoint *tp = VIK_TRACKPOINT(vtl->current_tpl->data);
8384
8385       // Shift up<->down to try not to obscure the trackpoint.
8386       trw_layer_dialog_shift ( vtl, GTK_WINDOW(vtl->tpwin), &(tp->coord), TRUE );
8387     }
8388   }
8389
8390   if ( vtl->current_tpl )
8391     if ( vtl->current_tp_track )
8392       vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
8393   /* set layer name and TP data */
8394 }
8395
8396 /***************************************************************************
8397  ** Tool code
8398  ***************************************************************************/
8399
8400 /*** Utility data structures and functions ****/
8401
8402 typedef struct {
8403   gint x, y;
8404   gint closest_x, closest_y;
8405   gboolean draw_images;
8406   gpointer *closest_wp_id;
8407   VikWaypoint *closest_wp;
8408   VikViewport *vvp;
8409 } WPSearchParams;
8410
8411 typedef struct {
8412   gint x, y;
8413   gint closest_x, closest_y;
8414   gpointer closest_track_id;
8415   VikTrackpoint *closest_tp;
8416   VikViewport *vvp;
8417   GList *closest_tpl;
8418   LatLonBBox bbox;
8419 } TPSearchParams;
8420
8421 static void waypoint_search_closest_tp ( gpointer id, VikWaypoint *wp, WPSearchParams *params )
8422 {
8423   gint x, y;
8424   if ( !wp->visible )
8425     return;
8426
8427   vik_viewport_coord_to_screen ( params->vvp, &(wp->coord), &x, &y );
8428
8429   // If waypoint has an image then use the image size to select
8430   if ( params->draw_images && wp->image ) {
8431     gint slackx, slacky;
8432     slackx = wp->image_width / 2;
8433     slacky = wp->image_height / 2;
8434
8435     if (    x <= params->x + slackx && x >= params->x - slackx
8436          && y <= params->y + slacky && y >= params->y - slacky ) {
8437       params->closest_wp_id = id;
8438       params->closest_wp = wp;
8439       params->closest_x = x;
8440       params->closest_y = y;
8441     }
8442   }
8443   else if ( abs (x - params->x) <= WAYPOINT_SIZE_APPROX && abs (y - params->y) <= WAYPOINT_SIZE_APPROX &&
8444             ((!params->closest_wp) ||        /* was the old waypoint we already found closer than this one? */
8445              abs(x - params->x)+abs(y - params->y) < abs(x - params->closest_x)+abs(y - params->closest_y)))
8446     {
8447       params->closest_wp_id = id;
8448       params->closest_wp = wp;
8449       params->closest_x = x;
8450       params->closest_y = y;
8451     }
8452 }
8453
8454 static void track_search_closest_tp ( gpointer id, VikTrack *t, TPSearchParams *params )
8455 {
8456   GList *tpl = t->trackpoints;
8457   VikTrackpoint *tp;
8458
8459   if ( !t->visible )
8460     return;
8461
8462   if ( ! BBOX_INTERSECT ( t->bbox, params->bbox ) )
8463     return;
8464
8465   while (tpl)
8466   {
8467     gint x, y;
8468     tp = VIK_TRACKPOINT(tpl->data);
8469
8470     vik_viewport_coord_to_screen ( params->vvp, &(tp->coord), &x, &y );
8471  
8472     if ( abs (x - params->x) <= TRACKPOINT_SIZE_APPROX && abs (y - params->y) <= TRACKPOINT_SIZE_APPROX &&
8473         ((!params->closest_tp) ||        /* was the old trackpoint we already found closer than this one? */
8474           abs(x - params->x)+abs(y - params->y) < abs(x - params->closest_x)+abs(y - params->closest_y)))
8475     {
8476       params->closest_track_id = id;
8477       params->closest_tp = tp;
8478       params->closest_tpl = tpl;
8479       params->closest_x = x;
8480       params->closest_y = y;
8481     }
8482     tpl = tpl->next;
8483   }
8484 }
8485
8486 // ATM: Leave this as 'Track' only.
8487 //  Not overly bothered about having a snap to route trackpoint capability
8488 static VikTrackpoint *closest_tp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y )
8489 {
8490   TPSearchParams params;
8491   params.x = x;
8492   params.y = y;
8493   params.vvp = vvp;
8494   params.closest_track_id = NULL;
8495   params.closest_tp = NULL;
8496   vik_viewport_get_min_max_lat_lon ( params.vvp, &(params.bbox.south), &(params.bbox.north), &(params.bbox.west), &(params.bbox.east) );
8497   g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, &params);
8498   return params.closest_tp;
8499 }
8500
8501 static VikWaypoint *closest_wp_in_five_pixel_interval ( VikTrwLayer *vtl, VikViewport *vvp, gint x, gint y )
8502 {
8503   WPSearchParams params;
8504   params.x = x;
8505   params.y = y;
8506   params.vvp = vvp;
8507   params.draw_images = vtl->drawimages;
8508   params.closest_wp = NULL;
8509   params.closest_wp_id = NULL;
8510   g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, &params);
8511   return params.closest_wp;
8512 }
8513
8514
8515 // Some forward declarations
8516 static void marker_begin_move ( tool_ed_t *t, gint x, gint y );
8517 static void marker_moveto ( tool_ed_t *t, gint x, gint y );
8518 static void marker_end_move ( tool_ed_t *t );
8519 //
8520
8521 static gboolean trw_layer_select_move ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t* t )
8522 {
8523   if ( t->holding ) {
8524     VikCoord new_coord;
8525     vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
8526
8527     // Here always allow snapping back to the original location
8528     //  this is useful when one decides not to move the thing afterall
8529     // If one wants to move the item only a little bit then don't hold down the 'snap' key!
8530  
8531     // snap to TP
8532     if ( event->state & GDK_CONTROL_MASK )
8533     {
8534       VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
8535       if ( tp )
8536         new_coord = tp->coord;
8537     }
8538
8539     // snap to WP
8540     if ( event->state & GDK_SHIFT_MASK )
8541     {
8542       VikWaypoint *wp = closest_wp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
8543       if ( wp )
8544         new_coord = wp->coord;
8545     }
8546     
8547     gint x, y;
8548     vik_viewport_coord_to_screen ( vvp, &new_coord, &x, &y );
8549
8550     marker_moveto ( t, x, y );
8551
8552     return TRUE;
8553   }
8554   return FALSE;
8555 }
8556
8557 static gboolean trw_layer_select_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t* t )
8558 {
8559   if ( t->holding && event->button == 1 )
8560   {
8561     VikCoord new_coord;
8562     vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
8563
8564     // snap to TP
8565     if ( event->state & GDK_CONTROL_MASK )
8566     {
8567       VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
8568       if ( tp )
8569         new_coord = tp->coord;
8570     }
8571
8572     // snap to WP
8573     if ( event->state & GDK_SHIFT_MASK )
8574     {
8575       VikWaypoint *wp = closest_wp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
8576       if ( wp )
8577         new_coord = wp->coord;
8578     }
8579
8580     marker_end_move ( t );
8581
8582     // Determine if working on a waypoint or a trackpoint
8583     if ( t->is_waypoint ) {
8584       // Update waypoint position
8585       vtl->current_wp->coord = new_coord;
8586       trw_layer_calculate_bounds_waypoints ( vtl );
8587       // Reset waypoint pointer
8588       vtl->current_wp    = NULL;
8589       vtl->current_wp_id = NULL;
8590     }
8591     else {
8592       if ( vtl->current_tpl ) {
8593         VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord;
8594
8595         if ( vtl->current_tp_track )
8596           vik_track_calculate_bounds ( vtl->current_tp_track );
8597
8598         if ( vtl->tpwin )
8599           if ( vtl->current_tp_track )
8600             vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
8601         // NB don't reset the selected trackpoint, thus ensuring it's still in the tpwin
8602       }
8603     }
8604
8605     vik_layer_emit_update ( VIK_LAYER(vtl) );
8606     return TRUE;
8607   }
8608   return FALSE;
8609 }
8610
8611 /*
8612   Returns true if a waypoint or track is found near the requested event position for this particular layer
8613   The item found is automatically selected
8614   This is a tool like feature but routed via the layer interface, since it's instigated by a 'global' layer tool in vikwindow.c
8615  */
8616 static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t* tet )
8617 {
8618   if ( event->button != 1 )
8619     return FALSE;
8620
8621   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
8622     return FALSE;
8623
8624   if ( !vtl->tracks_visible && !vtl->waypoints_visible && !vtl->routes_visible )
8625     return FALSE;
8626
8627   LatLonBBox bbox;
8628   vik_viewport_get_min_max_lat_lon ( vvp, &(bbox.south), &(bbox.north), &(bbox.west), &(bbox.east) );
8629
8630   // Go for waypoints first as these often will be near a track, but it's likely the wp is wanted rather then the track
8631
8632   if ( vtl->waypoints_visible && BBOX_INTERSECT (vtl->waypoints_bbox, bbox ) ) {
8633     WPSearchParams wp_params;
8634     wp_params.vvp = vvp;
8635     wp_params.x = event->x;
8636     wp_params.y = event->y;
8637     wp_params.draw_images = vtl->drawimages;
8638     wp_params.closest_wp_id = NULL;
8639     wp_params.closest_wp = NULL;
8640
8641     g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, &wp_params);
8642
8643     if ( wp_params.closest_wp )  {
8644
8645       // Select
8646       vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->waypoints_iters, wp_params.closest_wp_id ), TRUE );
8647
8648       // Too easy to move it so must be holding shift to start immediately moving it
8649       //   or otherwise be previously selected but not have an image (otherwise clicking within image bounds (again) moves it)
8650       if ( event->state & GDK_SHIFT_MASK ||
8651            ( vtl->current_wp == wp_params.closest_wp && !vtl->current_wp->image ) ) {
8652         // Put into 'move buffer'
8653         // NB vvp & vw already set in tet
8654         tet->vtl = (gpointer)vtl;
8655         tet->is_waypoint = TRUE;
8656       
8657         marker_begin_move (tet, event->x, event->y);
8658       }
8659
8660       vtl->current_wp =    wp_params.closest_wp;
8661       vtl->current_wp_id = wp_params.closest_wp_id;
8662
8663       vik_layer_emit_update ( VIK_LAYER(vtl) );
8664
8665       return TRUE;
8666     }
8667   }
8668
8669   // Used for both track and route lists
8670   TPSearchParams tp_params;
8671   tp_params.vvp = vvp;
8672   tp_params.x = event->x;
8673   tp_params.y = event->y;
8674   tp_params.closest_track_id = NULL;
8675   tp_params.closest_tp = NULL;
8676   tp_params.closest_tpl = NULL;
8677   tp_params.bbox = bbox;
8678
8679   if (vtl->tracks_visible) {
8680     g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, &tp_params);
8681
8682     if ( tp_params.closest_tp )  {
8683
8684       // Always select + highlight the track
8685       vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->tracks_iters, tp_params.closest_track_id ), TRUE );
8686
8687       tet->is_waypoint = FALSE;
8688
8689       // Select the Trackpoint
8690       // Can move it immediately when control held or it's the previously selected tp
8691       if ( event->state & GDK_CONTROL_MASK ||
8692            vtl->current_tpl == tp_params.closest_tpl ) {
8693         // Put into 'move buffer'
8694         // NB vvp & vw already set in tet
8695         tet->vtl = (gpointer)vtl;
8696         marker_begin_move (tet, event->x, event->y);
8697       }
8698
8699       vtl->current_tpl = tp_params.closest_tpl;
8700       vtl->current_tp_id = tp_params.closest_track_id;
8701       vtl->current_tp_track = g_hash_table_lookup ( vtl->tracks, tp_params.closest_track_id );
8702
8703       set_statusbar_msg_info_trkpt ( vtl, tp_params.closest_tp );
8704
8705       if ( vtl->tpwin )
8706         vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
8707
8708       vik_layer_emit_update ( VIK_LAYER(vtl) );
8709       return TRUE;
8710     }
8711   }
8712
8713   // Try again for routes
8714   if (vtl->routes_visible) {
8715     g_hash_table_foreach ( vtl->routes, (GHFunc) track_search_closest_tp, &tp_params);
8716
8717     if ( tp_params.closest_tp )  {
8718
8719       // Always select + highlight the track
8720       vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->routes_iters, tp_params.closest_track_id ), TRUE );
8721
8722       tet->is_waypoint = FALSE;
8723
8724       // Select the Trackpoint
8725       // Can move it immediately when control held or it's the previously selected tp
8726       if ( event->state & GDK_CONTROL_MASK ||
8727            vtl->current_tpl == tp_params.closest_tpl ) {
8728         // Put into 'move buffer'
8729         // NB vvp & vw already set in tet
8730         tet->vtl = (gpointer)vtl;
8731         marker_begin_move (tet, event->x, event->y);
8732       }
8733
8734       vtl->current_tpl = tp_params.closest_tpl;
8735       vtl->current_tp_id = tp_params.closest_track_id;
8736       vtl->current_tp_track = g_hash_table_lookup ( vtl->routes, tp_params.closest_track_id );
8737
8738       set_statusbar_msg_info_trkpt ( vtl, tp_params.closest_tp );
8739
8740       if ( vtl->tpwin )
8741         vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
8742
8743       vik_layer_emit_update ( VIK_LAYER(vtl) );
8744       return TRUE;
8745     }
8746   }
8747
8748   /* these aren't the droids you're looking for */
8749   vtl->current_wp    = NULL;
8750   vtl->current_wp_id = NULL;
8751   trw_layer_cancel_current_tp ( vtl, FALSE );
8752
8753   // Blank info
8754   vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO, "" );
8755
8756   return FALSE;
8757 }
8758
8759 static gboolean trw_layer_show_selected_viewport_menu ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
8760 {
8761   if ( event->button != 3 )
8762     return FALSE;
8763
8764   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
8765     return FALSE;
8766
8767   if ( !vtl->tracks_visible && !vtl->waypoints_visible && !vtl->routes_visible )
8768     return FALSE;
8769
8770   /* Post menu for the currently selected item */
8771
8772   /* See if a track is selected */
8773   VikTrack *track = (VikTrack*)vik_window_get_selected_track ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) );
8774   if ( track && track->visible ) {
8775
8776     if ( track->name ) {
8777
8778       if ( vtl->track_right_click_menu )
8779         g_object_ref_sink ( G_OBJECT(vtl->track_right_click_menu) );
8780
8781       vtl->track_right_click_menu = GTK_MENU ( gtk_menu_new () );
8782       
8783       trku_udata udataU;
8784       udataU.trk  = track;
8785       udataU.uuid = NULL;
8786
8787       gpointer *trkf;
8788       if ( track->is_route )
8789         trkf = g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find_uuid, &udataU );
8790       else
8791         trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udataU );
8792
8793       if ( trkf && udataU.uuid ) {
8794
8795         GtkTreeIter *iter;
8796         if ( track->is_route )
8797           iter = g_hash_table_lookup ( vtl->routes_iters, udataU.uuid );
8798         else
8799           iter = g_hash_table_lookup ( vtl->tracks_iters, udataU.uuid );
8800
8801         trw_layer_sublayer_add_menu_items ( vtl,
8802                                             vtl->track_right_click_menu,
8803                                             NULL,
8804                                             track->is_route ? VIK_TRW_LAYER_SUBLAYER_ROUTE : VIK_TRW_LAYER_SUBLAYER_TRACK,
8805                                             udataU.uuid,
8806                                             iter,
8807                                             vvp );
8808       }
8809
8810       gtk_menu_popup ( vtl->track_right_click_menu, NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time() );
8811         
8812       return TRUE;
8813     }
8814   }
8815
8816   /* See if a waypoint is selected */
8817   VikWaypoint *waypoint = (VikWaypoint*)vik_window_get_selected_waypoint ( (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl) );
8818   if ( waypoint && waypoint->visible ) {
8819     if ( waypoint->name ) {
8820
8821       if ( vtl->wp_right_click_menu )
8822         g_object_ref_sink ( G_OBJECT(vtl->wp_right_click_menu) );
8823
8824       vtl->wp_right_click_menu = GTK_MENU ( gtk_menu_new () );
8825
8826       wpu_udata udata;
8827       udata.wp   = waypoint;
8828       udata.uuid = NULL;
8829
8830       gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata );
8831
8832       if ( wpf && udata.uuid ) {
8833         GtkTreeIter *iter = g_hash_table_lookup ( vtl->waypoints_iters, udata.uuid );
8834
8835         trw_layer_sublayer_add_menu_items ( vtl,
8836                                             vtl->wp_right_click_menu,
8837                                             NULL,
8838                                             VIK_TRW_LAYER_SUBLAYER_WAYPOINT,
8839                                             udata.uuid,
8840                                             iter,
8841                                             vvp );
8842       }
8843       gtk_menu_popup ( vtl->wp_right_click_menu, NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time() );
8844
8845       return TRUE;
8846     }
8847   }
8848
8849   return FALSE;
8850 }
8851
8852 /* background drawing hook, to be passed the viewport */
8853 static gboolean tool_sync_done = TRUE;
8854
8855 static gboolean tool_sync(gpointer data)
8856 {
8857   VikViewport *vvp = data;
8858   gdk_threads_enter();
8859   vik_viewport_sync(vvp);
8860   tool_sync_done = TRUE;
8861   gdk_threads_leave();
8862   return FALSE;
8863 }
8864
8865 static void marker_begin_move ( tool_ed_t *t, gint x, gint y )
8866 {
8867   t->holding = TRUE;
8868   t->gc = vik_viewport_new_gc (t->vvp, "black", 2);
8869   gdk_gc_set_function ( t->gc, GDK_INVERT );
8870   vik_viewport_draw_rectangle ( t->vvp, t->gc, FALSE, x-3, y-3, 6, 6 );
8871   vik_viewport_sync(t->vvp);
8872   t->oldx = x;
8873   t->oldy = y;
8874 }
8875
8876 static void marker_moveto ( tool_ed_t *t, gint x, gint y )
8877 {
8878   VikViewport *vvp =  t->vvp;
8879   vik_viewport_draw_rectangle ( vvp, t->gc, FALSE, t->oldx-3, t->oldy-3, 6, 6 );
8880   vik_viewport_draw_rectangle ( vvp, t->gc, FALSE, x-3, y-3, 6, 6 );
8881   t->oldx = x;
8882   t->oldy = y;
8883
8884   if (tool_sync_done) {
8885     g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, tool_sync, vvp, NULL);
8886     tool_sync_done = FALSE;
8887   }
8888 }
8889
8890 static void marker_end_move ( tool_ed_t *t )
8891 {
8892   vik_viewport_draw_rectangle ( t->vvp, t->gc, FALSE, t->oldx-3, t->oldy-3, 6, 6 );
8893   g_object_unref ( t->gc );
8894   t->holding = FALSE;
8895 }
8896
8897 /*** Edit waypoint ****/
8898
8899 static gpointer tool_edit_waypoint_create ( VikWindow *vw, VikViewport *vvp)
8900 {
8901   tool_ed_t *t = g_new(tool_ed_t, 1);
8902   t->vvp = vvp;
8903   t->holding = FALSE;
8904   return t;
8905 }
8906
8907 static void tool_edit_waypoint_destroy ( tool_ed_t *t )
8908 {
8909   g_free ( t );
8910 }
8911
8912 static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data )
8913 {
8914   WPSearchParams params;
8915   tool_ed_t *t = data;
8916   VikViewport *vvp = t->vvp;
8917
8918   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
8919     return FALSE;
8920
8921   if ( t->holding ) {
8922     return TRUE;
8923   }
8924
8925   if ( !vtl->vl.visible || !vtl->waypoints_visible )
8926     return FALSE;
8927
8928   if ( vtl->current_wp && vtl->current_wp->visible )
8929   {
8930     /* first check if current WP is within area (other may be 'closer', but we want to move the current) */
8931     gint x, y;
8932     vik_viewport_coord_to_screen ( vvp, &(vtl->current_wp->coord), &x, &y );
8933
8934     if ( abs(x - event->x) <= WAYPOINT_SIZE_APPROX &&
8935          abs(y - event->y) <= WAYPOINT_SIZE_APPROX )
8936     {
8937       if ( event->button == 3 )
8938         vtl->waypoint_rightclick = TRUE; /* remember that we're clicking; other layers will ignore release signal */
8939       else {
8940         marker_begin_move(t, event->x, event->y);
8941       }
8942       return TRUE;
8943     }
8944   }
8945
8946   params.vvp = vvp;
8947   params.x = event->x;
8948   params.y = event->y;
8949   params.draw_images = vtl->drawimages;
8950   params.closest_wp_id = NULL;
8951   /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */
8952   params.closest_wp = NULL;
8953   g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, &params);
8954   if ( vtl->current_wp == params.closest_wp && vtl->current_wp != NULL )
8955   {
8956     // how do we get here?
8957     marker_begin_move(t, event->x, event->y);
8958     g_critical("shouldn't be here");
8959     return FALSE;
8960   }
8961   else if ( params.closest_wp )
8962   {
8963     if ( event->button == 3 )
8964       vtl->waypoint_rightclick = TRUE; /* remember that we're clicking; other layers will ignore release signal */
8965     else
8966       vtl->waypoint_rightclick = FALSE;
8967
8968     vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->waypoints_iters, params.closest_wp_id ), TRUE );
8969
8970     vtl->current_wp = params.closest_wp;
8971     vtl->current_wp_id = params.closest_wp_id;
8972
8973     /* could make it so don't update if old WP is off screen and new is null but oh well */
8974     vik_layer_emit_update ( VIK_LAYER(vtl) );
8975     return TRUE;
8976   }
8977
8978   vtl->current_wp = NULL;
8979   vtl->current_wp_id = NULL;
8980   vtl->waypoint_rightclick = FALSE;
8981   vik_layer_emit_update ( VIK_LAYER(vtl) );
8982   return FALSE;
8983 }
8984
8985 static gboolean tool_edit_waypoint_move ( VikTrwLayer *vtl, GdkEventMotion *event, gpointer data )
8986 {
8987   tool_ed_t *t = data;
8988   VikViewport *vvp = t->vvp;
8989
8990   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
8991     return FALSE;
8992
8993   if ( t->holding ) {
8994     VikCoord new_coord;
8995     vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
8996
8997     /* snap to TP */
8998     if ( event->state & GDK_CONTROL_MASK )
8999     {
9000       VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
9001       if ( tp )
9002         new_coord = tp->coord;
9003     }
9004
9005     /* snap to WP */
9006     if ( event->state & GDK_SHIFT_MASK )
9007     {
9008       VikWaypoint *wp = closest_wp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
9009       if ( wp && wp != vtl->current_wp )
9010         new_coord = wp->coord;
9011     }
9012     
9013     { 
9014       gint x, y;
9015       vik_viewport_coord_to_screen ( vvp, &new_coord, &x, &y );
9016
9017       marker_moveto ( t, x, y );
9018     } 
9019     return TRUE;
9020   }
9021   return FALSE;
9022 }
9023
9024 static gboolean tool_edit_waypoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data )
9025 {
9026   tool_ed_t *t = data;
9027   VikViewport *vvp = t->vvp;
9028
9029   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
9030     return FALSE;
9031   
9032   if ( t->holding && event->button == 1 )
9033   {
9034     VikCoord new_coord;
9035     vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
9036
9037     /* snap to TP */
9038     if ( event->state & GDK_CONTROL_MASK )
9039     {
9040       VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
9041       if ( tp )
9042         new_coord = tp->coord;
9043     }
9044
9045     /* snap to WP */
9046     if ( event->state & GDK_SHIFT_MASK )
9047     {
9048       VikWaypoint *wp = closest_wp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
9049       if ( wp && wp != vtl->current_wp )
9050         new_coord = wp->coord;
9051     }
9052
9053     marker_end_move ( t );
9054
9055     vtl->current_wp->coord = new_coord;
9056
9057     trw_layer_calculate_bounds_waypoints ( vtl );
9058     vik_layer_emit_update ( VIK_LAYER(vtl) );
9059     return TRUE;
9060   }
9061   /* PUT IN RIGHT PLACE!!! */
9062   if ( event->button == 3 && vtl->waypoint_rightclick )
9063   {
9064     if ( vtl->wp_right_click_menu )
9065       g_object_ref_sink ( G_OBJECT(vtl->wp_right_click_menu) );
9066     if ( vtl->current_wp ) {
9067       vtl->wp_right_click_menu = GTK_MENU ( gtk_menu_new () );
9068       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 );
9069       gtk_menu_popup ( vtl->wp_right_click_menu, NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time() );
9070     }
9071     vtl->waypoint_rightclick = FALSE;
9072   }
9073   return FALSE;
9074 }
9075
9076 /*** New track ****/
9077
9078 static gpointer tool_new_track_create ( VikWindow *vw, VikViewport *vvp)
9079 {
9080   return vvp;
9081 }
9082
9083 typedef struct {
9084   VikTrwLayer *vtl;
9085   GdkDrawable *drawable;
9086   GdkGC *gc;
9087   GdkPixmap *pixmap;
9088 } draw_sync_t;
9089
9090 /*
9091  * Draw specified pixmap
9092  */
9093 static gboolean draw_sync ( gpointer data )
9094 {
9095   draw_sync_t *ds = (draw_sync_t*) data;
9096   // Sometimes don't want to draw
9097   //  normally because another update has taken precedent such as panning the display
9098   //   which means this pixmap is no longer valid
9099   if ( ds->vtl->draw_sync_do ) {
9100     gdk_threads_enter();
9101     gdk_draw_drawable (ds->drawable,
9102                        ds->gc,
9103                        ds->pixmap,
9104                        0, 0, 0, 0, -1, -1);
9105     ds->vtl->draw_sync_done = TRUE;
9106     gdk_threads_leave();
9107   }
9108   g_free ( ds );
9109   return FALSE;
9110 }
9111
9112 static gchar* distance_string (gdouble distance)
9113 {
9114   gchar str[128];
9115
9116   /* draw label with distance */
9117   vik_units_distance_t dist_units = a_vik_get_units_distance ();
9118   switch (dist_units) {
9119   case VIK_UNITS_DISTANCE_MILES:
9120     if (distance >= VIK_MILES_TO_METERS(1) && distance < VIK_MILES_TO_METERS(100)) {
9121       g_sprintf(str, "%3.2f miles", VIK_METERS_TO_MILES(distance));
9122     } else if (distance < 1609.4) {
9123       g_sprintf(str, "%d yards", (int)(distance*1.0936133));
9124     } else {
9125       g_sprintf(str, "%d miles", (int)VIK_METERS_TO_MILES(distance));
9126     }
9127     break;
9128   default:
9129     // VIK_UNITS_DISTANCE_KILOMETRES
9130     if (distance >= 1000 && distance < 100000) {
9131       g_sprintf(str, "%3.2f km", distance/1000.0);
9132     } else if (distance < 1000) {
9133       g_sprintf(str, "%d m", (int)distance);
9134     } else {
9135       g_sprintf(str, "%d km", (int)distance/1000);
9136     }
9137     break;
9138   }
9139   return g_strdup (str);
9140 }
9141
9142 /*
9143  * Actually set the message in statusbar
9144  */
9145 static void statusbar_write (gdouble distance, gdouble elev_gain, gdouble elev_loss, gdouble last_step, gdouble angle, VikTrwLayer *vtl )
9146 {
9147   // Only show elevation data when track has some elevation properties
9148   gchar str_gain_loss[64];
9149   str_gain_loss[0] = '\0';
9150   gchar str_last_step[64];
9151   str_last_step[0] = '\0';
9152   gchar *str_total = distance_string (distance);
9153   
9154   if ( (elev_gain > 0.1) || (elev_loss > 0.1) ) {
9155     if ( a_vik_get_units_height () == VIK_UNITS_HEIGHT_METRES )
9156       g_sprintf(str_gain_loss, _(" - Gain %dm:Loss %dm"), (int)elev_gain, (int)elev_loss);
9157     else
9158       g_sprintf(str_gain_loss, _(" - Gain %dft:Loss %dft"), (int)VIK_METERS_TO_FEET(elev_gain), (int)VIK_METERS_TO_FEET(elev_loss));
9159   }
9160   
9161   if ( last_step > 0 ) {
9162       gchar *tmp = distance_string (last_step);
9163       g_sprintf(str_last_step, _(" - Bearing %3.1f° - Step %s"), RAD2DEG(angle), tmp);
9164       g_free ( tmp );
9165   }
9166   
9167   VikWindow *vw = VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl));
9168
9169   // Write with full gain/loss information
9170   gchar *msg = g_strdup_printf ( "Total %s%s%s", str_total, str_last_step, str_gain_loss);
9171   vik_statusbar_set_message ( vik_window_get_statusbar (vw), VIK_STATUSBAR_INFO, msg );
9172   g_free ( msg );
9173   g_free ( str_total );
9174 }
9175
9176 /*
9177  * Figure out what information should be set in the statusbar and then write it
9178  */
9179 static void update_statusbar ( VikTrwLayer *vtl )
9180 {
9181   // Get elevation data
9182   gdouble elev_gain, elev_loss;
9183   vik_track_get_total_elevation_gain ( vtl->current_track, &elev_gain, &elev_loss);
9184
9185   /* Find out actual distance of current track */
9186   gdouble distance = vik_track_get_length (vtl->current_track);
9187
9188   statusbar_write (distance, elev_gain, elev_loss, 0, 0, vtl);
9189 }
9190
9191
9192 static VikLayerToolFuncStatus tool_new_track_move ( VikTrwLayer *vtl, GdkEventMotion *event, VikViewport *vvp )
9193 {
9194   /* if we haven't sync'ed yet, we don't have time to do more. */
9195   if ( vtl->draw_sync_done && vtl->current_track && vtl->current_track->trackpoints ) {
9196     GList *iter = g_list_last ( vtl->current_track->trackpoints );
9197     VikTrackpoint *last_tpt = VIK_TRACKPOINT(iter->data);
9198
9199     static GdkPixmap *pixmap = NULL;
9200     int w1, h1, w2, h2;
9201     // Need to check in case window has been resized
9202     w1 = vik_viewport_get_width(vvp);
9203     h1 = vik_viewport_get_height(vvp);
9204     if (!pixmap) {
9205       pixmap = gdk_pixmap_new ( gtk_widget_get_window(GTK_WIDGET(vvp)), w1, h1, -1 );
9206     }
9207     gdk_drawable_get_size (pixmap, &w2, &h2);
9208     if (w1 != w2 || h1 != h2) {
9209       g_object_unref ( G_OBJECT ( pixmap ) );
9210       pixmap = gdk_pixmap_new ( gtk_widget_get_window(GTK_WIDGET(vvp)), w1, h1, -1 );
9211     }
9212
9213     // Reset to background
9214     gdk_draw_drawable (pixmap,
9215                        vtl->current_track_newpoint_gc,
9216                        vik_viewport_get_pixmap(vvp),
9217                        0, 0, 0, 0, -1, -1);
9218
9219     draw_sync_t *passalong;
9220     gint x1, y1;
9221
9222     vik_viewport_coord_to_screen ( vvp, &(last_tpt->coord), &x1, &y1 );
9223
9224     // FOR SCREEN OVERLAYS WE MUST DRAW INTO THIS PIXMAP (when using the reset method)
9225     //  otherwise using vik_viewport_draw_* functions puts the data into the base pixmap,
9226     //  thus when we come to reset to the background it would include what we have already drawn!!
9227     gdk_draw_line ( pixmap,
9228                     vtl->current_track_newpoint_gc,
9229                     x1, y1, event->x, event->y );
9230     // Using this reset method is more reliable than trying to undraw previous efforts via the GDK_INVERT method
9231
9232     /* Find out actual distance of current track */
9233     gdouble distance = vik_track_get_length (vtl->current_track);
9234
9235     // Now add distance to where the pointer is //
9236     VikCoord coord;
9237     struct LatLon ll;
9238     vik_viewport_screen_to_coord ( vvp, (gint) event->x, (gint) event->y, &coord );
9239     vik_coord_to_latlon ( &coord, &ll );
9240     gdouble last_step = vik_coord_diff( &coord, &(last_tpt->coord));
9241     distance = distance + last_step;
9242
9243     // Get elevation data
9244     gdouble elev_gain, elev_loss;
9245     vik_track_get_total_elevation_gain ( vtl->current_track, &elev_gain, &elev_loss);
9246
9247     // Adjust elevation data (if available) for the current pointer position
9248     gdouble elev_new;
9249     elev_new = (gdouble) a_dems_get_elev_by_coord ( &coord, VIK_DEM_INTERPOL_BEST );
9250     if ( elev_new != VIK_DEM_INVALID_ELEVATION ) {
9251       if ( last_tpt->altitude != VIK_DEFAULT_ALTITUDE ) {
9252         // Adjust elevation of last track point
9253         if ( elev_new > last_tpt->altitude )
9254           // Going up
9255           elev_gain += elev_new - last_tpt->altitude;
9256         else
9257           // Going down
9258           elev_loss += last_tpt->altitude - elev_new;
9259       }
9260     }
9261
9262     //
9263     // Display of the distance 'tooltip' during track creation is controlled by a preference
9264     //
9265     if ( a_vik_get_create_track_tooltip() ) {
9266
9267       gchar *str = distance_string (distance);
9268
9269       PangoLayout *pl = gtk_widget_create_pango_layout (GTK_WIDGET(vvp), NULL);
9270       pango_layout_set_font_description (pl, gtk_widget_get_style(GTK_WIDGET(vvp))->font_desc);
9271       pango_layout_set_text (pl, str, -1);
9272       gint wd, hd;
9273       pango_layout_get_pixel_size ( pl, &wd, &hd );
9274
9275       gint xd,yd;
9276       // offset from cursor a bit depending on font size
9277       xd = event->x + 10;
9278       yd = event->y - hd;
9279
9280       // Create a background block to make the text easier to read over the background map
9281       GdkGC *background_block_gc = vik_viewport_new_gc ( vvp, "#cccccc", 1);
9282       gdk_draw_rectangle (pixmap, background_block_gc, TRUE, xd-2, yd-2, wd+4, hd+2);
9283       gdk_draw_layout (pixmap, vtl->current_track_newpoint_gc, xd, yd, pl);
9284
9285       g_object_unref ( G_OBJECT ( pl ) );
9286       g_object_unref ( G_OBJECT ( background_block_gc ) );
9287       g_free (str);
9288     }
9289
9290     passalong = g_new(draw_sync_t,1); // freed by draw_sync()
9291     passalong->vtl = vtl;
9292     passalong->pixmap = pixmap;
9293     passalong->drawable = gtk_widget_get_window(GTK_WIDGET(vvp));
9294     passalong->gc = vtl->current_track_newpoint_gc;
9295
9296     gdouble angle;
9297     gdouble baseangle;
9298     vik_viewport_compute_bearing ( vvp, x1, y1, event->x, event->y, &angle, &baseangle );
9299
9300     // Update statusbar with full gain/loss information
9301     statusbar_write (distance, elev_gain, elev_loss, last_step, angle, vtl);
9302
9303     // draw pixmap when we have time to
9304     g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, draw_sync, passalong, NULL);
9305     vtl->draw_sync_done = FALSE;
9306     return VIK_LAYER_TOOL_ACK_GRAB_FOCUS;
9307   }
9308   return VIK_LAYER_TOOL_ACK;
9309 }
9310
9311 static gboolean tool_new_track_key_press ( VikTrwLayer *vtl, GdkEventKey *event, VikViewport *vvp )
9312 {
9313   if ( vtl->current_track && event->keyval == GDK_Escape ) {
9314     vtl->current_track = NULL;
9315     vik_layer_emit_update ( VIK_LAYER(vtl) );
9316     return TRUE;
9317   } else if ( vtl->current_track && event->keyval == GDK_BackSpace ) {
9318     /* undo */
9319     if ( vtl->current_track->trackpoints )
9320     {
9321       GList *last = g_list_last(vtl->current_track->trackpoints);
9322       g_free ( last->data );
9323       vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last );
9324     }
9325
9326     update_statusbar ( vtl );
9327
9328     vik_layer_emit_update ( VIK_LAYER(vtl) );
9329     return TRUE;
9330   }
9331   return FALSE;
9332 }
9333
9334 /*
9335  * Common function to handle trackpoint button requests on either a route or a track
9336  *  . enables adding a point via normal click
9337  *  . enables removal of last point via right click
9338  *  . finishing of the track or route via double clicking
9339  */
9340 static gboolean tool_new_track_or_route_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
9341 {
9342   VikTrackpoint *tp;
9343
9344   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
9345     return FALSE;
9346
9347   if ( event->button == 2 ) {
9348     // As the display is panning, the new track pixmap is now invalid so don't draw it
9349     //  otherwise this drawing done results in flickering back to an old image
9350     vtl->draw_sync_do = FALSE;
9351     return FALSE;
9352   }
9353
9354   if ( event->button == 3 )
9355   {
9356     if ( !vtl->current_track )
9357       return FALSE;
9358     /* undo */
9359     if ( vtl->current_track->trackpoints )
9360     {
9361       GList *last = g_list_last(vtl->current_track->trackpoints);
9362       g_free ( last->data );
9363       vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last );
9364     }
9365     vik_track_calculate_bounds ( vtl->current_track );
9366     update_statusbar ( vtl );
9367
9368     vik_layer_emit_update ( VIK_LAYER(vtl) );
9369     return TRUE;
9370   }
9371
9372   if ( event->type == GDK_2BUTTON_PRESS )
9373   {
9374     /* subtract last (duplicate from double click) tp then end */
9375     if ( vtl->current_track && vtl->current_track->trackpoints && vtl->ct_x1 == vtl->ct_x2 && vtl->ct_y1 == vtl->ct_y2 )
9376     {
9377       GList *last = g_list_last(vtl->current_track->trackpoints);
9378       g_free ( last->data );
9379       vtl->current_track->trackpoints = g_list_remove_link ( vtl->current_track->trackpoints, last );
9380       /* undo last, then end */
9381       vtl->current_track = NULL;
9382     }
9383     vik_layer_emit_update ( VIK_LAYER(vtl) );
9384     return TRUE;
9385   }
9386
9387   tp = vik_trackpoint_new();
9388   vik_viewport_screen_to_coord ( vvp, event->x, event->y, &(tp->coord) );
9389
9390   /* snap to other TP */
9391   if ( event->state & GDK_CONTROL_MASK )
9392   {
9393     VikTrackpoint *other_tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
9394     if ( other_tp )
9395       tp->coord = other_tp->coord;
9396   }
9397
9398   tp->newsegment = FALSE;
9399   tp->has_timestamp = FALSE;
9400   tp->timestamp = 0;
9401
9402   if ( vtl->current_track ) {
9403     vik_track_add_trackpoint ( vtl->current_track, tp, TRUE ); // Ensure bounds is updated
9404     /* Auto attempt to get elevation from DEM data (if it's available) */
9405     vik_track_apply_dem_data_last_trackpoint ( vtl->current_track );
9406   }
9407
9408   vtl->ct_x1 = vtl->ct_x2;
9409   vtl->ct_y1 = vtl->ct_y2;
9410   vtl->ct_x2 = event->x;
9411   vtl->ct_y2 = event->y;
9412
9413   vik_layer_emit_update ( VIK_LAYER(vtl) );
9414   return TRUE;
9415 }
9416
9417 static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
9418 {
9419   // ----------------------------------------------------- if current is a route - switch to new track
9420   if ( event->button == 1 && ( ! vtl->current_track || (vtl->current_track && vtl->current_track->is_route ) ))
9421   {
9422     gchar *name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, _("Track"));
9423     if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), name, FALSE ) ) )
9424     {
9425       new_track_create_common ( vtl, name );
9426       g_free ( name );
9427     }
9428     else
9429       return TRUE;
9430   }
9431   return tool_new_track_or_route_click ( vtl, event, vvp );
9432 }
9433
9434 static void tool_new_track_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
9435 {
9436   if ( event->button == 2 ) {
9437     // Pan moving ended - enable potential point drawing again
9438     vtl->draw_sync_do = TRUE;
9439     vtl->draw_sync_done = TRUE;
9440   }
9441 }
9442
9443 /*** New route ****/
9444
9445 static gpointer tool_new_route_create ( VikWindow *vw, VikViewport *vvp)
9446 {
9447   return vvp;
9448 }
9449
9450 static gboolean tool_new_route_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
9451 {
9452   // -------------------------- if current is a track - switch to new route
9453   if ( event->button == 1 && ( ! vtl->current_track || (vtl->current_track && !vtl->current_track->is_route ) ) )
9454   {
9455     gchar *name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_ROUTE, _("Route"));
9456     if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), name, TRUE ) ) ) {
9457       new_route_create_common ( vtl, name );
9458       g_free ( name );
9459     }
9460     else
9461       return TRUE;
9462   }
9463   return tool_new_track_or_route_click ( vtl, event, vvp );
9464 }
9465
9466 /*** New waypoint ****/
9467
9468 static gpointer tool_new_waypoint_create ( VikWindow *vw, VikViewport *vvp)
9469 {
9470   return vvp;
9471 }
9472
9473 static gboolean tool_new_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
9474 {
9475   VikCoord coord;
9476   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
9477     return FALSE;
9478   vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
9479   if (vik_trw_layer_new_waypoint ( vtl, VIK_GTK_WINDOW_FROM_LAYER(vtl), &coord ) && VIK_LAYER(vtl)->visible) {
9480     trw_layer_calculate_bounds_waypoints ( vtl );
9481     vik_layer_emit_update ( VIK_LAYER(vtl) );
9482   }
9483   return TRUE;
9484 }
9485
9486
9487 /*** Edit trackpoint ****/
9488
9489 static gpointer tool_edit_trackpoint_create ( VikWindow *vw, VikViewport *vvp)
9490 {
9491   tool_ed_t *t = g_new(tool_ed_t, 1);
9492   t->vvp = vvp;
9493   t->holding = FALSE;
9494   return t;
9495 }
9496
9497 static void tool_edit_trackpoint_destroy ( tool_ed_t *t )
9498 {
9499   g_free ( t );
9500 }
9501
9502 static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data )
9503 {
9504   tool_ed_t *t = data;
9505   VikViewport *vvp = t->vvp;
9506   TPSearchParams params;
9507   /* OUTDATED DOCUMENTATION:
9508    find 5 pixel range on each side. then put these UTM, and a pointer
9509    to the winning track name (and maybe the winning track itself), and a
9510    pointer to the winning trackpoint, inside an array or struct. pass 
9511    this along, do a foreach on the tracks which will do a foreach on the 
9512    trackpoints. */
9513   params.vvp = vvp;
9514   params.x = event->x;
9515   params.y = event->y;
9516   params.closest_track_id = NULL;
9517   /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */
9518   params.closest_tp = NULL;
9519   params.closest_tpl = NULL;
9520   vik_viewport_get_min_max_lat_lon ( vvp, &(params.bbox.south), &(params.bbox.north), &(params.bbox.west), &(params.bbox.east) );
9521
9522   if ( event->button != 1 ) 
9523     return FALSE;
9524
9525   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
9526     return FALSE;
9527
9528   if ( !vtl->vl.visible || !vtl->tracks_visible || !vtl->routes_visible )
9529     return FALSE;
9530
9531   if ( vtl->current_tpl )
9532   {
9533     /* 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.) */
9534     VikTrackpoint *tp = VIK_TRACKPOINT(vtl->current_tpl->data);
9535     VikTrack *current_tr = VIK_TRACK(g_hash_table_lookup(vtl->tracks, vtl->current_tp_id));
9536     if ( !current_tr )
9537       return FALSE;
9538
9539     gint x, y;
9540     vik_viewport_coord_to_screen ( vvp, &(tp->coord), &x, &y );
9541
9542     if ( current_tr->visible && 
9543          abs(x - event->x) < TRACKPOINT_SIZE_APPROX &&
9544          abs(y - event->y) < TRACKPOINT_SIZE_APPROX ) {
9545       marker_begin_move ( t, event->x, event->y );
9546       return TRUE;
9547     }
9548
9549   }
9550
9551   if ( vtl->tracks_visible )
9552     g_hash_table_foreach ( vtl->tracks, (GHFunc) track_search_closest_tp, &params);
9553
9554   if ( params.closest_tp )
9555   {
9556     vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->tracks_iters, params.closest_track_id ), TRUE );
9557     vtl->current_tpl = params.closest_tpl;
9558     vtl->current_tp_id = params.closest_track_id;
9559     vtl->current_tp_track = g_hash_table_lookup ( vtl->tracks, params.closest_track_id );
9560     trw_layer_tpwin_init ( vtl );
9561     set_statusbar_msg_info_trkpt ( vtl, params.closest_tp );
9562     vik_layer_emit_update ( VIK_LAYER(vtl) );
9563     return TRUE;
9564   }
9565
9566   if ( vtl->routes_visible )
9567     g_hash_table_foreach ( vtl->routes, (GHFunc) track_search_closest_tp, &params);
9568
9569   if ( params.closest_tp )
9570   {
9571     vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup ( vtl->routes_iters, params.closest_track_id ), TRUE );
9572     vtl->current_tpl = params.closest_tpl;
9573     vtl->current_tp_id = params.closest_track_id;
9574     vtl->current_tp_track = g_hash_table_lookup ( vtl->routes, params.closest_track_id );
9575     trw_layer_tpwin_init ( vtl );
9576     set_statusbar_msg_info_trkpt ( vtl, params.closest_tp );
9577     vik_layer_emit_update ( VIK_LAYER(vtl) );
9578     return TRUE;
9579   }
9580
9581   /* these aren't the droids you're looking for */
9582   return FALSE;
9583 }
9584
9585 static gboolean tool_edit_trackpoint_move ( VikTrwLayer *vtl, GdkEventMotion *event, gpointer data )
9586 {
9587   tool_ed_t *t = data;
9588   VikViewport *vvp = t->vvp;
9589
9590   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
9591     return FALSE;
9592
9593   if ( t->holding )
9594   {
9595     VikCoord new_coord;
9596     vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
9597
9598     /* snap to TP */
9599     if ( event->state & GDK_CONTROL_MASK )
9600     {
9601       VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
9602       if ( tp && tp != vtl->current_tpl->data )
9603         new_coord = tp->coord;
9604     }
9605     //    VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord;
9606     { 
9607       gint x, y;
9608       vik_viewport_coord_to_screen ( vvp, &new_coord, &x, &y );
9609       marker_moveto ( t, x, y );
9610     } 
9611
9612     return TRUE;
9613   }
9614   return FALSE;
9615 }
9616
9617 static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data )
9618 {
9619   tool_ed_t *t = data;
9620   VikViewport *vvp = t->vvp;
9621
9622   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
9623     return FALSE;
9624   if ( event->button != 1) 
9625     return FALSE;
9626
9627   if ( t->holding ) {
9628     VikCoord new_coord;
9629     vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
9630
9631     /* snap to TP */
9632     if ( event->state & GDK_CONTROL_MASK )
9633     {
9634       VikTrackpoint *tp = closest_tp_in_five_pixel_interval ( vtl, vvp, event->x, event->y );
9635       if ( tp && tp != vtl->current_tpl->data )
9636         new_coord = tp->coord;
9637     }
9638
9639     VIK_TRACKPOINT(vtl->current_tpl->data)->coord = new_coord;
9640     if ( vtl->current_tp_track )
9641       vik_track_calculate_bounds ( vtl->current_tp_track );
9642
9643     marker_end_move ( t );
9644
9645     /* diff dist is diff from orig */
9646     if ( vtl->tpwin )
9647       vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
9648
9649     vik_layer_emit_update ( VIK_LAYER(vtl) );
9650     return TRUE;
9651   }
9652   return FALSE;
9653 }
9654
9655
9656 /*** Route Finder ***/
9657 static gpointer tool_route_finder_create ( VikWindow *vw, VikViewport *vvp)
9658 {
9659   return vvp;
9660 }
9661
9662 static gboolean tool_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
9663 {
9664   VikCoord tmp;
9665   if ( !vtl ) return FALSE;
9666   vik_viewport_screen_to_coord ( vvp, event->x, event->y, &tmp );
9667   if ( event->button == 3 && vtl->route_finder_current_track ) {
9668     VikCoord *new_end;
9669     new_end = vik_track_cut_back_to_double_point ( vtl->route_finder_current_track );
9670     if ( new_end ) {
9671       vtl->route_finder_coord = *new_end;
9672       g_free ( new_end );
9673       vik_layer_emit_update ( VIK_LAYER(vtl) );
9674       /* remove last ' to:...' */
9675       if ( vtl->route_finder_current_track->comment ) {
9676         gchar *last_to = strrchr ( vtl->route_finder_current_track->comment, 't' );
9677         if ( last_to && (last_to - vtl->route_finder_current_track->comment > 1) ) {
9678           gchar *new_comment = g_strndup ( vtl->route_finder_current_track->comment,
9679                                            last_to - vtl->route_finder_current_track->comment - 1);
9680           vik_track_set_comment_no_copy ( vtl->route_finder_current_track, new_comment );
9681         }
9682       }
9683     }
9684   }
9685   else if ( vtl->route_finder_started || (event->state & GDK_CONTROL_MASK && vtl->route_finder_current_track) ) {
9686     struct LatLon start, end;
9687
9688     vik_coord_to_latlon ( &(vtl->route_finder_coord), &start );
9689     vik_coord_to_latlon ( &(tmp), &end );
9690     vtl->route_finder_coord = tmp; /* for continuations */
9691
9692     /* these are checked when adding a track from a file (vik_trw_layer_filein_add_track) */
9693     if ( event->state & GDK_CONTROL_MASK && vtl->route_finder_current_track ) {
9694       vtl->route_finder_append = TRUE;  // merge tracks. keep started true.
9695     } else {
9696       vtl->route_finder_check_added_track = TRUE;
9697       vtl->route_finder_started = FALSE;
9698     }
9699
9700     vik_routing_default_find ( vtl, start, end);
9701
9702     /* see if anything was done -- a track was added or appended to */
9703     if ( vtl->route_finder_check_added_track && vtl->route_finder_added_track ) {
9704       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 ) );
9705     } else if ( vtl->route_finder_append == FALSE && vtl->route_finder_current_track ) {
9706       /* route_finder_append was originally TRUE but set to FALSE by filein_add_track */
9707       gchar *new_comment = g_strdup_printf("%s to: %f,%f", vtl->route_finder_current_track->comment, end.lat, end.lon );
9708       vik_track_set_comment_no_copy ( vtl->route_finder_current_track, new_comment );
9709     }
9710
9711     if ( vtl->route_finder_added_track )
9712       vik_track_calculate_bounds ( vtl->route_finder_added_track );
9713
9714     vtl->route_finder_added_track = NULL;
9715     vtl->route_finder_check_added_track = FALSE;
9716     vtl->route_finder_append = FALSE;
9717
9718     vik_layer_emit_update ( VIK_LAYER(vtl) );
9719   } else {
9720     vtl->route_finder_started = TRUE;
9721     vtl->route_finder_coord = tmp;
9722     vtl->route_finder_current_track = NULL;
9723   }
9724   return TRUE;
9725 }
9726
9727 /*** Show picture ****/
9728
9729 static gpointer tool_show_picture_create ( VikWindow *vw, VikViewport *vvp)
9730 {
9731   return vvp;
9732 }
9733
9734 /* Params are: vvp, event, last match found or NULL */
9735 static void tool_show_picture_wp ( const gpointer id, VikWaypoint *wp, gpointer params[3] )
9736 {
9737   if ( wp->image && wp->visible )
9738   {
9739     gint x, y, slackx, slacky;
9740     GdkEventButton *event = (GdkEventButton *) params[1];
9741
9742     vik_viewport_coord_to_screen ( VIK_VIEWPORT(params[0]), &(wp->coord), &x, &y );
9743     slackx = wp->image_width / 2;
9744     slacky = wp->image_height / 2;
9745     if (    x <= event->x + slackx && x >= event->x - slackx
9746          && y <= event->y + slacky && y >= event->y - slacky )
9747     {
9748       params[2] = wp->image; /* we've found a match. however continue searching
9749                               * since we want to find the last match -- that
9750                               * is, the match that was drawn last. */
9751     }
9752   }
9753 }
9754
9755 static void trw_layer_show_picture ( gpointer pass_along[6] )
9756 {
9757   /* thanks to the Gaim people for showing me ShellExecute and g_spawn_command_line_async */
9758 #ifdef WINDOWS
9759   ShellExecute(NULL, "open", (char *) pass_along[5], NULL, NULL, SW_SHOWNORMAL);
9760 #else /* WINDOWS */
9761   GError *err = NULL;
9762   gchar *quoted_file = g_shell_quote ( (gchar *) pass_along[5] );
9763   gchar *cmd = g_strdup_printf ( "%s %s", a_vik_get_image_viewer(), quoted_file );
9764   g_free ( quoted_file );
9765   if ( ! g_spawn_command_line_async ( cmd, &err ) )
9766     {
9767       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() );
9768       g_error_free ( err );
9769     }
9770   g_free ( cmd );
9771 #endif /* WINDOWS */
9772 }
9773
9774 static gboolean tool_show_picture_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
9775 {
9776   gpointer params[3] = { vvp, event, NULL };
9777   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
9778     return FALSE;
9779   g_hash_table_foreach ( vtl->waypoints, (GHFunc) tool_show_picture_wp, params );
9780   if ( params[2] )
9781   {
9782     static gpointer pass_along[6];
9783     pass_along[0] = vtl;
9784     pass_along[5] = params[2];
9785     trw_layer_show_picture ( pass_along );
9786     return TRUE; /* found a match */
9787   }
9788   else
9789     return FALSE; /* go through other layers, searching for a match */
9790 }
9791
9792 /***************************************************************************
9793  ** End tool code 
9794  ***************************************************************************/
9795
9796
9797 static void image_wp_make_list ( const gpointer id, VikWaypoint *wp, GSList **pics )
9798 {
9799   if ( wp->image && ( ! a_thumbnails_exists ( wp->image ) ) )
9800     *pics = g_slist_append ( *pics, (gpointer) g_strdup ( wp->image ) );
9801 }
9802
9803 /* Structure for thumbnail creating data used in the background thread */
9804 typedef struct {
9805   VikTrwLayer *vtl; // Layer needed for redrawing
9806   GSList *pics;     // Image list
9807 } thumbnail_create_thread_data;
9808
9809 static int create_thumbnails_thread ( thumbnail_create_thread_data *tctd, gpointer threaddata )
9810 {
9811   guint total = g_slist_length(tctd->pics), done = 0;
9812   while ( tctd->pics )
9813   {
9814     a_thumbnails_create ( (gchar *) tctd->pics->data );
9815     int result = a_background_thread_progress ( threaddata, ((gdouble) ++done) / total );
9816     if ( result != 0 )
9817       return -1; /* Abort thread */
9818
9819     tctd->pics = tctd->pics->next;
9820   }
9821
9822   // Redraw to show the thumbnails as they are now created
9823   if ( IS_VIK_LAYER(tctd->vtl) )
9824     vik_layer_emit_update ( VIK_LAYER(tctd->vtl) ); // NB update from background thread
9825
9826   return 0;
9827 }
9828
9829 static void thumbnail_create_thread_free ( thumbnail_create_thread_data *tctd )
9830 {
9831   while ( tctd->pics )
9832   {
9833     g_free ( tctd->pics->data );
9834     tctd->pics = g_slist_delete_link ( tctd->pics, tctd->pics );
9835   }
9836   g_free ( tctd );
9837 }
9838
9839 void trw_layer_verify_thumbnails ( VikTrwLayer *vtl, GtkWidget *vp )
9840 {
9841   if ( ! vtl->has_verified_thumbnails )
9842   {
9843     GSList *pics = NULL;
9844     g_hash_table_foreach ( vtl->waypoints, (GHFunc) image_wp_make_list, &pics );
9845     if ( pics )
9846     {
9847       gint len = g_slist_length ( pics );
9848       gchar *tmp = g_strdup_printf ( _("Creating %d Image Thumbnails..."), len );
9849       thumbnail_create_thread_data *tctd = g_malloc ( sizeof(thumbnail_create_thread_data) );
9850       tctd->vtl = vtl;
9851       tctd->pics = pics;
9852       a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
9853                             tmp,
9854                             (vik_thr_func) create_thumbnails_thread,
9855                             tctd,
9856                             (vik_thr_free_func) thumbnail_create_thread_free,
9857                             NULL,
9858                             len );
9859       g_free ( tmp );
9860     }
9861   }
9862 }
9863
9864 static const gchar* my_track_colors ( gint ii )
9865 {
9866   static const gchar* colors[VIK_TRW_LAYER_TRACK_GCS] = {
9867     "#2d870a",
9868     "#135D34",
9869     "#0a8783",
9870     "#0e4d87",
9871     "#05469f",
9872     "#695CBB",
9873     "#2d059f",
9874     "#4a059f",
9875     "#5A171A",
9876     "#96059f"
9877   };
9878   // Fast and reliable way of returning a colour
9879   return colors[(ii % VIK_TRW_LAYER_TRACK_GCS)];
9880 }
9881
9882 static void trw_layer_track_alloc_colors ( VikTrwLayer *vtl )
9883 {
9884   GHashTableIter iter;
9885   gpointer key, value;
9886
9887   gint ii = 0;
9888   // Tracks
9889   g_hash_table_iter_init ( &iter, vtl->tracks );
9890
9891   while ( g_hash_table_iter_next (&iter, &key, &value) ) {
9892
9893     // Tracks get a random spread of colours if not already assigned
9894     if ( ! VIK_TRACK(value)->has_color ) {
9895       if ( vtl->drawmode == DRAWMODE_ALL_SAME_COLOR )
9896         VIK_TRACK(value)->color = vtl->track_color;
9897       else {
9898         gdk_color_parse ( my_track_colors (ii), &(VIK_TRACK(value)->color) );
9899       }
9900       VIK_TRACK(value)->has_color = TRUE;
9901     }
9902
9903     trw_layer_update_treeview ( vtl, VIK_TRACK(value) );
9904
9905     ii++;
9906     if (ii > VIK_TRW_LAYER_TRACK_GCS)
9907       ii = 0;
9908   }
9909
9910   // Routes
9911   ii = 0;
9912   g_hash_table_iter_init ( &iter, vtl->routes );
9913
9914   while ( g_hash_table_iter_next (&iter, &key, &value) ) {
9915
9916     // Routes get an intermix of reds
9917     if ( ! VIK_TRACK(value)->has_color ) {
9918       if ( ii )
9919         gdk_color_parse ( "#FF0000" , &(VIK_TRACK(value)->color) ); // Red
9920       else
9921         gdk_color_parse ( "#B40916" , &(VIK_TRACK(value)->color) ); // Dark Red
9922       VIK_TRACK(value)->has_color = TRUE;
9923     }
9924
9925     trw_layer_update_treeview ( vtl, VIK_TRACK(value) );
9926
9927     ii = !ii;
9928   }
9929 }
9930
9931 /*
9932  * (Re)Calculate the bounds of the waypoints in this layer,
9933  * This should be called whenever waypoints are changed
9934  */
9935 void trw_layer_calculate_bounds_waypoints ( VikTrwLayer *vtl )
9936 {
9937   struct LatLon topleft = { 0.0, 0.0 };
9938   struct LatLon bottomright = { 0.0, 0.0 };
9939   struct LatLon ll;
9940
9941   GHashTableIter iter;
9942   gpointer key, value;
9943
9944   g_hash_table_iter_init ( &iter, vtl->waypoints );
9945
9946   // Set bounds to first point
9947   if ( g_hash_table_iter_next (&iter, &key, &value) ) {
9948     vik_coord_to_latlon ( &(VIK_WAYPOINT(value)->coord), &topleft );
9949     vik_coord_to_latlon ( &(VIK_WAYPOINT(value)->coord), &bottomright );
9950   }
9951
9952   // Ensure there is another point...
9953   if ( g_hash_table_size ( vtl->waypoints ) > 1 ) {
9954
9955     while ( g_hash_table_iter_next (&iter, &key, &value) ) {
9956
9957       // See if this point increases the bounds.
9958       vik_coord_to_latlon ( &(VIK_WAYPOINT(value)->coord), &ll );
9959
9960       if ( ll.lat > topleft.lat) topleft.lat = ll.lat;
9961       if ( ll.lon < topleft.lon) topleft.lon = ll.lon;
9962       if ( ll.lat < bottomright.lat) bottomright.lat = ll.lat;
9963       if ( ll.lon > bottomright.lon) bottomright.lon = ll.lon;
9964     }
9965   }
9966
9967   vtl->waypoints_bbox.north = topleft.lat;
9968   vtl->waypoints_bbox.east = bottomright.lon;
9969   vtl->waypoints_bbox.south = bottomright.lat;
9970   vtl->waypoints_bbox.west = topleft.lon;
9971 }
9972
9973 static void trw_layer_calculate_bounds_track ( gpointer id, VikTrack *trk )
9974 {
9975   vik_track_calculate_bounds ( trk );
9976 }
9977
9978 static void trw_layer_calculate_bounds_tracks ( VikTrwLayer *vtl )
9979 {
9980   g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_calculate_bounds_track, NULL );
9981   g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_calculate_bounds_track, NULL );
9982 }
9983
9984 static void trw_layer_sort_all ( VikTrwLayer *vtl )
9985 {
9986   if ( ! VIK_LAYER(vtl)->vt )
9987     return;
9988
9989   // Obviously need 2 to tango - sorting with only 1 (or less) is a lonely activity!
9990   if ( g_hash_table_size (vtl->tracks) > 1 )
9991     vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), vtl->track_sort_order );
9992
9993   if ( g_hash_table_size (vtl->routes) > 1 )
9994     vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter), vtl->track_sort_order );
9995
9996   if ( g_hash_table_size (vtl->waypoints) > 1 )
9997     vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), vtl->wp_sort_order );
9998 }
9999
10000 static void trw_layer_post_read ( VikTrwLayer *vtl, GtkWidget *vvp, gboolean from_file )
10001 {
10002   if ( VIK_LAYER(vtl)->realized )
10003     trw_layer_verify_thumbnails ( vtl, vvp );
10004   trw_layer_track_alloc_colors ( vtl );
10005
10006   trw_layer_calculate_bounds_waypoints ( vtl );
10007   trw_layer_calculate_bounds_tracks ( vtl );
10008
10009   // Apply treeview sort after loading all the tracks for this layer
10010   //  (rather than sorted insert on each individual track additional)
10011   //  and after subsequent changes to the properties as the specified order may have changed.
10012   //  since the sorting of a treeview section is now very quick
10013   // NB sorting is also performed after every name change as well to maintain the list order
10014   trw_layer_sort_all ( vtl );
10015 }
10016
10017 VikCoordMode vik_trw_layer_get_coord_mode ( VikTrwLayer *vtl )
10018 {
10019   return vtl->coord_mode;
10020 }
10021
10022 /**
10023  * Uniquify the whole layer
10024  * Also requires the layers panel as the names shown there need updating too
10025  * Returns whether the operation was successful or not
10026  */
10027 gboolean vik_trw_layer_uniquify ( VikTrwLayer *vtl, VikLayersPanel *vlp )
10028 {
10029   if ( vtl && vlp ) {
10030     vik_trw_layer_uniquify_tracks ( vtl, vlp, vtl->tracks, TRUE );
10031     vik_trw_layer_uniquify_tracks ( vtl, vlp, vtl->routes, FALSE );
10032     vik_trw_layer_uniquify_waypoints ( vtl, vlp );
10033     return TRUE;
10034   }
10035   return FALSE;
10036 }
10037
10038 static void waypoint_convert ( const gpointer id, VikWaypoint *wp, VikCoordMode *dest_mode )
10039 {
10040   vik_coord_convert ( &(wp->coord), *dest_mode );
10041 }
10042
10043 static void track_convert ( const gpointer id, VikTrack *tr, VikCoordMode *dest_mode )
10044 {
10045   vik_track_convert ( tr, *dest_mode );
10046 }
10047
10048 static void trw_layer_change_coord_mode ( VikTrwLayer *vtl, VikCoordMode dest_mode )
10049 {
10050   if ( vtl->coord_mode != dest_mode )
10051   {
10052     vtl->coord_mode = dest_mode;
10053     g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_convert, &dest_mode );
10054     g_hash_table_foreach ( vtl->tracks, (GHFunc) track_convert, &dest_mode );
10055     g_hash_table_foreach ( vtl->routes, (GHFunc) track_convert, &dest_mode );
10056   }
10057 }
10058
10059 static void trw_layer_set_menu_selection ( VikTrwLayer *vtl, guint16 selection )
10060 {
10061   vtl->menu_selection = selection;
10062 }
10063
10064 static guint16 trw_layer_get_menu_selection ( VikTrwLayer *vtl )
10065 {
10066   return (vtl->menu_selection);
10067 }
10068
10069 /* ----------- Downloading maps along tracks --------------- */
10070
10071 static int get_download_area_width(VikViewport *vvp, gdouble zoom_level, struct LatLon *wh)
10072 {
10073   /* TODO: calculating based on current size of viewport */
10074   const gdouble w_at_zoom_0_125 = 0.0013;
10075   const gdouble h_at_zoom_0_125 = 0.0011;
10076   gdouble zoom_factor = zoom_level/0.125;
10077
10078   wh->lat = h_at_zoom_0_125 * zoom_factor;
10079   wh->lon = w_at_zoom_0_125 * zoom_factor;
10080
10081   return 0;   /* all OK */
10082 }
10083
10084 static VikCoord *get_next_coord(VikCoord *from, VikCoord *to, struct LatLon *dist, gdouble gradient)
10085 {
10086   if ((dist->lon >= ABS(to->east_west - from->east_west)) &&
10087       (dist->lat >= ABS(to->north_south - from->north_south)))
10088     return NULL;
10089
10090   VikCoord *coord = g_malloc(sizeof(VikCoord));
10091   coord->mode = VIK_COORD_LATLON;
10092
10093   if (ABS(gradient) < 1) {
10094     if (from->east_west > to->east_west)
10095       coord->east_west = from->east_west - dist->lon;
10096     else
10097       coord->east_west = from->east_west + dist->lon;
10098     coord->north_south = gradient * (coord->east_west - from->east_west) + from->north_south;
10099   } else {
10100     if (from->north_south > to->north_south)
10101       coord->north_south = from->north_south - dist->lat;
10102     else
10103       coord->north_south = from->north_south + dist->lat;
10104     coord->east_west = (1/gradient) * (coord->north_south - from->north_south) + from->north_south;
10105   }
10106
10107   return coord;
10108 }
10109
10110 static GList *add_fillins(GList *list, VikCoord *from, VikCoord *to, struct LatLon *dist)
10111 {
10112   /* TODO: handle virtical track (to->east_west - from->east_west == 0) */
10113   gdouble gradient = (to->north_south - from->north_south)/(to->east_west - from->east_west);
10114
10115   VikCoord *next = from;
10116   while (TRUE) {
10117     if ((next = get_next_coord(next, to, dist, gradient)) == NULL)
10118         break;
10119     list = g_list_prepend(list, next);
10120   }
10121
10122   return list;
10123 }
10124
10125 void vik_track_download_map(VikTrack *tr, VikMapsLayer *vml, VikViewport *vvp, gdouble zoom_level)
10126 {
10127   typedef struct _Rect {
10128     VikCoord tl;
10129     VikCoord br;
10130     VikCoord center;
10131   } Rect;
10132 #define GLRECT(iter) ((Rect *)((iter)->data))
10133
10134   struct LatLon wh;
10135   GList *rects_to_download = NULL;
10136   GList *rect_iter;
10137
10138   if (get_download_area_width(vvp, zoom_level, &wh))
10139     return;
10140
10141   GList *iter = tr->trackpoints;
10142   if (!iter)
10143     return;
10144
10145   gboolean new_map = TRUE;
10146   VikCoord *cur_coord, tl, br;
10147   Rect *rect;
10148   while (iter) {
10149     cur_coord = &(VIK_TRACKPOINT(iter->data))->coord;
10150     if (new_map) {
10151       vik_coord_set_area(cur_coord, &wh, &tl, &br);
10152       rect = g_malloc(sizeof(Rect));
10153       rect->tl = tl;
10154       rect->br = br;
10155       rect->center = *cur_coord;
10156       rects_to_download = g_list_prepend(rects_to_download, rect);
10157       new_map = FALSE;
10158       iter = iter->next;
10159       continue;
10160     }
10161     gboolean found = FALSE;
10162     for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next) {
10163       if (vik_coord_inside(cur_coord, &GLRECT(rect_iter)->tl, &GLRECT(rect_iter)->br)) {
10164         found = TRUE;
10165         break;
10166       }
10167     }
10168     if (found)
10169         iter = iter->next;
10170     else
10171       new_map = TRUE;
10172   }
10173
10174   GList *fillins = NULL;
10175   /* 'fillin' doesn't work in UTM mode - potentially ending up in massive loop continually allocating memory - hence don't do it */
10176   /* seems that ATM the function get_next_coord works only for LATLON */
10177   if ( cur_coord->mode == VIK_COORD_LATLON ) {
10178     /* fill-ins for far apart points */
10179     GList *cur_rect, *next_rect;
10180     for (cur_rect = rects_to_download;
10181          (next_rect = cur_rect->next) != NULL;
10182          cur_rect = cur_rect->next) {
10183       if ((wh.lon < ABS(GLRECT(cur_rect)->center.east_west - GLRECT(next_rect)->center.east_west)) ||
10184           (wh.lat < ABS(GLRECT(cur_rect)->center.north_south - GLRECT(next_rect)->center.north_south))) {
10185         fillins = add_fillins(fillins, &GLRECT(cur_rect)->center, &GLRECT(next_rect)->center, &wh);
10186       }
10187     }
10188   } else
10189     g_message("%s: this feature works only in Mercator mode", __FUNCTION__);
10190
10191   if (fillins) {
10192     GList *iter = fillins;
10193     while (iter) {
10194       cur_coord = (VikCoord *)(iter->data);
10195       vik_coord_set_area(cur_coord, &wh, &tl, &br);
10196       rect = g_malloc(sizeof(Rect));
10197       rect->tl = tl;
10198       rect->br = br;
10199       rect->center = *cur_coord;
10200       rects_to_download = g_list_prepend(rects_to_download, rect);
10201       iter = iter->next;
10202     }
10203   }
10204
10205   for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next) {
10206     vik_maps_layer_download_section (vml, vvp, &(((Rect *)(rect_iter->data))->tl), &(((Rect *)(rect_iter->data))->br), zoom_level);
10207   }
10208
10209   if (fillins) {
10210     for (iter = fillins; iter; iter = iter->next)
10211       g_free(iter->data);
10212     g_list_free(fillins);
10213   }
10214   if (rects_to_download) {
10215     for (rect_iter = rects_to_download; rect_iter; rect_iter = rect_iter->next)
10216       g_free(rect_iter->data);
10217     g_list_free(rects_to_download);
10218   }
10219 }
10220
10221 static void trw_layer_download_map_along_track_cb ( gpointer pass_along[6] )
10222 {
10223   VikMapsLayer *vml;
10224   gint selected_map;
10225   gchar *zoomlist[] = {"0.125", "0.25", "0.5", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", NULL };
10226   gdouble zoom_vals[] = {0.125, 0.25, 0.5, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
10227   gint selected_zoom, default_zoom;
10228
10229   VikTrwLayer *vtl = pass_along[0];
10230   VikLayersPanel *vlp = pass_along[1];
10231   VikTrack *trk;
10232   if ( GPOINTER_TO_INT (pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
10233     trk = (VikTrack *) g_hash_table_lookup ( vtl->routes, pass_along[3] );
10234   else
10235     trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, pass_along[3] );
10236   if ( !trk )
10237     return;
10238
10239   VikViewport *vvp = vik_window_viewport((VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl)));
10240
10241   GList *vmls = vik_layers_panel_get_all_layers_of_type(vlp, VIK_LAYER_MAPS, TRUE); // Includes hidden map layer types
10242   int num_maps = g_list_length(vmls);
10243
10244   if (!num_maps) {
10245     a_dialog_error_msg(VIK_GTK_WINDOW_FROM_LAYER(vtl), _("No map layer in use. Create one first") );
10246     return;
10247   }
10248
10249   // Convert from list of vmls to list of names. Allowing the user to select one of them
10250   gchar **map_names = g_malloc(1 + num_maps * sizeof(gpointer));
10251   VikMapsLayer **map_layers = g_malloc(1 + num_maps * sizeof(gpointer));
10252
10253   gchar **np = map_names;
10254   VikMapsLayer **lp = map_layers;
10255   int i;
10256   for (i = 0; i < num_maps; i++) {
10257     vml = (VikMapsLayer *)(vmls->data);
10258     *lp++ = vml;
10259     *np++ = vik_maps_layer_get_map_label(vml);
10260     vmls = vmls->next;
10261   }
10262   // Mark end of the array lists
10263   *lp = NULL;
10264   *np = NULL;
10265
10266   gdouble cur_zoom = vik_viewport_get_zoom(vvp);
10267   for (default_zoom = 0; default_zoom < G_N_ELEMENTS(zoom_vals); default_zoom++) {
10268     if (cur_zoom == zoom_vals[default_zoom])
10269       break;
10270   }
10271   default_zoom = (default_zoom == G_N_ELEMENTS(zoom_vals)) ? G_N_ELEMENTS(zoom_vals) - 1 : default_zoom;
10272
10273   if (!a_dialog_map_n_zoom(VIK_GTK_WINDOW_FROM_LAYER(vtl), map_names, 0, zoomlist, default_zoom, &selected_map, &selected_zoom))
10274     goto done;
10275
10276   vik_track_download_map(trk, map_layers[selected_map], vvp, zoom_vals[selected_zoom]);
10277
10278 done:
10279   for (i = 0; i < num_maps; i++)
10280     g_free(map_names[i]);
10281   g_free(map_names);
10282   g_free(map_layers);
10283
10284   g_list_free(vmls);
10285
10286 }
10287
10288 /**** lowest waypoint number calculation ***/
10289 static gint highest_wp_number_name_to_number(const gchar *name) {
10290   if ( strlen(name) == 3 ) {
10291     int n = atoi(name);
10292     if ( n < 100 && name[0] != '0' )
10293       return -1;
10294     if ( n < 10 && name[0] != '0' )
10295       return -1;
10296     return n;
10297   }
10298   return -1;
10299 }
10300
10301
10302 static void highest_wp_number_reset(VikTrwLayer *vtl)
10303 {
10304   vtl->highest_wp_number = -1;
10305 }
10306
10307 static void highest_wp_number_add_wp(VikTrwLayer *vtl, const gchar *new_wp_name)
10308 {
10309   /* if is bigger that top, add it */
10310   gint new_wp_num = highest_wp_number_name_to_number(new_wp_name);
10311   if ( new_wp_num > vtl->highest_wp_number )
10312     vtl->highest_wp_number = new_wp_num;
10313 }
10314
10315 static void highest_wp_number_remove_wp(VikTrwLayer *vtl, const gchar *old_wp_name)
10316 {
10317   /* if wasn't top, do nothing. if was top, count backwards until we find one used */
10318   gint old_wp_num = highest_wp_number_name_to_number(old_wp_name);
10319   if ( vtl->highest_wp_number == old_wp_num ) {
10320     gchar buf[4];
10321     vtl->highest_wp_number--;
10322
10323     g_snprintf(buf,4,"%03d", vtl->highest_wp_number );
10324     /* search down until we find something that *does* exist */
10325
10326     while ( vtl->highest_wp_number > 0 && ! vik_trw_layer_get_waypoint ( vtl, buf )) {
10327       vtl->highest_wp_number--;
10328       g_snprintf(buf,4,"%03d", vtl->highest_wp_number );
10329     }
10330   }
10331 }
10332
10333 /* get lowest unused number */
10334 static gchar *highest_wp_number_get(VikTrwLayer *vtl)
10335 {
10336   gchar buf[4];
10337   if ( vtl->highest_wp_number < 0 || vtl->highest_wp_number >= 999 )
10338     return NULL;
10339   g_snprintf(buf,4,"%03d", vtl->highest_wp_number+1 );
10340   return g_strdup(buf);
10341 }
10342
10343 /**
10344  * trw_layer_create_track_list_both:
10345  *
10346  * Create the latest list of tracks and routes
10347  */
10348 static GList* trw_layer_create_track_list_both ( VikLayer *vl, gpointer user_data )
10349 {
10350   VikTrwLayer *vtl = VIK_TRW_LAYER(vl);
10351   GList *tracks = NULL;
10352   tracks = g_list_concat ( tracks, g_hash_table_get_values ( vik_trw_layer_get_tracks ( vtl ) ) );
10353   tracks = g_list_concat ( tracks, g_hash_table_get_values ( vik_trw_layer_get_routes ( vtl ) ) );
10354
10355   return vik_trw_layer_build_track_list_t ( vtl, tracks );
10356 }
10357
10358 static void trw_layer_track_list_dialog_single ( gpointer pass_along[6] )
10359 {
10360   VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]);
10361
10362   gchar *title = NULL;
10363   if ( GPOINTER_TO_INT(pass_along[2]) == VIK_TRW_LAYER_SUBLAYER_TRACKS )
10364     title = g_strdup_printf ( _("%s: Track List"), VIK_LAYER(vtl)->name );
10365   else
10366     title = g_strdup_printf ( _("%s: Route List"), VIK_LAYER(vtl)->name );
10367
10368   vik_trw_layer_track_list_show_dialog ( title, VIK_LAYER(vtl), pass_along[2], trw_layer_create_track_list, FALSE );
10369   g_free ( title );
10370 }
10371
10372 static void trw_layer_track_list_dialog ( gpointer lav[2] )
10373 {
10374   VikTrwLayer *vtl = VIK_TRW_LAYER(lav[0]);
10375   //VikLayersPanel *vlp = VIK_LAYERS_PANEL(lav[1]);
10376
10377   gchar *title = g_strdup_printf ( _("%s: Track and Route List"), VIK_LAYER(vtl)->name );
10378   vik_trw_layer_track_list_show_dialog ( title, VIK_LAYER(vtl), NULL, trw_layer_create_track_list_both, FALSE );
10379   g_free ( title );
10380 }
10381
10382 static void trw_layer_waypoint_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: Waypoint List"), VIK_LAYER(vtl)->name );
10388   vik_trw_layer_waypoint_list_show_dialog ( title, VIK_LAYER(vtl), NULL, trw_layer_create_waypoint_list, FALSE );
10389   g_free ( title );
10390 }