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