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