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