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