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