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