]> git.street.me.uk Git - andy/viking.git/blob - src/vikwindow.c
Really empty GPS realtime layers.
[andy/viking.git] / src / vikwindow.c
1 /*
2  * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3  *
4  * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
5  * Copyright (C) 2005-2006, Alex Foobarian <foobarian@gmail.com>
6  * Copyright (C) 2012-2015, Rob Norris <rw_norris@hotmail.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include "viking.h"
29 #include "background.h"
30 #include "acquire.h"
31 #include "datasources.h"
32 #include "geojson.h"
33 #include "vikgoto.h"
34 #include "dems.h"
35 #include "mapcache.h"
36 #include "print.h"
37 #include "preferences.h"
38 #include "toolbar.h"
39 #include "viklayer_defaults.h"
40 #include "icons/icons.h"
41 #include "vikexttools.h"
42 #include "vikexttool_datasources.h"
43 #include "garminsymbols.h"
44 #include "vikmapslayer.h"
45 #include "vikrouting.h"
46 #include "geonamessearch.h"
47 #include "vikutils.h"
48 #include "dir.h"
49 #include "kmz.h"
50
51 #ifdef HAVE_STDLIB_H
52 #include <stdlib.h>
53 #endif
54 #ifdef HAVE_MATH_H
55 #include <math.h>
56 #endif
57 #ifdef HAVE_STRING_H
58 #include <string.h>
59 #endif
60 #include <ctype.h>
61 #include <glib.h>
62 #include <glib/gstdio.h>
63 #include <glib/gprintf.h>
64 #include <glib/gi18n.h>
65 #include <gio/gio.h>
66 #include <gdk/gdkkeysyms.h>
67
68 // This seems rather arbitary, quite large and pointless
69 //  I mean, if you have a thousand windows open;
70 //   why not be allowed to open a thousand more...
71 #define MAX_WINDOWS 1024
72 static guint window_count = 0;
73 static GSList *window_list = NULL;
74
75 #define VIKING_WINDOW_WIDTH      1000
76 #define VIKING_WINDOW_HEIGHT     800
77 #define DRAW_IMAGE_DEFAULT_WIDTH 1280
78 #define DRAW_IMAGE_DEFAULT_HEIGHT 1024
79 #define DRAW_IMAGE_DEFAULT_SAVE_AS_PNG TRUE
80
81 // The last used directories
82 static gchar *last_folder_files_uri = NULL;
83 static gchar *last_folder_images_uri = NULL;
84
85 static void window_finalize ( GObject *gob );
86 static GObjectClass *parent_class;
87
88 static void window_set_filename ( VikWindow *vw, const gchar *filename );
89 static const gchar *window_get_filename ( VikWindow *vw );
90
91 static VikWindow *window_new ();
92
93 static void draw_update ( VikWindow *vw );
94
95 static void newwindow_cb ( GtkAction *a, VikWindow *vw );
96
97 // Signals
98 static void open_window ( VikWindow *vw, GSList *files );
99 static void destroy_window ( GtkWidget *widget,
100                              gpointer   data );
101
102 /* Drawing & stuff */
103
104 static gboolean delete_event( VikWindow *vw );
105
106 static gboolean key_press_event( VikWindow *vw, GdkEventKey *event, gpointer data );
107
108 static void center_changed_cb ( VikWindow *vw );
109 static void window_configure_event ( VikWindow *vw );
110 static void draw_sync ( VikWindow *vw );
111 static void draw_redraw ( VikWindow *vw );
112 static void draw_scroll  ( VikWindow *vw, GdkEventScroll *event );
113 static void draw_click  ( VikWindow *vw, GdkEventButton *event );
114 static void draw_release ( VikWindow *vw, GdkEventButton *event );
115 static void draw_mouse_motion ( VikWindow *vw, GdkEventMotion *event );
116 static void draw_zoom_cb ( GtkAction *a, VikWindow *vw );
117 static void draw_goto_cb ( GtkAction *a, VikWindow *vw );
118 static void draw_refresh_cb ( GtkAction *a, VikWindow *vw );
119
120 static void draw_status ( VikWindow *vw );
121
122 /* End Drawing Functions */
123
124 static void toggle_draw_scale ( GtkAction *a, VikWindow *vw );
125 static void toggle_draw_centermark ( GtkAction *a, VikWindow *vw );
126 static void toggle_draw_highlight ( GtkAction *a, VikWindow *vw );
127
128 static void menu_addlayer_cb ( GtkAction *a, VikWindow *vw );
129 static void menu_properties_cb ( GtkAction *a, VikWindow *vw );
130 static void menu_delete_layer_cb ( GtkAction *a, VikWindow *vw );
131
132 /* tool management */
133 typedef struct {
134   VikToolInterface ti;
135   gpointer state;
136   gint layer_type;
137 } toolbox_tool_t;
138 #define TOOL_LAYER_TYPE_NONE -1
139
140 typedef struct {
141   int                   active_tool;
142   int                   n_tools;
143   toolbox_tool_t        *tools;
144   VikWindow *vw;
145 } toolbox_tools_t;
146
147 static void menu_cb ( GtkAction *old, GtkAction *a, VikWindow *vw );
148 static void window_change_coord_mode_cb ( GtkAction *old, GtkAction *a, VikWindow *vw );
149 static toolbox_tools_t* toolbox_create(VikWindow *vw);
150 static void toolbox_add_tool(toolbox_tools_t *vt, VikToolInterface *vti, gint layer_type );
151 static int toolbox_get_tool(toolbox_tools_t *vt, const gchar *tool_name);
152 static void toolbox_activate(toolbox_tools_t *vt, const gchar *tool_name);
153 static const GdkCursor *toolbox_get_cursor(toolbox_tools_t *vt, const gchar *tool_name);
154 static void toolbox_click (toolbox_tools_t *vt, GdkEventButton *event);
155 static void toolbox_move (toolbox_tools_t *vt, GdkEventMotion *event);
156 static void toolbox_release (toolbox_tools_t *vt, GdkEventButton *event);
157
158
159 /* ui creation */
160 static void window_create_ui( VikWindow *window );
161 static void register_vik_icons (GtkIconFactory *icon_factory);
162
163 /* i/o */
164 static void load_file ( GtkAction *a, VikWindow *vw );
165 static gboolean save_file_as ( GtkAction *a, VikWindow *vw );
166 static gboolean save_file ( GtkAction *a, VikWindow *vw );
167 static gboolean save_file_and_exit ( GtkAction *a, VikWindow *vw );
168 static gboolean window_save ( VikWindow *vw );
169
170 struct _VikWindow {
171   GtkWindow gtkwindow;
172   GtkWidget *hpaned;
173   VikViewport *viking_vvp;
174   VikLayersPanel *viking_vlp;
175   VikStatusbar *viking_vs;
176   VikToolbar *viking_vtb;
177
178   GtkWidget *main_vbox;
179   GtkWidget *menu_hbox;
180
181   GdkCursor *busy_cursor;
182   GdkCursor *viewport_cursor; // only a reference
183
184   /* tool management state */
185   guint current_tool;
186   toolbox_tools_t *vt;
187   guint16 tool_layer_id;
188   guint16 tool_tool_id;
189
190   GtkActionGroup *action_group;
191
192   // Display controls
193   // NB scale, centermark and highlight are in viewport.
194   gboolean show_full_screen;
195   gboolean show_side_panel;
196   gboolean show_statusbar;
197   gboolean show_toolbar;
198   gboolean show_main_menu;
199
200   gboolean select_move;
201   gboolean pan_move;
202   gint pan_x, pan_y;
203   gint delayed_pan_x, delayed_pan_y; // Temporary storage
204   gboolean single_click_pending;
205
206   guint draw_image_width, draw_image_height;
207   gboolean draw_image_save_as_png;
208
209   gchar *filename;
210   gboolean modified;
211   VikLoadType_t loaded_type;
212
213   gboolean only_updating_coord_mode_ui; /* hack for a bug in GTK */
214   GtkUIManager *uim;
215
216   GThread  *thread;
217   /* half-drawn update */
218   VikLayer *trigger;
219   VikCoord trigger_center;
220
221   /* Store at this level for highlighted selection drawing since it applies to the viewport and the layers panel */
222   /* Only one of these items can be selected at the same time */
223   gpointer selected_vtl; /* notionally VikTrwLayer */
224   GHashTable *selected_tracks;
225   gpointer selected_track; /* notionally VikTrack */
226   GHashTable *selected_waypoints;
227   gpointer selected_waypoint; /* notionally VikWaypoint */
228   /* only use for individual track or waypoint */
229   /* For track(s) & waypoint(s) it is the layer they are in - this helps refering to the individual item easier */
230   gpointer containing_vtl; /* notionally VikTrwLayer */
231 };
232
233 enum {
234  TOOL_PAN = 0,
235  TOOL_ZOOM,
236  TOOL_RULER,
237  TOOL_SELECT,
238  TOOL_LAYER,
239  NUMBER_OF_TOOLS
240 };
241
242 enum {
243   VW_NEWWINDOW_SIGNAL,
244   VW_OPENWINDOW_SIGNAL,
245   VW_LAST_SIGNAL
246 };
247
248 static guint window_signals[VW_LAST_SIGNAL] = { 0 };
249
250 // TODO get rid of this as this is unnecessary duplication...
251 static gchar *tool_names[NUMBER_OF_TOOLS] = { N_("Pan"), N_("Zoom"), N_("Ruler"), N_("Select") };
252
253 G_DEFINE_TYPE (VikWindow, vik_window, GTK_TYPE_WINDOW)
254
255 VikViewport * vik_window_viewport(VikWindow *vw)
256 {
257   return(vw->viking_vvp);
258 }
259
260 VikLayersPanel * vik_window_layers_panel(VikWindow *vw)
261 {
262   return(vw->viking_vlp);
263 }
264
265 /**
266  *  Returns the statusbar for the window
267  */
268 VikStatusbar * vik_window_get_statusbar ( VikWindow *vw )
269 {
270   return vw->viking_vs;
271 }
272
273 /**
274  *  Returns the 'project' filename
275  */
276 const gchar *vik_window_get_filename (VikWindow *vw)
277 {
278   return vw->filename;
279 }
280
281 typedef struct {
282   VikStatusbar *vs;
283   vik_statusbar_type_t vs_type;
284   gchar* message; // Always make a copy of this data
285 } statusbar_idle_data;
286
287 /**
288  * For the actual statusbar update!
289  */
290 static gboolean statusbar_idle_update ( statusbar_idle_data *sid )
291 {
292   vik_statusbar_set_message ( sid->vs, sid->vs_type, sid->message );
293   g_free ( sid->message );
294   g_free ( sid );
295   return FALSE;
296 }
297
298 /**
299  * vik_window_statusbar_update:
300  * @vw:      The main window in which the statusbar will be updated.
301  * @message: The string to be displayed. This is copied.
302  * @vs_type: The part of the statusbar to be updated.
303  *
304  * This updates any part of the statusbar with the new string.
305  * It handles calling from the main thread or any background thread
306  * ATM this mostly used from background threads - as from the main thread
307  *  one may use the vik_statusbar_set_message() directly.
308  */
309 void vik_window_statusbar_update ( VikWindow *vw, const gchar* message, vik_statusbar_type_t vs_type )
310 {
311   GThread *thread = vik_window_get_thread ( vw );
312   if ( !thread )
313     // Do nothing
314     return;
315
316   statusbar_idle_data *sid = g_malloc ( sizeof (statusbar_idle_data) );
317   sid->vs = vw->viking_vs;
318   sid->vs_type = vs_type;
319   sid->message = g_strdup ( message );
320
321   if ( g_thread_self() == thread ) {
322     g_idle_add ( (GSourceFunc) statusbar_idle_update, sid );
323   }
324   else {
325     // From a background thread
326     gdk_threads_add_idle ( (GSourceFunc) statusbar_idle_update, sid );
327   }
328 }
329
330 // Actual signal handlers
331 static void destroy_window ( GtkWidget *widget,
332                              gpointer   data )
333 {
334     g_debug ( "%s", __FUNCTION__ );
335     if ( ! --window_count ) {
336       g_free ( last_folder_files_uri );
337       g_free ( last_folder_images_uri );
338       gtk_main_quit ();
339     }
340 }
341
342 #define VIK_SETTINGS_WIN_SIDEPANEL "window_sidepanel"
343 #define VIK_SETTINGS_WIN_STATUSBAR "window_statusbar"
344 #define VIK_SETTINGS_WIN_TOOLBAR "window_toolbar"
345 // Menubar setting to off is never auto saved in case it's accidentally turned off
346 // It's not so obvious so to recover the menu visibility.
347 // Thus this value is for setting manually via editting the settings file directly
348 #define VIK_SETTINGS_WIN_MENUBAR "window_menubar"
349
350 VikWindow *vik_window_new_window ()
351 {
352   if ( window_count < MAX_WINDOWS )
353   {
354     VikWindow *vw = window_new ();
355
356     if ( window_count == 0 ) {
357        vik_window_statusbar_update ( vw, _("This is Viking "VIKING_VERSION), VIK_STATUSBAR_INFO );
358     }
359
360     g_signal_connect (G_OBJECT (vw), "destroy",
361                       G_CALLBACK (destroy_window), NULL);
362     g_signal_connect (G_OBJECT (vw), "newwindow",
363                       G_CALLBACK (vik_window_new_window), NULL);
364     g_signal_connect (G_OBJECT (vw), "openwindow",
365                       G_CALLBACK (open_window), NULL);
366
367     gtk_widget_show_all ( GTK_WIDGET(vw) );
368
369     if ( a_vik_get_restore_window_state() ) {
370       // These settings are applied after the show all as these options hide widgets
371       gboolean sidepanel;
372       if ( a_settings_get_boolean ( VIK_SETTINGS_WIN_SIDEPANEL, &sidepanel ) )
373         if ( ! sidepanel ) {
374           gtk_widget_hide ( GTK_WIDGET(vw->viking_vlp) );
375           GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ViewSidePanel" );
376           gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), FALSE );
377         }
378
379       gboolean statusbar;
380       if ( a_settings_get_boolean ( VIK_SETTINGS_WIN_STATUSBAR, &statusbar ) )
381         if ( ! statusbar ) {
382           gtk_widget_hide ( GTK_WIDGET(vw->viking_vs) );
383           GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ViewStatusBar" );
384           gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), FALSE );
385         }
386
387       gboolean toolbar;
388       if ( a_settings_get_boolean ( VIK_SETTINGS_WIN_TOOLBAR, &toolbar ) )
389         if ( ! toolbar ) {
390           gtk_widget_hide ( toolbar_get_widget (vw->viking_vtb) );
391           GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ViewToolBar" );
392           gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), FALSE );
393         }
394
395       gboolean menubar;
396       if ( a_settings_get_boolean ( VIK_SETTINGS_WIN_MENUBAR, &menubar ) )
397         if ( ! menubar ) {
398           gtk_widget_hide ( gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu" ) );
399           GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ViewMainMenu" );
400           gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), FALSE );
401         }
402     }
403     window_count++;
404
405     return vw;
406   }
407   return NULL;
408 }
409
410 /**
411  * determine_location_thread:
412  * @vw:         The window that will get updated
413  * @threaddata: Data used by our background thread mechanism
414  *
415  * Use the features in vikgoto to determine where we are
416  * Then set up the viewport:
417  *  1. To goto the location
418  *  2. Set an appropriate level zoom for the location type
419  *  3. Some statusbar message feedback
420  */
421 static int determine_location_thread ( VikWindow *vw, gpointer threaddata )
422 {
423   struct LatLon ll;
424   gchar *name = NULL;
425   gint ans = a_vik_goto_where_am_i ( vw->viking_vvp, &ll, &name );
426
427   int result = a_background_thread_progress ( threaddata, 1.0 );
428   if ( result != 0 ) {
429     vik_window_statusbar_update ( vw, _("Location lookup aborted"), VIK_STATUSBAR_INFO );
430     return -1; /* Abort thread */
431   }
432
433   if ( ans ) {
434     // Zoom out a little
435     gdouble zoom = 16.0;
436
437     if ( ans == 2 ) {
438       // Position found with city precision - so zoom out more
439       zoom = 128.0;
440     }
441     else if ( ans == 3 ) {
442       // Position found via country name search - so zoom wayyyy out
443       zoom = 2048.0;
444     }
445
446     vik_viewport_set_zoom ( vw->viking_vvp, zoom );
447     vik_viewport_set_center_latlon ( vw->viking_vvp, &ll, FALSE );
448
449     gchar *message = g_strdup_printf ( _("Location found: %s"), name );
450     vik_window_statusbar_update ( vw, message, VIK_STATUSBAR_INFO );
451     g_free ( name );
452     g_free ( message );
453
454     // Signal to redraw from the background
455     vik_layers_panel_emit_update ( vw->viking_vlp );
456   }
457   else
458     vik_window_statusbar_update ( vw, _("Unable to determine location"), VIK_STATUSBAR_INFO );
459
460   return 0;
461 }
462
463 /**
464  * Steps to be taken once initial loading has completed
465  */
466 void vik_window_new_window_finish ( VikWindow *vw )
467 {
468   // Don't add a map if we've loaded a Viking file already
469   if ( vw->filename )
470     return;
471
472   // Maybe add a default map layer
473   if ( a_vik_get_add_default_map_layer () ) {
474     VikMapsLayer *vml = VIK_MAPS_LAYER ( vik_layer_create(VIK_LAYER_MAPS, vw->viking_vvp, FALSE) );
475     vik_layer_rename ( VIK_LAYER(vml), _("Default Map") );
476     vik_aggregate_layer_add_layer ( vik_layers_panel_get_top_layer(vw->viking_vlp), VIK_LAYER(vml), TRUE );
477
478     draw_update ( vw );
479   }
480
481   // If not loaded any file, maybe try the location lookup
482   if ( vw->loaded_type == LOAD_TYPE_READ_FAILURE ) {
483     if ( a_vik_get_startup_method ( ) == VIK_STARTUP_METHOD_AUTO_LOCATION ) {
484
485       vik_statusbar_set_message ( vw->viking_vs, VIK_STATUSBAR_INFO, _("Trying to determine location...") );
486
487       a_background_thread ( BACKGROUND_POOL_REMOTE,
488                             GTK_WINDOW(vw),
489                             _("Determining location"),
490                             (vik_thr_func) determine_location_thread,
491                             vw,
492                             NULL,
493                             NULL,
494                             1 );
495     }
496   }
497 }
498
499 static void open_window ( VikWindow *vw, GSList *files )
500 {
501   if ( !vw  )
502     return;
503   gboolean change_fn = (g_slist_length(files) == 1); /* only change fn if one file */
504   GSList *cur_file = files;
505   while ( cur_file ) {
506     // Only open a new window if a viking file
507     gchar *file_name = cur_file->data;
508     if (vw->filename && check_file_magic_vik ( file_name ) ) {
509       VikWindow *newvw = vik_window_new_window ();
510       if (newvw)
511         vik_window_open_file ( newvw, file_name, TRUE );
512     }
513     else {
514       vik_window_open_file ( vw, file_name, change_fn );
515     }
516     g_free (file_name);
517     cur_file = g_slist_next (cur_file);
518   }
519   g_slist_free (files);
520 }
521 // End signals
522
523 void vik_window_selected_layer(VikWindow *vw, VikLayer *vl)
524 {
525   int i, j, tool_count;
526   VikLayerInterface *layer_interface;
527
528   if (!vw->action_group) return;
529
530   for (i=0; i<VIK_LAYER_NUM_TYPES; i++) {
531     GtkAction *action;
532     layer_interface = vik_layer_get_interface(i);
533     tool_count = layer_interface->tools_count;
534
535     for (j = 0; j < tool_count; j++) {
536       action = gtk_action_group_get_action(vw->action_group,
537                                            layer_interface->tools[j].radioActionEntry.name);
538       g_object_set(action, "sensitive", i == vl->type, NULL);
539       toolbar_action_set_sensitive ( vw->viking_vtb, vik_layer_get_interface(i)->tools[j].radioActionEntry.name, i == vl->type );
540     }
541   }
542 }
543
544 static void window_finalize ( GObject *gob )
545 {
546   VikWindow *vw = VIK_WINDOW(gob);
547   g_return_if_fail ( vw != NULL );
548
549   a_background_remove_window ( vw );
550
551   window_list = g_slist_remove ( window_list, vw );
552
553   gdk_cursor_unref ( vw->busy_cursor );
554   int tt;
555   for (tt = 0; tt < vw->vt->n_tools; tt++ )
556     if ( vw->vt->tools[tt].ti.destroy )
557       vw->vt->tools[tt].ti.destroy ( vw->vt->tools[tt].state );
558   g_free ( vw->vt->tools );
559   g_free ( vw->vt );
560
561   vik_toolbar_finalize ( vw->viking_vtb );
562
563   G_OBJECT_CLASS(parent_class)->finalize(gob);
564 }
565
566
567 static void vik_window_class_init ( VikWindowClass *klass )
568 {
569   /* destructor */
570   GObjectClass *object_class;
571
572   window_signals[VW_NEWWINDOW_SIGNAL] = g_signal_new ( "newwindow", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (VikWindowClass, newwindow), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
573   window_signals[VW_OPENWINDOW_SIGNAL] = g_signal_new ( "openwindow", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (VikWindowClass, openwindow), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);
574
575   object_class = G_OBJECT_CLASS (klass);
576
577   object_class->finalize = window_finalize;
578
579   parent_class = g_type_class_peek_parent (klass);
580
581 }
582
583 static void zoom_changed (GtkMenuShell *menushell,
584               gpointer      user_data)
585 {
586   VikWindow *vw = VIK_WINDOW (user_data);
587
588   GtkWidget *aw = gtk_menu_get_active ( GTK_MENU (menushell) );
589   gint active = GPOINTER_TO_INT(g_object_get_data ( G_OBJECT (aw), "position" ));
590
591   gdouble zoom_request = pow (2, active-5 );
592
593   // But has it really changed?
594   gdouble current_zoom = vik_viewport_get_zoom ( vw->viking_vvp );
595   if ( current_zoom != 0.0 && zoom_request != current_zoom ) {
596     vik_viewport_set_zoom ( vw->viking_vvp, zoom_request );
597     // Force drawing update
598     draw_update ( vw );
599   }
600 }
601
602 /**
603  * @mpp: The initial zoom level
604  */
605 static GtkWidget *create_zoom_menu_all_levels ( gdouble mpp )
606 {
607   GtkWidget *menu = gtk_menu_new ();
608   char *itemLabels[] = { "0.031", "0.063", "0.125", "0.25", "0.5", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", "2048", "4096", "8192", "16384", "32768" };
609
610   int i;
611   for (i = 0 ; i < G_N_ELEMENTS(itemLabels) ; i++)
612     {
613       GtkWidget *item = gtk_menu_item_new_with_label (itemLabels[i]);
614       gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
615       gtk_widget_show (item);
616       g_object_set_data (G_OBJECT (item), "position", GINT_TO_POINTER(i));
617     }
618
619   gint active = 5 + round ( log (mpp) / log (2) );
620   // Ensure value derived from mpp is in bounds of the menu
621   if ( active >= G_N_ELEMENTS(itemLabels) )
622     active = G_N_ELEMENTS(itemLabels) - 1;
623   if ( active < 0 )
624     active = 0;
625   gtk_menu_set_active ( GTK_MENU(menu), active );
626
627   return menu;
628 }
629
630 static GtkWidget *create_zoom_combo_all_levels ()
631 {
632   GtkWidget *combo = vik_combo_box_text_new();
633   vik_combo_box_text_append ( combo, "0.25");
634   vik_combo_box_text_append ( combo, "0.5");
635   vik_combo_box_text_append ( combo, "1");
636   vik_combo_box_text_append ( combo, "2");
637   vik_combo_box_text_append ( combo, "4");
638   vik_combo_box_text_append ( combo, "8");
639   vik_combo_box_text_append ( combo, "16");
640   vik_combo_box_text_append ( combo, "32");
641   vik_combo_box_text_append ( combo, "64");
642   vik_combo_box_text_append ( combo, "128");
643   vik_combo_box_text_append ( combo, "256");
644   vik_combo_box_text_append ( combo, "512");
645   vik_combo_box_text_append ( combo, "1024");
646   vik_combo_box_text_append ( combo, "2048");
647   vik_combo_box_text_append ( combo, "4096");
648   vik_combo_box_text_append ( combo, "8192");
649   vik_combo_box_text_append ( combo, "16384");
650   vik_combo_box_text_append ( combo, "32768");
651   /* Create tooltip */
652   gtk_widget_set_tooltip_text (combo, _("Select zoom level"));
653   return combo;
654 }
655
656 static gint zoom_popup_handler (GtkWidget *widget)
657 {
658   GtkMenu *menu;
659
660   g_return_val_if_fail (widget != NULL, FALSE);
661   g_return_val_if_fail (GTK_IS_MENU (widget), FALSE);
662
663   /* The "widget" is the menu that was supplied when
664    * g_signal_connect_swapped() was called.
665    */
666   menu = GTK_MENU (widget);
667
668   gtk_menu_popup (menu, NULL, NULL, NULL, NULL,
669                   1, gtk_get_current_event_time());
670   return TRUE;
671 }
672
673 enum {
674   TARGET_URIS,
675 };
676
677 static void drag_data_received_cb ( GtkWidget *widget,
678                                     GdkDragContext *context,
679                                     gint x,
680                                     gint y,
681                                     GtkSelectionData *selection_data,
682                                     guint target_type,
683                                     guint time,
684                                     gpointer data )
685 {
686   gboolean success = FALSE;
687
688   if ( (selection_data != NULL) && (gtk_selection_data_get_length(selection_data) > 0) ) {
689     switch (target_type) {
690     case TARGET_URIS: {
691       gchar *str = (gchar*)gtk_selection_data_get_data(selection_data);
692       g_debug ("drag received string:%s \n", str);
693
694       // Convert string into GSList of individual entries for use with our open signal
695       gchar **entries = g_strsplit(str, "\r\n", 0);
696       GSList *filenames = NULL;
697       gint entry_runner = 0;
698       gchar *entry = entries[entry_runner];
699       while (entry) {
700         if ( g_strcmp0 ( entry, "" ) ) {
701           // Drag+Drop gives URIs. And so in particular, %20 in place of spaces in filenames
702           //  thus need to convert the text into a plain string
703           gchar *filename = g_filename_from_uri ( entry, NULL, NULL );
704           if ( filename )
705             filenames = g_slist_append ( filenames, filename );
706         }
707         entry_runner++;
708         entry = entries[entry_runner];
709       }
710
711       if ( filenames )
712         g_signal_emit ( G_OBJECT(VIK_WINDOW_FROM_WIDGET(widget)), window_signals[VW_OPENWINDOW_SIGNAL], 0, filenames );
713         // NB: GSList & contents are freed by main.open_window
714
715       success = TRUE;
716       break;
717     }
718     default: break;
719     }
720   }
721
722   gtk_drag_finish ( context, success, FALSE, time );
723 }
724
725 static void toolbar_tool_cb ( GtkAction *old, GtkAction *current, gpointer gp )
726 {
727   VikWindow *vw = (VikWindow*)gp;
728   GtkAction *action = gtk_action_group_get_action ( vw->action_group, gtk_action_get_name(current) );
729   if ( action )
730     gtk_action_activate ( action );
731 }
732
733 static void toolbar_reload_cb ( GtkActionGroup *grp, gpointer gp )
734 {
735   VikWindow *vw = (VikWindow*)gp;
736   center_changed_cb ( vw );
737 }
738
739 #define VIK_SETTINGS_WIN_MAX "window_maximized"
740 #define VIK_SETTINGS_WIN_FULLSCREEN "window_fullscreen"
741 #define VIK_SETTINGS_WIN_WIDTH "window_width"
742 #define VIK_SETTINGS_WIN_HEIGHT "window_height"
743 #define VIK_SETTINGS_WIN_PANE_POSITION "window_horizontal_pane_position"
744 #define VIK_SETTINGS_WIN_SAVE_IMAGE_WIDTH "window_save_image_width"
745 #define VIK_SETTINGS_WIN_SAVE_IMAGE_HEIGHT "window_save_image_height"
746 #define VIK_SETTINGS_WIN_SAVE_IMAGE_PNG "window_save_image_as_png"
747 #define VIK_SETTINGS_WIN_COPY_CENTRE_FULL_FORMAT "window_copy_centre_full_format"
748
749 #define VIKING_ACCELERATOR_KEY_FILE "keys.rc"
750
751 static void vik_window_init ( VikWindow *vw )
752 {
753   vw->action_group = NULL;
754
755   vw->viking_vvp = vik_viewport_new();
756   vw->viking_vlp = vik_layers_panel_new();
757   vik_layers_panel_set_viewport ( vw->viking_vlp, vw->viking_vvp );
758   vw->viking_vs = vik_statusbar_new();
759
760   vw->vt = toolbox_create(vw);
761   vw->viking_vtb = vik_toolbar_new ();
762   window_create_ui(vw);
763   window_set_filename (vw, NULL);
764
765   vw->busy_cursor = gdk_cursor_new ( GDK_WATCH );
766
767   vw->filename = NULL;
768   vw->loaded_type = LOAD_TYPE_READ_FAILURE; //AKA none
769   vw->modified = FALSE;
770   vw->only_updating_coord_mode_ui = FALSE;
771
772   vw->select_move = FALSE;
773   vw->pan_move = FALSE; 
774   vw->pan_x = vw->pan_y = -1;
775   vw->single_click_pending = FALSE;
776
777   gint draw_image_width;
778   if ( a_settings_get_integer ( VIK_SETTINGS_WIN_SAVE_IMAGE_WIDTH, &draw_image_width ) )
779     vw->draw_image_width = draw_image_width;
780   else
781     vw->draw_image_width = DRAW_IMAGE_DEFAULT_WIDTH;
782   gint draw_image_height;
783   if ( a_settings_get_integer ( VIK_SETTINGS_WIN_SAVE_IMAGE_HEIGHT, &draw_image_height ) )
784     vw->draw_image_height = draw_image_height;
785   else
786     vw->draw_image_height = DRAW_IMAGE_DEFAULT_HEIGHT;
787   gboolean draw_image_save_as_png;
788   if ( a_settings_get_boolean ( VIK_SETTINGS_WIN_SAVE_IMAGE_PNG, &draw_image_save_as_png ) )
789     vw->draw_image_save_as_png = draw_image_save_as_png;
790   else
791     vw->draw_image_save_as_png = DRAW_IMAGE_DEFAULT_SAVE_AS_PNG;
792
793   vw->main_vbox = gtk_vbox_new(FALSE, 1);
794   gtk_container_add (GTK_CONTAINER (vw), vw->main_vbox);
795   vw->menu_hbox = gtk_hbox_new(FALSE, 1);
796   GtkWidget *menu_bar = gtk_ui_manager_get_widget (vw->uim, "/MainMenu");
797   gtk_box_pack_start (GTK_BOX(vw->menu_hbox), menu_bar, FALSE, TRUE, 0);
798   gtk_box_pack_start (GTK_BOX(vw->main_vbox), vw->menu_hbox, FALSE, TRUE, 0);
799
800   toolbar_init(vw->viking_vtb,
801                &vw->gtkwindow,
802                vw->main_vbox,
803                vw->menu_hbox,
804                toolbar_tool_cb,
805                toolbar_reload_cb,
806                (gpointer)vw); // This auto packs toolbar into the vbox
807   // Must be performed post toolbar init
808   gint i,j;
809   for (i=0; i<VIK_LAYER_NUM_TYPES; i++) {
810     for ( j = 0; j < vik_layer_get_interface(i)->tools_count; j++ ) {
811       toolbar_action_set_sensitive ( vw->viking_vtb, vik_layer_get_interface(i)->tools[j].radioActionEntry.name, FALSE );
812     }
813   }
814
815   vik_ext_tool_datasources_add_menu_items ( vw, vw->uim );
816
817   GtkWidget * zoom_levels = gtk_ui_manager_get_widget (vw->uim, "/MainMenu/View/SetZoom");
818   GtkWidget * zoom_levels_menu = create_zoom_menu_all_levels ( vik_viewport_get_zoom(vw->viking_vvp) );
819   gtk_menu_item_set_submenu (GTK_MENU_ITEM (zoom_levels), zoom_levels_menu);
820   g_signal_connect ( G_OBJECT(zoom_levels_menu), "selection-done", G_CALLBACK(zoom_changed), vw);
821   g_signal_connect_swapped ( G_OBJECT(vw->viking_vs), "clicked", G_CALLBACK(zoom_popup_handler), zoom_levels_menu );
822
823   g_signal_connect (G_OBJECT (vw), "delete_event", G_CALLBACK (delete_event), NULL);
824
825   // Own signals
826   g_signal_connect_swapped (G_OBJECT(vw->viking_vvp), "updated_center", G_CALLBACK(center_changed_cb), vw);
827   // Signals from GTK
828   g_signal_connect_swapped (G_OBJECT(vw->viking_vvp), "expose_event", G_CALLBACK(draw_sync), vw);
829   g_signal_connect_swapped (G_OBJECT(vw->viking_vvp), "configure_event", G_CALLBACK(window_configure_event), vw);
830   gtk_widget_add_events ( GTK_WIDGET(vw->viking_vvp), GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK );
831   g_signal_connect_swapped (G_OBJECT(vw->viking_vvp), "scroll_event", G_CALLBACK(draw_scroll), vw);
832   g_signal_connect_swapped (G_OBJECT(vw->viking_vvp), "button_press_event", G_CALLBACK(draw_click), vw);
833   g_signal_connect_swapped (G_OBJECT(vw->viking_vvp), "button_release_event", G_CALLBACK(draw_release), vw);
834   g_signal_connect_swapped (G_OBJECT(vw->viking_vvp), "motion_notify_event", G_CALLBACK(draw_mouse_motion), vw);
835
836   g_signal_connect_swapped (G_OBJECT(vw->viking_vlp), "update", G_CALLBACK(draw_update), vw);
837   g_signal_connect_swapped (G_OBJECT(vw->viking_vlp), "delete_layer", G_CALLBACK(vik_window_clear_highlight), vw);
838
839   // Allow key presses to be processed anywhere
840   g_signal_connect_swapped (G_OBJECT (vw), "key_press_event", G_CALLBACK (key_press_event), vw);
841
842   // Set initial button sensitivity
843   center_changed_cb ( vw );
844
845   vw->hpaned = gtk_hpaned_new ();
846   gtk_paned_pack1 ( GTK_PANED(vw->hpaned), GTK_WIDGET (vw->viking_vlp), FALSE, TRUE );
847   gtk_paned_pack2 ( GTK_PANED(vw->hpaned), GTK_WIDGET (vw->viking_vvp), TRUE, TRUE );
848
849   /* This packs the button into the window (a gtk container). */
850   gtk_box_pack_start (GTK_BOX(vw->main_vbox), vw->hpaned, TRUE, TRUE, 0);
851
852   gtk_box_pack_end (GTK_BOX(vw->main_vbox), GTK_WIDGET(vw->viking_vs), FALSE, TRUE, 0);
853
854   a_background_add_window ( vw );
855
856   window_list = g_slist_prepend ( window_list, vw);
857
858   gint height = VIKING_WINDOW_HEIGHT;
859   gint width = VIKING_WINDOW_WIDTH;
860
861   if ( a_vik_get_restore_window_state() ) {
862     if ( a_settings_get_integer ( VIK_SETTINGS_WIN_HEIGHT, &height ) ) {
863       // Enforce a basic minimum size
864       if ( height < 160 )
865         height = 160;
866     }
867     else
868       // No setting - so use default
869       height = VIKING_WINDOW_HEIGHT;
870
871     if ( a_settings_get_integer ( VIK_SETTINGS_WIN_WIDTH, &width ) ) {
872       // Enforce a basic minimum size
873       if ( width < 320 )
874         width = 320;
875     }
876     else
877       // No setting - so use default
878       width = VIKING_WINDOW_WIDTH;
879
880     gboolean maxed;
881     if ( a_settings_get_boolean ( VIK_SETTINGS_WIN_MAX, &maxed ) )
882       if ( maxed )
883         gtk_window_maximize ( GTK_WINDOW(vw) );
884
885     gboolean full;
886     if ( a_settings_get_boolean ( VIK_SETTINGS_WIN_FULLSCREEN, &full ) ) {
887       if ( full ) {
888         vw->show_full_screen = TRUE;
889         gtk_window_fullscreen ( GTK_WINDOW(vw) );
890         GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/FullScreen" );
891         if ( check_box )
892           gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), TRUE );
893       }
894     }
895
896     gint position = -1; // Let GTK determine default positioning
897     if ( !a_settings_get_integer ( VIK_SETTINGS_WIN_PANE_POSITION, &position ) ) {
898       position = -1;
899     }
900     gtk_paned_set_position ( GTK_PANED(vw->hpaned), position );
901   }
902
903   gtk_window_set_default_size ( GTK_WINDOW(vw), width, height );
904
905   vw->show_side_panel = TRUE;
906   vw->show_statusbar = TRUE;
907   vw->show_toolbar = TRUE;
908   vw->show_main_menu = TRUE;
909
910   // Only accept Drag and Drop of files onto the viewport
911   gtk_drag_dest_set ( GTK_WIDGET(vw->viking_vvp), GTK_DEST_DEFAULT_ALL, NULL, 0, GDK_ACTION_COPY );
912   gtk_drag_dest_add_uri_targets ( GTK_WIDGET(vw->viking_vvp) );
913   g_signal_connect ( GTK_WIDGET(vw->viking_vvp), "drag-data-received", G_CALLBACK(drag_data_received_cb), NULL );
914
915   // Store the thread value so comparisons can be made to determine the gdk update method
916   // Hopefully we are storing the main thread value here :)
917   //  [ATM any window initialization is always be performed by the main thread]
918   vw->thread = g_thread_self();
919
920   // Set the default tool + mode
921   gtk_action_activate ( gtk_action_group_get_action ( vw->action_group, "Pan" ) );
922   gtk_action_activate ( gtk_action_group_get_action ( vw->action_group, "ModeMercator" ) );
923
924   gchar *accel_file_name = g_build_filename ( a_get_viking_dir(), VIKING_ACCELERATOR_KEY_FILE, NULL );
925   gtk_accel_map_load ( accel_file_name );
926   g_free ( accel_file_name );
927 }
928
929 static VikWindow *window_new ()
930 {
931   return VIK_WINDOW ( g_object_new ( VIK_WINDOW_TYPE, NULL ) );
932 }
933
934 /**
935  * Update the displayed map
936  *  Only update the top most visible map layer
937  *  ATM this assumes (as per defaults) the top most map has full alpha setting
938  *   such that other other maps even though they may be active will not be seen
939  *  It's more complicated to work out which maps are actually visible due to alpha settings
940  *   and overkill for this simple refresh method.
941  */
942 static void simple_map_update ( VikWindow *vw, gboolean only_new )
943 {
944   // Find the most relevent single map layer to operate on
945   VikLayer *vl = vik_aggregate_layer_get_top_visible_layer_of_type (vik_layers_panel_get_top_layer(vw->viking_vlp), VIK_LAYER_MAPS);
946   if ( vl )
947         vik_maps_layer_download ( VIK_MAPS_LAYER(vl), vw->viking_vvp, only_new );
948 }
949
950 /**
951  * This is the global key press handler
952  *  Global shortcuts are available at any time and hence are not restricted to when a certain tool is enabled
953  */
954 static gboolean key_press_event( VikWindow *vw, GdkEventKey *event, gpointer data )
955 {
956   // The keys handled here are not in the menuing system for a couple of reasons:
957   //  . Keeps the menu size compact (alebit at expense of discoverably)
958   //  . Allows differing key bindings to perform the same actions
959
960   // First decide if key events are related to the maps layer
961   gboolean map_download = FALSE;
962   gboolean map_download_only_new = TRUE; // Only new or reload
963
964   GdkModifierType modifiers = gtk_accelerator_get_default_mod_mask();
965
966   // Standard 'Refresh' keys: F5 or Ctrl+r
967   // Note 'F5' is actually handled via draw_refresh_cb() later on
968   //  (not 'R' it's 'r' notice the case difference!!)
969   if ( event->keyval == GDK_r && (event->state & modifiers) == GDK_CONTROL_MASK ) {
970         map_download = TRUE;
971         map_download_only_new = TRUE;
972   }
973   // Full cache reload with Ctrl+F5 or Ctrl+Shift+r [This is not in the menu system]
974   // Note the use of uppercase R here since shift key has been pressed
975   else if ( (event->keyval == GDK_F5 && (event->state & modifiers) == GDK_CONTROL_MASK ) ||
976            ( event->keyval == GDK_R && (event->state & modifiers) == (GDK_CONTROL_MASK + GDK_SHIFT_MASK) ) ) {
977         map_download = TRUE;
978         map_download_only_new = FALSE;
979   }
980   // Standard Ctrl+KP+ / Ctrl+KP- to zoom in/out respectively
981   else if ( event->keyval == GDK_KEY_KP_Add && (event->state & modifiers) == GDK_CONTROL_MASK ) {
982     vik_viewport_zoom_in ( vw->viking_vvp );
983     draw_update(vw);
984     return TRUE; // handled keypress
985   }
986   else if ( event->keyval == GDK_KEY_KP_Subtract && (event->state & modifiers) == GDK_CONTROL_MASK ) {
987     vik_viewport_zoom_out ( vw->viking_vvp );
988     draw_update(vw);
989     return TRUE; // handled keypress
990   }
991
992   if ( map_download ) {
993     simple_map_update ( vw, map_download_only_new );
994     return TRUE; // handled keypress
995   }
996
997   VikLayer *vl = vik_layers_panel_get_selected ( vw->viking_vlp );
998   if (vl && vw->vt->active_tool != -1 && vw->vt->tools[vw->vt->active_tool].ti.key_press ) {
999     gint ltype = vw->vt->tools[vw->vt->active_tool].layer_type;
1000     if ( vl && ltype == vl->type )
1001       return vw->vt->tools[vw->vt->active_tool].ti.key_press(vl, event, vw->vt->tools[vw->vt->active_tool].state);
1002   }
1003
1004   // Ensure called only on window tools (i.e. not on any of the Layer tools since the layer is NULL)
1005   if ( vw->current_tool < TOOL_LAYER ) {
1006     // No layer - but enable window tool keypress processing - these should be able to handle a NULL layer
1007     if ( vw->vt->tools[vw->vt->active_tool].ti.key_press ) {
1008       return vw->vt->tools[vw->vt->active_tool].ti.key_press ( vl, event, vw->vt->tools[vw->vt->active_tool].state );
1009     }
1010   }
1011
1012   /* Restore Main Menu via Escape key if the user has hidden it */
1013   /* This key is more likely to be used as they may not remember the function key */
1014   if ( event->keyval == GDK_Escape ) {
1015     GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ViewMainMenu" );
1016     if ( check_box ) {
1017       gboolean state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box) );
1018       if ( !state ) {
1019         gtk_widget_show ( gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu" ) );
1020         gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), TRUE );
1021         return TRUE; /* handled keypress */
1022       }
1023     }
1024   }
1025
1026   return FALSE; /* don't handle the keypress */
1027 }
1028
1029 static gboolean delete_event( VikWindow *vw )
1030 {
1031 #ifdef VIKING_PROMPT_IF_MODIFIED
1032   if ( vw->modified )
1033 #else
1034   if (0)
1035 #endif
1036   {
1037     GtkDialog *dia;
1038     dia = GTK_DIALOG ( gtk_message_dialog_new ( GTK_WINDOW(vw), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
1039       _("Do you want to save the changes you made to the document \"%s\"?\n"
1040         "\n"
1041         "Your changes will be lost if you don't save them."),
1042       window_get_filename ( vw ) ) );
1043     gtk_dialog_add_buttons ( dia, _("Don't Save"), GTK_RESPONSE_NO, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_YES, NULL );
1044     switch ( gtk_dialog_run ( dia ) )
1045     {
1046       case GTK_RESPONSE_NO: gtk_widget_destroy ( GTK_WIDGET(dia) ); return FALSE;
1047       case GTK_RESPONSE_CANCEL: gtk_widget_destroy ( GTK_WIDGET(dia) ); return TRUE;
1048       default: gtk_widget_destroy ( GTK_WIDGET(dia) ); return ! save_file(NULL, vw);
1049     }
1050   }
1051
1052   if ( window_count == 1 ) {
1053     // On the final window close - save latest state - if it's wanted...
1054     if ( a_vik_get_restore_window_state() ) {
1055       gint state = gdk_window_get_state ( GTK_WIDGET(vw)->window );
1056       gboolean state_max = state & GDK_WINDOW_STATE_MAXIMIZED;
1057       a_settings_set_boolean ( VIK_SETTINGS_WIN_MAX, state_max );
1058
1059       gboolean state_fullscreen = state & GDK_WINDOW_STATE_FULLSCREEN;
1060       a_settings_set_boolean ( VIK_SETTINGS_WIN_FULLSCREEN, state_fullscreen );
1061
1062       a_settings_set_boolean ( VIK_SETTINGS_WIN_SIDEPANEL, GTK_WIDGET_VISIBLE (GTK_WIDGET(vw->viking_vlp)) );
1063
1064       a_settings_set_boolean ( VIK_SETTINGS_WIN_STATUSBAR, GTK_WIDGET_VISIBLE (GTK_WIDGET(vw->viking_vs)) );
1065
1066       a_settings_set_boolean ( VIK_SETTINGS_WIN_TOOLBAR, GTK_WIDGET_VISIBLE (toolbar_get_widget(vw->viking_vtb)) );
1067
1068       // If supersized - no need to save the enlarged width+height values
1069       if ( ! (state_fullscreen || state_max) ) {
1070         gint width, height;
1071         gtk_window_get_size ( GTK_WINDOW (vw), &width, &height );
1072         a_settings_set_integer ( VIK_SETTINGS_WIN_WIDTH, width );
1073         a_settings_set_integer ( VIK_SETTINGS_WIN_HEIGHT, height );
1074       }
1075
1076       a_settings_set_integer ( VIK_SETTINGS_WIN_PANE_POSITION, gtk_paned_get_position (GTK_PANED(vw->hpaned)) );
1077     }
1078
1079     a_settings_set_integer ( VIK_SETTINGS_WIN_SAVE_IMAGE_WIDTH, vw->draw_image_width );
1080     a_settings_set_integer ( VIK_SETTINGS_WIN_SAVE_IMAGE_HEIGHT, vw->draw_image_height );
1081     a_settings_set_boolean ( VIK_SETTINGS_WIN_SAVE_IMAGE_PNG, vw->draw_image_save_as_png );
1082
1083     gchar *accel_file_name = g_build_filename ( a_get_viking_dir(), VIKING_ACCELERATOR_KEY_FILE, NULL );
1084     gtk_accel_map_save ( accel_file_name );
1085     g_free ( accel_file_name );
1086   }
1087
1088   return FALSE;
1089 }
1090
1091 /* Drawing stuff */
1092 static void newwindow_cb ( GtkAction *a, VikWindow *vw )
1093 {
1094   g_signal_emit ( G_OBJECT(vw), window_signals[VW_NEWWINDOW_SIGNAL], 0 );
1095 }
1096
1097 static void draw_update ( VikWindow *vw )
1098 {
1099   draw_redraw (vw);
1100   draw_sync (vw);
1101 }
1102
1103 static void draw_sync ( VikWindow *vw )
1104 {
1105   vik_viewport_sync(vw->viking_vvp);
1106   draw_status ( vw );
1107 }
1108
1109 /*
1110  * Split the status update, as sometimes only need to update the tool part
1111  *  also on initialization the zoom related stuff is not ready to be used
1112  */
1113 static void draw_status_tool ( VikWindow *vw )
1114 {
1115   if ( vw->current_tool == TOOL_LAYER )
1116     // Use tooltip rather than the internal name as the tooltip is i8n
1117     vik_statusbar_set_message ( vw->viking_vs, VIK_STATUSBAR_TOOL, vik_layer_get_interface(vw->tool_layer_id)->tools[vw->tool_tool_id].radioActionEntry.tooltip );
1118   else
1119     vik_statusbar_set_message ( vw->viking_vs, VIK_STATUSBAR_TOOL, _(tool_names[vw->current_tool]) );
1120 }
1121
1122 static void draw_status ( VikWindow *vw )
1123 {
1124   static gchar zoom_level[22];
1125   gdouble xmpp = vik_viewport_get_xmpp (vw->viking_vvp);
1126   gdouble ympp = vik_viewport_get_ympp(vw->viking_vvp);
1127   gchar *unit = vik_viewport_get_coord_mode(vw->viking_vvp) == VIK_COORD_UTM ? _("mpp") : _("pixelfact");
1128   if (xmpp != ympp)
1129     g_snprintf ( zoom_level, 22, "%.3f/%.3f %s", xmpp, ympp, unit );
1130   else
1131     if ( (int)xmpp - xmpp < 0.0 )
1132       g_snprintf ( zoom_level, 22, "%.3f %s", xmpp, unit );
1133     else
1134       /* xmpp should be a whole number so don't show useless .000 bit */
1135       g_snprintf ( zoom_level, 22, "%d %s", (int)xmpp, unit );
1136
1137   vik_statusbar_set_message ( vw->viking_vs, VIK_STATUSBAR_ZOOM, zoom_level );
1138
1139   draw_status_tool ( vw );  
1140 }
1141
1142 void vik_window_set_redraw_trigger(VikLayer *vl)
1143 {
1144   VikWindow *vw = VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vl));
1145   if (NULL != vw)
1146     vw->trigger = vl;
1147 }
1148
1149 static void window_configure_event ( VikWindow *vw )
1150 {
1151   static int first = 1;
1152   draw_redraw ( vw );
1153   if (first) {
1154     // This is a hack to set the cursor corresponding to the first tool
1155     // FIXME find the correct way to initialize both tool and its cursor
1156     first = 0;
1157     vw->viewport_cursor = (GdkCursor *)toolbox_get_cursor(vw->vt, "Pan");
1158     /* We set cursor, even if it is NULL: it resets to default */
1159     gdk_window_set_cursor ( gtk_widget_get_window(GTK_WIDGET(vw->viking_vvp)), vw->viewport_cursor );
1160   }
1161 }
1162
1163 static void draw_redraw ( VikWindow *vw )
1164 {
1165   VikCoord old_center = vw->trigger_center;
1166   vw->trigger_center = *(vik_viewport_get_center(vw->viking_vvp));
1167   VikLayer *new_trigger = vw->trigger;
1168   vw->trigger = NULL;
1169   VikLayer *old_trigger = VIK_LAYER(vik_viewport_get_trigger(vw->viking_vvp));
1170
1171   if ( ! new_trigger )
1172     ; /* do nothing -- have to redraw everything. */
1173   else if ( (old_trigger != new_trigger) || !vik_coord_equals(&old_center, &vw->trigger_center) || (new_trigger->type == VIK_LAYER_AGGREGATE) )
1174     vik_viewport_set_trigger ( vw->viking_vvp, new_trigger ); /* todo: set to half_drawn mode if new trigger is above old */
1175   else
1176     vik_viewport_set_half_drawn ( vw->viking_vvp, TRUE );
1177
1178   /* actually draw */
1179   vik_viewport_clear ( vw->viking_vvp);
1180   // Main layer drawing
1181   vik_layers_panel_draw_all ( vw->viking_vlp );
1182   // Draw highlight (possibly again but ensures it is on top - especially for when tracks overlap)
1183   if ( vik_viewport_get_draw_highlight (vw->viking_vvp) ) {
1184     if ( vw->containing_vtl && (vw->selected_tracks || vw->selected_waypoints ) ) {
1185       vik_trw_layer_draw_highlight_items ( vw->containing_vtl, vw->selected_tracks, vw->selected_waypoints, vw->viking_vvp );
1186     }
1187     else if ( vw->containing_vtl && (vw->selected_track || vw->selected_waypoint) ) {
1188       vik_trw_layer_draw_highlight_item ( vw->containing_vtl, vw->selected_track, vw->selected_waypoint, vw->viking_vvp );
1189     }
1190     else if ( vw->selected_vtl ) {
1191       vik_trw_layer_draw_highlight ( vw->selected_vtl, vw->viking_vvp );
1192     }
1193   }
1194   // Other viewport decoration items on top if they are enabled/in use
1195   vik_viewport_draw_scale ( vw->viking_vvp );
1196   vik_viewport_draw_copyright ( vw->viking_vvp );
1197   vik_viewport_draw_centermark ( vw->viking_vvp );
1198   vik_viewport_draw_logo ( vw->viking_vvp );
1199
1200   vik_viewport_set_half_drawn ( vw->viking_vvp, FALSE ); /* just in case. */
1201 }
1202
1203 gboolean draw_buf_done = TRUE;
1204
1205 static gboolean draw_buf(gpointer data)
1206 {
1207   gpointer *pass_along = data;
1208   gdk_draw_drawable (pass_along[0], pass_along[1],
1209                      pass_along[2], 0, 0, 0, 0, -1, -1);
1210   draw_buf_done = TRUE;
1211   return FALSE;
1212 }
1213
1214
1215 /* Mouse event handlers ************************************************************************/
1216
1217 static void vik_window_pan_click (VikWindow *vw, GdkEventButton *event)
1218 {
1219   /* set panning origin */
1220   vw->pan_move = FALSE;
1221   vw->pan_x = (gint) event->x;
1222   vw->pan_y = (gint) event->y;
1223 }
1224
1225 static void draw_click (VikWindow *vw, GdkEventButton *event)
1226 {
1227   gtk_widget_grab_focus ( GTK_WIDGET(vw->viking_vvp) );
1228
1229   /* middle button pressed.  we reserve all middle button and scroll events
1230    * for panning and zooming; tools only get left/right/movement 
1231    */
1232   if ( event->button == 2) {
1233     if ( vw->vt->tools[vw->vt->active_tool].ti.pan_handler )
1234       // Tool still may need to do something (such as disable something)
1235       toolbox_click(vw->vt, event);
1236     vik_window_pan_click ( vw, event );
1237   } 
1238   else {
1239     toolbox_click(vw->vt, event);
1240   }
1241 }
1242
1243 static void vik_window_pan_move (VikWindow *vw, GdkEventMotion *event)
1244 {
1245   if ( vw->pan_x != -1 ) {
1246     vik_viewport_set_center_screen ( vw->viking_vvp, vik_viewport_get_width(vw->viking_vvp)/2 - event->x + vw->pan_x,
1247                                      vik_viewport_get_height(vw->viking_vvp)/2 - event->y + vw->pan_y );
1248     vw->pan_move = TRUE;
1249     vw->pan_x = event->x;
1250     vw->pan_y = event->y;
1251     draw_update ( vw );
1252   }
1253 }
1254
1255 /**
1256  * get_location_strings:
1257  *
1258  * Utility function to get positional strings for the given location
1259  * lat and lon strings will get allocated and so need to be freed after use
1260  */
1261 static void get_location_strings ( VikWindow *vw, struct UTM utm, gchar **lat, gchar **lon )
1262 {
1263   if ( vik_viewport_get_drawmode ( vw->viking_vvp ) == VIK_VIEWPORT_DRAWMODE_UTM ) {
1264     // Reuse lat for the first part (Zone + N or S, and lon for the second part (easting and northing) of a UTM format:
1265     //  ZONE[N|S] EASTING NORTHING
1266     *lat = g_malloc(4*sizeof(gchar));
1267     // NB zone is stored in a char but is an actual number
1268     g_snprintf (*lat, 4, "%d%c", utm.zone, utm.letter);
1269     *lon = g_malloc(16*sizeof(gchar));
1270     g_snprintf (*lon, 16, "%d %d", (gint)utm.easting, (gint)utm.northing);
1271   }
1272   else {
1273     struct LatLon ll;
1274     a_coords_utm_to_latlon ( &utm, &ll );
1275     a_coords_latlon_to_string ( &ll, lat, lon );
1276   }
1277 }
1278
1279 static void draw_mouse_motion (VikWindow *vw, GdkEventMotion *event)
1280 {
1281   static VikCoord coord;
1282   static struct UTM utm;
1283   #define BUFFER_SIZE 50
1284   static char pointer_buf[BUFFER_SIZE];
1285   gchar *lat = NULL, *lon = NULL;
1286   gint16 alt;
1287   gdouble zoom;
1288   VikDemInterpol interpol_method;
1289
1290   /* This is a hack, but work far the best, at least for single pointer systems.
1291    * See http://bugzilla.gnome.org/show_bug.cgi?id=587714 for more. */
1292   gint x, y;
1293   gdk_window_get_pointer (event->window, &x, &y, NULL);
1294   event->x = x;
1295   event->y = y;
1296
1297   toolbox_move(vw->vt, event);
1298
1299   vik_viewport_screen_to_coord ( vw->viking_vvp, event->x, event->y, &coord );
1300   vik_coord_to_utm ( &coord, &utm );
1301
1302   get_location_strings ( vw, utm, &lat, &lon );
1303
1304   /* Change interpolate method according to scale */
1305   zoom = vik_viewport_get_zoom(vw->viking_vvp);
1306   if (zoom > 2.0)
1307     interpol_method = VIK_DEM_INTERPOL_NONE;
1308   else if (zoom >= 1.0)
1309     interpol_method = VIK_DEM_INTERPOL_SIMPLE;
1310   else
1311     interpol_method = VIK_DEM_INTERPOL_BEST;
1312   if ((alt = a_dems_get_elev_by_coord(&coord, interpol_method)) != VIK_DEM_INVALID_ELEVATION) {
1313     if ( a_vik_get_units_height () == VIK_UNITS_HEIGHT_METRES )
1314       g_snprintf ( pointer_buf, BUFFER_SIZE, _("%s %s %dm"), lat, lon, alt );
1315     else
1316       g_snprintf ( pointer_buf, BUFFER_SIZE, _("%s %s %dft"), lat, lon, (int)VIK_METERS_TO_FEET(alt) );
1317   }
1318   else
1319     g_snprintf ( pointer_buf, BUFFER_SIZE, _("%s %s"), lat, lon );
1320   g_free (lat);
1321   lat = NULL;
1322   g_free (lon);
1323   lon = NULL;
1324   vik_statusbar_set_message ( vw->viking_vs, VIK_STATUSBAR_POSITION, pointer_buf );
1325
1326   vik_window_pan_move ( vw, event );
1327
1328   /* This is recommended by the GTK+ documentation, but does not work properly.
1329    * Use deprecated way until GTK+ gets a solution for correct motion hint handling:
1330    * http://bugzilla.gnome.org/show_bug.cgi?id=587714
1331   */
1332   /* gdk_event_request_motions ( event ); */
1333 }
1334
1335 /**
1336  * Action the single click after a small timeout
1337  * If a double click has occurred then this will do nothing
1338  */
1339 static gboolean vik_window_pan_timeout (VikWindow *vw)
1340 {
1341   if ( ! vw->single_click_pending ) {
1342     // Double click happened, so don't do anything
1343     return FALSE;
1344   }
1345
1346   /* set panning origin */
1347   vw->pan_move = FALSE;
1348   vw->single_click_pending = FALSE;
1349   vik_viewport_set_center_screen ( vw->viking_vvp, vw->delayed_pan_x, vw->delayed_pan_y );
1350   draw_update ( vw );
1351
1352   // Really turn off the pan moving!!
1353   vw->pan_x = vw->pan_y = -1;
1354   return FALSE;
1355 }
1356
1357 static void vik_window_pan_release ( VikWindow *vw, GdkEventButton *event )
1358 {
1359   gboolean do_draw = TRUE;
1360
1361   if ( vw->pan_move == FALSE ) {
1362     vw->single_click_pending = !vw->single_click_pending;
1363
1364     if ( vw->single_click_pending ) {
1365       // Store offset to use
1366       vw->delayed_pan_x = vw->pan_x;
1367       vw->delayed_pan_y = vw->pan_y;
1368       // Get double click time
1369       GtkSettings *gs = gtk_widget_get_settings ( GTK_WIDGET(vw) );
1370       GValue dct = { 0 }; // = G_VALUE_INIT; // GLIB 2.30+ only
1371       g_value_init ( &dct, G_TYPE_INT );
1372       g_object_get_property ( G_OBJECT(gs), "gtk-double-click-time", &dct );
1373       // Give chance for a double click to occur
1374       gint timer = g_value_get_int ( &dct ) + 50;
1375       g_timeout_add ( timer, (GSourceFunc)vik_window_pan_timeout, vw );
1376       do_draw = FALSE;
1377     }
1378     else {
1379       vik_viewport_set_center_screen ( vw->viking_vvp, vw->pan_x, vw->pan_y );
1380     }
1381   }
1382   else {
1383      vik_viewport_set_center_screen ( vw->viking_vvp, vik_viewport_get_width(vw->viking_vvp)/2 - event->x + vw->pan_x,
1384                                       vik_viewport_get_height(vw->viking_vvp)/2 - event->y + vw->pan_y );
1385   }
1386
1387   vw->pan_move = FALSE;
1388   vw->pan_x = vw->pan_y = -1;
1389   if ( do_draw )
1390     draw_update ( vw );
1391 }
1392
1393 static void draw_release ( VikWindow *vw, GdkEventButton *event )
1394 {
1395   gtk_widget_grab_focus ( GTK_WIDGET(vw->viking_vvp) );
1396
1397   if ( event->button == 2 ) {  /* move / pan */
1398     if ( vw->vt->tools[vw->vt->active_tool].ti.pan_handler )
1399       // Tool still may need to do something (such as reenable something)
1400       toolbox_release(vw->vt, event);
1401     vik_window_pan_release ( vw, event );
1402   }
1403   else {
1404     toolbox_release(vw->vt, event);
1405   }
1406 }
1407
1408 static void draw_scroll (VikWindow *vw, GdkEventScroll *event)
1409 {
1410   guint modifiers = event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK);
1411   if ( modifiers == GDK_CONTROL_MASK ) {
1412     /* control == pan up & down */
1413     if ( event->direction == GDK_SCROLL_UP )
1414       vik_viewport_set_center_screen ( vw->viking_vvp, vik_viewport_get_width(vw->viking_vvp)/2, vik_viewport_get_height(vw->viking_vvp)/3 );
1415     else
1416       vik_viewport_set_center_screen ( vw->viking_vvp, vik_viewport_get_width(vw->viking_vvp)/2, vik_viewport_get_height(vw->viking_vvp)*2/3 );
1417   } else if ( modifiers == GDK_SHIFT_MASK ) {
1418     /* shift == pan left & right */
1419     if ( event->direction == GDK_SCROLL_UP )
1420       vik_viewport_set_center_screen ( vw->viking_vvp, vik_viewport_get_width(vw->viking_vvp)/3, vik_viewport_get_height(vw->viking_vvp)/2 );
1421     else
1422       vik_viewport_set_center_screen ( vw->viking_vvp, vik_viewport_get_width(vw->viking_vvp)*2/3, vik_viewport_get_height(vw->viking_vvp)/2 );
1423   } else if ( modifiers == (GDK_CONTROL_MASK | GDK_SHIFT_MASK) ) {
1424     // This zoom is on the center position
1425     if ( event->direction == GDK_SCROLL_UP )
1426       vik_viewport_zoom_in (vw->viking_vvp);
1427     else
1428       vik_viewport_zoom_out (vw->viking_vvp);
1429   } else {
1430     /* make sure mouse is still over the same point on the map when we zoom */
1431     VikCoord coord;
1432     gint x, y;
1433     gint center_x = vik_viewport_get_width ( vw->viking_vvp ) / 2;
1434     gint center_y = vik_viewport_get_height ( vw->viking_vvp ) / 2;
1435     vik_viewport_screen_to_coord ( vw->viking_vvp, event->x, event->y, &coord );
1436     if ( event->direction == GDK_SCROLL_UP )
1437       vik_viewport_zoom_in (vw->viking_vvp);
1438     else
1439       vik_viewport_zoom_out(vw->viking_vvp);
1440     vik_viewport_coord_to_screen ( vw->viking_vvp, &coord, &x, &y );
1441     vik_viewport_set_center_screen ( vw->viking_vvp, center_x + (x - event->x),
1442                                      center_y + (y - event->y) );
1443   }
1444
1445   draw_update(vw);
1446 }
1447
1448
1449
1450 /********************************************************************************
1451  ** Ruler tool code
1452  ********************************************************************************/
1453 static void draw_ruler(VikViewport *vvp, GdkDrawable *d, GdkGC *gc, gint x1, gint y1, gint x2, gint y2, gdouble distance)
1454 {
1455   PangoLayout *pl;
1456   gchar str[128];
1457   GdkGC *labgc = vik_viewport_new_gc ( vvp, "#cccccc", 1);
1458   GdkGC *thickgc = gdk_gc_new(d);
1459   
1460   gdouble len = sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
1461   gdouble dx = (x2-x1)/len*10; 
1462   gdouble dy = (y2-y1)/len*10;
1463   gdouble c = cos(DEG2RAD(15.0));
1464   gdouble s = sin(DEG2RAD(15.0));
1465   gdouble angle;
1466   gdouble baseangle = 0;
1467   gint i;
1468
1469   /* draw line with arrow ends */
1470   {
1471     gint tmp_x1=x1, tmp_y1=y1, tmp_x2=x2, tmp_y2=y2;
1472     a_viewport_clip_line(&tmp_x1, &tmp_y1, &tmp_x2, &tmp_y2);
1473     gdk_draw_line(d, gc, tmp_x1, tmp_y1, tmp_x2, tmp_y2);
1474   }
1475
1476   a_viewport_clip_line(&x1, &y1, &x2, &y2);
1477   gdk_draw_line(d, gc, x1, y1, x2, y2);
1478
1479   gdk_draw_line(d, gc, x1 - dy, y1 + dx, x1 + dy, y1 - dx);
1480   gdk_draw_line(d, gc, x2 - dy, y2 + dx, x2 + dy, y2 - dx);
1481   gdk_draw_line(d, gc, x2, y2, x2 - (dx * c + dy * s), y2 - (dy * c - dx * s));
1482   gdk_draw_line(d, gc, x2, y2, x2 - (dx * c - dy * s), y2 - (dy * c + dx * s));
1483   gdk_draw_line(d, gc, x1, y1, x1 + (dx * c + dy * s), y1 + (dy * c - dx * s));
1484   gdk_draw_line(d, gc, x1, y1, x1 + (dx * c - dy * s), y1 + (dy * c + dx * s));
1485
1486   /* draw compass */
1487 #define CR 80
1488 #define CW 4
1489
1490   vik_viewport_compute_bearing ( vvp, x1, y1, x2, y2, &angle, &baseangle );
1491
1492   {
1493     GdkColor color;
1494     gdk_gc_copy(thickgc, gc);
1495     gdk_gc_set_line_attributes(thickgc, CW, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
1496     gdk_color_parse("#2255cc", &color);
1497     gdk_gc_set_rgb_fg_color(thickgc, &color);
1498   }
1499   gdk_draw_arc (d, thickgc, FALSE, x1-CR+CW/2, y1-CR+CW/2, 2*CR-CW, 2*CR-CW, (90 - RAD2DEG(baseangle))*64, -RAD2DEG(angle)*64);
1500
1501
1502   gdk_gc_copy(thickgc, gc);
1503   gdk_gc_set_line_attributes(thickgc, 2, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
1504   for (i=0; i<180; i++) {
1505     c = cos(DEG2RAD(i)*2 + baseangle);
1506     s = sin(DEG2RAD(i)*2 + baseangle);
1507
1508     if (i%5) {
1509       gdk_draw_line (d, gc, x1 + CR*c, y1 + CR*s, x1 + (CR+CW)*c, y1 + (CR+CW)*s);
1510     } else {
1511       gdouble ticksize = 2*CW;
1512       gdk_draw_line (d, thickgc, x1 + (CR-CW)*c, y1 + (CR-CW)*s, x1 + (CR+ticksize)*c, y1 + (CR+ticksize)*s);
1513     }
1514   }
1515
1516   gdk_draw_arc (d, gc, FALSE, x1-CR, y1-CR, 2*CR, 2*CR, 0, 64*360);
1517   gdk_draw_arc (d, gc, FALSE, x1-CR-CW, y1-CR-CW, 2*(CR+CW), 2*(CR+CW), 0, 64*360);
1518   gdk_draw_arc (d, gc, FALSE, x1-CR+CW, y1-CR+CW, 2*(CR-CW), 2*(CR-CW), 0, 64*360);
1519   c = (CR+CW*2)*cos(baseangle);
1520   s = (CR+CW*2)*sin(baseangle);
1521   gdk_draw_line (d, gc, x1-c, y1-s, x1+c, y1+s);
1522   gdk_draw_line (d, gc, x1+s, y1-c, x1-s, y1+c);
1523
1524   /* draw labels */
1525 #define LABEL(x, y, w, h) { \
1526     gdk_draw_rectangle(d, labgc, TRUE, (x)-2, (y)-1, (w)+4, (h)+1); \
1527     gdk_draw_rectangle(d, gc, FALSE, (x)-2, (y)-1, (w)+4, (h)+1); \
1528     gdk_draw_layout(d, gc, (x), (y), pl); } 
1529   {
1530     gint wd, hd, xd, yd;
1531     gint wb, hb, xb, yb;
1532
1533     pl = gtk_widget_create_pango_layout (GTK_WIDGET(vvp), NULL);
1534     pango_layout_set_font_description (pl, gtk_widget_get_style(GTK_WIDGET(vvp))->font_desc);
1535     pango_layout_set_text(pl, "N", -1);
1536     gdk_draw_layout(d, gc, x1-5, y1-CR-3*CW-8, pl);
1537
1538     /* draw label with distance */
1539     vik_units_distance_t dist_units = a_vik_get_units_distance ();
1540     switch (dist_units) {
1541     case VIK_UNITS_DISTANCE_KILOMETRES:
1542       if (distance >= 1000 && distance < 100000) {
1543         g_sprintf(str, "%3.2f km", distance/1000.0);
1544       } else if (distance < 1000) {
1545         g_sprintf(str, "%d m", (int)distance);
1546       } else {
1547         g_sprintf(str, "%d km", (int)distance/1000);
1548       }
1549       break;
1550     case VIK_UNITS_DISTANCE_MILES:
1551       if (distance >= VIK_MILES_TO_METERS(1) && distance < VIK_MILES_TO_METERS(100)) {
1552         g_sprintf(str, "%3.2f miles", VIK_METERS_TO_MILES(distance));
1553       } else if (distance < VIK_MILES_TO_METERS(1)) {
1554         g_sprintf(str, "%d yards", (int)(distance*1.0936133));
1555       } else {
1556         g_sprintf(str, "%d miles", (int)VIK_METERS_TO_MILES(distance));
1557       }
1558       break;
1559     case VIK_UNITS_DISTANCE_NAUTICAL_MILES:
1560       if (distance >= VIK_NAUTICAL_MILES_TO_METERS(1) && distance < VIK_NAUTICAL_MILES_TO_METERS(100)) {
1561         g_sprintf(str, "%3.2f NM", VIK_METERS_TO_NAUTICAL_MILES(distance));
1562       } else if (distance < VIK_NAUTICAL_MILES_TO_METERS(1)) {
1563         g_sprintf(str, "%d yards", (int)(distance*1.0936133));
1564       } else {
1565         g_sprintf(str, "%d NM", (int)VIK_METERS_TO_NAUTICAL_MILES(distance));
1566       }
1567       break;
1568     default:
1569       g_critical("Houston, we've had a problem. distance=%d", dist_units);
1570     }
1571
1572     pango_layout_set_text(pl, str, -1);
1573
1574     pango_layout_get_pixel_size ( pl, &wd, &hd );
1575     if (dy>0) {
1576       xd = (x1+x2)/2 + dy;
1577       yd = (y1+y2)/2 - hd/2 - dx;
1578     } else {
1579       xd = (x1+x2)/2 - dy;
1580       yd = (y1+y2)/2 - hd/2 + dx;
1581     }
1582
1583     if ( xd < -5 || yd < -5 || xd > vik_viewport_get_width(vvp)+5 || yd > vik_viewport_get_height(vvp)+5 ) {
1584       xd = x2 + 10;
1585       yd = y2 - 5;
1586     }
1587
1588     LABEL(xd, yd, wd, hd);
1589
1590     /* draw label with bearing */
1591     g_sprintf(str, "%3.1f°", RAD2DEG(angle));
1592     pango_layout_set_text(pl, str, -1);
1593     pango_layout_get_pixel_size ( pl, &wb, &hb );
1594     xb = x1 + CR*cos(angle-M_PI_2);
1595     yb = y1 + CR*sin(angle-M_PI_2);
1596
1597     if ( xb < -5 || yb < -5 || xb > vik_viewport_get_width(vvp)+5 || yb > vik_viewport_get_height(vvp)+5 ) {
1598       xb = x2 + 10;
1599       yb = y2 + 10;
1600     }
1601
1602     {
1603       GdkRectangle r1 = {xd-2, yd-1, wd+4, hd+1}, r2 = {xb-2, yb-1, wb+4, hb+1};
1604       if (gdk_rectangle_intersect(&r1, &r2, &r2)) {
1605         xb = xd + wd + 5;
1606       }
1607     }
1608     LABEL(xb, yb, wb, hb);
1609   }
1610 #undef LABEL
1611
1612   g_object_unref ( G_OBJECT ( pl ) );
1613   g_object_unref ( G_OBJECT ( labgc ) );
1614   g_object_unref ( G_OBJECT ( thickgc ) );
1615 }
1616
1617 typedef struct {
1618   VikWindow *vw;
1619   VikViewport *vvp;
1620   gboolean has_oldcoord;
1621   VikCoord oldcoord;
1622 } ruler_tool_state_t;
1623
1624 static gpointer ruler_create (VikWindow *vw, VikViewport *vvp) 
1625 {
1626   ruler_tool_state_t *s = g_new(ruler_tool_state_t, 1);
1627   s->vw = vw;
1628   s->vvp = vvp;
1629   s->has_oldcoord = FALSE;
1630   return s;
1631 }
1632
1633 static void ruler_destroy (ruler_tool_state_t *s)
1634 {
1635   g_free(s);
1636 }
1637
1638 static VikLayerToolFuncStatus ruler_click (VikLayer *vl, GdkEventButton *event, ruler_tool_state_t *s)
1639 {
1640   struct LatLon ll;
1641   VikCoord coord;
1642   gchar *temp;
1643   if ( event->button == 1 ) {
1644     gchar *lat=NULL, *lon=NULL;
1645     vik_viewport_screen_to_coord ( s->vvp, (gint) event->x, (gint) event->y, &coord );
1646     vik_coord_to_latlon ( &coord, &ll );
1647     a_coords_latlon_to_string ( &ll, &lat, &lon );
1648     if ( s->has_oldcoord ) {
1649       vik_units_distance_t dist_units = a_vik_get_units_distance ();
1650       switch (dist_units) {
1651       case VIK_UNITS_DISTANCE_KILOMETRES:
1652         temp = g_strdup_printf ( "%s %s DIFF %f meters", lat, lon, vik_coord_diff( &coord, &(s->oldcoord) ) );
1653         break;
1654       case VIK_UNITS_DISTANCE_MILES:
1655         temp = g_strdup_printf ( "%s %s DIFF %f miles", lat, lon, VIK_METERS_TO_MILES(vik_coord_diff( &coord, &(s->oldcoord) )) );
1656         break;
1657       case VIK_UNITS_DISTANCE_NAUTICAL_MILES:
1658         temp = g_strdup_printf ( "%s %s DIFF %f NM", lat, lon, VIK_METERS_TO_NAUTICAL_MILES(vik_coord_diff( &coord, &(s->oldcoord) )) );
1659         break;
1660       default:
1661         temp = g_strdup_printf ("Just to keep the compiler happy");
1662         g_critical("Houston, we've had a problem. distance=%d", dist_units);
1663       }
1664
1665       s->has_oldcoord = FALSE;
1666     }
1667     else {
1668       temp = g_strdup_printf ( "%s %s", lat, lon );
1669       s->has_oldcoord = TRUE;
1670     }
1671
1672     vik_statusbar_set_message ( s->vw->viking_vs, VIK_STATUSBAR_INFO, temp );
1673     g_free ( temp );
1674
1675     s->oldcoord = coord;
1676   }
1677   else {
1678     vik_viewport_set_center_screen ( s->vvp, (gint) event->x, (gint) event->y );
1679     draw_update ( s->vw );
1680   }
1681   return VIK_LAYER_TOOL_ACK;
1682 }
1683
1684 static VikLayerToolFuncStatus ruler_move (VikLayer *vl, GdkEventMotion *event, ruler_tool_state_t *s)
1685 {
1686   VikViewport *vvp = s->vvp;
1687   VikWindow *vw = s->vw;
1688
1689   struct LatLon ll;
1690   VikCoord coord;
1691   gchar *temp;
1692
1693   if ( s->has_oldcoord ) {
1694     int oldx, oldy, w1, h1, w2, h2;
1695     static GdkPixmap *buf = NULL;
1696     gchar *lat=NULL, *lon=NULL;
1697     w1 = vik_viewport_get_width(vvp); 
1698     h1 = vik_viewport_get_height(vvp);
1699     if (!buf) {
1700       buf = gdk_pixmap_new ( gtk_widget_get_window(GTK_WIDGET(vvp)), w1, h1, -1 );
1701     }
1702     gdk_drawable_get_size(buf, &w2, &h2);
1703     if (w1 != w2 || h1 != h2) {
1704       g_object_unref ( G_OBJECT ( buf ) );
1705       buf = gdk_pixmap_new ( gtk_widget_get_window(GTK_WIDGET(vvp)), w1, h1, -1 );
1706     }
1707
1708     vik_viewport_screen_to_coord ( vvp, (gint) event->x, (gint) event->y, &coord );
1709     vik_coord_to_latlon ( &coord, &ll );
1710     vik_viewport_coord_to_screen ( vvp, &s->oldcoord, &oldx, &oldy );
1711
1712     gdk_draw_drawable (buf, gtk_widget_get_style(GTK_WIDGET(vvp))->black_gc,
1713                        vik_viewport_get_pixmap(vvp), 0, 0, 0, 0, -1, -1);
1714     draw_ruler(vvp, buf, gtk_widget_get_style(GTK_WIDGET(vvp))->black_gc, oldx, oldy, event->x, event->y, vik_coord_diff( &coord, &(s->oldcoord)) );
1715     if (draw_buf_done) {
1716       static gpointer pass_along[3];
1717       pass_along[0] = gtk_widget_get_window(GTK_WIDGET(vvp));
1718       pass_along[1] = gtk_widget_get_style(GTK_WIDGET(vvp))->black_gc;
1719       pass_along[2] = buf;
1720       g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, draw_buf, pass_along, NULL);
1721       draw_buf_done = FALSE;
1722     }
1723     a_coords_latlon_to_string(&ll, &lat, &lon);
1724     vik_units_distance_t dist_units = a_vik_get_units_distance ();
1725     switch (dist_units) {
1726     case VIK_UNITS_DISTANCE_KILOMETRES:
1727       temp = g_strdup_printf ( "%s %s DIFF %f meters", lat, lon, vik_coord_diff( &coord, &(s->oldcoord) ) );
1728       break;
1729     case VIK_UNITS_DISTANCE_MILES:
1730       temp = g_strdup_printf ( "%s %s DIFF %f miles", lat, lon, VIK_METERS_TO_MILES (vik_coord_diff( &coord, &(s->oldcoord) )) );
1731       break;
1732     case VIK_UNITS_DISTANCE_NAUTICAL_MILES:
1733       temp = g_strdup_printf ( "%s %s DIFF %f NM", lat, lon, VIK_METERS_TO_NAUTICAL_MILES (vik_coord_diff( &coord, &(s->oldcoord) )) );
1734       break;
1735     default:
1736       temp = g_strdup_printf ("Just to keep the compiler happy");
1737       g_critical("Houston, we've had a problem. distance=%d", dist_units);
1738     }
1739     vik_statusbar_set_message ( vw->viking_vs, VIK_STATUSBAR_INFO, temp );
1740     g_free ( temp );
1741   }
1742   return VIK_LAYER_TOOL_ACK;
1743 }
1744
1745 static VikLayerToolFuncStatus ruler_release (VikLayer *vl, GdkEventButton *event, ruler_tool_state_t *s)
1746 {
1747   return VIK_LAYER_TOOL_ACK;
1748 }
1749
1750 static void ruler_deactivate (VikLayer *vl, ruler_tool_state_t *s)
1751 {
1752   draw_update ( s->vw );
1753 }
1754
1755 static gboolean ruler_key_press (VikLayer *vl, GdkEventKey *event, ruler_tool_state_t *s)
1756 {
1757   if (event->keyval == GDK_Escape) {
1758     s->has_oldcoord = FALSE;
1759     ruler_deactivate ( vl, s );
1760     return TRUE;
1761   }
1762   // Regardless of whether we used it, return false so other GTK things may use it
1763   return FALSE;
1764 }
1765
1766 static VikToolInterface ruler_tool =
1767   // NB Ctrl+Shift+R is used for Refresh (deemed more important), so use 'U' instead
1768   { { "Ruler", "vik-icon-ruler", N_("_Ruler"), "<control><shift>U", N_("Ruler Tool"), 2 },
1769     (VikToolConstructorFunc) ruler_create,
1770     (VikToolDestructorFunc) ruler_destroy,
1771     (VikToolActivationFunc) NULL,
1772     (VikToolActivationFunc) ruler_deactivate, 
1773     (VikToolMouseFunc) ruler_click, 
1774     (VikToolMouseMoveFunc) ruler_move, 
1775     (VikToolMouseFunc) ruler_release,
1776     (VikToolKeyFunc) ruler_key_press,
1777     FALSE,
1778     GDK_CURSOR_IS_PIXMAP,
1779     &cursor_ruler_pixbuf,
1780     NULL };
1781 /*** end ruler code ********************************************************/
1782
1783
1784
1785 /********************************************************************************
1786  ** Zoom tool code
1787  ********************************************************************************/
1788
1789 typedef struct {
1790   VikWindow *vw;
1791   GdkPixmap *pixmap;
1792   // Track zoom bounds for zoom tool with shift modifier:
1793   gboolean bounds_active;
1794   gint start_x;
1795   gint start_y;
1796 } zoom_tool_state_t;
1797
1798 /*
1799  * In case the screen size has changed
1800  */
1801 static void zoomtool_resize_pixmap (zoom_tool_state_t *zts)
1802 {
1803     int w1, h1, w2, h2;
1804
1805     // Allocate a drawing area the size of the viewport
1806     w1 = vik_viewport_get_width ( zts->vw->viking_vvp );
1807     h1 = vik_viewport_get_height ( zts->vw->viking_vvp );
1808
1809     if ( !zts->pixmap ) {
1810       // Totally new
1811       zts->pixmap = gdk_pixmap_new ( gtk_widget_get_window(GTK_WIDGET(zts->vw->viking_vvp)), w1, h1, -1 );
1812     }
1813
1814     gdk_drawable_get_size ( zts->pixmap, &w2, &h2 );
1815
1816     if ( w1 != w2 || h1 != h2 ) {
1817       // Has changed - delete and recreate with new values
1818       g_object_unref ( G_OBJECT ( zts->pixmap ) );
1819       zts->pixmap = gdk_pixmap_new ( gtk_widget_get_window(GTK_WIDGET(zts->vw->viking_vvp)), w1, h1, -1 );
1820     }
1821 }
1822
1823 static gpointer zoomtool_create (VikWindow *vw, VikViewport *vvp)
1824 {
1825   zoom_tool_state_t *zts = g_new(zoom_tool_state_t, 1);
1826   zts->vw = vw;
1827   zts->pixmap = NULL;
1828   zts->start_x = 0;
1829   zts->start_y = 0;
1830   zts->bounds_active = FALSE;
1831   return zts;
1832 }
1833
1834 static void zoomtool_destroy ( zoom_tool_state_t *zts)
1835 {
1836   if ( zts->pixmap )
1837     g_object_unref ( G_OBJECT ( zts->pixmap ) );
1838   g_free(zts);
1839 }
1840
1841 static VikLayerToolFuncStatus zoomtool_click (VikLayer *vl, GdkEventButton *event, zoom_tool_state_t *zts)
1842 {
1843   zts->vw->modified = TRUE;
1844   guint modifiers = event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK);
1845
1846   VikCoord coord;
1847   gint x, y;
1848   gint center_x = vik_viewport_get_width ( zts->vw->viking_vvp ) / 2;
1849   gint center_y = vik_viewport_get_height ( zts->vw->viking_vvp ) / 2;
1850
1851   gboolean skip_update = FALSE;
1852
1853   zts->bounds_active = FALSE;
1854
1855   if ( modifiers == (GDK_CONTROL_MASK | GDK_SHIFT_MASK) ) {
1856     // This zoom is on the center position
1857     vik_viewport_set_center_screen ( zts->vw->viking_vvp, center_x, center_y );
1858     if ( event->button == 1 )
1859       vik_viewport_zoom_in (zts->vw->viking_vvp);
1860     else if ( event->button == 3 )
1861       vik_viewport_zoom_out (zts->vw->viking_vvp);
1862   }
1863   else if ( modifiers == GDK_CONTROL_MASK ) {
1864     // This zoom is to recenter on the mouse position
1865     vik_viewport_set_center_screen ( zts->vw->viking_vvp, (gint) event->x, (gint) event->y );
1866     if ( event->button == 1 )
1867       vik_viewport_zoom_in (zts->vw->viking_vvp);
1868     else if ( event->button == 3 )
1869       vik_viewport_zoom_out (zts->vw->viking_vvp);
1870   }
1871   else if ( modifiers == GDK_SHIFT_MASK ) {
1872     // Get start of new zoom bounds
1873     if ( event->button == 1 ) {
1874       zts->bounds_active = TRUE;
1875       zts->start_x = (gint) event->x;
1876       zts->start_y = (gint) event->y;
1877       skip_update = TRUE;
1878     }
1879   }
1880   else {
1881     /* make sure mouse is still over the same point on the map when we zoom */
1882     vik_viewport_screen_to_coord ( zts->vw->viking_vvp, event->x, event->y, &coord );
1883     if ( event->button == 1 )
1884       vik_viewport_zoom_in (zts->vw->viking_vvp);
1885     else if ( event->button == 3 )
1886       vik_viewport_zoom_out(zts->vw->viking_vvp);
1887     vik_viewport_coord_to_screen ( zts->vw->viking_vvp, &coord, &x, &y );
1888     vik_viewport_set_center_screen ( zts->vw->viking_vvp,
1889                                      center_x + (x - event->x),
1890                                      center_y + (y - event->y) );
1891   }
1892
1893   if ( !skip_update )
1894     draw_update ( zts->vw );
1895
1896   return VIK_LAYER_TOOL_ACK;
1897 }
1898
1899 static VikLayerToolFuncStatus zoomtool_move (VikLayer *vl, GdkEventMotion *event, zoom_tool_state_t *zts)
1900 {
1901   guint modifiers = event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK);
1902
1903   if ( zts->bounds_active && modifiers == GDK_SHIFT_MASK ) {
1904     zoomtool_resize_pixmap ( zts );
1905
1906     // Blank out currently drawn area
1907     gdk_draw_drawable ( zts->pixmap,
1908                         gtk_widget_get_style(GTK_WIDGET(zts->vw->viking_vvp))->black_gc,
1909                         vik_viewport_get_pixmap(zts->vw->viking_vvp),
1910                         0, 0, 0, 0, -1, -1);
1911
1912     // Calculate new box starting point & size in pixels
1913     int xx, yy, width, height;
1914     if ( event->y > zts->start_y ) {
1915       yy = zts->start_y;
1916       height = event->y-zts->start_y;
1917     }
1918     else {
1919       yy = event->y;
1920       height = zts->start_y-event->y;
1921     }
1922     if ( event->x > zts->start_x ) {
1923       xx = zts->start_x;
1924       width = event->x-zts->start_x;
1925     }
1926     else {
1927       xx = event->x;
1928       width = zts->start_x-event->x;
1929     }
1930
1931     // Draw the box
1932     gdk_draw_rectangle (zts->pixmap, gtk_widget_get_style(GTK_WIDGET(zts->vw->viking_vvp))->black_gc, FALSE, xx, yy, width, height);
1933
1934     // Only actually draw when there's time to do so
1935     if (draw_buf_done) {
1936       static gpointer pass_along[3];
1937       pass_along[0] = gtk_widget_get_window(GTK_WIDGET(zts->vw->viking_vvp));
1938       pass_along[1] = gtk_widget_get_style(GTK_WIDGET(zts->vw->viking_vvp))->black_gc;
1939       pass_along[2] = zts->pixmap;
1940       g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, draw_buf, pass_along, NULL);
1941       draw_buf_done = FALSE;
1942     }
1943   }
1944   else
1945     zts->bounds_active = FALSE;
1946
1947   return VIK_LAYER_TOOL_ACK;
1948 }
1949
1950 static VikLayerToolFuncStatus zoomtool_release (VikLayer *vl, GdkEventButton *event, zoom_tool_state_t *zts)
1951 {
1952   guint modifiers = event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK);
1953
1954   // Ensure haven't just released on the exact same position
1955   //  i.e. probably haven't moved the mouse at all
1956   if ( zts->bounds_active && modifiers == GDK_SHIFT_MASK &&
1957      ( event->x < zts->start_x-5 || event->x > zts->start_x+5 ) &&
1958      ( event->y < zts->start_y-5 || event->y > zts->start_y+5 ) ) {
1959
1960     VikCoord coord1, coord2;
1961     vik_viewport_screen_to_coord ( zts->vw->viking_vvp, zts->start_x, zts->start_y, &coord1);
1962     vik_viewport_screen_to_coord ( zts->vw->viking_vvp, event->x, event->y, &coord2);
1963
1964     // From the extend of the bounds pick the best zoom level
1965     // c.f. trw_layer_zoom_to_show_latlons()
1966     // Maybe refactor...
1967     struct LatLon ll1, ll2;
1968     vik_coord_to_latlon(&coord1, &ll1);
1969     vik_coord_to_latlon(&coord2, &ll2);
1970     struct LatLon average = { (ll1.lat+ll2.lat)/2,
1971                               (ll1.lon+ll2.lon)/2 };
1972
1973     VikCoord new_center;
1974     vik_coord_load_from_latlon ( &new_center, vik_viewport_get_coord_mode ( zts->vw->viking_vvp ), &average );
1975     vik_viewport_set_center_coord ( zts->vw->viking_vvp, &new_center, FALSE );
1976
1977     /* Convert into definite 'smallest' and 'largest' positions */
1978     struct LatLon minmin;
1979     if ( ll1.lat < ll2.lat )
1980       minmin.lat = ll1.lat;
1981     else
1982       minmin.lat = ll2.lat;
1983
1984     struct LatLon maxmax;
1985     if ( ll1.lon > ll2.lon )
1986       maxmax.lon = ll1.lon;
1987     else
1988       maxmax.lon = ll2.lon;
1989
1990     /* Always recalculate the 'best' zoom level */
1991     gdouble zoom = VIK_VIEWPORT_MIN_ZOOM;
1992     vik_viewport_set_zoom ( zts->vw->viking_vvp, zoom );
1993
1994     gdouble min_lat, max_lat, min_lon, max_lon;
1995     /* Should only be a maximum of about 18 iterations from min to max zoom levels */
1996     while ( zoom <= VIK_VIEWPORT_MAX_ZOOM ) {
1997       vik_viewport_get_min_max_lat_lon ( zts->vw->viking_vvp, &min_lat, &max_lat, &min_lon, &max_lon );
1998       /* NB I think the logic used in this test to determine if the bounds is within view
1999          fails if track goes across 180 degrees longitude.
2000          Hopefully that situation is not too common...
2001          Mind you viking doesn't really do edge locations to well anyway */
2002       if ( min_lat < minmin.lat &&
2003            max_lat > minmin.lat &&
2004            min_lon < maxmax.lon &&
2005            max_lon > maxmax.lon )
2006         /* Found within zoom level */
2007         break;
2008
2009       /* Try next */
2010       zoom = zoom * 2;
2011       vik_viewport_set_zoom ( zts->vw->viking_vvp, zoom );
2012     }
2013   }
2014   else {
2015      // When pressing shift and clicking for zoom, then jump three levels
2016      if ( modifiers == GDK_SHIFT_MASK ) {
2017        // Zoom in/out by three if possible
2018        vik_viewport_set_center_screen ( zts->vw->viking_vvp, event->x, event->y );
2019        if ( event->button == 1 ) {
2020           vik_viewport_zoom_in ( zts->vw->viking_vvp );
2021           vik_viewport_zoom_in ( zts->vw->viking_vvp );
2022           vik_viewport_zoom_in ( zts->vw->viking_vvp );
2023        }
2024        else if ( event->button == 3 ) {
2025           vik_viewport_zoom_out ( zts->vw->viking_vvp );
2026           vik_viewport_zoom_out ( zts->vw->viking_vvp );
2027           vik_viewport_zoom_out ( zts->vw->viking_vvp );
2028        }
2029      }
2030   }
2031
2032   draw_update ( zts->vw );
2033
2034   // Reset
2035   zts->bounds_active = FALSE;
2036
2037   return VIK_LAYER_TOOL_ACK;
2038 }
2039
2040 static VikToolInterface zoom_tool = 
2041   { { "Zoom", "vik-icon-zoom", N_("_Zoom"), "<control><shift>Z", N_("Zoom Tool"), 1 },
2042     (VikToolConstructorFunc) zoomtool_create,
2043     (VikToolDestructorFunc) zoomtool_destroy,
2044     (VikToolActivationFunc) NULL,
2045     (VikToolActivationFunc) NULL,
2046     (VikToolMouseFunc) zoomtool_click, 
2047     (VikToolMouseMoveFunc) zoomtool_move,
2048     (VikToolMouseFunc) zoomtool_release,
2049     NULL,
2050     FALSE,
2051     GDK_CURSOR_IS_PIXMAP,
2052     &cursor_zoom_pixbuf,
2053     NULL };
2054 /*** end zoom code ********************************************************/
2055
2056 /********************************************************************************
2057  ** Pan tool code
2058  ********************************************************************************/
2059 static gpointer pantool_create (VikWindow *vw, VikViewport *vvp)
2060 {
2061   return vw;
2062 }
2063
2064 // NB Double clicking means this gets called THREE times!!!
2065 static VikLayerToolFuncStatus pantool_click (VikLayer *vl, GdkEventButton *event, VikWindow *vw)
2066 {
2067   vw->modified = TRUE;
2068
2069   if ( event->type == GDK_2BUTTON_PRESS ) {
2070     // Zoom in / out on double click
2071     // No need to change the center as that has already occurred in the first click of a double click occurrence
2072     if ( event->button == 1 ) {
2073       guint modifier = event->state & GDK_SHIFT_MASK;
2074       if ( modifier )
2075         vik_viewport_zoom_out ( vw->viking_vvp );
2076       else
2077         vik_viewport_zoom_in ( vw->viking_vvp );
2078     }
2079     else if ( event->button == 3 )
2080       vik_viewport_zoom_out ( vw->viking_vvp );
2081
2082     draw_update ( vw );
2083   }
2084   else
2085     // Standard pan click
2086     if ( event->button == 1 )
2087       vik_window_pan_click ( vw, event );
2088
2089   return VIK_LAYER_TOOL_ACK;
2090 }
2091
2092 static VikLayerToolFuncStatus pantool_move (VikLayer *vl, GdkEventMotion *event, VikWindow *vw)
2093 {
2094   vik_window_pan_move ( vw, event );
2095   return VIK_LAYER_TOOL_ACK;
2096 }
2097
2098 static VikLayerToolFuncStatus pantool_release (VikLayer *vl, GdkEventButton *event, VikWindow *vw)
2099 {
2100   if ( event->button == 1 )
2101     vik_window_pan_release ( vw, event );
2102   return VIK_LAYER_TOOL_ACK;
2103 }
2104
2105 static VikToolInterface pan_tool = 
2106   { { "Pan", "vik-icon-pan", N_("_Pan"), "<control><shift>P", N_("Pan Tool"), 0 },
2107     (VikToolConstructorFunc) pantool_create,
2108     (VikToolDestructorFunc) NULL,
2109     (VikToolActivationFunc) NULL,
2110     (VikToolActivationFunc) NULL,
2111     (VikToolMouseFunc) pantool_click, 
2112     (VikToolMouseMoveFunc) pantool_move,
2113     (VikToolMouseFunc) pantool_release,
2114     NULL,
2115     FALSE,
2116     GDK_FLEUR,
2117     NULL,
2118     NULL };
2119 /*** end pan code ********************************************************/
2120
2121 /********************************************************************************
2122  ** Select tool code
2123  ********************************************************************************/
2124 static gpointer selecttool_create (VikWindow *vw, VikViewport *vvp)
2125 {
2126   tool_ed_t *t = g_new(tool_ed_t, 1);
2127   t->vw = vw;
2128   t->vvp = vvp;
2129   t->vtl = NULL;
2130   t->is_waypoint = FALSE;
2131   return t;
2132 }
2133
2134 static void selecttool_destroy (tool_ed_t *t)
2135 {
2136   g_free(t);
2137 }
2138
2139 typedef struct {
2140   gboolean cont;
2141   VikViewport *vvp;
2142   GdkEventButton *event;
2143   tool_ed_t *tool_edit;
2144 } clicker;
2145
2146 static void click_layer_selected (VikLayer *vl, clicker *ck)
2147 {
2148   /* Do nothing when function call returns true; */
2149   /* i.e. stop on first found item */
2150   if ( ck->cont )
2151     if ( vl->visible )
2152       if ( vik_layer_get_interface(vl->type)->select_click )
2153         ck->cont = !vik_layer_get_interface(vl->type)->select_click ( vl, ck->event, ck->vvp, ck->tool_edit );
2154 }
2155
2156 #ifdef WINDOWS
2157 // Hopefully Alt keys by default
2158 #define VIK_MOVE_MODIFIER GDK_MOD1_MASK
2159 #else
2160 // Alt+mouse on Linux desktops tend to be used by the desktop manager
2161 // Thus use an alternate modifier - you may need to set something into this group
2162 #define VIK_MOVE_MODIFIER GDK_MOD5_MASK
2163 #endif
2164
2165 static VikLayerToolFuncStatus selecttool_click (VikLayer *vl, GdkEventButton *event, tool_ed_t *t)
2166 {
2167   t->vw->select_move = FALSE;
2168   /* Only allow selection on primary button */
2169   if ( event->button == 1 ) {
2170
2171     if ( event->state & VIK_MOVE_MODIFIER )
2172       vik_window_pan_click ( t->vw, event );
2173     else {
2174       /* Enable click to apply callback to potentially all track/waypoint layers */
2175       /* Useful as we can find things that aren't necessarily in the currently selected layer */
2176       GList* gl = vik_layers_panel_get_all_layers_of_type ( t->vw->viking_vlp, VIK_LAYER_TRW, FALSE ); // Don't get invisible layers
2177       clicker ck;
2178       ck.cont = TRUE;
2179       ck.vvp = t->vw->viking_vvp;
2180       ck.event = event;
2181       ck.tool_edit = t;
2182       g_list_foreach ( gl, (GFunc) click_layer_selected, &ck );
2183       g_list_free ( gl );
2184
2185       // If nothing found then deselect & redraw screen if necessary to remove the highlight
2186       if ( ck.cont ) {
2187         GtkTreeIter iter;
2188         VikTreeview *vtv = vik_layers_panel_get_treeview ( t->vw->viking_vlp );
2189
2190         if ( vik_treeview_get_selected_iter ( vtv, &iter ) ) {
2191           // Only clear if selected thing is a TrackWaypoint layer or a sublayer
2192           gint type = vik_treeview_item_get_type ( vtv, &iter );
2193           if ( type == VIK_TREEVIEW_TYPE_SUBLAYER ||
2194             VIK_LAYER(vik_treeview_item_get_pointer ( vtv, &iter ))->type == VIK_LAYER_TRW ) {
2195    
2196             vik_treeview_item_unselect ( vtv, &iter );
2197             if ( vik_window_clear_highlight ( t->vw ) )
2198               draw_update ( t->vw );
2199           }
2200         }
2201       }
2202       else {
2203         // Something found - so enable movement
2204         t->vw->select_move = TRUE;
2205       }
2206     }
2207   }
2208   else if ( ( event->button == 3 ) && ( vl && ( vl->type == VIK_LAYER_TRW ) ) ) {
2209     if ( vl->visible )
2210       /* Act on currently selected item to show menu */
2211       if ( t->vw->selected_track || t->vw->selected_waypoint )
2212         if ( vik_layer_get_interface(vl->type)->show_viewport_menu )
2213           vik_layer_get_interface(vl->type)->show_viewport_menu ( vl, event, t->vw->viking_vvp );
2214   }
2215
2216   return VIK_LAYER_TOOL_ACK;
2217 }
2218
2219 static VikLayerToolFuncStatus selecttool_move (VikLayer *vl, GdkEventMotion *event, tool_ed_t *t)
2220 {
2221   if ( t->vw->select_move ) {
2222     // Don't care about vl here
2223     if ( t->vtl )
2224       if ( vik_layer_get_interface(VIK_LAYER_TRW)->select_move )
2225         vik_layer_get_interface(VIK_LAYER_TRW)->select_move ( vl, event, t->vvp, t );
2226   }
2227   else
2228     // Optional Panning
2229     if ( event->state & VIK_MOVE_MODIFIER )
2230       vik_window_pan_move ( t->vw, event );
2231
2232   return VIK_LAYER_TOOL_ACK;
2233 }
2234
2235 static VikLayerToolFuncStatus selecttool_release (VikLayer *vl, GdkEventButton *event, tool_ed_t *t)
2236 {
2237   if ( t->vw->select_move ) {
2238     // Don't care about vl here
2239     if ( t->vtl )
2240       if ( vik_layer_get_interface(VIK_LAYER_TRW)->select_release )
2241         vik_layer_get_interface(VIK_LAYER_TRW)->select_release ( (VikLayer*)t->vtl, event, t->vvp, t );
2242   }
2243
2244   if ( event->button == 1 && (event->state & VIK_MOVE_MODIFIER) )
2245       vik_window_pan_release ( t->vw, event );
2246
2247   // Force pan off incase it was on
2248   t->vw->pan_move = FALSE;
2249   t->vw->pan_x = t->vw->pan_y = -1;
2250
2251   // End of this select movement
2252   t->vw->select_move = FALSE;
2253
2254   return VIK_LAYER_TOOL_ACK;
2255 }
2256
2257 static VikToolInterface select_tool =
2258   { { "Select", "vik-icon-select", N_("_Select"), "<control><shift>S", N_("Select Tool"), 3 },
2259     (VikToolConstructorFunc) selecttool_create,
2260     (VikToolDestructorFunc) selecttool_destroy,
2261     (VikToolActivationFunc) NULL,
2262     (VikToolActivationFunc) NULL,
2263     (VikToolMouseFunc) selecttool_click,
2264     (VikToolMouseMoveFunc) selecttool_move,
2265     (VikToolMouseFunc) selecttool_release,
2266     (VikToolKeyFunc) NULL,
2267     FALSE,
2268     GDK_LEFT_PTR,
2269     NULL,
2270     NULL };
2271 /*** end select tool code ********************************************************/
2272
2273 static void draw_pan_cb ( GtkAction *a, VikWindow *vw )
2274 {
2275   // Since the treeview cell editting intercepts standard keyboard handlers, it means we can receive events here
2276   // Thus if currently editting, ensure we don't move the viewport when Ctrl+<arrow> is received
2277   VikLayer *sel = vik_layers_panel_get_selected ( vw->viking_vlp );
2278   if ( sel && vik_treeview_get_editing ( sel->vt ) )
2279     return;
2280
2281   if (!strcmp(gtk_action_get_name(a), "PanNorth")) {
2282     vik_viewport_set_center_screen ( vw->viking_vvp, vik_viewport_get_width(vw->viking_vvp)/2, 0 );
2283   } else if (!strcmp(gtk_action_get_name(a), "PanEast")) {
2284     vik_viewport_set_center_screen ( vw->viking_vvp, vik_viewport_get_width(vw->viking_vvp), vik_viewport_get_height(vw->viking_vvp)/2 );
2285   } else if (!strcmp(gtk_action_get_name(a), "PanSouth")) {
2286     vik_viewport_set_center_screen ( vw->viking_vvp, vik_viewport_get_width(vw->viking_vvp)/2, vik_viewport_get_height(vw->viking_vvp) );
2287   } else if (!strcmp(gtk_action_get_name(a), "PanWest")) {
2288     vik_viewport_set_center_screen ( vw->viking_vvp, 0, vik_viewport_get_height(vw->viking_vvp)/2 );
2289   }
2290   draw_update ( vw );
2291 }
2292
2293 static void draw_zoom_cb ( GtkAction *a, VikWindow *vw )
2294 {
2295   guint what = 128;
2296
2297   if (!strcmp(gtk_action_get_name(a), "ZoomIn")) {
2298     what = -3;
2299   } 
2300   else if (!strcmp(gtk_action_get_name(a), "ZoomOut")) {
2301     what = -4;
2302   }
2303   else if (!strcmp(gtk_action_get_name(a), "Zoom0.25")) {
2304     what = -2;
2305   }
2306   else if (!strcmp(gtk_action_get_name(a), "Zoom0.5")) {
2307     what = -1;
2308   }
2309   else {
2310     gchar *s = (gchar *)gtk_action_get_name(a);
2311     what = atoi(s+4);
2312   }
2313
2314   switch (what)
2315   {
2316     case -3: vik_viewport_zoom_in ( vw->viking_vvp ); break;
2317     case -4: vik_viewport_zoom_out ( vw->viking_vvp ); break;
2318     case -1: vik_viewport_set_zoom ( vw->viking_vvp, 0.5 ); break;
2319     case -2: vik_viewport_set_zoom ( vw->viking_vvp, 0.25 ); break;
2320     default: vik_viewport_set_zoom ( vw->viking_vvp, what );
2321   }
2322   draw_update ( vw );
2323 }
2324
2325 static void draw_goto_cb ( GtkAction *a, VikWindow *vw )
2326 {
2327   VikCoord new_center;
2328
2329   if (!strcmp(gtk_action_get_name(a), "GotoLL")) {
2330     struct LatLon ll, llold;
2331     vik_coord_to_latlon ( vik_viewport_get_center ( vw->viking_vvp ), &llold );
2332     if ( a_dialog_goto_latlon ( GTK_WINDOW(vw), &ll, &llold ) )
2333       vik_coord_load_from_latlon ( &new_center, vik_viewport_get_coord_mode(vw->viking_vvp), &ll );
2334     else
2335       return;
2336   }
2337   else if (!strcmp(gtk_action_get_name(a), "GotoUTM")) {
2338     struct UTM utm, utmold;
2339     vik_coord_to_utm ( vik_viewport_get_center ( vw->viking_vvp ), &utmold );
2340     if ( a_dialog_goto_utm ( GTK_WINDOW(vw), &utm, &utmold ) )
2341       vik_coord_load_from_utm ( &new_center, vik_viewport_get_coord_mode(vw->viking_vvp), &utm );
2342     else
2343      return;
2344   }
2345   else {
2346     g_critical("Houston, we've had a problem.");
2347     return;
2348   }
2349
2350   vik_viewport_set_center_coord ( vw->viking_vvp, &new_center, TRUE );
2351   draw_update ( vw );
2352 }
2353
2354 /**
2355  * center_changed_cb:
2356  */
2357 static void center_changed_cb ( VikWindow *vw )
2358 {
2359 // ATM Keep back always available, so when we pan - we can jump to the last requested position
2360 /*
2361   GtkAction* action_back = gtk_action_group_get_action ( vw->action_group, "GoBack" );
2362   if ( action_back ) {
2363     gtk_action_set_sensitive ( action_back, vik_viewport_back_available(vw->viking_vvp) );
2364   }
2365 */
2366   GtkAction* action_forward = gtk_action_group_get_action ( vw->action_group, "GoForward" );
2367   if ( action_forward ) {
2368     gtk_action_set_sensitive ( action_forward, vik_viewport_forward_available(vw->viking_vvp) );
2369   }
2370
2371   toolbar_action_set_sensitive ( vw->viking_vtb, "GoForward", vik_viewport_forward_available(vw->viking_vvp) );
2372 }
2373
2374 /**
2375  * draw_goto_back_and_forth:
2376  */
2377 static void draw_goto_back_and_forth ( GtkAction *a, VikWindow *vw )
2378 {
2379   gboolean changed = FALSE;
2380   if (!strcmp(gtk_action_get_name(a), "GoBack")) {
2381     changed = vik_viewport_go_back ( vw->viking_vvp );
2382   }
2383   else if (!strcmp(gtk_action_get_name(a), "GoForward")) {
2384     changed = vik_viewport_go_forward ( vw->viking_vvp );
2385   }
2386   else {
2387     return;
2388   }
2389
2390   // Recheck buttons sensitivities, as the center changed signal is not sent on back/forward changes
2391   //  (otherwise we would get stuck in an infinite loop!)
2392   center_changed_cb ( vw );
2393
2394   if ( changed )
2395     draw_update ( vw );
2396 }
2397
2398 /**
2399  * Refresh maps displayed
2400  */
2401 static void draw_refresh_cb ( GtkAction *a, VikWindow *vw )
2402 {
2403   // Only get 'new' maps
2404   simple_map_update ( vw, TRUE );
2405 }
2406
2407 static void menu_addlayer_cb ( GtkAction *a, VikWindow *vw )
2408 {
2409  VikLayerTypeEnum type;
2410   for ( type = 0; type < VIK_LAYER_NUM_TYPES; type++ ) {
2411     if (!strcmp(vik_layer_get_interface(type)->name, gtk_action_get_name(a))) {
2412       if ( vik_layers_panel_new_layer ( vw->viking_vlp, type ) ) {
2413         draw_update ( vw );
2414         vw->modified = TRUE;
2415       }
2416     }
2417   }
2418 }
2419
2420 static void menu_copy_layer_cb ( GtkAction *a, VikWindow *vw )
2421 {
2422   a_clipboard_copy_selected ( vw->viking_vlp );
2423 }
2424
2425 static void menu_cut_layer_cb ( GtkAction *a, VikWindow *vw )
2426 {
2427   vik_layers_panel_cut_selected ( vw->viking_vlp );
2428   vw->modified = TRUE;
2429 }
2430
2431 static void menu_paste_layer_cb ( GtkAction *a, VikWindow *vw )
2432 {
2433   if ( vik_layers_panel_paste_selected ( vw->viking_vlp ) )
2434   {
2435     vw->modified = TRUE;
2436   }
2437 }
2438
2439 static void menu_properties_cb ( GtkAction *a, VikWindow *vw )
2440 {
2441   if ( ! vik_layers_panel_properties ( vw->viking_vlp ) )
2442     a_dialog_info_msg ( GTK_WINDOW(vw), _("You must select a layer to show its properties.") );
2443 }
2444
2445 static void help_help_cb ( GtkAction *a, VikWindow *vw )
2446 {
2447 #ifdef WINDOWS
2448   ShellExecute(NULL, "open", ""PACKAGE".pdf", NULL, NULL, SW_SHOWNORMAL);
2449 #else /* WINDOWS */
2450   gchar *uri;
2451   uri = g_strdup_printf("ghelp:%s", PACKAGE);
2452   GError *error = NULL;
2453   gboolean show = gtk_show_uri (NULL, uri, GDK_CURRENT_TIME, &error);
2454   if ( !show && !error )
2455     // No error to show, so unlikely this will get called
2456     a_dialog_error_msg ( GTK_WINDOW(vw), _("The help system is not available.") );
2457   else if ( error ) {
2458     // Main error path
2459     a_dialog_error_msg_extra ( GTK_WINDOW(vw), _("Help is not available because: %s.\nEnsure a Mime Type ghelp handler program is installed (e.g. yelp)."), error->message );
2460     g_error_free ( error );
2461   }
2462   g_free(uri);
2463 #endif /* WINDOWS */
2464 }
2465
2466 static void toggle_side_panel ( VikWindow *vw )
2467 {
2468   vw->show_side_panel = !vw->show_side_panel;
2469   if ( vw->show_side_panel )
2470     gtk_widget_show(GTK_WIDGET(vw->viking_vlp));
2471   else
2472     gtk_widget_hide(GTK_WIDGET(vw->viking_vlp));
2473 }
2474
2475 static void toggle_full_screen ( VikWindow *vw )
2476 {
2477   vw->show_full_screen = !vw->show_full_screen;
2478   if ( vw->show_full_screen )
2479     gtk_window_fullscreen ( GTK_WINDOW(vw) );
2480   else
2481     gtk_window_unfullscreen ( GTK_WINDOW(vw) );
2482 }
2483
2484 static void toggle_statusbar ( VikWindow *vw )
2485 {
2486   vw->show_statusbar = !vw->show_statusbar;
2487   if ( vw->show_statusbar )
2488     gtk_widget_show ( GTK_WIDGET(vw->viking_vs) );
2489   else
2490     gtk_widget_hide ( GTK_WIDGET(vw->viking_vs) );
2491 }
2492
2493 static void toggle_toolbar ( VikWindow *vw )
2494 {
2495   vw->show_toolbar = !vw->show_toolbar;
2496   if ( vw->show_toolbar )
2497     gtk_widget_show ( toolbar_get_widget (vw->viking_vtb) );
2498   else
2499     gtk_widget_hide ( toolbar_get_widget (vw->viking_vtb) );
2500 }
2501
2502 static void toggle_main_menu ( VikWindow *vw )
2503 {
2504   vw->show_main_menu = !vw->show_main_menu;
2505   if ( vw->show_main_menu )
2506     gtk_widget_show ( gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu" ) );
2507   else
2508     gtk_widget_hide ( gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu" ) );
2509 }
2510
2511 // Only for 'view' toggle menu widgets ATM.
2512 GtkWidget *get_show_widget_by_name(VikWindow *vw, const gchar *name)
2513 {
2514   g_return_val_if_fail(name != NULL, NULL);
2515
2516   // ATM only FullScreen is *not* in SetShow path
2517   gchar *path;
2518   if ( g_strcmp0 ("FullScreen", name ) )
2519     path = g_strconcat("/ui/MainMenu/View/SetShow/", name, NULL);
2520   else
2521     path = g_strconcat("/ui/MainMenu/View/", name, NULL);
2522
2523   GtkWidget *widget = gtk_ui_manager_get_widget(vw->uim, path);
2524   g_free(path);
2525
2526   return widget;
2527 }
2528
2529 static void tb_view_side_panel_cb ( GtkAction *a, VikWindow *vw )
2530 {
2531   gboolean next_state = !vw->show_side_panel;
2532   GtkWidget *check_box = get_show_widget_by_name ( vw, gtk_action_get_name(a) );
2533   gboolean menu_state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box) );
2534   if ( next_state != menu_state )
2535     gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), next_state );
2536   else
2537     toggle_side_panel ( vw );
2538 }
2539
2540 static void tb_full_screen_cb ( GtkAction *a, VikWindow *vw )
2541 {
2542   gboolean next_state = !vw->show_full_screen;
2543   GtkWidget *check_box = get_show_widget_by_name ( vw, gtk_action_get_name(a) );
2544   gboolean menu_state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box) );
2545   if ( next_state != menu_state )
2546     gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), next_state );
2547   else
2548     toggle_full_screen ( vw );
2549 }
2550
2551 static void tb_view_statusbar_cb ( GtkAction *a, VikWindow *vw )
2552 {
2553   gboolean next_state = !vw->show_statusbar;
2554   GtkWidget *check_box = get_show_widget_by_name ( vw, gtk_action_get_name(a) );
2555   gboolean menu_state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box) );
2556   if ( next_state != menu_state )
2557     gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), next_state );
2558   else
2559     toggle_statusbar ( vw );
2560 }
2561
2562 static void tb_view_toolbar_cb ( GtkAction *a, VikWindow *vw )
2563 {
2564   gboolean next_state = !vw->show_toolbar;
2565   GtkWidget *check_box = get_show_widget_by_name ( vw, gtk_action_get_name(a) );
2566   gboolean menu_state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box) );
2567   if ( next_state != menu_state )
2568     gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), next_state );
2569   else
2570     toggle_toolbar ( vw );
2571 }
2572
2573 static void tb_view_main_menu_cb ( GtkAction *a, VikWindow *vw )
2574 {
2575   gboolean next_state = !vw->show_main_menu;
2576   GtkWidget *check_box = get_show_widget_by_name ( vw, gtk_action_get_name(a) );
2577   gboolean menu_state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box) );
2578   if ( next_state != menu_state )
2579     gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), next_state );
2580   else
2581     toggle_main_menu ( vw );
2582 }
2583
2584 static void tb_set_draw_scale ( GtkAction *a, VikWindow *vw )
2585 {
2586   gboolean next_state = !vik_viewport_get_draw_scale ( vw->viking_vvp );
2587   GtkWidget *check_box = get_show_widget_by_name ( vw, gtk_action_get_name(a) );
2588   gboolean menu_state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box) );
2589   if ( next_state != menu_state )
2590     gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), next_state );
2591   else {
2592     vik_viewport_set_draw_scale ( vw->viking_vvp, next_state );
2593     draw_update ( vw );
2594   }
2595 }
2596
2597 static void tb_set_draw_centermark ( GtkAction *a, VikWindow *vw )
2598 {
2599   gboolean next_state = !vik_viewport_get_draw_centermark ( vw->viking_vvp );
2600   GtkWidget *check_box = get_show_widget_by_name ( vw, gtk_action_get_name(a) );
2601   gboolean menu_state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box) );
2602   if ( next_state != menu_state )
2603     gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), next_state );
2604   else {
2605     vik_viewport_set_draw_centermark ( vw->viking_vvp, next_state );
2606     draw_update ( vw );
2607   }
2608 }
2609
2610 static void tb_set_draw_highlight ( GtkAction *a, VikWindow *vw )
2611 {
2612   gboolean next_state = !vik_viewport_get_draw_highlight ( vw->viking_vvp );
2613   GtkWidget *check_box = get_show_widget_by_name ( vw, gtk_action_get_name(a) );
2614   gboolean menu_state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box) );
2615   if ( next_state != menu_state )
2616     gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), next_state );
2617   else {
2618     vik_viewport_set_draw_highlight ( vw->viking_vvp, next_state );
2619     draw_update ( vw );
2620   }
2621 }
2622
2623 static void help_about_cb ( GtkAction *a, VikWindow *vw )
2624 {
2625   a_dialog_about(GTK_WINDOW(vw));
2626 }
2627
2628 static void help_cache_info_cb ( GtkAction *a, VikWindow *vw )
2629 {
2630   // NB: No i18n as this is just for debug
2631   gint byte_size = a_mapcache_get_size();
2632   gchar *msg_sz = NULL;
2633   gchar *msg = NULL;
2634 #if GLIB_CHECK_VERSION(2,30,0)
2635   msg_sz = g_format_size_full ( byte_size, G_FORMAT_SIZE_LONG_FORMAT );
2636 #else
2637   msg_sz = g_format_size_for_display ( byte_size );
2638 #endif
2639   msg = g_strdup_printf ( "Map Cache size is %s with %d items", msg_sz, a_mapcache_get_count());
2640   a_dialog_info_msg_extra ( GTK_WINDOW(vw), "%s", msg );
2641   g_free ( msg_sz );
2642   g_free ( msg );
2643 }
2644
2645 static void back_forward_info_cb ( GtkAction *a, VikWindow *vw )
2646 {
2647   vik_viewport_show_centers ( vw->viking_vvp, GTK_WINDOW(vw) );
2648 }
2649
2650 static void menu_delete_layer_cb ( GtkAction *a, VikWindow *vw )
2651 {
2652   if ( vik_layers_panel_get_selected ( vw->viking_vlp ) )
2653   {
2654     vik_layers_panel_delete_selected ( vw->viking_vlp );
2655     vw->modified = TRUE;
2656   }
2657   else
2658     a_dialog_info_msg ( GTK_WINDOW(vw), _("You must select a layer to delete.") );
2659 }
2660
2661 static void full_screen_cb ( GtkAction *a, VikWindow *vw )
2662 {
2663   gboolean next_state = !vw->show_full_screen;
2664   GtkToggleToolButton *tbutton = (GtkToggleToolButton *)toolbar_get_widget_by_name ( vw->viking_vtb, gtk_action_get_name(a) );
2665   if ( tbutton ) {
2666     gboolean tb_state = gtk_toggle_tool_button_get_active ( tbutton );
2667     if ( next_state != tb_state )
2668       gtk_toggle_tool_button_set_active ( tbutton, next_state );
2669     else
2670       toggle_full_screen ( vw );
2671   }
2672   else
2673     toggle_full_screen ( vw );
2674 }
2675
2676 static void view_side_panel_cb ( GtkAction *a, VikWindow *vw )
2677 {
2678   gboolean next_state = !vw->show_side_panel;
2679   GtkToggleToolButton *tbutton = (GtkToggleToolButton *)toolbar_get_widget_by_name ( vw->viking_vtb, gtk_action_get_name(a) );
2680   if ( tbutton ) {
2681     gboolean tb_state = gtk_toggle_tool_button_get_active ( tbutton );
2682     if ( next_state != tb_state )
2683       gtk_toggle_tool_button_set_active ( tbutton, next_state );
2684     else
2685       toggle_side_panel ( vw );
2686   }
2687   else
2688     toggle_side_panel ( vw );
2689 }
2690
2691 static void view_statusbar_cb ( GtkAction *a, VikWindow *vw )
2692 {
2693   gboolean next_state = !vw->show_statusbar;
2694   GtkToggleToolButton *tbutton = (GtkToggleToolButton *)toolbar_get_widget_by_name ( vw->viking_vtb, gtk_action_get_name(a) );
2695   if ( tbutton ) {
2696     gboolean tb_state = gtk_toggle_tool_button_get_active ( tbutton );
2697     if ( next_state != tb_state )
2698       gtk_toggle_tool_button_set_active ( tbutton, next_state );
2699     else
2700       toggle_statusbar ( vw );
2701   }
2702   else
2703     toggle_statusbar ( vw );
2704 }
2705
2706 static void view_toolbar_cb ( GtkAction *a, VikWindow *vw )
2707 {
2708   gboolean next_state = !vw->show_toolbar;
2709   GtkToggleToolButton *tbutton = (GtkToggleToolButton *)toolbar_get_widget_by_name ( vw->viking_vtb, gtk_action_get_name(a) );
2710   if ( tbutton ) {
2711     gboolean tb_state = gtk_toggle_tool_button_get_active ( tbutton );
2712     if ( next_state != tb_state )
2713       gtk_toggle_tool_button_set_active ( tbutton, next_state );
2714     else
2715       toggle_toolbar ( vw );
2716   }
2717   else
2718     toggle_toolbar ( vw );
2719 }
2720
2721 static void view_main_menu_cb ( GtkAction *a, VikWindow *vw )
2722 {
2723   gboolean next_state = !vw->show_main_menu;
2724   GtkToggleToolButton *tbutton = (GtkToggleToolButton *)toolbar_get_widget_by_name ( vw->viking_vtb, gtk_action_get_name(a) );
2725   if ( tbutton ) {
2726     gboolean tb_state = gtk_toggle_tool_button_get_active ( tbutton );
2727     if ( next_state != tb_state )
2728       gtk_toggle_tool_button_set_active ( tbutton, next_state );
2729     else
2730       toggle_main_menu ( vw );
2731   }
2732   else
2733     toggle_main_menu ( vw );
2734 }
2735
2736 /***************************************
2737  ** tool management routines
2738  **
2739  ***************************************/
2740
2741 static toolbox_tools_t* toolbox_create(VikWindow *vw)
2742 {
2743   toolbox_tools_t *vt = g_new(toolbox_tools_t, 1);
2744   vt->tools = NULL;
2745   vt->n_tools = 0;
2746   vt->active_tool = -1;
2747   vt->vw = vw;
2748   return vt;
2749 }
2750
2751 static void toolbox_add_tool(toolbox_tools_t *vt, VikToolInterface *vti, gint layer_type )
2752 {
2753   vt->tools = g_renew(toolbox_tool_t, vt->tools, vt->n_tools+1);
2754   vt->tools[vt->n_tools].ti = *vti;
2755   vt->tools[vt->n_tools].layer_type = layer_type;
2756   if (vti->create) {
2757     vt->tools[vt->n_tools].state = vti->create(vt->vw, vt->vw->viking_vvp);
2758   } 
2759   else {
2760     vt->tools[vt->n_tools].state = NULL;
2761   }
2762   vt->n_tools++;
2763 }
2764
2765 static int toolbox_get_tool(toolbox_tools_t *vt, const gchar *tool_name)
2766 {
2767   int i;
2768   for (i=0; i<vt->n_tools; i++) {
2769     if (!strcmp(tool_name, vt->tools[i].ti.radioActionEntry.name)) {
2770       break;
2771     }
2772   }
2773   return i;
2774 }
2775
2776 static void toolbox_activate(toolbox_tools_t *vt, const gchar *tool_name)
2777 {
2778   int tool = toolbox_get_tool(vt, tool_name);
2779   toolbox_tool_t *t = &vt->tools[tool];
2780   VikLayer *vl = vik_layers_panel_get_selected ( vt->vw->viking_vlp );
2781
2782   if (tool == vt->n_tools) {
2783     g_critical("trying to activate a non-existent tool...");
2784     return;
2785   }
2786   /* is the tool already active? */
2787   if (vt->active_tool == tool) {
2788     return;
2789   }
2790
2791   if (vt->active_tool != -1) {
2792     if (vt->tools[vt->active_tool].ti.deactivate) {
2793       vt->tools[vt->active_tool].ti.deactivate(NULL, vt->tools[vt->active_tool].state);
2794     }
2795   }
2796   if (t->ti.activate) {
2797     t->ti.activate(vl, t->state);
2798   }
2799   vt->active_tool = tool;
2800 }
2801
2802 static const GdkCursor *toolbox_get_cursor(toolbox_tools_t *vt, const gchar *tool_name)
2803 {
2804   int tool = toolbox_get_tool(vt, tool_name);
2805   toolbox_tool_t *t = &vt->tools[tool];
2806   if (t->ti.cursor == NULL) {
2807     if (t->ti.cursor_type == GDK_CURSOR_IS_PIXMAP && t->ti.cursor_data != NULL) {
2808       GdkPixbuf *cursor_pixbuf = gdk_pixbuf_from_pixdata (t->ti.cursor_data, FALSE, NULL);
2809       /* TODO: settable offeset */
2810       t->ti.cursor = gdk_cursor_new_from_pixbuf ( gdk_display_get_default(), cursor_pixbuf, 3, 3 );
2811       g_object_unref ( G_OBJECT(cursor_pixbuf) );
2812     } else {
2813       t->ti.cursor = gdk_cursor_new ( t->ti.cursor_type );
2814     }
2815   }
2816   return t->ti.cursor;
2817 }
2818
2819 static void toolbox_click (toolbox_tools_t *vt, GdkEventButton *event)
2820 {
2821   VikLayer *vl = vik_layers_panel_get_selected ( vt->vw->viking_vlp );
2822   if (vt->active_tool != -1 && vt->tools[vt->active_tool].ti.click) {
2823     gint ltype = vt->tools[vt->active_tool].layer_type;
2824     if ( ltype == TOOL_LAYER_TYPE_NONE || (vl && ltype == vl->type) )
2825       vt->tools[vt->active_tool].ti.click(vl, event, vt->tools[vt->active_tool].state);
2826   }
2827 }
2828
2829 static void toolbox_move (toolbox_tools_t *vt, GdkEventMotion *event)
2830 {
2831   VikLayer *vl = vik_layers_panel_get_selected ( vt->vw->viking_vlp );
2832   if (vt->active_tool != -1 && vt->tools[vt->active_tool].ti.move) {
2833     gint ltype = vt->tools[vt->active_tool].layer_type;
2834     if ( ltype == TOOL_LAYER_TYPE_NONE || (vl && ltype == vl->type) )
2835       if ( VIK_LAYER_TOOL_ACK_GRAB_FOCUS == vt->tools[vt->active_tool].ti.move(vl, event, vt->tools[vt->active_tool].state) )
2836         gtk_widget_grab_focus ( GTK_WIDGET(vt->vw->viking_vvp) );
2837   }
2838 }
2839
2840 static void toolbox_release (toolbox_tools_t *vt, GdkEventButton *event)
2841 {
2842   VikLayer *vl = vik_layers_panel_get_selected ( vt->vw->viking_vlp );
2843   if (vt->active_tool != -1 && vt->tools[vt->active_tool].ti.release ) {
2844     gint ltype = vt->tools[vt->active_tool].layer_type;
2845     if ( ltype == TOOL_LAYER_TYPE_NONE || (vl && ltype == vl->type) )
2846       vt->tools[vt->active_tool].ti.release(vl, event, vt->tools[vt->active_tool].state);
2847   }
2848 }
2849 /** End tool management ************************************/
2850
2851 void vik_window_enable_layer_tool ( VikWindow *vw, gint layer_id, gint tool_id )
2852 {
2853   gtk_action_activate ( gtk_action_group_get_action ( vw->action_group, vik_layer_get_interface(layer_id)->tools[tool_id].radioActionEntry.name ) );
2854 }
2855
2856 // Be careful with usage - as it may trigger actions being continually alternately by the menu and toolbar items
2857 // DON'T Use this from menu callback with toggle toolbar items!!
2858 static void toolbar_sync ( VikWindow *vw, const gchar *name, gboolean state )
2859 {
2860   GtkToggleToolButton *tbutton = (GtkToggleToolButton *)toolbar_get_widget_by_name ( vw->viking_vtb, name );
2861   if ( tbutton ) {
2862     // Causes toggle signal action to be raised.
2863     gtk_toggle_tool_button_set_active ( tbutton, state );
2864   }
2865 }
2866
2867 /* this function gets called whenever a menu is clicked */
2868 // Note old is not used
2869 static void menu_cb ( GtkAction *old, GtkAction *a, VikWindow *vw )
2870 {
2871   // Ensure Toolbar kept in sync
2872   const gchar *name = gtk_action_get_name(a);
2873   toolbar_sync ( vw, name, TRUE );
2874
2875   /* White Magic, my friends ... White Magic... */
2876   gint tool_id;
2877   toolbox_activate(vw->vt, name);
2878
2879   vw->viewport_cursor = (GdkCursor *)toolbox_get_cursor(vw->vt, name);
2880
2881   if ( gtk_widget_get_window(GTK_WIDGET(vw->viking_vvp)) )
2882     /* We set cursor, even if it is NULL: it resets to default */
2883     gdk_window_set_cursor ( gtk_widget_get_window(GTK_WIDGET(vw->viking_vvp)), vw->viewport_cursor );
2884
2885   if (!g_strcmp0(name, "Pan")) {
2886     vw->current_tool = TOOL_PAN;
2887   } 
2888   else if (!g_strcmp0(name, "Zoom")) {
2889     vw->current_tool = TOOL_ZOOM;
2890   } 
2891   else if (!g_strcmp0(name, "Ruler")) {
2892     vw->current_tool = TOOL_RULER;
2893   }
2894   else if (!g_strcmp0(name, "Select")) {
2895     vw->current_tool = TOOL_SELECT;
2896   }
2897   else {
2898     VikLayerTypeEnum layer_id;
2899     for (layer_id=0; layer_id<VIK_LAYER_NUM_TYPES; layer_id++) {
2900       for ( tool_id = 0; tool_id < vik_layer_get_interface(layer_id)->tools_count; tool_id++ ) {
2901         if (!g_strcmp0(vik_layer_get_interface(layer_id)->tools[tool_id].radioActionEntry.name, name)) {
2902            vw->current_tool = TOOL_LAYER;
2903            vw->tool_layer_id = layer_id;
2904            vw->tool_tool_id = tool_id;
2905         }
2906       }
2907     }
2908   }
2909   draw_status_tool ( vw );
2910 }
2911
2912 static void window_set_filename ( VikWindow *vw, const gchar *filename )
2913 {
2914   gchar *title;
2915   const gchar *file;
2916   if ( vw->filename )
2917     g_free ( vw->filename );
2918   if ( filename == NULL )
2919   {
2920     vw->filename = NULL;
2921   }
2922   else
2923   {
2924     vw->filename = g_strdup(filename);
2925   }
2926
2927   /* Refresh window's title */
2928   file = window_get_filename ( vw );
2929   title = g_strdup_printf( "%s - Viking", file );
2930   gtk_window_set_title ( GTK_WINDOW(vw), title );
2931   g_free ( title );
2932 }
2933
2934 static const gchar *window_get_filename ( VikWindow *vw )
2935 {
2936   return vw->filename ? a_file_basename ( vw->filename ) : _("Untitled");
2937 }
2938
2939 GtkWidget *vik_window_get_drawmode_button ( VikWindow *vw, VikViewportDrawMode mode )
2940 {
2941   GtkWidget *mode_button;
2942   gchar *buttonname;
2943   switch ( mode ) {
2944 #ifdef VIK_CONFIG_EXPEDIA
2945     case VIK_VIEWPORT_DRAWMODE_EXPEDIA: buttonname = "/ui/MainMenu/View/ModeExpedia"; break;
2946 #endif
2947     case VIK_VIEWPORT_DRAWMODE_MERCATOR: buttonname = "/ui/MainMenu/View/ModeMercator"; break;
2948     case VIK_VIEWPORT_DRAWMODE_LATLON: buttonname = "/ui/MainMenu/View/ModeLatLon"; break;
2949     default: buttonname = "/ui/MainMenu/View/ModeUTM";
2950   }
2951   mode_button = gtk_ui_manager_get_widget ( vw->uim, buttonname );
2952   g_assert ( mode_button );
2953   return mode_button;
2954 }
2955
2956 /**
2957  * vik_window_get_pan_move:
2958  * @vw: some VikWindow
2959  *
2960  * Retrieves @vw's pan_move.
2961  *
2962  * Should be removed as soon as possible.
2963  *
2964  * Returns: @vw's pan_move
2965  *
2966  * Since: 0.9.96
2967  **/
2968 gboolean vik_window_get_pan_move ( VikWindow *vw )
2969 {
2970   return vw->pan_move;
2971 }
2972
2973 /**
2974  * Remove the potentially auto added map
2975  */
2976 static void remove_default_map_layer ( VikWindow *vw )
2977 {
2978   if ( a_vik_get_add_default_map_layer () ) {
2979     VikAggregateLayer *top = vik_layers_panel_get_top_layer(vw->viking_vlp);
2980     if ( vik_aggregate_layer_count(top) == 1 ) {
2981       VikLayer *vl = vik_aggregate_layer_get_top_visible_layer_of_type (top, VIK_LAYER_MAPS);
2982       // Could try to compare name vs _("Default Map") but this might have i8n issues if not translated
2983       if ( vl )
2984         vik_aggregate_layer_delete_layer ( top, vl );
2985     }
2986   }
2987 }
2988
2989 static void on_activate_recent_item (GtkRecentChooser *chooser,
2990                                      VikWindow *self)
2991 {
2992   gchar *filename;
2993
2994   filename = gtk_recent_chooser_get_current_uri (chooser);
2995   if (filename != NULL)
2996   {
2997     GFile *file = g_file_new_for_uri ( filename );
2998     gchar *path = g_file_get_path ( file );
2999     g_object_unref ( file );
3000     if ( self->filename )
3001     {
3002       GSList *filenames = NULL;
3003       filenames = g_slist_append ( filenames, path );
3004       g_signal_emit ( G_OBJECT(self), window_signals[VW_OPENWINDOW_SIGNAL], 0, filenames );
3005       // NB: GSList & contents are freed by main.open_window
3006     }
3007     else {
3008       remove_default_map_layer ( self );
3009       vik_window_open_file ( self, path, TRUE );
3010       g_free ( path );
3011     }
3012   }
3013
3014   g_free (filename);
3015 }
3016
3017 static void setup_recent_files (VikWindow *self)
3018 {
3019   GtkRecentManager *manager;
3020   GtkRecentFilter *filter;
3021   GtkWidget *menu, *menu_item;
3022
3023   filter = gtk_recent_filter_new ();
3024   /* gtk_recent_filter_add_application (filter, g_get_application_name()); */
3025   gtk_recent_filter_add_group(filter, "viking");
3026
3027   manager = gtk_recent_manager_get_default ();
3028   menu = gtk_recent_chooser_menu_new_for_manager (manager);
3029   gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu), GTK_RECENT_SORT_MRU);
3030   gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu), filter);
3031   gtk_recent_chooser_set_limit (GTK_RECENT_CHOOSER (menu), a_vik_get_recent_number_files() );
3032
3033   menu_item = gtk_ui_manager_get_widget (self->uim, "/ui/MainMenu/File/OpenRecentFile");
3034   gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), menu);
3035
3036   g_signal_connect (G_OBJECT (menu), "item-activated",
3037                     G_CALLBACK (on_activate_recent_item), (gpointer) self);
3038 }
3039
3040 /*
3041  *
3042  */
3043 static void update_recently_used_document (VikWindow *vw, const gchar *filename)
3044 {
3045   /* Update Recently Used Document framework */
3046   GtkRecentManager *manager = gtk_recent_manager_get_default();
3047   GtkRecentData *recent_data = g_slice_new (GtkRecentData);
3048   gchar *groups[] = {"viking", NULL};
3049   GFile *file = g_file_new_for_commandline_arg(filename);
3050   gchar *uri = g_file_get_uri(file);
3051   gchar *basename = g_path_get_basename(filename);
3052   g_object_unref(file);
3053   file = NULL;
3054
3055   recent_data->display_name   = basename;
3056   recent_data->description    = NULL;
3057   recent_data->mime_type      = "text/x-gps-data";
3058   recent_data->app_name       = (gchar *) g_get_application_name ();
3059   recent_data->app_exec       = g_strjoin (" ", g_get_prgname (), "%f", NULL);
3060   recent_data->groups         = groups;
3061   recent_data->is_private     = FALSE;
3062   if (!gtk_recent_manager_add_full (manager, uri, recent_data))
3063   {
3064     gchar *msg = g_strdup_printf (_("Unable to add '%s' to the list of recently used documents"), uri);
3065     vik_statusbar_set_message ( vw->viking_vs, VIK_STATUSBAR_INFO, msg );
3066     g_free ( msg );
3067   }
3068
3069   g_free (uri);
3070   g_free (basename);
3071   g_free (recent_data->app_exec);
3072   g_slice_free (GtkRecentData, recent_data);
3073 }
3074
3075 /**
3076  * Call this before doing things that may take a long time and otherwise not show any other feedback
3077  *  such as loading and saving files
3078  */
3079 void vik_window_set_busy_cursor ( VikWindow *vw )
3080 {
3081   gdk_window_set_cursor ( gtk_widget_get_window(GTK_WIDGET(vw)), vw->busy_cursor );
3082   // Viewport has a separate cursor
3083   gdk_window_set_cursor ( gtk_widget_get_window(GTK_WIDGET(vw->viking_vvp)), vw->busy_cursor );
3084   // Ensure cursor updated before doing stuff
3085   while( gtk_events_pending() )
3086     gtk_main_iteration();
3087 }
3088
3089 void vik_window_clear_busy_cursor ( VikWindow *vw )
3090 {
3091   gdk_window_set_cursor ( gtk_widget_get_window(GTK_WIDGET(vw)), NULL );
3092   // Restore viewport cursor
3093   gdk_window_set_cursor ( gtk_widget_get_window(GTK_WIDGET(vw->viking_vvp)), vw->viewport_cursor );
3094 }
3095
3096 void vik_window_open_file ( VikWindow *vw, const gchar *filename, gboolean change_filename )
3097 {
3098   vik_window_set_busy_cursor ( vw );
3099
3100   // Enable the *new* filename to be accessible by the Layers codez
3101   gchar *original_filename = g_strdup ( vw->filename );
3102   g_free ( vw->filename );
3103   vw->filename = g_strdup ( filename );
3104   gboolean success = FALSE;
3105   gboolean restore_original_filename = FALSE;
3106   vw->loaded_type = a_file_load ( vik_layers_panel_get_top_layer(vw->viking_vlp), vw->viking_vvp, vw->containing_vtl, filename );
3107   switch ( vw->loaded_type )
3108   {
3109     case LOAD_TYPE_READ_FAILURE:
3110       a_dialog_error_msg ( GTK_WINDOW(vw), _("The file you requested could not be opened.") );
3111       break;
3112     case LOAD_TYPE_GPSBABEL_FAILURE:
3113       a_dialog_error_msg ( GTK_WINDOW(vw), _("GPSBabel is required to load files of this type or GPSBabel encountered problems.") );
3114       break;
3115     case LOAD_TYPE_GPX_FAILURE:
3116       a_dialog_error_msg_extra ( GTK_WINDOW(vw), _("Unable to load malformed GPX file %s"), filename );
3117       break;
3118     case LOAD_TYPE_UNSUPPORTED_FAILURE:
3119       a_dialog_error_msg_extra ( GTK_WINDOW(vw), _("Unsupported file type for %s"), filename );
3120       break;
3121     case LOAD_TYPE_VIK_FAILURE_NON_FATAL:
3122     {
3123       // Since we can process .vik files with issues just show a warning in the status bar
3124       // Not that a user can do much about it... or tells them what this issue is yet...
3125       gchar *msg = g_strdup_printf (_("WARNING: issues encountered loading %s"), a_file_basename (filename) );
3126       vik_statusbar_set_message ( vw->viking_vs, VIK_STATUSBAR_INFO, msg );
3127       g_free ( msg );
3128     }
3129       // No break, carry on to show any data
3130     case LOAD_TYPE_VIK_SUCCESS:
3131     {
3132       restore_original_filename = TRUE; // NB Will actually get inverted by the 'success' component below
3133       GtkWidget *mode_button;
3134       /* Update UI */
3135       if ( change_filename )
3136         window_set_filename ( vw, filename );
3137       mode_button = vik_window_get_drawmode_button ( vw, vik_viewport_get_drawmode ( vw->viking_vvp ) );
3138       vw->only_updating_coord_mode_ui = TRUE; /* if we don't set this, it will change the coord to UTM if we click Lat/Lon. I don't know why. */
3139       gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(mode_button), TRUE );
3140       vw->only_updating_coord_mode_ui = FALSE;
3141
3142       vik_layers_panel_change_coord_mode ( vw->viking_vlp, vik_viewport_get_coord_mode ( vw->viking_vvp ) );
3143
3144       // Slightly long winded methods to align loaded viewport settings with the UI
3145       //  Since the rewrite for toolbar + menu actions
3146       //  there no longer exists a simple way to directly change the UI to a value for toggle settings
3147       //  it only supports toggling the existing setting (otherwise get infinite loops in trying to align tb+menu elements)
3148       // Thus get state, compare them, if different then invert viewport setting and (re)sync the setting (via toggling)
3149       gboolean vp_state_scale = vik_viewport_get_draw_scale ( vw->viking_vvp );
3150       gboolean ui_state_scale = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(get_show_widget_by_name(vw, "ShowScale")) );
3151       if ( vp_state_scale != ui_state_scale ) {
3152         vik_viewport_set_draw_scale ( vw->viking_vvp, !vp_state_scale );
3153         toggle_draw_scale ( NULL, vw );
3154       }
3155       gboolean vp_state_centermark = vik_viewport_get_draw_centermark ( vw->viking_vvp );
3156       gboolean ui_state_centermark = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(get_show_widget_by_name(vw, "ShowCenterMark")) );
3157       if ( vp_state_centermark != ui_state_centermark ) {
3158         vik_viewport_set_draw_centermark ( vw->viking_vvp, !vp_state_centermark );
3159         toggle_draw_centermark ( NULL, vw );
3160       }
3161       gboolean vp_state_highlight = vik_viewport_get_draw_highlight ( vw->viking_vvp );
3162       gboolean ui_state_highlight = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(get_show_widget_by_name(vw, "ShowHighlight")) );
3163       if ( vp_state_highlight != ui_state_highlight ) {
3164         vik_viewport_set_draw_highlight ( vw->viking_vvp, !vp_state_highlight );
3165         toggle_draw_highlight ( NULL, vw );
3166       }
3167     }
3168       // NB No break, carry on to redraw
3169     //case LOAD_TYPE_OTHER_SUCCESS:
3170     default:
3171       success = TRUE;
3172       // When LOAD_TYPE_OTHER_SUCCESS *only*, this will maintain the existing Viking project
3173       restore_original_filename = ! restore_original_filename;
3174       update_recently_used_document (vw, filename);
3175       draw_update ( vw );
3176       break;
3177   }
3178
3179   if ( ! success || restore_original_filename )
3180     // Load didn't work or want to keep as the existing Viking project, keep using the original name
3181     window_set_filename ( vw, original_filename );
3182   g_free ( original_filename );
3183
3184   vik_window_clear_busy_cursor ( vw );
3185 }
3186
3187 static void load_file ( GtkAction *a, VikWindow *vw )
3188 {
3189   GSList *files = NULL;
3190   GSList *cur_file = NULL;
3191   gboolean newwindow;
3192   if (!strcmp(gtk_action_get_name(a), "Open")) {
3193     newwindow = TRUE;
3194   } 
3195   else if (!strcmp(gtk_action_get_name(a), "Append")) {
3196     newwindow = FALSE;
3197   } 
3198   else {
3199     g_critical("Houston, we've had a problem.");
3200     return;
3201   }
3202
3203   GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Please select a GPS data file to open. "),
3204                                                    GTK_WINDOW(vw),
3205                                                    GTK_FILE_CHOOSER_ACTION_OPEN,
3206                                                    GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
3207                                                    GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
3208                                                    NULL);
3209   if ( last_folder_files_uri )
3210     gtk_file_chooser_set_current_folder_uri ( GTK_FILE_CHOOSER(dialog), last_folder_files_uri );
3211
3212   GtkFileFilter *filter;
3213   // NB file filters are listed this way for alphabetical ordering
3214 #ifdef VIK_CONFIG_GEOCACHES
3215   filter = gtk_file_filter_new ();
3216   gtk_file_filter_set_name( filter, _("Geocaching") );
3217   gtk_file_filter_add_pattern ( filter, "*.loc" ); // No MIME type available
3218   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter);
3219 #endif
3220
3221   filter = gtk_file_filter_new ();
3222   gtk_file_filter_set_name( filter, _("Google Earth") );
3223   gtk_file_filter_add_mime_type ( filter, "application/vnd.google-earth.kml+xml");
3224   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter);
3225
3226   filter = gtk_file_filter_new ();
3227   gtk_file_filter_set_name( filter, _("GPX") );
3228   gtk_file_filter_add_pattern ( filter, "*.gpx" ); // No MIME type available
3229   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter);
3230
3231   filter = gtk_file_filter_new ();
3232   gtk_file_filter_set_name ( filter, _("JPG") );
3233   gtk_file_filter_add_mime_type ( filter, "image/jpeg");
3234   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter);
3235
3236   filter = gtk_file_filter_new ();
3237   gtk_file_filter_set_name( filter, _("Viking") );
3238   gtk_file_filter_add_pattern ( filter, "*.vik" );
3239   gtk_file_filter_add_pattern ( filter, "*.viking" );
3240   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter);
3241
3242   // NB could have filters for gpspoint (*.gps,*.gpsoint?) + gpsmapper (*.gsm,*.gpsmapper?)
3243   // However assume this are barely used and thus not worthy of inclusion
3244   //   as they'll just make the options too many and have no clear file pattern
3245   //   one can always use the all option
3246   filter = gtk_file_filter_new ();
3247   gtk_file_filter_set_name( filter, _("All") );
3248   gtk_file_filter_add_pattern ( filter, "*" );
3249   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter);
3250   // Default to any file - same as before open filters were added
3251   gtk_file_chooser_set_filter (GTK_FILE_CHOOSER(dialog), filter);
3252
3253   gtk_file_chooser_set_select_multiple ( GTK_FILE_CHOOSER(dialog), TRUE );
3254   gtk_window_set_transient_for ( GTK_WINDOW(dialog), GTK_WINDOW(vw) );
3255   gtk_window_set_destroy_with_parent ( GTK_WINDOW(dialog), TRUE );
3256
3257   if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
3258   {
3259     g_free ( last_folder_files_uri );
3260     last_folder_files_uri = gtk_file_chooser_get_current_folder_uri ( GTK_FILE_CHOOSER(dialog) );
3261
3262 #ifdef VIKING_PROMPT_IF_MODIFIED
3263     if ( (vw->modified || vw->filename) && newwindow )
3264 #else
3265     if ( vw->filename && newwindow )
3266 #endif
3267       g_signal_emit ( G_OBJECT(vw), window_signals[VW_OPENWINDOW_SIGNAL], 0, gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER(dialog) ) );
3268     else {
3269
3270       files = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER(dialog) );
3271       gboolean change_fn = newwindow && (g_slist_length(files)==1); /* only change fn if one file */
3272       gboolean first_vik_file = TRUE;
3273       cur_file = files;
3274       while ( cur_file ) {
3275
3276         gchar *file_name = cur_file->data;
3277         if ( newwindow && check_file_magic_vik ( file_name ) ) {
3278           // Load first of many .vik files in current window
3279           if ( first_vik_file ) {
3280             remove_default_map_layer ( vw );
3281             vik_window_open_file ( vw, file_name, TRUE );
3282             first_vik_file = FALSE;
3283           }
3284           else {
3285             // Load each subsequent .vik file in a separate window
3286             VikWindow *newvw = vik_window_new_window ();
3287             if (newvw)
3288               vik_window_open_file ( newvw, file_name, TRUE );
3289           }
3290         }
3291         else
3292           // Other file types
3293           vik_window_open_file ( vw, file_name, change_fn );
3294
3295         g_free (file_name);
3296         cur_file = g_slist_next (cur_file);
3297       }
3298       g_slist_free (files);
3299     }
3300   }
3301   gtk_widget_destroy ( dialog );
3302 }
3303
3304 static gboolean save_file_as ( GtkAction *a, VikWindow *vw )
3305 {
3306   gboolean rv = FALSE;
3307   const gchar *fn;
3308
3309   GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Save as Viking File."),
3310                                                    GTK_WINDOW(vw),
3311                                                    GTK_FILE_CHOOSER_ACTION_SAVE,
3312                                                    GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
3313                                                    GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
3314                                                    NULL);
3315   if ( last_folder_files_uri )
3316     gtk_file_chooser_set_current_folder_uri ( GTK_FILE_CHOOSER(dialog), last_folder_files_uri );
3317
3318   GtkFileFilter *filter;
3319   filter = gtk_file_filter_new ();
3320   gtk_file_filter_set_name( filter, _("All") );
3321   gtk_file_filter_add_pattern ( filter, "*" );
3322   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter);
3323
3324   filter = gtk_file_filter_new ();
3325   gtk_file_filter_set_name( filter, _("Viking") );
3326   gtk_file_filter_add_pattern ( filter, "*.vik" );
3327   gtk_file_filter_add_pattern ( filter, "*.viking" );
3328   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter);
3329   // Default to a Viking file
3330   gtk_file_chooser_set_filter (GTK_FILE_CHOOSER(dialog), filter);
3331
3332   gtk_window_set_transient_for ( GTK_WINDOW(dialog), GTK_WINDOW(vw) );
3333   gtk_window_set_destroy_with_parent ( GTK_WINDOW(dialog), TRUE );
3334
3335   // Auto append / replace extension with '.vik' to the suggested file name as it's going to be a Viking File
3336   gchar* auto_save_name = g_strdup ( window_get_filename ( vw ) );
3337   if ( ! a_file_check_ext ( auto_save_name, ".vik" ) )
3338     auto_save_name = g_strconcat ( auto_save_name, ".vik", NULL );
3339
3340   gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER(dialog), auto_save_name);
3341
3342   while ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
3343   {
3344     fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(dialog) );
3345     if ( g_file_test ( fn, G_FILE_TEST_EXISTS ) == FALSE || a_dialog_yes_or_no ( GTK_WINDOW(dialog), _("The file \"%s\" exists, do you wish to overwrite it?"), a_file_basename ( fn ) ) )
3346     {
3347       window_set_filename ( vw, fn );
3348       rv = window_save ( vw );
3349       if ( rv ) {
3350         vw->modified = FALSE;
3351         g_free ( last_folder_files_uri );
3352         last_folder_files_uri = gtk_file_chooser_get_current_folder_uri ( GTK_FILE_CHOOSER(dialog) );
3353       }
3354       break;
3355     }
3356   }
3357   g_free ( auto_save_name );
3358   gtk_widget_destroy ( dialog );
3359   return rv;
3360 }
3361
3362 static gboolean window_save ( VikWindow *vw )
3363 {
3364   vik_window_set_busy_cursor ( vw );
3365   gboolean success = TRUE;
3366
3367   if ( a_file_save ( vik_layers_panel_get_top_layer ( vw->viking_vlp ), vw->viking_vvp, vw->filename ) )
3368   {
3369     update_recently_used_document ( vw, vw->filename );
3370   }
3371   else
3372   {
3373     a_dialog_error_msg ( GTK_WINDOW(vw), _("The filename you requested could not be opened for writing.") );
3374     success = FALSE;
3375   }
3376   vik_window_clear_busy_cursor ( vw );
3377   return success;
3378 }
3379
3380 static gboolean save_file ( GtkAction *a, VikWindow *vw )
3381 {
3382   if ( ! vw->filename )
3383     return save_file_as ( NULL, vw );
3384   else
3385   {
3386     vw->modified = FALSE;
3387     return window_save ( vw );
3388   }
3389 }
3390
3391 /**
3392  * export_to:
3393  *
3394  * Export all TRW Layers in the list to individual files in the specified directory
3395  *
3396  * Returns: %TRUE on success
3397  */
3398 static gboolean export_to ( VikWindow *vw, GList *gl, VikFileType_t vft, const gchar *dir, const gchar *extension )
3399 {
3400   gboolean success = TRUE;
3401
3402   gint export_count = 0;
3403
3404   vik_window_set_busy_cursor ( vw );
3405
3406   while ( gl ) {
3407
3408     gchar *fn = g_strconcat ( dir, G_DIR_SEPARATOR_S, VIK_LAYER(gl->data)->name, extension, NULL );
3409
3410     // Some protection in attempting to write too many same named files
3411     // As this will get horribly slow...
3412     gboolean safe = FALSE;
3413     gint ii = 2;
3414     while ( ii < 5000 ) {
3415       if ( g_file_test ( fn, G_FILE_TEST_EXISTS ) ) {
3416         // Try rename
3417         g_free ( fn );
3418         fn = g_strdup_printf ( "%s%s%s#%03d%s", dir, G_DIR_SEPARATOR_S, VIK_LAYER(gl->data)->name, ii, extension );
3419           }
3420           else {
3421                   safe = TRUE;
3422                   break;
3423           }
3424           ii++;
3425     }
3426     if ( ii == 5000 )
3427       success = FALSE;
3428
3429     // NB: We allow exporting empty layers
3430     if ( safe ) {
3431       gboolean this_success = a_file_export ( VIK_TRW_LAYER(gl->data), fn, vft, NULL, TRUE );
3432
3433       // Show some progress
3434       if ( this_success ) {
3435         export_count++;
3436         gchar *message = g_strdup_printf ( _("Exporting to file: %s"), fn );
3437         vik_statusbar_set_message ( vw->viking_vs, VIK_STATUSBAR_INFO, message );
3438         while ( gtk_events_pending() )
3439           gtk_main_iteration ();
3440         g_free ( message );
3441       }
3442       
3443       success = success && this_success;
3444     }
3445
3446     g_free ( fn );
3447     gl = g_list_next ( gl );
3448   }
3449
3450   vik_window_clear_busy_cursor ( vw );
3451
3452   // Confirm what happened.
3453   gchar *message = g_strdup_printf ( _("Exported files: %d"), export_count );
3454   vik_statusbar_set_message ( vw->viking_vs, VIK_STATUSBAR_INFO, message );
3455   g_free ( message );
3456
3457   return success;
3458 }
3459
3460 static void export_to_common ( VikWindow *vw, VikFileType_t vft, const gchar *extension )
3461 {
3462   GList *gl = vik_layers_panel_get_all_layers_of_type ( vw->viking_vlp, VIK_LAYER_TRW, TRUE );
3463
3464   if ( !gl ) {
3465     a_dialog_info_msg ( GTK_WINDOW(vw), _("Nothing to Export!") );
3466     return;
3467   }
3468
3469   GtkWidget *dialog = gtk_file_chooser_dialog_new ( _("Export to directory"),
3470                                                     GTK_WINDOW(vw),
3471                                                     GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
3472                                                     GTK_STOCK_CANCEL,
3473                                                     GTK_RESPONSE_REJECT,
3474                                                     GTK_STOCK_OK,
3475                                                     GTK_RESPONSE_ACCEPT,
3476                                                     NULL );
3477   gtk_window_set_transient_for ( GTK_WINDOW(dialog), GTK_WINDOW(vw) );
3478   gtk_window_set_destroy_with_parent ( GTK_WINDOW(dialog), TRUE );
3479   gtk_window_set_modal ( GTK_WINDOW(dialog), TRUE );
3480
3481   gtk_widget_show_all ( dialog );
3482
3483   if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT ) {
3484     gchar *dir = gtk_file_chooser_get_filename ( GTK_FILE_CHOOSER(dialog) );
3485     gtk_widget_destroy ( dialog );
3486     if ( dir ) {
3487       if ( !export_to ( vw, gl, vft, dir, extension ) )
3488         a_dialog_error_msg ( GTK_WINDOW(vw),_("Could not convert all files") );
3489       g_free ( dir );
3490     }
3491   }
3492   else
3493     gtk_widget_destroy ( dialog );
3494
3495   g_list_free ( gl );
3496 }
3497
3498 static void export_to_gpx ( GtkAction *a, VikWindow *vw )
3499 {
3500   export_to_common ( vw, FILE_TYPE_GPX, ".gpx" );
3501 }
3502
3503 static void export_to_kml ( GtkAction *a, VikWindow *vw )
3504 {
3505   export_to_common ( vw, FILE_TYPE_KML, ".kml" );
3506 }
3507
3508 static void file_properties_cb ( GtkAction *a, VikWindow *vw )
3509 {
3510   gchar *message = NULL;
3511   if ( vw->filename ) {
3512     if ( g_file_test ( vw->filename, G_FILE_TEST_EXISTS ) ) {
3513       // Get some timestamp information of the file
3514       GStatBuf stat_buf;
3515       if ( g_stat ( vw->filename, &stat_buf ) == 0 ) {
3516         gchar time_buf[64];
3517         strftime ( time_buf, sizeof(time_buf), "%c", gmtime((const time_t *)&stat_buf.st_mtime) );
3518         gchar *size = NULL;
3519         gint byte_size = stat_buf.st_size;
3520 #if GLIB_CHECK_VERSION(2,30,0)
3521         size = g_format_size_full ( byte_size, G_FORMAT_SIZE_DEFAULT );
3522 #else
3523         size = g_format_size_for_display ( byte_size );
3524 #endif
3525         message = g_strdup_printf ( "%s\n\n%s\n\n%s", vw->filename, time_buf, size );
3526         g_free (size);
3527       }
3528     }
3529     else
3530       message = g_strdup ( _("File not accessible") );
3531   }
3532   else
3533     message = g_strdup ( _("No Viking File") );
3534
3535   // Show the info
3536   a_dialog_info_msg ( GTK_WINDOW(vw), message );
3537   g_free ( message );
3538 }
3539
3540 static void my_acquire ( VikWindow *vw, VikDataSourceInterface *datasource )
3541 {
3542   vik_datasource_mode_t mode = datasource->mode;
3543   if ( mode == VIK_DATASOURCE_AUTO_LAYER_MANAGEMENT )
3544     mode = VIK_DATASOURCE_CREATENEWLAYER;
3545   a_acquire ( vw, vw->viking_vlp, vw->viking_vvp, mode, datasource, NULL, NULL );
3546 }
3547
3548 static void acquire_from_gps ( GtkAction *a, VikWindow *vw )
3549 {
3550   my_acquire ( vw, &vik_datasource_gps_interface );
3551 }
3552
3553 static void acquire_from_file ( GtkAction *a, VikWindow *vw )
3554 {
3555   my_acquire ( vw, &vik_datasource_file_interface );
3556 }
3557
3558 static void acquire_from_geojson ( GtkAction *a, VikWindow *vw )
3559 {
3560   my_acquire ( vw, &vik_datasource_geojson_interface );
3561 }
3562
3563 static void acquire_from_routing ( GtkAction *a, VikWindow *vw )
3564 {
3565   my_acquire ( vw, &vik_datasource_routing_interface );
3566 }
3567
3568 #ifdef VIK_CONFIG_OPENSTREETMAP
3569 static void acquire_from_osm ( GtkAction *a, VikWindow *vw )
3570 {
3571   my_acquire ( vw, &vik_datasource_osm_interface );
3572 }
3573
3574 static void acquire_from_my_osm ( GtkAction *a, VikWindow *vw )
3575 {
3576   my_acquire ( vw, &vik_datasource_osm_my_traces_interface );
3577 }
3578 #endif
3579
3580 #ifdef VIK_CONFIG_GEOCACHES
3581 static void acquire_from_gc ( GtkAction *a, VikWindow *vw )
3582 {
3583   my_acquire ( vw, &vik_datasource_gc_interface );
3584 }
3585 #endif
3586
3587 #ifdef VIK_CONFIG_GEOTAG
3588 static void acquire_from_geotag ( GtkAction *a, VikWindow *vw )
3589 {
3590   my_acquire ( vw, &vik_datasource_geotag_interface );
3591 }
3592 #endif
3593
3594 #ifdef VIK_CONFIG_GEONAMES
3595 static void acquire_from_wikipedia ( GtkAction *a, VikWindow *vw )
3596 {
3597   my_acquire ( vw, &vik_datasource_wikipedia_interface );
3598 }
3599 #endif
3600
3601 static void acquire_from_url ( GtkAction *a, VikWindow *vw )
3602 {
3603   my_acquire ( vw, &vik_datasource_url_interface );
3604 }
3605
3606 static void goto_default_location( GtkAction *a, VikWindow *vw)
3607 {
3608   struct LatLon ll;
3609   ll.lat = a_vik_get_default_lat();
3610   ll.lon = a_vik_get_default_long();
3611   vik_viewport_set_center_latlon(vw->viking_vvp, &ll, TRUE);
3612   vik_layers_panel_emit_update(vw->viking_vlp);
3613 }
3614
3615
3616 static void goto_address( GtkAction *a, VikWindow *vw)
3617 {
3618   a_vik_goto ( vw, vw->viking_vvp );
3619   vik_layers_panel_emit_update ( vw->viking_vlp );
3620 }
3621
3622 static void mapcache_flush_cb ( GtkAction *a, VikWindow *vw )
3623 {
3624   a_mapcache_flush();
3625 }
3626
3627 static void menu_copy_centre_cb ( GtkAction *a, VikWindow *vw )
3628 {
3629   const VikCoord* coord;
3630   struct UTM utm;
3631   gchar *lat = NULL, *lon = NULL;
3632
3633   coord = vik_viewport_get_center ( vw->viking_vvp );
3634   vik_coord_to_utm ( coord, &utm );
3635
3636   gboolean full_format = FALSE;
3637   (void)a_settings_get_boolean ( VIK_SETTINGS_WIN_COPY_CENTRE_FULL_FORMAT, &full_format );
3638
3639   if ( full_format )
3640     // Bells & Whistles - may include degrees, minutes and second symbols
3641     get_location_strings ( vw, utm, &lat, &lon );
3642   else {
3643     // Simple x.xx y.yy format
3644     struct LatLon ll;
3645     a_coords_utm_to_latlon ( &utm, &ll );
3646     lat = g_strdup_printf ( "%.6f", ll.lat );
3647     lon = g_strdup_printf ( "%.6f", ll.lon );
3648   }
3649
3650   gchar *msg = g_strdup_printf ( "%s %s", lat, lon );
3651   g_free (lat);
3652   g_free (lon);
3653
3654   a_clipboard_copy ( VIK_CLIPBOARD_DATA_TEXT, 0, 0, 0, msg, NULL );
3655
3656   g_free ( msg );
3657 }
3658
3659 static void layer_defaults_cb ( GtkAction *a, VikWindow *vw )
3660 {
3661   gchar **texts = g_strsplit ( gtk_action_get_name(a), "Layer", 0 );
3662
3663   if ( !texts[1] )
3664     return; // Internally broken :(
3665
3666   if ( ! a_layer_defaults_show_window ( GTK_WINDOW(vw), texts[1] ) )
3667     a_dialog_info_msg ( GTK_WINDOW(vw), _("This layer has no configurable properties.") );
3668   // NB no update needed
3669
3670   g_strfreev ( texts );
3671 }
3672
3673 static void preferences_change_update ( VikWindow *vw, gpointer data )
3674 {
3675   // Want to update all TrackWaypoint layers
3676   GList *layers = vik_layers_panel_get_all_layers_of_type ( vw->viking_vlp, VIK_LAYER_TRW, TRUE );
3677
3678   if ( !layers )
3679     return;
3680
3681   while ( layers ) {
3682     // Reset the individual waypoints themselves due to the preferences change
3683     VikTrwLayer *vtl = VIK_TRW_LAYER(layers->data);
3684     vik_trw_layer_reset_waypoints ( vtl );
3685     layers = g_list_next ( layers );
3686   }
3687
3688   g_list_free ( layers );
3689
3690   draw_update ( vw );
3691 }
3692
3693 static void preferences_cb ( GtkAction *a, VikWindow *vw )
3694 {
3695   gboolean wp_icon_size = a_vik_get_use_large_waypoint_icons();
3696
3697   a_preferences_show_window ( GTK_WINDOW(vw) );
3698
3699   // Has the waypoint size setting changed?
3700   if (wp_icon_size != a_vik_get_use_large_waypoint_icons()) {
3701     // Delete icon indexing 'cache' and so automatically regenerates with the new setting when changed
3702     clear_garmin_icon_syms ();
3703
3704     // Update all windows
3705     g_slist_foreach ( window_list, (GFunc) preferences_change_update, NULL );
3706   }
3707
3708   // Ensure TZ Lookup initialized
3709   if ( a_vik_get_time_ref_frame() == VIK_TIME_REF_WORLD )
3710     vu_setup_lat_lon_tz_lookup();
3711
3712   toolbar_apply_settings ( vw->viking_vtb, vw->main_vbox, vw->menu_hbox, TRUE );
3713 }
3714
3715 static void default_location_cb ( GtkAction *a, VikWindow *vw )
3716 {
3717   /* Simplistic repeat of preference setting
3718      Only the name & type are important for setting the preference via this 'external' way */
3719   VikLayerParam pref_lat[] = {
3720     { VIK_LAYER_NUM_TYPES,
3721       VIKING_PREFERENCES_NAMESPACE "default_latitude",
3722       VIK_LAYER_PARAM_DOUBLE,
3723       VIK_LAYER_GROUP_NONE,
3724       NULL,
3725       VIK_LAYER_WIDGET_SPINBUTTON,
3726       NULL,
3727       NULL,
3728       NULL,
3729       NULL,
3730       NULL,
3731       NULL,
3732     },
3733   };
3734   VikLayerParam pref_lon[] = {
3735     { VIK_LAYER_NUM_TYPES,
3736       VIKING_PREFERENCES_NAMESPACE "default_longitude",
3737       VIK_LAYER_PARAM_DOUBLE,
3738       VIK_LAYER_GROUP_NONE,
3739       NULL,
3740       VIK_LAYER_WIDGET_SPINBUTTON,
3741       NULL,
3742       NULL,
3743       NULL,
3744       NULL,
3745       NULL,
3746       NULL,
3747     },
3748   };
3749
3750   /* Get current center */
3751   struct LatLon ll;
3752   vik_coord_to_latlon ( vik_viewport_get_center ( vw->viking_vvp ), &ll );
3753
3754   /* Apply to preferences */
3755   VikLayerParamData vlp_data;
3756   vlp_data.d = ll.lat;
3757   a_preferences_run_setparam (vlp_data, pref_lat);
3758   vlp_data.d = ll.lon;
3759   a_preferences_run_setparam (vlp_data, pref_lon);
3760   /* Remember to save */
3761   a_preferences_save_to_file();
3762 }
3763
3764 /**
3765  * Delete All
3766  */
3767 static void clear_cb ( GtkAction *a, VikWindow *vw )
3768 {
3769   // Do nothing if empty
3770   VikAggregateLayer *top = vik_layers_panel_get_top_layer(vw->viking_vlp);
3771   if ( ! vik_aggregate_layer_is_empty(top) ) {
3772     if ( a_dialog_yes_or_no ( GTK_WINDOW(vw), _("Are you sure you wish to delete all layers?"), NULL ) ) {
3773       vik_layers_panel_clear ( vw->viking_vlp );
3774       window_set_filename ( vw, NULL );
3775       draw_update ( vw );
3776     }
3777   }
3778 }
3779
3780 static void window_close ( GtkAction *a, VikWindow *vw )
3781 {
3782   if ( ! delete_event ( vw ) )
3783     gtk_widget_destroy ( GTK_WIDGET(vw) );
3784 }
3785
3786 static gboolean save_file_and_exit ( GtkAction *a, VikWindow *vw )
3787 {
3788   if (save_file( NULL, vw)) {
3789     window_close( NULL, vw);
3790     return(TRUE);
3791   }
3792   else
3793     return(FALSE);
3794 }
3795
3796 static void zoom_to_cb ( GtkAction *a, VikWindow *vw )
3797 {
3798   gdouble xmpp = vik_viewport_get_xmpp ( vw->viking_vvp ), ympp = vik_viewport_get_ympp ( vw->viking_vvp );
3799   if ( a_dialog_custom_zoom ( GTK_WINDOW(vw), &xmpp, &ympp ) )
3800   {
3801     vik_viewport_set_xmpp ( vw->viking_vvp, xmpp );
3802     vik_viewport_set_ympp ( vw->viking_vvp, ympp );
3803     draw_update ( vw );
3804   }
3805 }
3806
3807 static void save_image_file ( VikWindow *vw, const gchar *fn, guint w, guint h, gdouble zoom, gboolean save_as_png, gboolean save_kmz )
3808 {
3809   /* more efficient way: stuff draws directly to pixbuf (fork viewport) */
3810   GdkPixbuf *pixbuf_to_save;
3811   gdouble old_xmpp, old_ympp;
3812   GError *error = NULL;
3813
3814   GtkWidget *msgbox = gtk_message_dialog_new ( GTK_WINDOW(vw),
3815                                                GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
3816                                                GTK_MESSAGE_INFO,
3817                                                GTK_BUTTONS_NONE,
3818                                                _("Generating image file...") );
3819
3820   g_signal_connect_swapped (msgbox, "response", G_CALLBACK (gtk_widget_destroy), msgbox);
3821   // Ensure dialog shown
3822   gtk_widget_show_all ( msgbox );
3823   // Try harder...
3824   vik_statusbar_set_message ( vw->viking_vs, VIK_STATUSBAR_INFO, _("Generating image file...") );
3825   while ( gtk_events_pending() )
3826     gtk_main_iteration ();
3827   // Despite many efforts & variations, GTK on my Linux system doesn't show the actual msgbox contents :(
3828   // At least the empty box can give a clue something's going on + the statusbar msg...
3829   // Windows version under Wine OK!
3830
3831   /* backup old zoom & set new */
3832   old_xmpp = vik_viewport_get_xmpp ( vw->viking_vvp );
3833   old_ympp = vik_viewport_get_ympp ( vw->viking_vvp );
3834   vik_viewport_set_zoom ( vw->viking_vvp, zoom );
3835
3836   /* reset width and height: */
3837   vik_viewport_configure_manually ( vw->viking_vvp, w, h );
3838
3839   /* draw all layers */
3840   draw_redraw ( vw );
3841
3842   /* save buffer as file. */
3843   pixbuf_to_save = gdk_pixbuf_get_from_drawable ( NULL, GDK_DRAWABLE(vik_viewport_get_pixmap ( vw->viking_vvp )), NULL, 0, 0, 0, 0, w, h);
3844   if ( !pixbuf_to_save ) {
3845     g_warning("Failed to generate internal pixmap size: %d x %d", w, h);
3846     gtk_message_dialog_set_markup ( GTK_MESSAGE_DIALOG(msgbox), _("Failed to generate internal image.\n\nTry creating a smaller image.") );
3847     goto cleanup;
3848   }
3849
3850   int ans = 0; // Default to success
3851
3852   if ( save_kmz ) {
3853     gdouble north, east, south, west;
3854     vik_viewport_get_min_max_lat_lon ( vw->viking_vvp, &south, &north, &west, &east );
3855     ans = kmz_save_file ( pixbuf_to_save, fn, north, east, south, west );
3856   }
3857   else {
3858     gdk_pixbuf_save ( pixbuf_to_save, fn, save_as_png ? "png" : "jpeg", &error, NULL );
3859     if (error) {
3860       g_warning("Unable to write to file %s: %s", fn, error->message );
3861       g_error_free (error);
3862       ans = 42;
3863     }
3864   }
3865
3866   if ( ans == 0 )
3867     gtk_message_dialog_set_markup ( GTK_MESSAGE_DIALOG(msgbox), _("Image file generated.") );
3868   else
3869     gtk_message_dialog_set_markup ( GTK_MESSAGE_DIALOG(msgbox), _("Failed to generate image file.") );
3870
3871   g_object_unref ( G_OBJECT(pixbuf_to_save) );
3872
3873  cleanup:
3874   vik_statusbar_set_message ( vw->viking_vs, VIK_STATUSBAR_INFO, "" );
3875   gtk_dialog_add_button ( GTK_DIALOG(msgbox), GTK_STOCK_OK, GTK_RESPONSE_OK );
3876   gtk_dialog_run ( GTK_DIALOG(msgbox) ); // Don't care about the result
3877
3878   /* pretend like nothing happened ;) */
3879   vik_viewport_set_xmpp ( vw->viking_vvp, old_xmpp );
3880   vik_viewport_set_ympp ( vw->viking_vvp, old_ympp );
3881   vik_viewport_configure ( vw->viking_vvp );
3882   draw_update ( vw );
3883 }
3884
3885 static void save_image_dir ( VikWindow *vw, const gchar *fn, guint w, guint h, gdouble zoom, gboolean save_as_png, guint tiles_w, guint tiles_h )
3886 {
3887   gulong size = sizeof(gchar) * (strlen(fn) + 15);
3888   gchar *name_of_file = g_malloc ( size );
3889   guint x = 1, y = 1;
3890   struct UTM utm_orig, utm;
3891
3892   /* *** copied from above *** */
3893   GdkPixbuf *pixbuf_to_save;
3894   gdouble old_xmpp, old_ympp;
3895   GError *error = NULL;
3896
3897   /* backup old zoom & set new */
3898   old_xmpp = vik_viewport_get_xmpp ( vw->viking_vvp );
3899   old_ympp = vik_viewport_get_ympp ( vw->viking_vvp );
3900   vik_viewport_set_zoom ( vw->viking_vvp, zoom );
3901
3902   /* reset width and height: do this only once for all images (same size) */
3903   vik_viewport_configure_manually ( vw->viking_vvp, w, h );
3904   /* *** end copy from above *** */
3905
3906   g_assert ( vik_viewport_get_coord_mode ( vw->viking_vvp ) == VIK_COORD_UTM );
3907
3908   if ( g_mkdir(fn,0777) != 0 )
3909     g_warning ( "%s: Failed to create directory %s", __FUNCTION__, fn );
3910
3911   utm_orig = *((const struct UTM *)vik_viewport_get_center ( vw->viking_vvp ));
3912
3913   for ( y = 1; y <= tiles_h; y++ )
3914   {
3915     for ( x = 1; x <= tiles_w; x++ )
3916     {
3917       g_snprintf ( name_of_file, size, "%s%cy%d-x%d.%s", fn, G_DIR_SEPARATOR, y, x, save_as_png ? "png" : "jpg" );
3918       utm = utm_orig;
3919       if ( tiles_w & 0x1 )
3920         utm.easting += ((gdouble)x - ceil(((gdouble)tiles_w)/2)) * (w*zoom);
3921       else
3922         utm.easting += ((gdouble)x - (((gdouble)tiles_w)+1)/2) * (w*zoom);
3923       if ( tiles_h & 0x1 ) /* odd */
3924         utm.northing -= ((gdouble)y - ceil(((gdouble)tiles_h)/2)) * (h*zoom);
3925       else /* even */
3926         utm.northing -= ((gdouble)y - (((gdouble)tiles_h)+1)/2) * (h*zoom);
3927
3928       /* move to correct place. */
3929       vik_viewport_set_center_utm ( vw->viking_vvp, &utm, FALSE );
3930
3931       draw_redraw ( vw );
3932
3933       /* save buffer as file. */
3934       pixbuf_to_save = gdk_pixbuf_get_from_drawable ( NULL, GDK_DRAWABLE(vik_viewport_get_pixmap ( vw->viking_vvp )), NULL, 0, 0, 0, 0, w, h);
3935       gdk_pixbuf_save ( pixbuf_to_save, name_of_file, save_as_png ? "png" : "jpeg", &error, NULL );
3936       if (error)
3937       {
3938         gchar *msg = g_strdup_printf (_("Unable to write to file %s: %s"), name_of_file, error->message );
3939         vik_statusbar_set_message ( vw->viking_vs, VIK_STATUSBAR_INFO, msg );
3940         g_free ( msg );
3941         g_error_free (error);
3942       }
3943
3944       g_object_unref ( G_OBJECT(pixbuf_to_save) );
3945     }
3946   }
3947
3948   vik_viewport_set_center_utm ( vw->viking_vvp, &utm_orig, FALSE );
3949   vik_viewport_set_xmpp ( vw->viking_vvp, old_xmpp );
3950   vik_viewport_set_ympp ( vw->viking_vvp, old_ympp );
3951   vik_viewport_configure ( vw->viking_vvp );
3952   draw_update ( vw );
3953
3954   g_free ( name_of_file );
3955 }
3956
3957 static void draw_to_image_file_current_window_cb(GtkWidget* widget,GdkEventButton *event,gpointer *pass_along)
3958 {
3959   VikWindow *vw = VIK_WINDOW(pass_along[0]);
3960   GtkSpinButton *width_spin = GTK_SPIN_BUTTON(pass_along[1]), *height_spin = GTK_SPIN_BUTTON(pass_along[2]);
3961
3962   gint active = gtk_combo_box_get_active ( GTK_COMBO_BOX(pass_along[3]) );
3963   gdouble zoom = pow (2, active-2 );
3964
3965   gdouble width_min, width_max, height_min, height_max;
3966   gint width, height;
3967
3968   gtk_spin_button_get_range ( width_spin, &width_min, &width_max );
3969   gtk_spin_button_get_range ( height_spin, &height_min, &height_max );
3970
3971   /* TODO: support for xzoom and yzoom values */
3972   width = vik_viewport_get_width ( vw->viking_vvp ) * vik_viewport_get_xmpp ( vw->viking_vvp ) / zoom;
3973   height = vik_viewport_get_height ( vw->viking_vvp ) * vik_viewport_get_xmpp ( vw->viking_vvp ) / zoom;
3974
3975   if ( width > width_max || width < width_min || height > height_max || height < height_min )
3976     a_dialog_info_msg ( GTK_WINDOW(vw), _("Viewable region outside allowable pixel size bounds for image. Clipping width/height values.") );
3977
3978   gtk_spin_button_set_value ( width_spin, width );
3979   gtk_spin_button_set_value ( height_spin, height );
3980 }
3981
3982 static void draw_to_image_file_total_area_cb (GtkSpinButton *spinbutton, gpointer *pass_along)
3983 {
3984   GtkSpinButton *width_spin = GTK_SPIN_BUTTON(pass_along[1]), *height_spin = GTK_SPIN_BUTTON(pass_along[2]);
3985
3986   gint active = gtk_combo_box_get_active ( GTK_COMBO_BOX(pass_along[3]) );
3987   gdouble zoom = pow (2, active-2 );
3988
3989   gchar *label_text;
3990   gdouble w, h;
3991   w = gtk_spin_button_get_value(width_spin) * zoom;
3992   h = gtk_spin_button_get_value(height_spin) * zoom;
3993   if (pass_along[4]) /* save many images; find TOTAL area covered */
3994   {
3995     w *= gtk_spin_button_get_value(GTK_SPIN_BUTTON(pass_along[4]));
3996     h *= gtk_spin_button_get_value(GTK_SPIN_BUTTON(pass_along[5]));
3997   }
3998   vik_units_distance_t dist_units = a_vik_get_units_distance ();
3999   switch (dist_units) {
4000   case VIK_UNITS_DISTANCE_KILOMETRES:
4001     label_text = g_strdup_printf ( _("Total area: %ldm x %ldm (%.3f sq. km)"), (glong)w, (glong)h, (w*h/1000000));
4002     break;
4003   case VIK_UNITS_DISTANCE_MILES:
4004     label_text = g_strdup_printf ( _("Total area: %ldm x %ldm (%.3f sq. miles)"), (glong)w, (glong)h, (w*h/2589988.11));
4005     break;
4006   case VIK_UNITS_DISTANCE_NAUTICAL_MILES:
4007     label_text = g_strdup_printf ( _("Total area: %ldm x %ldm (%.3f sq. NM)"), (glong)w, (glong)h, (w*h/(1852.0*1852.0)));
4008     break;
4009   default:
4010     label_text = g_strdup_printf ("Just to keep the compiler happy");
4011     g_critical("Houston, we've had a problem. distance=%d", dist_units);
4012   }
4013
4014   gtk_label_set_text(GTK_LABEL(pass_along[6]), label_text);
4015   g_free ( label_text );
4016 }
4017
4018 typedef enum {
4019   VW_GEN_SINGLE_IMAGE,
4020   VW_GEN_DIRECTORY_OF_IMAGES,
4021   VW_GEN_KMZ_FILE,
4022 } img_generation_t;
4023
4024 /*
4025  * Get an allocated filename (or directory as specified)
4026  */
4027 static gchar* draw_image_filename ( VikWindow *vw, img_generation_t img_gen )
4028 {
4029   gchar *fn = NULL;
4030   if ( img_gen != VW_GEN_DIRECTORY_OF_IMAGES )
4031   {
4032     // Single file
4033     GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Save Image"),
4034                                                      GTK_WINDOW(vw),
4035                                                      GTK_FILE_CHOOSER_ACTION_SAVE,
4036                                                      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
4037                                                      GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
4038                                                      NULL);
4039     if ( last_folder_images_uri )
4040       gtk_file_chooser_set_current_folder_uri ( GTK_FILE_CHOOSER(dialog), last_folder_images_uri );
4041
4042     GtkFileChooser *chooser = GTK_FILE_CHOOSER ( dialog );
4043     /* Add filters */
4044     GtkFileFilter *filter;
4045     filter = gtk_file_filter_new ();
4046     gtk_file_filter_set_name ( filter, _("All") );
4047     gtk_file_filter_add_pattern ( filter, "*" );
4048     gtk_file_chooser_add_filter ( chooser, filter );
4049
4050     if ( img_gen == VW_GEN_KMZ_FILE ) {
4051       filter = gtk_file_filter_new ();
4052       gtk_file_filter_set_name ( filter, _("KMZ") );
4053       gtk_file_filter_add_mime_type ( filter, "vnd.google-earth.kmz");
4054       gtk_file_filter_add_pattern ( filter, "*.kmz" );
4055       gtk_file_chooser_add_filter ( chooser, filter );
4056       gtk_file_chooser_set_filter ( chooser, filter );
4057     }
4058     else {
4059       filter = gtk_file_filter_new ();
4060       gtk_file_filter_set_name ( filter, _("JPG") );
4061       gtk_file_filter_add_mime_type ( filter, "image/jpeg");
4062       gtk_file_chooser_add_filter ( chooser, filter );
4063
4064       if ( !vw->draw_image_save_as_png )
4065         gtk_file_chooser_set_filter ( chooser, filter );
4066
4067       filter = gtk_file_filter_new ();
4068       gtk_file_filter_set_name ( filter, _("PNG") );
4069       gtk_file_filter_add_mime_type ( filter, "image/png");
4070       gtk_file_chooser_add_filter ( chooser, filter );
4071
4072       if ( vw->draw_image_save_as_png )
4073         gtk_file_chooser_set_filter ( chooser, filter );
4074     }
4075
4076     gtk_window_set_transient_for ( GTK_WINDOW(dialog), GTK_WINDOW(vw) );
4077     gtk_window_set_destroy_with_parent ( GTK_WINDOW(dialog), TRUE );
4078
4079     if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT ) {
4080       g_free ( last_folder_images_uri );
4081       last_folder_images_uri = gtk_file_chooser_get_current_folder_uri ( GTK_FILE_CHOOSER(dialog) );
4082
4083       fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(dialog) );
4084       if ( g_file_test ( fn, G_FILE_TEST_EXISTS ) )
4085         if ( ! a_dialog_yes_or_no ( GTK_WINDOW(dialog), _("The file \"%s\" exists, do you wish to overwrite it?"), a_file_basename ( fn ) ) )
4086           fn = NULL;
4087     }
4088     gtk_widget_destroy ( dialog );
4089   }
4090   else {
4091     // A directory
4092     // For some reason this method is only written to work in UTM...
4093     if ( vik_viewport_get_coord_mode(vw->viking_vvp) != VIK_COORD_UTM ) {
4094       a_dialog_error_msg ( GTK_WINDOW(vw), _("You must be in UTM mode to use this feature") );
4095       return fn;
4096     }
4097
4098     GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Choose a directory to hold images"),
4099                                                      GTK_WINDOW(vw),
4100                                                      GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
4101                                                      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
4102                                                      GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
4103                                                      NULL);
4104     gtk_window_set_transient_for ( GTK_WINDOW(dialog), GTK_WINDOW(vw) );
4105     gtk_window_set_destroy_with_parent ( GTK_WINDOW(dialog), TRUE );
4106
4107     if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT ) {
4108       fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(dialog) );
4109     }
4110     gtk_widget_destroy ( dialog );
4111   }
4112   return fn;
4113 }
4114
4115 static void draw_to_image_file ( VikWindow *vw, img_generation_t img_gen )
4116 {
4117   /* todo: default for answers inside VikWindow or static (thruout instance) */
4118   GtkWidget *dialog = gtk_dialog_new_with_buttons ( _("Save to Image File"), GTK_WINDOW(vw),
4119                                                   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4120                                                   GTK_STOCK_CANCEL,
4121                                                   GTK_RESPONSE_REJECT,
4122                                                   GTK_STOCK_OK,
4123                                                   GTK_RESPONSE_ACCEPT,
4124                                                   NULL );
4125   GtkWidget *width_label, *width_spin, *height_label, *height_spin;
4126   GtkWidget *current_window_button;
4127   gpointer current_window_pass_along[7];
4128   GtkWidget *zoom_label, *zoom_combo;
4129   GtkWidget *total_size_label;
4130
4131   // only used for VW_GEN_DIRECTORY_OF_IMAGES
4132   GtkWidget *tiles_width_spin = NULL, *tiles_height_spin = NULL;
4133
4134   width_label = gtk_label_new ( _("Width (pixels):") );
4135   width_spin = gtk_spin_button_new ( GTK_ADJUSTMENT(gtk_adjustment_new ( vw->draw_image_width, 10, 50000, 10, 100, 0 )), 10, 0 );
4136   height_label = gtk_label_new ( _("Height (pixels):") );
4137   height_spin = gtk_spin_button_new ( GTK_ADJUSTMENT(gtk_adjustment_new ( vw->draw_image_height, 10, 50000, 10, 100, 0 )), 10, 0 );
4138 #ifdef WINDOWS
4139   GtkWidget *win_warning_label = gtk_label_new ( _("WARNING: USING LARGE IMAGES OVER 10000x10000\nMAY CRASH THE PROGRAM!") );
4140 #endif
4141   zoom_label = gtk_label_new ( _("Zoom (meters per pixel):") );
4142   /* TODO: separate xzoom and yzoom factors */
4143   zoom_combo = create_zoom_combo_all_levels();
4144
4145   gdouble mpp = vik_viewport_get_xmpp(vw->viking_vvp);
4146   gint active = 2 + round ( log (mpp) / log (2) );
4147
4148   // Can we not hard code size here?
4149   if ( active > 17 )
4150     active = 17;
4151   if ( active < 0 )
4152     active = 0;
4153   gtk_combo_box_set_active ( GTK_COMBO_BOX(zoom_combo), active );
4154
4155   total_size_label = gtk_label_new ( NULL );
4156
4157   current_window_button = gtk_button_new_with_label ( _("Area in current viewable window") );
4158   current_window_pass_along [0] = vw;
4159   current_window_pass_along [1] = width_spin;
4160   current_window_pass_along [2] = height_spin;
4161   current_window_pass_along [3] = zoom_combo;
4162   current_window_pass_along [4] = NULL; // Only for directory of tiles: width
4163   current_window_pass_along [5] = NULL; // Only for directory of tiles: height
4164   current_window_pass_along [6] = total_size_label;
4165   g_signal_connect ( G_OBJECT(current_window_button), "button_press_event", G_CALLBACK(draw_to_image_file_current_window_cb), current_window_pass_along );
4166
4167   GtkWidget *png_radio = gtk_radio_button_new_with_label ( NULL, _("Save as PNG") );
4168   GtkWidget *jpeg_radio = gtk_radio_button_new_with_label_from_widget ( GTK_RADIO_BUTTON(png_radio), _("Save as JPEG") );
4169
4170   if ( img_gen == VW_GEN_KMZ_FILE ) {
4171     // Don't show image type selection if creating a KMZ (always JPG internally)
4172     // Start with viewable area by default
4173     draw_to_image_file_current_window_cb ( current_window_button, NULL, current_window_pass_along );
4174   } else {
4175     gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), jpeg_radio, FALSE, FALSE, 0);
4176     gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), png_radio, FALSE, FALSE, 0);
4177   }
4178
4179   if ( ! vw->draw_image_save_as_png )
4180     gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON(jpeg_radio), TRUE );
4181
4182   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), width_label, FALSE, FALSE, 0);
4183   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), width_spin, FALSE, FALSE, 0);
4184   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), height_label, FALSE, FALSE, 0);
4185   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), height_spin, FALSE, FALSE, 0);
4186 #ifdef WINDOWS
4187   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), win_warning_label, FALSE, FALSE, 0);
4188 #endif
4189   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), current_window_button, FALSE, FALSE, 0);
4190   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), zoom_label, FALSE, FALSE, 0);
4191   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), zoom_combo, FALSE, FALSE, 0);
4192
4193   if ( img_gen == VW_GEN_DIRECTORY_OF_IMAGES )
4194   {
4195     GtkWidget *tiles_width_label, *tiles_height_label;
4196
4197     tiles_width_label = gtk_label_new ( _("East-west image tiles:") );
4198     tiles_width_spin = gtk_spin_button_new ( GTK_ADJUSTMENT(gtk_adjustment_new ( 5, 1, 10, 1, 100, 0 )), 1, 0 );
4199     tiles_height_label = gtk_label_new ( _("North-south image tiles:") );
4200     tiles_height_spin = gtk_spin_button_new ( GTK_ADJUSTMENT(gtk_adjustment_new ( 5, 1, 10, 1, 100, 0 )), 1, 0 );
4201     gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), tiles_width_label, FALSE, FALSE, 0);
4202     gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), tiles_width_spin, FALSE, FALSE, 0);
4203     gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), tiles_height_label, FALSE, FALSE, 0);
4204     gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), tiles_height_spin, FALSE, FALSE, 0);
4205
4206     current_window_pass_along [4] = tiles_width_spin;
4207     current_window_pass_along [5] = tiles_height_spin;
4208     g_signal_connect ( G_OBJECT(tiles_width_spin), "value-changed", G_CALLBACK(draw_to_image_file_total_area_cb), current_window_pass_along );
4209     g_signal_connect ( G_OBJECT(tiles_height_spin), "value-changed", G_CALLBACK(draw_to_image_file_total_area_cb), current_window_pass_along );
4210   }
4211   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), total_size_label, FALSE, FALSE, 0);
4212   g_signal_connect ( G_OBJECT(width_spin), "value-changed", G_CALLBACK(draw_to_image_file_total_area_cb), current_window_pass_along );
4213   g_signal_connect ( G_OBJECT(height_spin), "value-changed", G_CALLBACK(draw_to_image_file_total_area_cb), current_window_pass_along );
4214   g_signal_connect ( G_OBJECT(zoom_combo), "changed", G_CALLBACK(draw_to_image_file_total_area_cb), current_window_pass_along );
4215
4216   draw_to_image_file_total_area_cb ( NULL, current_window_pass_along ); /* set correct size info now */
4217
4218   gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
4219
4220   gtk_widget_show_all ( gtk_dialog_get_content_area(GTK_DIALOG(dialog)) );
4221
4222   if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
4223   {
4224     gtk_widget_hide ( GTK_WIDGET(dialog) );
4225
4226     gchar *fn = draw_image_filename ( vw, img_gen );
4227     if ( !fn )
4228       return;
4229
4230     gint active_z = gtk_combo_box_get_active ( GTK_COMBO_BOX(zoom_combo) );
4231     gdouble zoom = pow (2, active_z-2 );
4232
4233     if ( img_gen == VW_GEN_SINGLE_IMAGE )
4234       save_image_file ( vw, fn, 
4235                       vw->draw_image_width = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(width_spin) ),
4236                       vw->draw_image_height = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(height_spin) ),
4237                       zoom,
4238                       vw->draw_image_save_as_png = gtk_toggle_button_get_active ( GTK_TOGGLE_BUTTON(png_radio) ),
4239                       FALSE );
4240     else if ( img_gen == VW_GEN_KMZ_FILE ) {
4241       // Remove some viewport overlays as these aren't useful in KMZ file.
4242       gboolean restore_xhair = vik_viewport_get_draw_centermark ( vw->viking_vvp );
4243       if ( restore_xhair )
4244         vik_viewport_set_draw_centermark ( vw->viking_vvp, FALSE );
4245       gboolean restore_scale = vik_viewport_get_draw_scale ( vw->viking_vvp );
4246       if ( restore_scale )
4247         vik_viewport_set_draw_scale ( vw->viking_vvp, FALSE );
4248
4249       save_image_file ( vw,
4250                         fn,
4251                         gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(width_spin) ),
4252                         gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(height_spin) ),
4253                         zoom,
4254                         FALSE, // JPG
4255                         TRUE );
4256
4257       if ( restore_xhair )
4258         vik_viewport_set_draw_centermark ( vw->viking_vvp, TRUE );
4259       if ( restore_scale )
4260         vik_viewport_set_draw_scale ( vw->viking_vvp, TRUE );
4261       if ( restore_xhair || restore_scale )
4262         draw_update ( vw );
4263     }
4264     else {
4265       // NB is in UTM mode ATM
4266       save_image_dir ( vw, fn,
4267                        vw->draw_image_width = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(width_spin) ),
4268                        vw->draw_image_height = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(height_spin) ),
4269                        zoom,
4270                        vw->draw_image_save_as_png = gtk_toggle_button_get_active ( GTK_TOGGLE_BUTTON(png_radio) ),
4271                        gtk_spin_button_get_value ( GTK_SPIN_BUTTON(tiles_width_spin) ),
4272                        gtk_spin_button_get_value ( GTK_SPIN_BUTTON(tiles_height_spin) ) );
4273     }
4274
4275     g_free ( fn );
4276   }
4277   gtk_widget_destroy ( GTK_WIDGET(dialog) );
4278 }
4279
4280 static void draw_to_kmz_file_cb ( GtkAction *a, VikWindow *vw )
4281 {
4282   if ( vik_viewport_get_coord_mode(vw->viking_vvp) == VIK_COORD_UTM ) {
4283     a_dialog_error_msg ( GTK_WINDOW(vw), _("This feature is not available in UTM mode") );
4284     return;
4285   }
4286   // NB ATM This only generates a KMZ file with the current viewport image - intended mostly for map images [but will include any lines/icons from track & waypoints that are drawn]
4287   // (it does *not* include a full KML dump of every track, waypoint etc...)
4288   draw_to_image_file ( vw, VW_GEN_KMZ_FILE );
4289 }
4290
4291 static void draw_to_image_file_cb ( GtkAction *a, VikWindow *vw )
4292 {
4293   draw_to_image_file ( vw, VW_GEN_SINGLE_IMAGE );
4294 }
4295
4296 static void draw_to_image_dir_cb ( GtkAction *a, VikWindow *vw )
4297 {
4298   draw_to_image_file ( vw, VW_GEN_DIRECTORY_OF_IMAGES );
4299 }
4300
4301 /**
4302  *
4303  */
4304 static void import_kmz_file_cb ( GtkAction *a, VikWindow *vw )
4305 {
4306   GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Open File"),
4307                                                    GTK_WINDOW(vw),
4308                                                    GTK_FILE_CHOOSER_ACTION_OPEN,
4309                                                    GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
4310                                                    GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
4311                                                    NULL);
4312
4313   GtkFileFilter *filter;
4314   filter = gtk_file_filter_new ();
4315   gtk_file_filter_set_name ( filter, _("KMZ") );
4316   gtk_file_filter_add_mime_type ( filter, "vnd.google-earth.kmz");
4317   gtk_file_filter_add_pattern ( filter, "*.kmz" );
4318   gtk_file_chooser_add_filter ( GTK_FILE_CHOOSER(dialog), filter );
4319   gtk_file_chooser_set_filter ( GTK_FILE_CHOOSER(dialog), filter );
4320
4321   filter = gtk_file_filter_new ();
4322   gtk_file_filter_set_name( filter, _("All") );
4323   gtk_file_filter_add_pattern ( filter, "*" );
4324   gtk_file_chooser_add_filter ( GTK_FILE_CHOOSER(dialog), filter );
4325   // Default to any file - same as before open filters were added
4326   gtk_file_chooser_set_filter ( GTK_FILE_CHOOSER(dialog), filter );
4327
4328   if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )  {
4329     gchar *fn = gtk_file_chooser_get_filename ( GTK_FILE_CHOOSER(dialog) );
4330     // TODO convert ans value into readable explaination of failure...
4331     int ans = kmz_open_file ( fn, vw->viking_vvp, vw->viking_vlp );
4332     if ( ans )
4333       a_dialog_error_msg_extra ( GTK_WINDOW(vw), _("Unable to import %s."), fn );
4334
4335     draw_update ( vw );
4336   }
4337   gtk_widget_destroy ( dialog );
4338 }
4339
4340 static void print_cb ( GtkAction *a, VikWindow *vw )
4341 {
4342   a_print(vw, vw->viking_vvp);
4343 }
4344
4345 /* really a misnomer: changes coord mode (actual coordinates) AND/OR draw mode (viewport only) */
4346 static void window_change_coord_mode_cb ( GtkAction *old_a, GtkAction *a, VikWindow *vw )
4347 {
4348   const gchar *name = gtk_action_get_name(a);
4349   GtkToggleToolButton *tbutton = (GtkToggleToolButton *)toolbar_get_widget_by_name ( vw->viking_vtb, name );
4350   if ( tbutton )
4351     gtk_toggle_tool_button_set_active ( tbutton, TRUE );
4352
4353   VikViewportDrawMode drawmode;
4354   if (!g_strcmp0(name, "ModeUTM")) {
4355     drawmode = VIK_VIEWPORT_DRAWMODE_UTM;
4356   }
4357   else if (!g_strcmp0(name, "ModeLatLon")) {
4358     drawmode = VIK_VIEWPORT_DRAWMODE_LATLON;
4359   }
4360   else if (!g_strcmp0(name, "ModeExpedia")) {
4361     drawmode = VIK_VIEWPORT_DRAWMODE_EXPEDIA;
4362   }
4363   else if (!g_strcmp0(name, "ModeMercator")) {
4364     drawmode = VIK_VIEWPORT_DRAWMODE_MERCATOR;
4365   }
4366   else {
4367     g_critical("Houston, we've had a problem.");
4368     return;
4369   }
4370
4371   if ( !vw->only_updating_coord_mode_ui )
4372   {
4373     VikViewportDrawMode olddrawmode = vik_viewport_get_drawmode ( vw->viking_vvp );
4374     if ( olddrawmode != drawmode )
4375     {
4376       /* this takes care of coord mode too */
4377       vik_viewport_set_drawmode ( vw->viking_vvp, drawmode );
4378       if ( drawmode == VIK_VIEWPORT_DRAWMODE_UTM ) {
4379         vik_layers_panel_change_coord_mode ( vw->viking_vlp, VIK_COORD_UTM );
4380       } else if ( olddrawmode == VIK_VIEWPORT_DRAWMODE_UTM ) {
4381         vik_layers_panel_change_coord_mode ( vw->viking_vlp, VIK_COORD_LATLON );
4382       }
4383       draw_update ( vw );
4384     }
4385   }
4386 }
4387
4388 static void toggle_draw_scale ( GtkAction *a, VikWindow *vw )
4389 {
4390   gboolean state = !vik_viewport_get_draw_scale ( vw->viking_vvp );
4391   GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ShowScale" );
4392   if ( !check_box )
4393     return;
4394   gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), state );
4395   vik_viewport_set_draw_scale ( vw->viking_vvp, state );
4396   draw_update ( vw );
4397 }
4398
4399 static void toggle_draw_centermark ( GtkAction *a, VikWindow *vw )
4400 {
4401   gboolean state = !vik_viewport_get_draw_centermark ( vw->viking_vvp );
4402   GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ShowCenterMark" );
4403   if ( !check_box )
4404     return;
4405   gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), state );
4406   vik_viewport_set_draw_centermark ( vw->viking_vvp, state );
4407   draw_update ( vw );
4408 }
4409
4410 static void toggle_draw_highlight ( GtkAction *a, VikWindow *vw )
4411 {
4412   gboolean state = !vik_viewport_get_draw_highlight ( vw->viking_vvp );
4413   GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ShowHighlight" );
4414   if ( !check_box )
4415     return;
4416   gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), state );
4417   vik_viewport_set_draw_highlight ( vw->viking_vvp, state );
4418   draw_update ( vw );
4419 }
4420
4421 static void set_bg_color ( GtkAction *a, VikWindow *vw )
4422 {
4423   GtkWidget *colorsd = gtk_color_selection_dialog_new ( _("Choose a background color") );
4424   GdkColor *color = vik_viewport_get_background_gdkcolor ( vw->viking_vvp );
4425   gtk_color_selection_set_previous_color ( GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(colorsd))), color );
4426   gtk_color_selection_set_current_color ( GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(colorsd))), color );
4427   if ( gtk_dialog_run ( GTK_DIALOG(colorsd) ) == GTK_RESPONSE_OK )
4428   {
4429     gtk_color_selection_get_current_color ( GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(colorsd))), color );
4430     vik_viewport_set_background_gdkcolor ( vw->viking_vvp, color );
4431     draw_update ( vw );
4432   }
4433   g_free ( color );
4434   gtk_widget_destroy ( colorsd );
4435 }
4436
4437 static void set_highlight_color ( GtkAction *a, VikWindow *vw )
4438 {
4439   GtkWidget *colorsd = gtk_color_selection_dialog_new ( _("Choose a track highlight color") );
4440   GdkColor *color = vik_viewport_get_highlight_gdkcolor ( vw->viking_vvp );
4441   gtk_color_selection_set_previous_color ( GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(colorsd))), color );
4442   gtk_color_selection_set_current_color ( GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(colorsd))), color );
4443   if ( gtk_dialog_run ( GTK_DIALOG(colorsd) ) == GTK_RESPONSE_OK )
4444   {
4445     gtk_color_selection_get_current_color ( GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(colorsd))), color );
4446     vik_viewport_set_highlight_gdkcolor ( vw->viking_vvp, color );
4447     draw_update ( vw );
4448   }
4449   g_free ( color );
4450   gtk_widget_destroy ( colorsd );
4451 }
4452
4453
4454 /***********************************************************************************************
4455  ** GUI Creation
4456  ***********************************************************************************************/
4457
4458 static GtkActionEntry entries[] = {
4459   { "File", NULL, N_("_File"), 0, 0, 0 },
4460   { "Edit", NULL, N_("_Edit"), 0, 0, 0 },
4461   { "View", NULL, N_("_View"), 0, 0, 0 },
4462   { "SetShow", NULL, N_("_Show"), 0, 0, 0 },
4463   { "SetZoom", NULL, N_("_Zoom"), 0, 0, 0 },
4464   { "SetPan", NULL, N_("_Pan"), 0, 0, 0 },
4465   { "Layers", NULL, N_("_Layers"), 0, 0, 0 },
4466   { "Tools", NULL, N_("_Tools"), 0, 0, 0 },
4467   { "Exttools", NULL, N_("_Webtools"), 0, 0, 0 },
4468   { "Help", NULL, N_("_Help"), 0, 0, 0 },
4469
4470   { "New",       GTK_STOCK_NEW,          N_("_New"),                          "<control>N", N_("New file"),                                     (GCallback)newwindow_cb          },
4471   { "Open",      GTK_STOCK_OPEN,         N_("_Open..."),                         "<control>O", N_("Open a file"),                                  (GCallback)load_file             },
4472   { "OpenRecentFile", NULL,              N_("Open _Recent File"),         NULL,         NULL,                                               (GCallback)NULL },
4473   { "Append",    GTK_STOCK_ADD,          N_("Append _File..."),           NULL,         N_("Append data from a different file"),            (GCallback)load_file             },
4474   { "Export",    GTK_STOCK_CONVERT,      N_("_Export All"),               NULL,         N_("Export All TrackWaypoint Layers"),              (GCallback)NULL                  },
4475   { "ExportGPX", NULL,                   N_("_GPX..."),                       NULL,         N_("Export as GPX"),                                (GCallback)export_to_gpx         },
4476   { "Acquire",   GTK_STOCK_GO_DOWN,      N_("A_cquire"),                  NULL,         NULL,                                               (GCallback)NULL },
4477   { "AcquireRouting",   NULL,             N_("_Directions..."),     NULL,         N_("Get driving directions"),           (GCallback)acquire_from_routing   },
4478 #ifdef VIK_CONFIG_OPENSTREETMAP
4479   { "AcquireOSM",   NULL,                 N_("_OSM Traces..."),           NULL,         N_("Get traces from OpenStreetMap"),            (GCallback)acquire_from_osm       },
4480   { "AcquireMyOSM", NULL,                 N_("_My OSM Traces..."),        NULL,         N_("Get Your Own Traces from OpenStreetMap"),   (GCallback)acquire_from_my_osm    },
4481 #endif
4482 #ifdef VIK_CONFIG_GEOCACHES
4483   { "AcquireGC",   NULL,                 N_("Geo_caches..."),             NULL,         N_("Get Geocaches from geocaching.com"),            (GCallback)acquire_from_gc       },
4484 #endif
4485 #ifdef VIK_CONFIG_GEOTAG
4486   { "AcquireGeotag", NULL,               N_("From Geotagged _Images..."), NULL,         N_("Create waypoints from geotagged images"),       (GCallback)acquire_from_geotag   },
4487 #endif
4488   { "AcquireURL", NULL,                  N_("From _URL..."),              NULL,         N_("Get a file from a URL"),                        (GCallback)acquire_from_url },
4489 #ifdef VIK_CONFIG_GEONAMES
4490   { "AcquireWikipedia", NULL,            N_("From _Wikipedia Waypoints"), NULL,         N_("Create waypoints from Wikipedia items in the current view"), (GCallback)acquire_from_wikipedia },
4491 #endif
4492   { "Save",      GTK_STOCK_SAVE,         N_("_Save"),                         "<control>S", N_("Save the file"),                                (GCallback)save_file             },
4493   { "SaveAs",    GTK_STOCK_SAVE_AS,      N_("Save _As..."),                      NULL,  N_("Save the file under different name"),           (GCallback)save_file_as          },
4494   { "FileProperties", NULL,              N_("Properties..."),                    NULL,  N_("File Properties"),                              (GCallback)file_properties_cb },
4495 #ifdef HAVE_ZIP_H
4496   { "ImportKMZ", GTK_STOCK_CONVERT,      N_("Import KMZ _Map File..."),        NULL,  N_("Import a KMZ file"), (GCallback)import_kmz_file_cb },
4497   { "GenKMZ",    GTK_STOCK_DND,          N_("Generate _KMZ Map File..."),        NULL,  N_("Generate a KMZ file with an overlay of the current view"), (GCallback)draw_to_kmz_file_cb },
4498 #endif
4499   { "GenImg",    GTK_STOCK_FILE,         N_("_Generate Image File..."),          NULL,  N_("Save a snapshot of the workspace into a file"), (GCallback)draw_to_image_file_cb },
4500   { "GenImgDir", GTK_STOCK_DND_MULTIPLE, N_("Generate _Directory of Images..."), NULL,  N_("Generate _Directory of Images"),                (GCallback)draw_to_image_dir_cb },
4501   { "Print",    GTK_STOCK_PRINT,        N_("_Print..."),          NULL,         N_("Print maps"), (GCallback)print_cb },
4502   { "Exit",      GTK_STOCK_QUIT,         N_("E_xit"),                         "<control>W", N_("Exit the program"),                             (GCallback)window_close          },
4503   { "SaveExit",  GTK_STOCK_QUIT,         N_("Save and Exit"),                 NULL, N_("Save and Exit the program"),                             (GCallback)save_file_and_exit          },
4504
4505   { "GoBack",    GTK_STOCK_GO_BACK,      N_("Go to the Pre_vious Location"),  NULL,         N_("Go to the previous location"),              (GCallback)draw_goto_back_and_forth },
4506   { "GoForward", GTK_STOCK_GO_FORWARD,   N_("Go to the _Next Location"),      NULL,         N_("Go to the next location"),                  (GCallback)draw_goto_back_and_forth },
4507   { "GotoDefaultLocation", GTK_STOCK_HOME, N_("Go to the _Default Location"),  NULL,         N_("Go to the default location"),                     (GCallback)goto_default_location },
4508   { "GotoSearch", GTK_STOCK_JUMP_TO,     N_("Go to _Location..."),            NULL,         N_("Go to address/place using text search"),        (GCallback)goto_address       },
4509   { "GotoLL",    GTK_STOCK_JUMP_TO,      N_("_Go to Lat/Lon..."),           NULL,         N_("Go to arbitrary lat/lon coordinate"),         (GCallback)draw_goto_cb          },
4510   { "GotoUTM",   GTK_STOCK_JUMP_TO,      N_("Go to UTM..."),                  NULL,         N_("Go to arbitrary UTM coordinate"),               (GCallback)draw_goto_cb          },
4511   { "Refresh",   GTK_STOCK_REFRESH,      N_("_Refresh"),                      "F5",         N_("Refresh any maps displayed"),               (GCallback)draw_refresh_cb       },
4512   { "SetHLColor",GTK_STOCK_SELECT_COLOR, N_("Set _Highlight Color..."),       NULL,         N_("Set Highlight Color"),                      (GCallback)set_highlight_color },
4513   { "SetBGColor",GTK_STOCK_SELECT_COLOR, N_("Set Bac_kground Color..."),      NULL,         N_("Set Background Color"),                     (GCallback)set_bg_color },
4514   { "ZoomIn",    GTK_STOCK_ZOOM_IN,      N_("Zoom _In"),                  "<control>plus",  N_("Zoom In"),                                  (GCallback)draw_zoom_cb },
4515   { "ZoomOut",   GTK_STOCK_ZOOM_OUT,     N_("Zoom _Out"),                 "<control>minus", N_("Zoom Out"),                                 (GCallback)draw_zoom_cb },
4516   { "ZoomTo",    GTK_STOCK_ZOOM_FIT,     N_("Zoom _To..."),               "<control>Z",     N_("Zoom To"),                                  (GCallback)zoom_to_cb },
4517   { "PanNorth",  NULL,                   N_("Pan _North"),                "<control>Up",    NULL,                                           (GCallback)draw_pan_cb },
4518   { "PanEast",   NULL,                   N_("Pan _East"),                 "<control>Right", NULL,                                           (GCallback)draw_pan_cb },
4519   { "PanSouth",  NULL,                   N_("Pan _South"),                "<control>Down",  NULL,                                           (GCallback)draw_pan_cb },
4520   { "PanWest",   NULL,                   N_("Pan _West"),                 "<control>Left",  NULL,                                           (GCallback)draw_pan_cb },
4521   { "BGJobs",    GTK_STOCK_EXECUTE,      N_("Background _Jobs"),              NULL,         N_("Background Jobs"),                          (GCallback)a_background_show_window },
4522
4523   { "Cut",       GTK_STOCK_CUT,          N_("Cu_t"),                          NULL,         N_("Cut selected layer"),                       (GCallback)menu_cut_layer_cb     },
4524   { "Copy",      GTK_STOCK_COPY,         N_("_Copy"),                         NULL,         N_("Copy selected layer"),                      (GCallback)menu_copy_layer_cb    },
4525   { "Paste",     GTK_STOCK_PASTE,        N_("_Paste"),                        NULL,         N_("Paste layer into selected container layer or otherwise above selected layer"), (GCallback)menu_paste_layer_cb },
4526   { "Delete",    GTK_STOCK_DELETE,       N_("_Delete"),                       NULL,         N_("Remove selected layer"),                    (GCallback)menu_delete_layer_cb  },
4527   { "DeleteAll", NULL,                   N_("Delete All"),                    NULL,         NULL,                                           (GCallback)clear_cb              },
4528   { "CopyCentre",NULL,                   N_("Copy Centre _Location"),     "<control>h",     NULL,                                           (GCallback)menu_copy_centre_cb   },
4529   { "MapCacheFlush",NULL,                N_("_Flush Map Cache"),              NULL,         NULL,                                           (GCallback)mapcache_flush_cb     },
4530   { "SetDefaultLocation", GTK_STOCK_GO_FORWARD, N_("_Set the Default Location"), NULL, N_("Set the Default Location to the current position"),(GCallback)default_location_cb },
4531   { "Preferences",GTK_STOCK_PREFERENCES, N_("_Preferences"),                  NULL,         N_("Program Preferences"),                      (GCallback)preferences_cb },
4532   { "LayerDefaults",GTK_STOCK_PROPERTIES, N_("_Layer Defaults"),             NULL,         NULL,                                           NULL },
4533   { "Properties",GTK_STOCK_PROPERTIES,   N_("_Properties"),                   NULL,         N_("Layer Properties"),                         (GCallback)menu_properties_cb },
4534
4535   { "HelpEntry", GTK_STOCK_HELP,         N_("_Help"),                         "F1",         N_("Help"),                                     (GCallback)help_help_cb },
4536   { "About",     GTK_STOCK_ABOUT,        N_("_About"),                        NULL,         N_("About"),                                    (GCallback)help_about_cb },
4537 };
4538
4539 static GtkActionEntry debug_entries[] = {
4540   { "MapCacheInfo", NULL,                "_Map Cache Info",                   NULL,         NULL,                                           (GCallback)help_cache_info_cb    },
4541   { "BackForwardInfo", NULL,             "_Back/Forward Info",                NULL,         NULL,                                           (GCallback)back_forward_info_cb  },
4542 };
4543
4544 static GtkActionEntry entries_gpsbabel[] = {
4545   { "ExportKML", NULL,                   N_("_KML..."),                       NULL,         N_("Export as KML"),                                (GCallback)export_to_kml },
4546   { "AcquireGPS",   NULL,                N_("From _GPS..."),              NULL,         N_("Transfer data from a GPS device"),              (GCallback)acquire_from_gps      },
4547   { "AcquireGPSBabel", NULL,             N_("Import File With GPS_Babel..."), NULL,     N_("Import file via GPSBabel converter"),           (GCallback)acquire_from_file },
4548 };
4549
4550 static GtkActionEntry entries_geojson[] = {
4551   { "AcquireGeoJSON",   NULL,            N_("Import Geo_JSON File..."),   NULL,         N_("Import GeoJSON file"),                          (GCallback)acquire_from_geojson },
4552 };
4553
4554 /* Radio items */
4555 static GtkRadioActionEntry mode_entries[] = {
4556   { "ModeUTM",         NULL,         N_("_UTM Mode"),               "<control>u", NULL, VIK_VIEWPORT_DRAWMODE_UTM },
4557   { "ModeExpedia",     NULL,         N_("_Expedia Mode"),           "<control>e", NULL, VIK_VIEWPORT_DRAWMODE_EXPEDIA },
4558   { "ModeMercator",    NULL,         N_("_Mercator Mode"),          "<control>m", NULL, VIK_VIEWPORT_DRAWMODE_MERCATOR },
4559   { "ModeLatLon",      NULL,         N_("Lat_/Lon Mode"),           "<control>l", NULL, VIK_VIEWPORT_DRAWMODE_LATLON },
4560 };
4561
4562 static GtkToggleActionEntry toggle_entries[] = {
4563   { "ShowScale",      NULL,                 N_("Show _Scale"),               "<shift>F5",  N_("Show Scale"),                              (GCallback)toggle_draw_scale, TRUE },
4564   { "ShowCenterMark", NULL,                 N_("Show _Center Mark"),         "F6",         N_("Show Center Mark"),                        (GCallback)toggle_draw_centermark, TRUE },
4565   { "ShowHighlight",  GTK_STOCK_UNDERLINE,  N_("Show _Highlight"),           "F7",         N_("Show Highlight"),                          (GCallback)toggle_draw_highlight, TRUE },
4566   { "FullScreen",     GTK_STOCK_FULLSCREEN, N_("_Full Screen"),              "F11",        N_("Activate full screen mode"),               (GCallback)full_screen_cb, FALSE },
4567   { "ViewSidePanel",  GTK_STOCK_INDEX,      N_("Show Side _Panel"),          "F9",         N_("Show Side Panel"),                         (GCallback)view_side_panel_cb, TRUE },
4568   { "ViewStatusBar",  NULL,                 N_("Show Status_bar"),           "F12",        N_("Show Statusbar"),                          (GCallback)view_statusbar_cb, TRUE },
4569   { "ViewToolbar",    NULL,                 N_("Show _Toolbar"),             "F3",         N_("Show Toolbar"),                            (GCallback)view_toolbar_cb, TRUE },
4570   { "ViewMainMenu",   NULL,                 N_("Show _Menu"),                "F4",         N_("Show Menu"),                               (GCallback)view_main_menu_cb, TRUE },
4571 };
4572
4573 // This must match the toggle entries order above
4574 static gpointer toggle_entries_toolbar_cb[] = {
4575   (GCallback)tb_set_draw_scale,
4576   (GCallback)tb_set_draw_centermark,
4577   (GCallback)tb_set_draw_highlight,
4578   (GCallback)tb_full_screen_cb,
4579   (GCallback)tb_view_side_panel_cb,
4580   (GCallback)tb_view_statusbar_cb,
4581   (GCallback)tb_view_toolbar_cb,
4582   (GCallback)tb_view_main_menu_cb,
4583 };
4584
4585 #include "menu.xml.h"
4586 static void window_create_ui( VikWindow *window )
4587 {
4588   GtkUIManager *uim;
4589   GtkActionGroup *action_group;
4590   GtkAccelGroup *accel_group;
4591   GError *error;
4592   guint i, j, mid;
4593   GtkIconFactory *icon_factory;
4594   GtkIconSet *icon_set; 
4595   GtkRadioActionEntry *tools = NULL, *radio;
4596   guint ntools;
4597   
4598   uim = gtk_ui_manager_new ();
4599   window->uim = uim;
4600
4601   toolbox_add_tool(window->vt, &ruler_tool, TOOL_LAYER_TYPE_NONE);
4602   toolbox_add_tool(window->vt, &zoom_tool, TOOL_LAYER_TYPE_NONE);
4603   toolbox_add_tool(window->vt, &pan_tool, TOOL_LAYER_TYPE_NONE);
4604   toolbox_add_tool(window->vt, &select_tool, TOOL_LAYER_TYPE_NONE);
4605
4606   toolbar_action_tool_entry_register ( window->viking_vtb, &pan_tool.radioActionEntry );
4607   toolbar_action_tool_entry_register ( window->viking_vtb, &zoom_tool.radioActionEntry );
4608   toolbar_action_tool_entry_register ( window->viking_vtb, &ruler_tool.radioActionEntry );
4609   toolbar_action_tool_entry_register ( window->viking_vtb, &select_tool.radioActionEntry );
4610
4611   error = NULL;
4612   if (!(mid = gtk_ui_manager_add_ui_from_string (uim, menu_xml, -1, &error))) {
4613     g_error_free (error);
4614     exit (1);
4615   }
4616
4617   action_group = gtk_action_group_new ("MenuActions");
4618   gtk_action_group_set_translation_domain(action_group, PACKAGE_NAME);
4619   gtk_action_group_add_actions (action_group, entries, G_N_ELEMENTS (entries), window);
4620   gtk_action_group_add_toggle_actions (action_group, toggle_entries, G_N_ELEMENTS (toggle_entries), window);
4621   gtk_action_group_add_radio_actions (action_group, mode_entries, G_N_ELEMENTS (mode_entries), 4, (GCallback)window_change_coord_mode_cb, window);
4622   if ( vik_debug ) {
4623     if ( gtk_ui_manager_add_ui_from_string ( uim,
4624          "<ui><menubar name='MainMenu'><menu action='Help'>"
4625            "<menuitem action='MapCacheInfo'/>"
4626            "<menuitem action='BackForwardInfo'/>"
4627          "</menu></menubar></ui>",
4628          -1, NULL ) ) {
4629       gtk_action_group_add_actions (action_group, debug_entries, G_N_ELEMENTS (debug_entries), window);
4630     }
4631   }
4632
4633   for ( i=0; i < G_N_ELEMENTS (entries); i++ ) {
4634     if ( entries[i].callback )
4635       toolbar_action_entry_register ( window->viking_vtb, &entries[i] );
4636   }
4637
4638   if ( G_N_ELEMENTS (toggle_entries) !=  G_N_ELEMENTS (toggle_entries_toolbar_cb) ) {
4639     g_print ( "Broken entries definitions\n" );
4640     exit (1);
4641   }
4642   for ( i=0; i < G_N_ELEMENTS (toggle_entries); i++ ) {
4643     if ( toggle_entries_toolbar_cb[i] )
4644       toolbar_action_toggle_entry_register ( window->viking_vtb, &toggle_entries[i], toggle_entries_toolbar_cb[i] );
4645   }
4646
4647   for ( i=0; i < G_N_ELEMENTS (mode_entries); i++ ) {
4648     toolbar_action_mode_entry_register ( window->viking_vtb, &mode_entries[i] );
4649   }
4650
4651   // Use this to see if GPSBabel is available:
4652   if ( a_babel_available () ) {
4653     // If going to add more entries then might be worth creating a menu_gpsbabel.xml.h file
4654     if ( gtk_ui_manager_add_ui_from_string ( uim,
4655          "<ui>" \
4656          "<menubar name='MainMenu'>" \
4657          "<menu action='File'><menu action='Export'><menuitem action='ExportKML'/></menu></menu>" \
4658          "<menu action='File'><menu action='Acquire'><menuitem action='AcquireGPS'/></menu></menu>" \
4659          "<menu action='File'><menu action='Acquire'><menuitem action='AcquireGPSBabel'/></menu></menu>" \
4660          "</menubar>" \
4661          "</ui>",
4662          -1, &error ) )
4663       gtk_action_group_add_actions ( action_group, entries_gpsbabel, G_N_ELEMENTS (entries_gpsbabel), window );
4664   }
4665
4666   // GeoJSON import capability
4667   if ( g_find_program_in_path ( a_geojson_program_import() ) ) {
4668     if ( gtk_ui_manager_add_ui_from_string ( uim,
4669          "<ui><menubar name='MainMenu'><menu action='File'><menu action='Acquire'><menuitem action='AcquireGeoJSON'/></menu></menu></menubar></ui>",
4670          -1, &error ) )
4671       gtk_action_group_add_actions ( action_group, entries_geojson, G_N_ELEMENTS (entries_geojson), window );
4672   }
4673
4674   icon_factory = gtk_icon_factory_new ();
4675   gtk_icon_factory_add_default (icon_factory); 
4676
4677   register_vik_icons(icon_factory);
4678
4679   // Copy the tool RadioActionEntries out of the main Window structure into an extending array 'tools'
4680   //  so that it can be applied to the UI in one action group add function call below
4681   ntools = 0;
4682   for (i=0; i<window->vt->n_tools; i++) {
4683       tools = g_renew(GtkRadioActionEntry, tools, ntools+1);
4684       radio = &tools[ntools];
4685       ntools++;
4686       *radio = window->vt->tools[i].ti.radioActionEntry;
4687       radio->value = ntools;
4688   }
4689
4690   for (i=0; i<VIK_LAYER_NUM_TYPES; i++) {
4691     GtkActionEntry action;
4692     gtk_ui_manager_add_ui(uim, mid,  "/ui/MainMenu/Layers/", 
4693                           vik_layer_get_interface(i)->name,
4694                           vik_layer_get_interface(i)->name,
4695                           GTK_UI_MANAGER_MENUITEM, FALSE);
4696
4697     icon_set = gtk_icon_set_new_from_pixbuf (gdk_pixbuf_from_pixdata (vik_layer_get_interface(i)->icon, FALSE, NULL ));
4698     gtk_icon_factory_add (icon_factory, vik_layer_get_interface(i)->name, icon_set);
4699     gtk_icon_set_unref (icon_set);
4700
4701     action.name = vik_layer_get_interface(i)->name;
4702     action.stock_id = vik_layer_get_interface(i)->name;
4703     action.label = g_strdup_printf( _("New _%s Layer"), _(vik_layer_get_interface(i)->name));
4704     action.accelerator = vik_layer_get_interface(i)->accelerator;
4705     action.tooltip = NULL;
4706     action.callback = (GCallback)menu_addlayer_cb;
4707     gtk_action_group_add_actions(action_group, &action, 1, window);
4708
4709     g_free ( (gchar*)action.label );
4710
4711     if ( vik_layer_get_interface(i)->tools_count ) {
4712       gtk_ui_manager_add_ui(uim, mid,  "/ui/MainMenu/Tools/", vik_layer_get_interface(i)->name, NULL, GTK_UI_MANAGER_SEPARATOR, FALSE);
4713     }
4714
4715     // Further tool copying for to apply to the UI, also apply menu UI setup
4716     for ( j = 0; j < vik_layer_get_interface(i)->tools_count; j++ ) {
4717       tools = g_renew(GtkRadioActionEntry, tools, ntools+1);
4718       radio = &tools[ntools];
4719       ntools++;
4720       
4721       gtk_ui_manager_add_ui(uim, mid,  "/ui/MainMenu/Tools", 
4722                             vik_layer_get_interface(i)->tools[j].radioActionEntry.label,
4723                             vik_layer_get_interface(i)->tools[j].radioActionEntry.name,
4724                             GTK_UI_MANAGER_MENUITEM, FALSE);
4725
4726       toolbox_add_tool(window->vt, &(vik_layer_get_interface(i)->tools[j]), i);
4727       toolbar_action_tool_entry_register ( window->viking_vtb, &(vik_layer_get_interface(i)->tools[j].radioActionEntry) );
4728
4729       *radio = vik_layer_get_interface(i)->tools[j].radioActionEntry;
4730       // Overwrite with actual number to use
4731       radio->value = ntools;
4732     }
4733
4734     GtkActionEntry action_dl;
4735     gchar *layername = g_strdup_printf ( "Layer%s", vik_layer_get_interface(i)->fixed_layer_name );
4736     gtk_ui_manager_add_ui(uim, mid,  "/ui/MainMenu/Edit/LayerDefaults",
4737                           vik_layer_get_interface(i)->name,
4738                           layername,
4739                           GTK_UI_MANAGER_MENUITEM, FALSE);
4740     g_free (layername);
4741
4742     // For default layers use action names of the form 'Layer<LayerName>'
4743     // This is to avoid clashing with just the layer name used above for the tool actions
4744     action_dl.name = g_strconcat("Layer", vik_layer_get_interface(i)->fixed_layer_name, NULL);
4745     action_dl.stock_id = NULL;
4746     action_dl.label = g_strconcat(_(vik_layer_get_interface(i)->name), _("..."), NULL);
4747     action_dl.accelerator = NULL;
4748     action_dl.tooltip = NULL;
4749     action_dl.callback = (GCallback)layer_defaults_cb;
4750     gtk_action_group_add_actions(action_group, &action_dl, 1, window);
4751     g_free ( (gchar*)action_dl.name );
4752     g_free ( (gchar*)action_dl.label );
4753   }
4754   g_object_unref (icon_factory);
4755
4756   gtk_action_group_add_radio_actions(action_group, tools, ntools, 0, (GCallback)menu_cb, window);
4757   g_free(tools);
4758
4759   gtk_ui_manager_insert_action_group (uim, action_group, 0);
4760
4761   for (i=0; i<VIK_LAYER_NUM_TYPES; i++) {
4762     for ( j = 0; j < vik_layer_get_interface(i)->tools_count; j++ ) {
4763       GtkAction *action = gtk_action_group_get_action(action_group,
4764                             vik_layer_get_interface(i)->tools[j].radioActionEntry.name);
4765       g_object_set(action, "sensitive", FALSE, NULL);
4766     }
4767   }
4768
4769   // This is done last so we don't need to track the value of mid anymore
4770   vik_ext_tools_add_action_items ( window, window->uim, action_group, mid );
4771
4772   window->action_group = action_group;
4773
4774   accel_group = gtk_ui_manager_get_accel_group (uim);
4775   gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
4776   gtk_ui_manager_ensure_update (uim);
4777   
4778   setup_recent_files(window);
4779
4780   if ( vik_routing_number_of_engines(VIK_ROUTING_METHOD_DIRECTIONS) == 0 ) {
4781     GtkWidget *widget = gtk_ui_manager_get_widget ( uim, "/ui/MainMenu/File/Acquire/AcquireRouting" );
4782     if ( widget ) {
4783       g_object_set ( widget, "sensitive", FALSE, NULL );
4784     }
4785     g_warning ( "No direction routing engines available" );
4786   }
4787 }
4788
4789
4790 // TODO - add method to add tool icons defined from outside this file
4791 //  and remove the reverse dependency on icon definition from this file
4792 static struct { 
4793   const GdkPixdata *data;
4794   gchar *stock_id;
4795 } stock_icons[] = {
4796   { &mover_22_pixbuf,           "vik-icon-pan"      },
4797   { &zoom_18_pixbuf,            "vik-icon-zoom"     },
4798   { &ruler_18_pixbuf,           "vik-icon-ruler"    },
4799   { &select_18_pixbuf,          "vik-icon-select"   },
4800   { &vik_new_route_18_pixbuf,   "vik-icon-Create Route"     },
4801   { &route_finder_18_pixbuf,    "vik-icon-Route Finder"     },
4802   { &demdl_18_pixbuf,           "vik-icon-DEM Download"     },
4803   { &showpic_18_pixbuf,         "vik-icon-Show Picture"     },
4804   { &addtr_18_pixbuf,           "vik-icon-Create Track"     },
4805   { &edtr_18_pixbuf,            "vik-icon-Edit Trackpoint"  },
4806   { &addwp_18_pixbuf,           "vik-icon-Create Waypoint"  },
4807   { &edwp_18_pixbuf,            "vik-icon-Edit Waypoint"    },
4808   { &geozoom_18_pixbuf,         "vik-icon-Georef Zoom Tool" },
4809   { &geomove_18_pixbuf,         "vik-icon-Georef Move Map"  },
4810   { &mapdl_18_pixbuf,           "vik-icon-Maps Download"    },
4811 };
4812  
4813 static gint n_stock_icons = G_N_ELEMENTS (stock_icons);
4814
4815 static void
4816 register_vik_icons (GtkIconFactory *icon_factory)
4817 {
4818   GtkIconSet *icon_set; 
4819   gint i;
4820
4821   for (i = 0; i < n_stock_icons; i++) {
4822     icon_set = gtk_icon_set_new_from_pixbuf (gdk_pixbuf_from_pixdata (
4823                    stock_icons[i].data, FALSE, NULL ));
4824     gtk_icon_factory_add (icon_factory, stock_icons[i].stock_id, icon_set);
4825     gtk_icon_set_unref (icon_set);
4826   }
4827 }
4828
4829 gpointer vik_window_get_selected_trw_layer ( VikWindow *vw )
4830 {
4831   return vw->selected_vtl;
4832 }
4833
4834 void vik_window_set_selected_trw_layer ( VikWindow *vw, gpointer vtl )
4835 {
4836   vw->selected_vtl   = vtl;
4837   vw->containing_vtl = vtl;
4838   /* Clear others */
4839   vw->selected_track     = NULL;
4840   vw->selected_tracks    = NULL;
4841   vw->selected_waypoint  = NULL;
4842   vw->selected_waypoints = NULL;
4843   // Set highlight thickness
4844   vik_viewport_set_highlight_thickness ( vw->viking_vvp, vik_trw_layer_get_property_tracks_line_thickness (vw->containing_vtl) );
4845 }
4846
4847 GHashTable *vik_window_get_selected_tracks ( VikWindow *vw )
4848 {
4849   return vw->selected_tracks;
4850 }
4851
4852 void vik_window_set_selected_tracks ( VikWindow *vw, GHashTable *ght, gpointer vtl )
4853 {
4854   vw->selected_tracks = ght;
4855   vw->containing_vtl  = vtl;
4856   /* Clear others */
4857   vw->selected_vtl       = NULL;
4858   vw->selected_track     = NULL;
4859   vw->selected_waypoint  = NULL;
4860   vw->selected_waypoints = NULL;
4861   // Set highlight thickness
4862   vik_viewport_set_highlight_thickness ( vw->viking_vvp, vik_trw_layer_get_property_tracks_line_thickness (vw->containing_vtl) );
4863 }
4864
4865 gpointer vik_window_get_selected_track ( VikWindow *vw )
4866 {
4867   return vw->selected_track;
4868 }
4869
4870 void vik_window_set_selected_track ( VikWindow *vw, gpointer *vt, gpointer vtl )
4871 {
4872   vw->selected_track = vt;
4873   vw->containing_vtl = vtl;
4874   /* Clear others */
4875   vw->selected_vtl       = NULL;
4876   vw->selected_tracks    = NULL;
4877   vw->selected_waypoint  = NULL;
4878   vw->selected_waypoints = NULL;
4879   // Set highlight thickness
4880   vik_viewport_set_highlight_thickness ( vw->viking_vvp, vik_trw_layer_get_property_tracks_line_thickness (vw->containing_vtl) );
4881 }
4882
4883 GHashTable *vik_window_get_selected_waypoints ( VikWindow *vw )
4884 {
4885   return vw->selected_waypoints;
4886 }
4887
4888 void vik_window_set_selected_waypoints ( VikWindow *vw, GHashTable *ght, gpointer vtl )
4889 {
4890   vw->selected_waypoints = ght;
4891   vw->containing_vtl     = vtl;
4892   /* Clear others */
4893   vw->selected_vtl       = NULL;
4894   vw->selected_track     = NULL;
4895   vw->selected_tracks    = NULL;
4896   vw->selected_waypoint  = NULL;
4897 }
4898
4899 gpointer vik_window_get_selected_waypoint ( VikWindow *vw )
4900 {
4901   return vw->selected_waypoint;
4902 }
4903
4904 void vik_window_set_selected_waypoint ( VikWindow *vw, gpointer *vwp, gpointer vtl )
4905 {
4906   vw->selected_waypoint = vwp;
4907   vw->containing_vtl    = vtl;
4908   /* Clear others */
4909   vw->selected_vtl       = NULL;
4910   vw->selected_track     = NULL;
4911   vw->selected_tracks    = NULL;
4912   vw->selected_waypoints = NULL;
4913 }
4914
4915 gboolean vik_window_clear_highlight ( VikWindow *vw )
4916 {
4917   gboolean need_redraw = FALSE;
4918   vw->containing_vtl = NULL;
4919   if ( vw->selected_vtl != NULL ) {
4920     vw->selected_vtl = NULL;
4921     need_redraw = TRUE;
4922   }
4923   if ( vw->selected_track != NULL ) {
4924     vw->selected_track = NULL;
4925     need_redraw = TRUE;
4926   }
4927   if ( vw->selected_tracks != NULL ) {
4928     vw->selected_tracks = NULL;
4929     need_redraw = TRUE;
4930   }
4931   if ( vw->selected_waypoint != NULL ) {
4932     vw->selected_waypoint = NULL;
4933     need_redraw = TRUE;
4934   }
4935   if ( vw->selected_waypoints != NULL ) {
4936     vw->selected_waypoints = NULL;
4937     need_redraw = TRUE;
4938   }
4939   return need_redraw;
4940 }
4941
4942 /**
4943  * May return NULL if the window no longer exists
4944  */
4945 GThread *vik_window_get_thread ( VikWindow *vw )
4946 {
4947   if ( vw )
4948     return vw->thread;
4949   return NULL;
4950 }