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