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