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