]> git.street.me.uk Git - andy/viking.git/blame - src/vikwindow.c
Move window code that is unnecessarily in main.c to vikwindow.c
[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>
79dce0cb 6 * Copyright (C) 2012, 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"
f2f2f7bf 37#include "icons/icons.h"
92806042 38#include "vikexttools.h"
9be0449f 39#include "garminsymbols.h"
50a14534 40
8c00358d 41#ifdef HAVE_STDLIB_H
e4afc73a 42#include <stdlib.h>
8c00358d
GB
43#endif
44#ifdef HAVE_MATH_H
50a14534 45#include <math.h>
8c00358d
GB
46#endif
47#ifdef HAVE_STRING_H
50a14534 48#include <string.h>
8c00358d 49#endif
50a14534 50#include <ctype.h>
f83131b9
MA
51#include <glib.h>
52#include <glib/gstdio.h>
1d1bc3c1 53#include <glib/gprintf.h>
4c77d5e0 54#include <glib/gi18n.h>
314084b8 55#include <gio/gio.h>
7622022f 56#include <gdk/gdkkeysyms.h>
50a14534 57
8a13dbd2
RN
58// This seems rather arbitary, quite large and pointless
59// I mean, if you have a thousand windows open;
60// why not be allowed to open a thousand more...
61#define MAX_WINDOWS 1024
62static guint window_count = 0;
63
3570ad57
QT
64#define VIKING_WINDOW_WIDTH 1000
65#define VIKING_WINDOW_HEIGHT 800
50a14534
EB
66#define DRAW_IMAGE_DEFAULT_WIDTH 1280
67#define DRAW_IMAGE_DEFAULT_HEIGHT 1024
68#define DRAW_IMAGE_DEFAULT_SAVE_AS_PNG TRUE
69
70static void window_finalize ( GObject *gob );
71static GObjectClass *parent_class;
72
73static void window_init ( VikWindow *vw );
74static void window_class_init ( VikWindowClass *klass );
4c77d5e0 75static void window_set_filename ( VikWindow *vw, const gchar *filename );
50a14534 76
8a13dbd2
RN
77static VikWindow *window_new ();
78
50a14534
EB
79static void draw_update ( VikWindow *vw );
80
e4afc73a 81static void newwindow_cb ( GtkAction *a, VikWindow *vw );
50a14534 82
8a13dbd2
RN
83// Signals
84static void open_window ( VikWindow *vw, GSList *files );
85static void statusbar_update ( VikWindow *vw, const gchar *message );
86static void destroy_window ( GtkWidget *widget,
87 gpointer data );
88
50a14534
EB
89/* Drawing & stuff */
90
91static gboolean delete_event( VikWindow *vw );
92
777e2d4d
EB
93static gboolean key_press_event( VikWindow *vw, GdkEventKey *event, gpointer data );
94
bce3a7b0 95static void window_configure_event ( VikWindow *vw );
50a14534
EB
96static void draw_sync ( VikWindow *vw );
97static void draw_redraw ( VikWindow *vw );
941aa6e9 98static void draw_scroll ( VikWindow *vw, GdkEventScroll *event );
50a14534
EB
99static void draw_click ( VikWindow *vw, GdkEventButton *event );
100static void draw_release ( VikWindow *vw, GdkEventButton *event );
101static void draw_mouse_motion ( VikWindow *vw, GdkEventMotion *event );
e4afc73a
EB
102static void draw_zoom_cb ( GtkAction *a, VikWindow *vw );
103static void draw_goto_cb ( GtkAction *a, VikWindow *vw );
50a14534 104
c8430548 105static void draw_status ( VikWindow *vw );
50a14534
EB
106
107/* End Drawing Functions */
108
e4afc73a
EB
109static void menu_addlayer_cb ( GtkAction *a, VikWindow *vw );
110static void menu_properties_cb ( GtkAction *a, VikWindow *vw );
111static void menu_delete_layer_cb ( GtkAction *a, VikWindow *vw );
941aa6e9
AF
112
113/* tool management */
114typedef struct {
115 VikToolInterface ti;
116 gpointer state;
9593a4c9 117 gint layer_type;
941aa6e9 118} toolbox_tool_t;
9593a4c9 119#define TOOL_LAYER_TYPE_NONE -1
941aa6e9
AF
120
121typedef struct {
122 int active_tool;
123 int n_tools;
124 toolbox_tool_t *tools;
125 VikWindow *vw;
126} toolbox_tools_t;
127
e4afc73a 128static void menu_tool_cb ( GtkAction *old, GtkAction *a, VikWindow *vw );
941aa6e9 129static toolbox_tools_t* toolbox_create(VikWindow *vw);
9593a4c9 130static void toolbox_add_tool(toolbox_tools_t *vt, VikToolInterface *vti, gint layer_type );
941aa6e9
AF
131static int toolbox_get_tool(toolbox_tools_t *vt, const gchar *tool_name);
132static void toolbox_activate(toolbox_tools_t *vt, const gchar *tool_name);
f2f2f7bf 133static const GdkCursor *toolbox_get_cursor(toolbox_tools_t *vt, const gchar *tool_name);
941aa6e9 134static void toolbox_click (toolbox_tools_t *vt, GdkEventButton *event);
dc2c040e 135static void toolbox_move (toolbox_tools_t *vt, GdkEventMotion *event);
941aa6e9
AF
136static void toolbox_release (toolbox_tools_t *vt, GdkEventButton *event);
137
50a14534 138
941aa6e9 139/* ui creation */
e4afc73a 140static void window_create_ui( VikWindow *window );
941aa6e9 141static void register_vik_icons (GtkIconFactory *icon_factory);
50a14534 142
941aa6e9 143/* i/o */
e4afc73a
EB
144static void load_file ( GtkAction *a, VikWindow *vw );
145static gboolean save_file_as ( GtkAction *a, VikWindow *vw );
146static gboolean save_file ( GtkAction *a, VikWindow *vw );
2bf7cadd 147static gboolean save_file_and_exit ( GtkAction *a, VikWindow *vw );
50a14534
EB
148static gboolean window_save ( VikWindow *vw );
149
150struct _VikWindow {
151 GtkWindow gtkwindow;
152 VikViewport *viking_vvp;
153 VikLayersPanel *viking_vlp;
154 VikStatusbar *viking_vs;
155
e4afc73a
EB
156 GtkToolbar *toolbar;
157
50a14534
EB
158 GtkItemFactory *item_factory;
159
941aa6e9 160 /* tool management state */
50a14534 161 guint current_tool;
941aa6e9 162 toolbox_tools_t *vt;
50a14534
EB
163 guint16 tool_layer_id;
164 guint16 tool_tool_id;
165
79845167
QT
166 GtkActionGroup *action_group;
167
b71eff77 168 gboolean pan_move;
50a14534
EB
169 gint pan_x, pan_y;
170
171 guint draw_image_width, draw_image_height;
172 gboolean draw_image_save_as_png;
173
174 gchar *filename;
175 gboolean modified;
176
177 GtkWidget *open_dia, *save_dia;
f2a1ca71 178 GtkWidget *save_img_dia, *save_img_dir_dia;
50a14534
EB
179
180 gboolean only_updating_coord_mode_ui; /* hack for a bug in GTK */
e4afc73a 181 GtkUIManager *uim;
c9177aae
QT
182
183 /* half-drawn update */
184 VikLayer *trigger;
185 VikCoord trigger_center;
9d7c24ed
RN
186
187 /* Store at this level for highlighted selection drawing since it applies to the viewport and the layers panel */
188 /* Only one of these items can be selected at the same time */
189 gpointer selected_vtl; /* notionally VikTrwLayer */
190 gpointer selected_tracks; /* notionally GList */
191 gpointer selected_track; /* notionally VikTrack */
192 gpointer selected_waypoints; /* notionally GList */
193 gpointer selected_waypoint; /* notionally VikWaypoint */
43f2e1da 194 /* only use for individual track or waypoint */
43f2e1da
RN
195 ////// NEED TO THINK ABOUT VALIDITY OF THESE //////
196 ////// i.e. what happens when stuff is deleted elsewhere //////
a47bfefa
RN
197 ////// Generally seems alright as can not access them //////
198 ////// containing_vtl now seems unecessary //////
113c74f6
RN
199 /* For track(s) & waypoint(s) it is the layer they are in - this helps refering to the individual item easier */
200 gpointer containing_vtl; /* notionally VikTrwLayer */
50a14534
EB
201};
202
203enum {
576cbd17
GB
204 TOOL_PAN = 0,
205 TOOL_ZOOM,
50a14534 206 TOOL_RULER,
a47bfefa 207 TOOL_SELECT,
50a14534
EB
208 TOOL_LAYER,
209 NUMBER_OF_TOOLS
210};
211
212enum {
213 VW_NEWWINDOW_SIGNAL,
214 VW_OPENWINDOW_SIGNAL,
90142302 215 VW_STATUSBAR_UPDATE_SIGNAL,
50a14534
EB
216 VW_LAST_SIGNAL
217};
218
219static guint window_signals[VW_LAST_SIGNAL] = { 0 };
220
79dce0cb 221// TODO get rid of this as this is unnecessary duplication...
a47bfefa 222static gchar *tool_names[NUMBER_OF_TOOLS] = { N_("Pan"), N_("Zoom"), N_("Ruler"), N_("Select") };
50a14534
EB
223
224GType vik_window_get_type (void)
225{
226 static GType vw_type = 0;
227
228 if (!vw_type)
229 {
230 static const GTypeInfo vw_info =
231 {
232 sizeof (VikWindowClass),
233 NULL, /* base_init */
234 NULL, /* base_finalize */
235 (GClassInitFunc) window_class_init, /* class_init */
236 NULL, /* class_finalize */
237 NULL, /* class_data */
238 sizeof (VikWindow),
239 0,
240 (GInstanceInitFunc) window_init,
241 };
242 vw_type = g_type_register_static ( GTK_TYPE_WINDOW, "VikWindow", &vw_info, 0 );
243 }
244
245 return vw_type;
246}
247
014128f6
QT
248VikViewport * vik_window_viewport(VikWindow *vw)
249{
250 return(vw->viking_vvp);
251}
252
55477ce6
RN
253VikLayersPanel * vik_window_layers_panel(VikWindow *vw)
254{
255 return(vw->viking_vlp);
256}
257
c06a63ad
RN
258/**
259 * Returns the statusbar for the window
260 */
261VikStatusbar * vik_window_get_statusbar ( VikWindow *vw )
262{
263 return vw->viking_vs;
264}
265
90142302
RN
266/**
267 * For signalling the update from a background thread
268 */
269void vik_window_signal_statusbar_update (VikWindow *vw, const gchar* message )
270{
271 g_signal_emit ( G_OBJECT(vw), window_signals[VW_STATUSBAR_UPDATE_SIGNAL], 0, message );
272}
273
274/**
275 * For the actual statusbar update!
276 */
3ceb0792 277static gboolean statusbar_idle_update ( gpointer indata )
90142302
RN
278{
279 gpointer *data = indata;
280 vik_statusbar_set_message ( data[0], VIK_STATUSBAR_ITEMS, data[1] );
3ceb0792 281 return FALSE;
90142302
RN
282}
283
284/**
285 * Update statusbar in the main thread
286 */
287void vik_window_statusbar_update ( VikWindow *vw, const gchar* message )
288{
289 // ATM we know the message has been statically allocated so this is OK (no need to handle any freeing)
290 static gpointer data[2];
291 data[0] = vw->viking_vs;
292 data[1] = (gchar*) message;
293 g_idle_add ( (GSourceFunc) statusbar_idle_update, data );
294}
295
8a13dbd2
RN
296// Actual signal handlers
297static void destroy_window ( GtkWidget *widget,
298 gpointer data )
299{
300 if ( ! --window_count )
301 gtk_main_quit ();
302}
303
304static void statusbar_update ( VikWindow *vw, const gchar *message )
305{
306 vik_window_statusbar_update ( vw, message );
307}
308
309VikWindow *vik_window_new_window ()
310{
311 if ( window_count < MAX_WINDOWS )
312 {
313 VikWindow *vw = window_new ();
314
315 g_signal_connect (G_OBJECT (vw), "destroy",
316 G_CALLBACK (destroy_window), NULL);
317 g_signal_connect (G_OBJECT (vw), "newwindow",
318 G_CALLBACK (vik_window_new_window), NULL);
319 g_signal_connect (G_OBJECT (vw), "openwindow",
320 G_CALLBACK (open_window), NULL);
321 g_signal_connect (G_OBJECT (vw), "statusbarupdate",
322 G_CALLBACK (statusbar_update), NULL);
323
324 gtk_widget_show_all ( GTK_WIDGET(vw) );
325
326 window_count++;
327
328 return vw;
329 }
330 return NULL;
331}
332
333static void open_window ( VikWindow *vw, GSList *files )
334{
335 gboolean change_fn = (g_slist_length(files) == 1); /* only change fn if one file */
336 GSList *cur_file = files;
337 while ( cur_file ) {
338 // Only open a new window if a viking file
339 gchar *file_name = cur_file->data;
340 if (vw != NULL && check_file_magic_vik ( file_name ) ) {
341 VikWindow *newvw = vik_window_new_window ();
342 if (newvw)
343 vik_window_open_file ( newvw, file_name, change_fn );
344 }
345 else {
346 vik_window_open_file ( vw, file_name, change_fn );
347 }
348 g_free (file_name);
349 cur_file = g_slist_next (cur_file);
350 }
351 g_slist_free (files);
352}
353// End signals
354
79845167
QT
355void vik_window_selected_layer(VikWindow *vw, VikLayer *vl)
356{
357 int i, j, tool_count;
358 VikLayerInterface *layer_interface;
359
360 if (!vw->action_group) return;
361
362 for (i=0; i<VIK_LAYER_NUM_TYPES; i++) {
363 GtkAction *action;
364 layer_interface = vik_layer_get_interface(i);
365 tool_count = layer_interface->tools_count;
366
367 for (j = 0; j < tool_count; j++) {
368 action = gtk_action_group_get_action(vw->action_group,
79dce0cb 369 layer_interface->tools[j].radioActionEntry.name);
79845167
QT
370 g_object_set(action, "sensitive", i == vl->type, NULL);
371 }
372 }
373}
374
50a14534
EB
375static void window_finalize ( GObject *gob )
376{
377 VikWindow *vw = VIK_WINDOW(gob);
378 g_return_if_fail ( vw != NULL );
379
90142302 380 a_background_remove_window ( vw );
50a14534
EB
381
382 G_OBJECT_CLASS(parent_class)->finalize(gob);
383}
384
bce3a7b0 385
50a14534
EB
386static void window_class_init ( VikWindowClass *klass )
387{
388 /* destructor */
389 GObjectClass *object_class;
390
391 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 392 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);
90142302 393 window_signals[VW_STATUSBAR_UPDATE_SIGNAL] = g_signal_new ( "statusbarupdate", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (VikWindowClass, statusbarupdate), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);
50a14534
EB
394
395 object_class = G_OBJECT_CLASS (klass);
396
397 object_class->finalize = window_finalize;
398
399 parent_class = g_type_class_peek_parent (klass);
400
401}
402
403static void window_init ( VikWindow *vw )
404{
405 GtkWidget *main_vbox;
406 GtkWidget *hpaned;
407
79845167 408 vw->action_group = NULL;
50a14534 409
24277274 410 vw->viking_vvp = vik_viewport_new();
50a14534
EB
411 vw->viking_vlp = vik_layers_panel_new();
412 vik_layers_panel_set_viewport ( vw->viking_vlp, vw->viking_vvp );
413 vw->viking_vs = vik_statusbar_new();
414
941aa6e9
AF
415 vw->vt = toolbox_create(vw);
416 window_create_ui(vw);
4c77d5e0 417 window_set_filename (vw, NULL);
64e3d6c9
RN
418 vw->toolbar = GTK_TOOLBAR(gtk_ui_manager_get_widget (vw->uim, "/MainToolbar"));
419
33bc7c1b
RN
420 // Set the default tool
421 gtk_action_activate ( gtk_action_group_get_action ( vw->action_group, "Pan" ) );
941aa6e9 422
50a14534 423 vw->filename = NULL;
e4afc73a 424 vw->item_factory = NULL;
50a14534 425
50a14534
EB
426 vw->modified = FALSE;
427 vw->only_updating_coord_mode_ui = FALSE;
b71eff77
JJ
428
429 vw->pan_move = FALSE;
50a14534
EB
430 vw->pan_x = vw->pan_y = -1;
431 vw->draw_image_width = DRAW_IMAGE_DEFAULT_WIDTH;
432 vw->draw_image_height = DRAW_IMAGE_DEFAULT_HEIGHT;
433 vw->draw_image_save_as_png = DRAW_IMAGE_DEFAULT_SAVE_AS_PNG;
434
435 main_vbox = gtk_vbox_new(FALSE, 1);
436 gtk_container_add (GTK_CONTAINER (vw), main_vbox);
437
e4afc73a 438 gtk_box_pack_start (GTK_BOX(main_vbox), gtk_ui_manager_get_widget (vw->uim, "/MainMenu"), FALSE, TRUE, 0);
64e3d6c9
RN
439 gtk_box_pack_start (GTK_BOX(main_vbox), GTK_WIDGET(vw->toolbar), FALSE, TRUE, 0);
440 gtk_toolbar_set_icon_size (vw->toolbar, GTK_ICON_SIZE_SMALL_TOOLBAR);
441 gtk_toolbar_set_style (vw->toolbar, GTK_TOOLBAR_ICONS);
50a14534 442
92806042 443 vik_ext_tools_add_menu_items ( vw, vw->uim );
777e2d4d 444
50a14534
EB
445 g_signal_connect (G_OBJECT (vw), "delete_event", G_CALLBACK (delete_event), NULL);
446
447 g_signal_connect_swapped (G_OBJECT(vw->viking_vvp), "expose_event", G_CALLBACK(draw_sync), vw);
bce3a7b0 448 g_signal_connect_swapped (G_OBJECT(vw->viking_vvp), "configure_event", G_CALLBACK(window_configure_event), vw);
fe27d6d2 449 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
450 g_signal_connect_swapped (G_OBJECT(vw->viking_vvp), "scroll_event", G_CALLBACK(draw_scroll), vw);
451 g_signal_connect_swapped (G_OBJECT(vw->viking_vvp), "button_press_event", G_CALLBACK(draw_click), vw);
452 g_signal_connect_swapped (G_OBJECT(vw->viking_vvp), "button_release_event", G_CALLBACK(draw_release), vw);
453 g_signal_connect_swapped (G_OBJECT(vw->viking_vvp), "motion_notify_event", G_CALLBACK(draw_mouse_motion), vw);
454 g_signal_connect_swapped (G_OBJECT(vw->viking_vlp), "update", G_CALLBACK(draw_update), vw);
455
165d30aa 456 g_signal_connect_swapped (G_OBJECT (vw->viking_vvp), "key_press_event", G_CALLBACK (key_press_event), vw);
777e2d4d 457
9a3cdf12 458 gtk_window_set_default_size ( GTK_WINDOW(vw), VIKING_WINDOW_WIDTH, VIKING_WINDOW_HEIGHT);
50a14534
EB
459
460 hpaned = gtk_hpaned_new ();
181f5d0c
MA
461 gtk_paned_pack1 ( GTK_PANED(hpaned), GTK_WIDGET (vw->viking_vlp), FALSE, FALSE );
462 gtk_paned_pack2 ( GTK_PANED(hpaned), GTK_WIDGET (vw->viking_vvp), TRUE, TRUE );
50a14534
EB
463
464 /* This packs the button into the window (a gtk container). */
465 gtk_box_pack_start (GTK_BOX(main_vbox), hpaned, TRUE, TRUE, 0);
466
467 gtk_box_pack_end (GTK_BOX(main_vbox), GTK_WIDGET(vw->viking_vs), FALSE, TRUE, 0);
468
90142302 469 a_background_add_window ( vw );
50a14534
EB
470
471 vw->open_dia = NULL;
472 vw->save_dia = NULL;
f2a1ca71
QT
473 vw->save_img_dia = NULL;
474 vw->save_img_dir_dia = NULL;
50a14534
EB
475}
476
8a13dbd2 477static VikWindow *window_new ()
50a14534
EB
478{
479 return VIK_WINDOW ( g_object_new ( VIK_WINDOW_TYPE, NULL ) );
480}
481
777e2d4d
EB
482static gboolean key_press_event( VikWindow *vw, GdkEventKey *event, gpointer data )
483{
484 VikLayer *vl = vik_layers_panel_get_selected ( vw->viking_vlp );
485 if (vl && vw->vt->active_tool != -1 && vw->vt->tools[vw->vt->active_tool].ti.key_press ) {
486 gint ltype = vw->vt->tools[vw->vt->active_tool].layer_type;
487 if ( vl && ltype == vl->type )
488 return vw->vt->tools[vw->vt->active_tool].ti.key_press(vl, event, vw->vt->tools[vw->vt->active_tool].state);
489 }
7622022f 490
a7114521
RN
491 // No layer - but enable window tool keypress processing - these should be able to handle a NULL layer
492 if ( vw->vt->tools[vw->vt->active_tool].ti.key_press ) {
493 return vw->vt->tools[vw->vt->active_tool].ti.key_press ( vl, event, vw->vt->tools[vw->vt->active_tool].state );
494 }
495
7622022f
RN
496 /* Restore Main Menu via Escape key if the user has hidden it */
497 /* This key is more likely to be used as they may not remember the function key */
498 if ( event->keyval == GDK_Escape ) {
48df6aa3 499 GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ViewMainMenu" );
7622022f
RN
500 if ( check_box ) {
501 gboolean state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box) );
502 if ( !state ) {
503 gtk_widget_show ( gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu" ) );
504 gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), TRUE );
505 return TRUE; /* handled keypress */
506 }
507 }
508 }
509
777e2d4d
EB
510 return FALSE; /* don't handle the keypress */
511}
512
50a14534
EB
513static gboolean delete_event( VikWindow *vw )
514{
a5fd2196 515#ifdef VIKING_PROMPT_IF_MODIFIED
50a14534 516 if ( vw->modified )
a5fd2196
QT
517#else
518 if (0)
519#endif
50a14534
EB
520 {
521 GtkDialog *dia;
522 dia = GTK_DIALOG ( gtk_message_dialog_new ( GTK_WINDOW(vw), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
4c77d5e0
GB
523 _("Do you want to save the changes you made to the document \"%s\"?\n"
524 "\n"
525 "Your changes will be lost if you don't save them."),
526 vw->filename ? a_file_basename ( vw->filename ) : _("Untitled") ) );
527 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
528 switch ( gtk_dialog_run ( dia ) )
529 {
530 case GTK_RESPONSE_NO: gtk_widget_destroy ( GTK_WIDGET(dia) ); return FALSE;
531 case GTK_RESPONSE_CANCEL: gtk_widget_destroy ( GTK_WIDGET(dia) ); return TRUE;
e4afc73a 532 default: gtk_widget_destroy ( GTK_WIDGET(dia) ); return ! save_file(NULL, vw);
50a14534
EB
533 }
534 }
535 return FALSE;
536}
537
538/* Drawing stuff */
e4afc73a 539static void newwindow_cb ( GtkAction *a, VikWindow *vw )
50a14534
EB
540{
541 g_signal_emit ( G_OBJECT(vw), window_signals[VW_NEWWINDOW_SIGNAL], 0 );
542}
543
544static void draw_update ( VikWindow *vw )
545{
546 draw_redraw (vw);
547 draw_sync (vw);
548}
549
550static void draw_sync ( VikWindow *vw )
551{
552 vik_viewport_sync(vw->viking_vvp);
553 draw_status ( vw );
554 /* other things may be necc here later. */
555}
556
557static void draw_status ( VikWindow *vw )
558{
559 static gchar zoom_level[22];
82940cf6
GB
560 gdouble xmpp = vik_viewport_get_xmpp (vw->viking_vvp);
561 gdouble ympp = vik_viewport_get_ympp(vw->viking_vvp);
562 gchar *unit = vik_viewport_get_coord_mode(vw->viking_vvp) == VIK_COORD_UTM ? _("mpp") : _("pixelfact");
563 if (xmpp != ympp)
564 g_snprintf ( zoom_level, 22, "%.3f/%.3f %s", xmpp, ympp, unit );
565 else
fb5e99bb
RN
566 if ( (int)xmpp - xmpp < 0.0 )
567 g_snprintf ( zoom_level, 22, "%.3f %s", xmpp, unit );
568 else
569 /* xmpp should be a whole number so don't show useless .000 bit */
570 g_snprintf ( zoom_level, 22, "%d %s", (int)xmpp, unit );
50a14534 571 if ( vw->current_tool == TOOL_LAYER )
79dce0cb
RN
572 // Use tooltip rather than the internal name as the tooltip is i8n
573 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 );
50a14534 574 else
4efc10ca 575 vik_statusbar_set_message ( vw->viking_vs, VIK_STATUSBAR_TOOL, _(tool_names[vw->current_tool]) );
50a14534 576
4efc10ca 577 vik_statusbar_set_message ( vw->viking_vs, VIK_STATUSBAR_ZOOM, zoom_level );
50a14534
EB
578}
579
c9177aae
QT
580void vik_window_set_redraw_trigger(VikLayer *vl)
581{
730a38c1 582 VikWindow *vw = VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vl));
be3b5803
GB
583 if (NULL != vw)
584 vw->trigger = vl;
c9177aae
QT
585}
586
bce3a7b0
EB
587static void window_configure_event ( VikWindow *vw )
588{
f2f2f7bf 589 static int first = 1;
bce3a7b0 590 draw_redraw ( vw );
372132a6
GB
591 if (first) {
592 // This is a hack to set the cursor corresponding to the first tool
593 // FIXME find the correct way to initialize both tool and its cursor
f2f2f7bf 594 const GdkCursor *cursor = NULL;
372132a6 595 first = 0;
f2f2f7bf
GB
596 cursor = toolbox_get_cursor(vw->vt, "Pan");
597 /* We set cursor, even if it is NULL: it resets to default */
9b5dcb38 598 gdk_window_set_cursor ( GTK_WIDGET(vw->viking_vvp)->window, (GdkCursor *)cursor );
372132a6 599 }
bce3a7b0
EB
600}
601
50a14534
EB
602static void draw_redraw ( VikWindow *vw )
603{
c9177aae
QT
604 VikCoord old_center = vw->trigger_center;
605 vw->trigger_center = *(vik_viewport_get_center(vw->viking_vvp));
606 VikLayer *new_trigger = vw->trigger;
607 vw->trigger = NULL;
0df66d57
EB
608 VikLayer *old_trigger = VIK_LAYER(vik_viewport_get_trigger(vw->viking_vvp));
609
610 if ( ! new_trigger )
611 ; /* do nothing -- have to redraw everything. */
07c9d0bf 612 else if ( (old_trigger != new_trigger) || !vik_coord_equals(&old_center, &vw->trigger_center) || (new_trigger->type == VIK_LAYER_AGGREGATE) )
0df66d57
EB
613 vik_viewport_set_trigger ( vw->viking_vvp, new_trigger ); /* todo: set to half_drawn mode if new trigger is above old */
614 else
615 vik_viewport_set_half_drawn ( vw->viking_vvp, TRUE );
616
617 /* actually draw */
50a14534 618 vik_viewport_clear ( vw->viking_vvp);
50a14534 619 vik_layers_panel_draw_all ( vw->viking_vlp );
acaf7113 620 vik_viewport_draw_scale ( vw->viking_vvp );
82aa018d 621 vik_viewport_draw_copyright ( vw->viking_vvp );
c933487f 622 vik_viewport_draw_centermark ( vw->viking_vvp );
26336cf0 623 vik_viewport_draw_logo ( vw->viking_vvp );
0df66d57
EB
624
625 vik_viewport_set_half_drawn ( vw->viking_vvp, FALSE ); /* just in case. */
50a14534
EB
626}
627
941aa6e9
AF
628gboolean draw_buf_done = TRUE;
629
630static gboolean draw_buf(gpointer data)
631{
632 gpointer *pass_along = data;
633 gdk_threads_enter();
634 gdk_draw_drawable (pass_along[0], pass_along[1],
635 pass_along[2], 0, 0, 0, 0, -1, -1);
636 draw_buf_done = TRUE;
637 gdk_threads_leave();
638 return FALSE;
639}
640
641
642/* Mouse event handlers ************************************************************************/
643
b57126a3
GB
644static void vik_window_pan_click (VikWindow *vw, GdkEventButton *event)
645{
646 /* set panning origin */
b71eff77 647 vw->pan_move = FALSE;
b57126a3
GB
648 vw->pan_x = (gint) event->x;
649 vw->pan_y = (gint) event->y;
650}
651
941aa6e9
AF
652static void draw_click (VikWindow *vw, GdkEventButton *event)
653{
165d30aa 654 gtk_widget_grab_focus ( GTK_WIDGET(vw->viking_vvp) );
941aa6e9
AF
655
656 /* middle button pressed. we reserve all middle button and scroll events
657 * for panning and zooming; tools only get left/right/movement
658 */
659 if ( event->button == 2) {
ef5e8132
RN
660 if ( vw->vt->tools[vw->vt->active_tool].ti.pan_handler )
661 // Tool still may need to do something (such as disable something)
662 toolbox_click(vw->vt, event);
b57126a3 663 vik_window_pan_click ( vw, event );
941aa6e9
AF
664 }
665 else {
666 toolbox_click(vw->vt, event);
667 }
668}
669
b57126a3
GB
670static void vik_window_pan_move (VikWindow *vw, GdkEventMotion *event)
671{
672 if ( vw->pan_x != -1 ) {
b71eff77
JJ
673 vik_viewport_set_center_screen ( vw->viking_vvp, vik_viewport_get_width(vw->viking_vvp)/2 - event->x + vw->pan_x,
674 vik_viewport_get_height(vw->viking_vvp)/2 - event->y + vw->pan_y );
b71eff77
JJ
675 vw->pan_move = TRUE;
676 vw->pan_x = event->x;
677 vw->pan_y = event->y;
a7abaae5 678 draw_update ( vw );
b57126a3
GB
679 }
680}
681
941aa6e9
AF
682static void draw_mouse_motion (VikWindow *vw, GdkEventMotion *event)
683{
684 static VikCoord coord;
685 static struct UTM utm;
686 static struct LatLon ll;
a58aaed4
GB
687 #define BUFFER_SIZE 50
688 static char pointer_buf[BUFFER_SIZE];
689 gchar *lat = NULL, *lon = NULL;
071da616 690 gint16 alt;
228213c5
QT
691 gdouble zoom;
692 VikDemInterpol interpol_method;
941aa6e9 693
fe27d6d2
SB
694 /* This is a hack, but work far the best, at least for single pointer systems.
695 * See http://bugzilla.gnome.org/show_bug.cgi?id=587714 for more. */
696 gint x, y;
697 gdk_window_get_pointer (event->window, &x, &y, NULL);
698 event->x = x;
699 event->y = y;
700
576cbd17 701 toolbox_move(vw->vt, event);
941aa6e9
AF
702
703 vik_viewport_screen_to_coord ( vw->viking_vvp, event->x, event->y, &coord );
704 vik_coord_to_utm ( &coord, &utm );
705 a_coords_utm_to_latlon ( &utm, &ll );
a58aaed4 706 a_coords_latlon_to_string ( &ll, &lat, &lon );
228213c5
QT
707 /* Change interpolate method according to scale */
708 zoom = vik_viewport_get_zoom(vw->viking_vvp);
709 if (zoom > 2.0)
710 interpol_method = VIK_DEM_INTERPOL_NONE;
711 else if (zoom >= 1.0)
712 interpol_method = VIK_DEM_INTERPOL_SIMPLE;
713 else
714 interpol_method = VIK_DEM_INTERPOL_BEST;
8c5f013a
RN
715 if ((alt = a_dems_get_elev_by_coord(&coord, interpol_method)) != VIK_DEM_INVALID_ELEVATION) {
716 if ( a_vik_get_units_height () == VIK_UNITS_HEIGHT_METRES )
717 g_snprintf ( pointer_buf, BUFFER_SIZE, _("%s %s %dm"), lat, lon, alt );
718 else
6c20e59a 719 g_snprintf ( pointer_buf, BUFFER_SIZE, _("%s %s %dft"), lat, lon, (int)VIK_METERS_TO_FEET(alt) );
8c5f013a 720 }
071da616 721 else
a58aaed4
GB
722 g_snprintf ( pointer_buf, BUFFER_SIZE, _("%s %s"), lat, lon );
723 g_free (lat);
724 lat = NULL;
725 g_free (lon);
726 lon = NULL;
4efc10ca 727 vik_statusbar_set_message ( vw->viking_vs, VIK_STATUSBAR_POSITION, pointer_buf );
941aa6e9 728
b57126a3 729 vik_window_pan_move ( vw, event );
fe27d6d2
SB
730
731 /* This is recommended by the GTK+ documentation, but does not work properly.
732 * Use deprecated way until GTK+ gets a solution for correct motion hint handling:
733 * http://bugzilla.gnome.org/show_bug.cgi?id=587714
734 */
735 /* gdk_event_request_motions ( event ); */
b57126a3
GB
736}
737
738static void vik_window_pan_release ( VikWindow *vw, GdkEventButton *event )
739{
b71eff77 740 if ( vw->pan_move == FALSE )
b57126a3
GB
741 vik_viewport_set_center_screen ( vw->viking_vvp, vw->pan_x, vw->pan_y );
742 else
743 vik_viewport_set_center_screen ( vw->viking_vvp, vik_viewport_get_width(vw->viking_vvp)/2 - event->x + vw->pan_x,
744 vik_viewport_get_height(vw->viking_vvp)/2 - event->y + vw->pan_y );
a7abaae5 745 vw->pan_move = FALSE;
b57126a3 746 vw->pan_x = vw->pan_y = -1;
a7abaae5 747 draw_update ( vw );
941aa6e9
AF
748}
749
750static void draw_release ( VikWindow *vw, GdkEventButton *event )
751{
165d30aa
EB
752 gtk_widget_grab_focus ( GTK_WIDGET(vw->viking_vvp) );
753
941aa6e9 754 if ( event->button == 2 ) { /* move / pan */
ef5e8132
RN
755 if ( vw->vt->tools[vw->vt->active_tool].ti.pan_handler )
756 // Tool still may need to do something (such as reenable something)
757 toolbox_release(vw->vt, event);
758 vik_window_pan_release ( vw, event );
941aa6e9
AF
759 }
760 else {
761 toolbox_release(vw->vt, event);
762 }
763}
764
765static void draw_scroll (VikWindow *vw, GdkEventScroll *event)
766{
d1a45556
JN
767 guint modifiers = event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK);
768 if ( modifiers == GDK_CONTROL_MASK ) {
8c721f83
EB
769 /* control == pan up & down */
770 if ( event->direction == GDK_SCROLL_UP )
771 vik_viewport_set_center_screen ( vw->viking_vvp, vik_viewport_get_width(vw->viking_vvp)/2, vik_viewport_get_height(vw->viking_vvp)/3 );
772 else
773 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
774 } else if ( modifiers == GDK_SHIFT_MASK ) {
775 /* shift == pan left & right */
8c721f83
EB
776 if ( event->direction == GDK_SCROLL_UP )
777 vik_viewport_set_center_screen ( vw->viking_vvp, vik_viewport_get_width(vw->viking_vvp)/3, vik_viewport_get_height(vw->viking_vvp)/2 );
778 else
779 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 780 } else if ( modifiers == (GDK_CONTROL_MASK | GDK_SHIFT_MASK) ) {
15ff5402
RN
781 // This zoom is on the center position
782 if ( event->direction == GDK_SCROLL_UP )
783 vik_viewport_zoom_in (vw->viking_vvp);
784 else
785 vik_viewport_zoom_out (vw->viking_vvp);
786 } else {
787 /* make sure mouse is still over the same point on the map when we zoom */
3c575a4a
JN
788 VikCoord coord;
789 gint x, y;
790 gint center_x = vik_viewport_get_width ( vw->viking_vvp ) / 2;
791 gint center_y = vik_viewport_get_height ( vw->viking_vvp ) / 2;
792 vik_viewport_screen_to_coord ( vw->viking_vvp, event->x, event->y, &coord );
793 if ( event->direction == GDK_SCROLL_UP )
8c721f83 794 vik_viewport_zoom_in (vw->viking_vvp);
3c575a4a 795 else
8c721f83 796 vik_viewport_zoom_out(vw->viking_vvp);
3c575a4a
JN
797 vik_viewport_coord_to_screen ( vw->viking_vvp, &coord, &x, &y );
798 vik_viewport_set_center_screen ( vw->viking_vvp, center_x + (x - event->x),
799 center_y + (y - event->y) );
8c721f83
EB
800 }
801
941aa6e9
AF
802 draw_update(vw);
803}
804
805
806
807/********************************************************************************
808 ** Ruler tool code
809 ********************************************************************************/
e4847ce9
AF
810static void draw_ruler(VikViewport *vvp, GdkDrawable *d, GdkGC *gc, gint x1, gint y1, gint x2, gint y2, gdouble distance)
811{
812 PangoFontDescription *pfd;
813 PangoLayout *pl;
814 gchar str[128];
0dff88ea
AF
815 GdkGC *labgc = vik_viewport_new_gc ( vvp, "#cccccc", 1);
816 GdkGC *thickgc = gdk_gc_new(d);
817
e4847ce9
AF
818 gdouble len = sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
819 gdouble dx = (x2-x1)/len*10;
820 gdouble dy = (y2-y1)/len*10;
821 gdouble c = cos(15.0 * M_PI/180.0);
822 gdouble s = sin(15.0 * M_PI/180.0);
0dff88ea 823 gdouble angle;
15614495 824 gdouble baseangle = 0;
0dff88ea 825 gint i;
e4847ce9 826
0dff88ea 827 /* draw line with arrow ends */
d9ffd267
EB
828 {
829 gint tmp_x1=x1, tmp_y1=y1, tmp_x2=x2, tmp_y2=y2;
830 a_viewport_clip_line(&tmp_x1, &tmp_y1, &tmp_x2, &tmp_y2);
831 gdk_draw_line(d, gc, tmp_x1, tmp_y1, tmp_x2, tmp_y2);
832 }
833
15614495
AF
834 a_viewport_clip_line(&x1, &y1, &x2, &y2);
835 gdk_draw_line(d, gc, x1, y1, x2, y2);
d9ffd267 836
e4847ce9
AF
837 gdk_draw_line(d, gc, x1 - dy, y1 + dx, x1 + dy, y1 - dx);
838 gdk_draw_line(d, gc, x2 - dy, y2 + dx, x2 + dy, y2 - dx);
839 gdk_draw_line(d, gc, x2, y2, x2 - (dx * c + dy * s), y2 - (dy * c - dx * s));
840 gdk_draw_line(d, gc, x2, y2, x2 - (dx * c - dy * s), y2 - (dy * c + dx * s));
841 gdk_draw_line(d, gc, x1, y1, x1 + (dx * c + dy * s), y1 + (dy * c - dx * s));
842 gdk_draw_line(d, gc, x1, y1, x1 + (dx * c - dy * s), y1 + (dy * c + dx * s));
843
0dff88ea
AF
844 /* draw compass */
845#define CR 80
846#define CW 4
15614495
AF
847 angle = atan2(dy, dx) + M_PI_2;
848
849 if ( vik_viewport_get_drawmode ( vvp ) == VIK_VIEWPORT_DRAWMODE_UTM) {
850 VikCoord test;
851 struct LatLon ll;
852 struct UTM u;
853 gint tx, ty;
854
855 vik_viewport_screen_to_coord ( vvp, x1, y1, &test );
856 vik_coord_to_latlon ( &test, &ll );
857 ll.lat += vik_viewport_get_ympp ( vvp ) * vik_viewport_get_height ( vvp ) / 11000.0; // about 11km per degree latitude
858 a_coords_latlon_to_utm ( &ll, &u );
859 vik_coord_load_from_utm ( &test, VIK_VIEWPORT_DRAWMODE_UTM, &u );
860 vik_viewport_coord_to_screen ( vvp, &test, &tx, &ty );
861
862 baseangle = M_PI - atan2(tx-x1, ty-y1);
863 angle -= baseangle;
864 }
865
0dff88ea
AF
866 if (angle<0)
867 angle+=2*M_PI;
868 if (angle>2*M_PI)
869 angle-=2*M_PI;
870
871 {
872 GdkColor color;
873 gdk_gc_copy(thickgc, gc);
874 gdk_gc_set_line_attributes(thickgc, CW, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
875 gdk_color_parse("#2255cc", &color);
876 gdk_gc_set_rgb_fg_color(thickgc, &color);
877 }
15614495 878 gdk_draw_arc (d, thickgc, FALSE, x1-CR+CW/2, y1-CR+CW/2, 2*CR-CW, 2*CR-CW, (90 - baseangle*180/M_PI)*64, -angle*180/M_PI*64);
0dff88ea 879
e4847ce9 880
0dff88ea
AF
881 gdk_gc_copy(thickgc, gc);
882 gdk_gc_set_line_attributes(thickgc, 2, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
883 for (i=0; i<180; i++) {
15614495
AF
884 c = cos(i*M_PI/90.0 + baseangle);
885 s = sin(i*M_PI/90.0 + baseangle);
e4847ce9 886
0dff88ea
AF
887 if (i%5) {
888 gdk_draw_line (d, gc, x1 + CR*c, y1 + CR*s, x1 + (CR+CW)*c, y1 + (CR+CW)*s);
889 } else {
890 gdouble ticksize = 2*CW;
891 gdk_draw_line (d, thickgc, x1 + (CR-CW)*c, y1 + (CR-CW)*s, x1 + (CR+ticksize)*c, y1 + (CR+ticksize)*s);
892 }
e4847ce9 893 }
0dff88ea
AF
894
895 gdk_draw_arc (d, gc, FALSE, x1-CR, y1-CR, 2*CR, 2*CR, 0, 64*360);
896 gdk_draw_arc (d, gc, FALSE, x1-CR-CW, y1-CR-CW, 2*(CR+CW), 2*(CR+CW), 0, 64*360);
897 gdk_draw_arc (d, gc, FALSE, x1-CR+CW, y1-CR+CW, 2*(CR-CW), 2*(CR-CW), 0, 64*360);
15614495
AF
898 c = (CR+CW*2)*cos(baseangle);
899 s = (CR+CW*2)*sin(baseangle);
900 gdk_draw_line (d, gc, x1-c, y1-s, x1+c, y1+s);
901 gdk_draw_line (d, gc, x1+s, y1-c, x1-s, y1+c);
0dff88ea
AF
902
903 /* draw labels */
904#define LABEL(x, y, w, h) { \
905 gdk_draw_rectangle(d, labgc, TRUE, (x)-2, (y)-1, (w)+4, (h)+1); \
906 gdk_draw_rectangle(d, gc, FALSE, (x)-2, (y)-1, (w)+4, (h)+1); \
907 gdk_draw_layout(d, gc, (x), (y), pl); }
908 {
909 gint wd, hd, xd, yd;
910 gint wb, hb, xb, yb;
911
912 pl = gtk_widget_create_pango_layout (GTK_WIDGET(vvp), NULL);
913
914 pfd = pango_font_description_from_string ("Sans 8"); // FIXME: settable option? global variable?
915 pango_layout_set_font_description (pl, pfd);
916 pango_font_description_free (pfd);
917
918 pango_layout_set_text(pl, "N", -1);
919 gdk_draw_layout(d, gc, x1-5, y1-CR-3*CW-8, pl);
920
921 /* draw label with distance */
6f9336aa
RN
922 vik_units_distance_t dist_units = a_vik_get_units_distance ();
923 switch (dist_units) {
924 case VIK_UNITS_DISTANCE_KILOMETRES:
925 if (distance >= 1000 && distance < 100000) {
926 g_sprintf(str, "%3.2f km", distance/1000.0);
927 } else if (distance < 1000) {
928 g_sprintf(str, "%d m", (int)distance);
929 } else {
930 g_sprintf(str, "%d km", (int)distance/1000);
931 }
932 break;
933 case VIK_UNITS_DISTANCE_MILES:
433b3f7f
RN
934 if (distance >= VIK_MILES_TO_METERS(1) && distance < VIK_MILES_TO_METERS(100)) {
935 g_sprintf(str, "%3.2f miles", VIK_METERS_TO_MILES(distance));
936 } else if (distance < VIK_MILES_TO_METERS(1)) {
6f9336aa
RN
937 g_sprintf(str, "%d yards", (int)(distance*1.0936133));
938 } else {
433b3f7f 939 g_sprintf(str, "%d miles", (int)VIK_METERS_TO_MILES(distance));
6f9336aa
RN
940 }
941 break;
942 default:
943 g_critical("Houston, we've had a problem. distance=%d", dist_units);
0dff88ea 944 }
6f9336aa 945
0dff88ea
AF
946 pango_layout_set_text(pl, str, -1);
947
948 pango_layout_get_pixel_size ( pl, &wd, &hd );
949 if (dy>0) {
950 xd = (x1+x2)/2 + dy;
951 yd = (y1+y2)/2 - hd/2 - dx;
952 } else {
953 xd = (x1+x2)/2 - dy;
954 yd = (y1+y2)/2 - hd/2 + dx;
955 }
024f32c1
EB
956
957 if ( xd < -5 || yd < -5 || xd > vik_viewport_get_width(vvp)+5 || yd > vik_viewport_get_height(vvp)+5 ) {
958 xd = x2 + 10;
959 yd = y2 - 5;
960 }
961
0dff88ea
AF
962 LABEL(xd, yd, wd, hd);
963
964 /* draw label with bearing */
15614495 965 g_sprintf(str, "%3.1f°", angle*180.0/M_PI);
0dff88ea
AF
966 pango_layout_set_text(pl, str, -1);
967 pango_layout_get_pixel_size ( pl, &wb, &hb );
968 xb = x1 + CR*cos(angle-M_PI_2);
969 yb = y1 + CR*sin(angle-M_PI_2);
970
024f32c1
EB
971 if ( xb < -5 || yb < -5 || xb > vik_viewport_get_width(vvp)+5 || yb > vik_viewport_get_height(vvp)+5 ) {
972 xb = x2 + 10;
973 yb = y2 + 10;
974 }
975
0dff88ea
AF
976 {
977 GdkRectangle r1 = {xd-2, yd-1, wd+4, hd+1}, r2 = {xb-2, yb-1, wb+4, hb+1};
978 if (gdk_rectangle_intersect(&r1, &r2, &r2)) {
979 xb = xd + wd + 5;
980 }
981 }
982 LABEL(xb, yb, wb, hb);
e4847ce9 983 }
03d62e57 984#undef LABEL
e4847ce9 985
024f32c1 986 g_object_unref ( G_OBJECT ( pl ) );
0dff88ea
AF
987 g_object_unref ( G_OBJECT ( labgc ) );
988 g_object_unref ( G_OBJECT ( thickgc ) );
e4847ce9
AF
989}
990
941aa6e9
AF
991typedef struct {
992 VikWindow *vw;
993 VikViewport *vvp;
994 gboolean has_oldcoord;
995 VikCoord oldcoord;
996} ruler_tool_state_t;
03d62e57 997
941aa6e9 998static gpointer ruler_create (VikWindow *vw, VikViewport *vvp)
03d62e57 999{
941aa6e9
AF
1000 ruler_tool_state_t *s = g_new(ruler_tool_state_t, 1);
1001 s->vw = vw;
1002 s->vvp = vvp;
1003 s->has_oldcoord = FALSE;
1004 return s;
03d62e57
AF
1005}
1006
941aa6e9 1007static void ruler_destroy (ruler_tool_state_t *s)
50a14534 1008{
941aa6e9
AF
1009 g_free(s);
1010}
50a14534 1011
941aa6e9
AF
1012static VikLayerToolFuncStatus ruler_click (VikLayer *vl, GdkEventButton *event, ruler_tool_state_t *s)
1013{
1014 struct LatLon ll;
1015 VikCoord coord;
1016 gchar *temp;
1017 if ( event->button == 1 ) {
a58aaed4 1018 gchar *lat=NULL, *lon=NULL;
941aa6e9
AF
1019 vik_viewport_screen_to_coord ( s->vvp, (gint) event->x, (gint) event->y, &coord );
1020 vik_coord_to_latlon ( &coord, &ll );
a58aaed4 1021 a_coords_latlon_to_string ( &ll, &lat, &lon );
941aa6e9 1022 if ( s->has_oldcoord ) {
6f9336aa
RN
1023 vik_units_distance_t dist_units = a_vik_get_units_distance ();
1024 switch (dist_units) {
1025 case VIK_UNITS_DISTANCE_KILOMETRES:
1026 temp = g_strdup_printf ( "%s %s DIFF %f meters", lat, lon, vik_coord_diff( &coord, &(s->oldcoord) ) );
1027 break;
1028 case VIK_UNITS_DISTANCE_MILES:
433b3f7f 1029 temp = g_strdup_printf ( "%s %s DIFF %f miles", lat, lon, VIK_METERS_TO_MILES(vik_coord_diff( &coord, &(s->oldcoord) )) );
6f9336aa
RN
1030 break;
1031 default:
1032 temp = g_strdup_printf ("Just to keep the compiler happy");
1033 g_critical("Houston, we've had a problem. distance=%d", dist_units);
1034 }
1035
941aa6e9
AF
1036 s->has_oldcoord = FALSE;
1037 }
1038 else {
a58aaed4 1039 temp = g_strdup_printf ( "%s %s", lat, lon );
941aa6e9
AF
1040 s->has_oldcoord = TRUE;
1041 }
50a14534 1042
4efc10ca 1043 vik_statusbar_set_message ( s->vw->viking_vs, VIK_STATUSBAR_INFO, temp );
941aa6e9 1044 g_free ( temp );
e4847ce9 1045
941aa6e9
AF
1046 s->oldcoord = coord;
1047 }
1048 else {
1049 vik_viewport_set_center_screen ( s->vvp, (gint) event->x, (gint) event->y );
1050 draw_update ( s->vw );
1051 }
1052 return VIK_LAYER_TOOL_ACK;
1053}
e4847ce9 1054
dc2c040e 1055static VikLayerToolFuncStatus ruler_move (VikLayer *vl, GdkEventMotion *event, ruler_tool_state_t *s)
941aa6e9
AF
1056{
1057 VikViewport *vvp = s->vvp;
1058 VikWindow *vw = s->vw;
1059
1060 struct LatLon ll;
1061 VikCoord coord;
1062 gchar *temp;
1063
1064 if ( s->has_oldcoord ) {
1065 int oldx, oldy, w1, h1, w2, h2;
1066 static GdkPixmap *buf = NULL;
a58aaed4 1067 gchar *lat=NULL, *lon=NULL;
941aa6e9
AF
1068 w1 = vik_viewport_get_width(vvp);
1069 h1 = vik_viewport_get_height(vvp);
1070 if (!buf) {
1071 buf = gdk_pixmap_new ( GTK_WIDGET(vvp)->window, w1, h1, -1 );
1072 }
1073 gdk_drawable_get_size(buf, &w2, &h2);
1074 if (w1 != w2 || h1 != h2) {
1075 g_object_unref ( G_OBJECT ( buf ) );
1076 buf = gdk_pixmap_new ( GTK_WIDGET(vvp)->window, w1, h1, -1 );
e4847ce9 1077 }
e4847ce9 1078
941aa6e9
AF
1079 vik_viewport_screen_to_coord ( vvp, (gint) event->x, (gint) event->y, &coord );
1080 vik_coord_to_latlon ( &coord, &ll );
1081 vik_viewport_coord_to_screen ( vvp, &s->oldcoord, &oldx, &oldy );
1082
1083 gdk_draw_drawable (buf, GTK_WIDGET(vvp)->style->black_gc,
1084 vik_viewport_get_pixmap(vvp), 0, 0, 0, 0, -1, -1);
1085 draw_ruler(vvp, buf, GTK_WIDGET(vvp)->style->black_gc, oldx, oldy, event->x, event->y, vik_coord_diff( &coord, &(s->oldcoord)) );
1086 if (draw_buf_done) {
1087 static gpointer pass_along[3];
1088 pass_along[0] = GTK_WIDGET(vvp)->window;
1089 pass_along[1] = GTK_WIDGET(vvp)->style->black_gc;
1090 pass_along[2] = buf;
1091 g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, draw_buf, pass_along, NULL);
1092 draw_buf_done = FALSE;
1093 }
a58aaed4 1094 a_coords_latlon_to_string(&ll, &lat, &lon);
6f9336aa
RN
1095 vik_units_distance_t dist_units = a_vik_get_units_distance ();
1096 switch (dist_units) {
1097 case VIK_UNITS_DISTANCE_KILOMETRES:
1098 temp = g_strdup_printf ( "%s %s DIFF %f meters", lat, lon, vik_coord_diff( &coord, &(s->oldcoord) ) );
1099 break;
1100 case VIK_UNITS_DISTANCE_MILES:
433b3f7f 1101 temp = g_strdup_printf ( "%s %s DIFF %f miles", lat, lon, VIK_METERS_TO_MILES (vik_coord_diff( &coord, &(s->oldcoord) )) );
6f9336aa
RN
1102 break;
1103 default:
1104 temp = g_strdup_printf ("Just to keep the compiler happy");
1105 g_critical("Houston, we've had a problem. distance=%d", dist_units);
1106 }
4efc10ca 1107 vik_statusbar_set_message ( vw->viking_vs, VIK_STATUSBAR_INFO, temp );
941aa6e9 1108 g_free ( temp );
acaf7113 1109 }
941aa6e9
AF
1110 return VIK_LAYER_TOOL_ACK;
1111}
50a14534 1112
941aa6e9
AF
1113static VikLayerToolFuncStatus ruler_release (VikLayer *vl, GdkEventButton *event, ruler_tool_state_t *s)
1114{
1115 return VIK_LAYER_TOOL_ACK;
50a14534
EB
1116}
1117
941aa6e9 1118static void ruler_deactivate (VikLayer *vl, ruler_tool_state_t *s)
50a14534 1119{
941aa6e9 1120 draw_update ( s->vw );
50a14534
EB
1121}
1122
0eb26799
RN
1123static gboolean ruler_key_press (VikLayer *vl, GdkEventKey *event, ruler_tool_state_t *s)
1124{
1125 if (event->keyval == GDK_Escape) {
1126 s->has_oldcoord = FALSE;
1127 ruler_deactivate ( vl, s );
1128 return TRUE;
1129 }
1130 return FALSE;
1131}
1132
941aa6e9 1133static VikToolInterface ruler_tool =
79dce0cb 1134 { { "Ruler", "vik-icon-ruler", N_("_Ruler"), "<control><shift>R", N_("Ruler Tool"), 2 },
941aa6e9
AF
1135 (VikToolConstructorFunc) ruler_create,
1136 (VikToolDestructorFunc) ruler_destroy,
1137 (VikToolActivationFunc) NULL,
1138 (VikToolActivationFunc) ruler_deactivate,
1139 (VikToolMouseFunc) ruler_click,
dc2c040e 1140 (VikToolMouseMoveFunc) ruler_move,
f2f2f7bf 1141 (VikToolMouseFunc) ruler_release,
0eb26799 1142 (VikToolKeyFunc) ruler_key_press,
ef5e8132 1143 FALSE,
f2f2f7bf 1144 GDK_CURSOR_IS_PIXMAP,
5bfafde9 1145 &cursor_ruler_pixbuf };
941aa6e9
AF
1146/*** end ruler code ********************************************************/
1147
1148
1149
1150/********************************************************************************
1151 ** Zoom tool code
1152 ********************************************************************************/
2eea9a36
RN
1153
1154typedef struct {
1155 VikWindow *vw;
1156 GdkPixmap *pixmap;
1157 // Track zoom bounds for zoom tool with shift modifier:
1158 gboolean bounds_active;
1159 gint start_x;
1160 gint start_y;
1161} zoom_tool_state_t;
1162
1163/*
1164 * In case the screen size has changed
1165 */
1166static void zoomtool_resize_pixmap (zoom_tool_state_t *zts)
1167{
1168 int w1, h1, w2, h2;
1169
1170 // Allocate a drawing area the size of the viewport
1171 w1 = vik_viewport_get_width ( zts->vw->viking_vvp );
1172 h1 = vik_viewport_get_height ( zts->vw->viking_vvp );
1173
1174 if ( !zts->pixmap ) {
1175 // Totally new
1176 zts->pixmap = gdk_pixmap_new ( GTK_WIDGET(zts->vw->viking_vvp)->window, w1, h1, -1 );
1177 }
1178
1179 gdk_drawable_get_size ( zts->pixmap, &w2, &h2 );
1180
1181 if ( w1 != w2 || h1 != h2 ) {
1182 // Has changed - delete and recreate with new values
1183 g_object_unref ( G_OBJECT ( zts->pixmap ) );
1184 zts->pixmap = gdk_pixmap_new ( GTK_WIDGET(zts->vw->viking_vvp)->window, w1, h1, -1 );
1185 }
1186}
1187
941aa6e9 1188static gpointer zoomtool_create (VikWindow *vw, VikViewport *vvp)
50a14534 1189{
2eea9a36
RN
1190 zoom_tool_state_t *zts = g_new(zoom_tool_state_t, 1);
1191 zts->vw = vw;
1192 zts->pixmap = NULL;
1193 zts->start_x = 0;
1194 zts->start_y = 0;
1195 zts->bounds_active = FALSE;
1196 return zts;
50a14534
EB
1197}
1198
2eea9a36 1199static void zoomtool_destroy ( zoom_tool_state_t *zts)
50a14534 1200{
2eea9a36
RN
1201 if ( zts->pixmap )
1202 g_object_unref ( G_OBJECT ( zts->pixmap ) );
1203 g_free(zts);
1204}
1205
1206static VikLayerToolFuncStatus zoomtool_click (VikLayer *vl, GdkEventButton *event, zoom_tool_state_t *zts)
1207{
1208 zts->vw->modified = TRUE;
15ff5402
RN
1209 guint modifiers = event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK);
1210
1211 VikCoord coord;
1212 gint x, y;
2eea9a36
RN
1213 gint center_x = vik_viewport_get_width ( zts->vw->viking_vvp ) / 2;
1214 gint center_y = vik_viewport_get_height ( zts->vw->viking_vvp ) / 2;
1215
1216 gboolean skip_update = FALSE;
1217
1218 zts->bounds_active = FALSE;
15ff5402
RN
1219
1220 if ( modifiers == (GDK_CONTROL_MASK | GDK_SHIFT_MASK) ) {
1221 // This zoom is on the center position
2eea9a36 1222 vik_viewport_set_center_screen ( zts->vw->viking_vvp, center_x, center_y );
15ff5402 1223 if ( event->button == 1 )
2eea9a36 1224 vik_viewport_zoom_in (zts->vw->viking_vvp);
15ff5402 1225 else if ( event->button == 3 )
2eea9a36 1226 vik_viewport_zoom_out (zts->vw->viking_vvp);
15ff5402 1227 }
130ac805
RN
1228 else if ( modifiers == GDK_CONTROL_MASK ) {
1229 // This zoom is to recenter on the mouse position
2eea9a36 1230 vik_viewport_set_center_screen ( zts->vw->viking_vvp, (gint) event->x, (gint) event->y );
130ac805 1231 if ( event->button == 1 )
2eea9a36 1232 vik_viewport_zoom_in (zts->vw->viking_vvp);
130ac805 1233 else if ( event->button == 3 )
2eea9a36
RN
1234 vik_viewport_zoom_out (zts->vw->viking_vvp);
1235 }
1236 else if ( modifiers == GDK_SHIFT_MASK ) {
1237 // Get start of new zoom bounds
1238 if ( event->button == 1 ) {
1239 zts->bounds_active = TRUE;
1240 zts->start_x = (gint) event->x;
1241 zts->start_y = (gint) event->y;
1242 skip_update = TRUE;
1243 }
130ac805 1244 }
15ff5402
RN
1245 else {
1246 /* make sure mouse is still over the same point on the map when we zoom */
2eea9a36 1247 vik_viewport_screen_to_coord ( zts->vw->viking_vvp, event->x, event->y, &coord );
15ff5402 1248 if ( event->button == 1 )
2eea9a36 1249 vik_viewport_zoom_in (zts->vw->viking_vvp);
15ff5402 1250 else if ( event->button == 3 )
2eea9a36
RN
1251 vik_viewport_zoom_out(zts->vw->viking_vvp);
1252 vik_viewport_coord_to_screen ( zts->vw->viking_vvp, &coord, &x, &y );
1253 vik_viewport_set_center_screen ( zts->vw->viking_vvp,
15ff5402
RN
1254 center_x + (x - event->x),
1255 center_y + (y - event->y) );
1256 }
2eea9a36
RN
1257
1258 if ( !skip_update )
1259 draw_update ( zts->vw );
1260
941aa6e9
AF
1261 return VIK_LAYER_TOOL_ACK;
1262}
50a14534 1263
2eea9a36 1264static VikLayerToolFuncStatus zoomtool_move (VikLayer *vl, GdkEventMotion *event, zoom_tool_state_t *zts)
941aa6e9 1265{
2eea9a36
RN
1266 guint modifiers = event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK);
1267
1268 if ( zts->bounds_active && modifiers == GDK_SHIFT_MASK ) {
1269 zoomtool_resize_pixmap ( zts );
1270
1271 // Blank out currently drawn area
1272 gdk_draw_drawable ( zts->pixmap,
1273 GTK_WIDGET(zts->vw->viking_vvp)->style->black_gc,
1274 vik_viewport_get_pixmap(zts->vw->viking_vvp),
1275 0, 0, 0, 0, -1, -1);
1276
1277 // Calculate new box starting point & size in pixels
1278 int xx, yy, width, height;
1279 if ( event->y > zts->start_y ) {
1280 yy = zts->start_y;
1281 height = event->y-zts->start_y;
1282 }
1283 else {
1284 yy = event->y;
1285 height = zts->start_y-event->y;
1286 }
1287 if ( event->x > zts->start_x ) {
1288 xx = zts->start_x;
1289 width = event->x-zts->start_x;
1290 }
1291 else {
1292 xx = event->x;
1293 width = zts->start_x-event->x;
1294 }
1295
1296 // Draw the box
1297 gdk_draw_rectangle (zts->pixmap, GTK_WIDGET(zts->vw->viking_vvp)->style->black_gc, FALSE, xx, yy, width, height);
1298
1299 // Only actually draw when there's time to do so
1300 if (draw_buf_done) {
1301 static gpointer pass_along[3];
1302 pass_along[0] = GTK_WIDGET(zts->vw->viking_vvp)->window;
1303 pass_along[1] = GTK_WIDGET(zts->vw->viking_vvp)->style->black_gc;
1304 pass_along[2] = zts->pixmap;
1305 g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, draw_buf, pass_along, NULL);
1306 draw_buf_done = FALSE;
1307 }
1308 }
941aa6e9
AF
1309 return VIK_LAYER_TOOL_ACK;
1310}
50a14534 1311
2eea9a36 1312static VikLayerToolFuncStatus zoomtool_release (VikLayer *vl, GdkEventButton *event, zoom_tool_state_t *zts)
941aa6e9 1313{
2eea9a36
RN
1314 guint modifiers = event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK);
1315
1316 zts->bounds_active = FALSE;
1317
1318 // Ensure haven't just released on the exact same position
1319 // i.e. probably haven't moved the mouse at all
1320 if ( modifiers == GDK_SHIFT_MASK && !( ( event->x == zts->start_x ) && ( event->y == zts->start_y )) ) {
1321
1322 VikCoord coord1, coord2;
1323 vik_viewport_screen_to_coord ( zts->vw->viking_vvp, zts->start_x, zts->start_y, &coord1);
1324 vik_viewport_screen_to_coord ( zts->vw->viking_vvp, event->x, event->y, &coord2);
1325
1326 // From the extend of the bounds pick the best zoom level
1327 // c.f. trw_layer_zoom_to_show_latlons()
1328 // Maybe refactor...
1329 struct LatLon ll1, ll2;
1330 vik_coord_to_latlon(&coord1, &ll1);
1331 vik_coord_to_latlon(&coord2, &ll2);
1332 struct LatLon average = { (ll1.lat+ll2.lat)/2,
1333 (ll1.lon+ll2.lon)/2 };
1334
1335 VikCoord new_center;
1336 vik_coord_load_from_latlon ( &new_center, vik_viewport_get_coord_mode ( zts->vw->viking_vvp ), &average );
1337 vik_viewport_set_center_coord ( zts->vw->viking_vvp, &new_center );
1338
1339 /* Convert into definite 'smallest' and 'largest' positions */
1340 struct LatLon minmin;
1341 if ( ll1.lat < ll2.lat )
1342 minmin.lat = ll1.lat;
1343 else
1344 minmin.lat = ll2.lat;
1345
1346 struct LatLon maxmax;
1347 if ( ll1.lon > ll2.lon )
1348 maxmax.lon = ll1.lon;
1349 else
1350 maxmax.lon = ll2.lon;
1351
1352 /* Always recalculate the 'best' zoom level */
1353 gdouble zoom = VIK_VIEWPORT_MIN_ZOOM;
1354 vik_viewport_set_zoom ( zts->vw->viking_vvp, zoom );
1355
1356 gdouble min_lat, max_lat, min_lon, max_lon;
1357 /* Should only be a maximum of about 18 iterations from min to max zoom levels */
1358 while ( zoom <= VIK_VIEWPORT_MAX_ZOOM ) {
1359 vik_viewport_get_min_max_lat_lon ( zts->vw->viking_vvp, &min_lat, &max_lat, &min_lon, &max_lon );
1360 /* NB I think the logic used in this test to determine if the bounds is within view
1361 fails if track goes across 180 degrees longitude.
1362 Hopefully that situation is not too common...
1363 Mind you viking doesn't really do edge locations to well anyway */
1364 if ( min_lat < minmin.lat &&
1365 max_lat > minmin.lat &&
1366 min_lon < maxmax.lon &&
1367 max_lon > maxmax.lon )
1368 /* Found within zoom level */
1369 break;
1370
1371 /* Try next */
1372 zoom = zoom * 2;
1373 vik_viewport_set_zoom ( zts->vw->viking_vvp, zoom );
1374 }
1375
1376 draw_update ( zts->vw );
1377 }
941aa6e9 1378 return VIK_LAYER_TOOL_ACK;
50a14534
EB
1379}
1380
941aa6e9 1381static VikToolInterface zoom_tool =
79dce0cb 1382 { { "Zoom", "vik-icon-zoom", N_("_Zoom"), "<control><shift>Z", N_("Zoom Tool"), 1 },
941aa6e9 1383 (VikToolConstructorFunc) zoomtool_create,
2eea9a36 1384 (VikToolDestructorFunc) zoomtool_destroy,
941aa6e9
AF
1385 (VikToolActivationFunc) NULL,
1386 (VikToolActivationFunc) NULL,
1387 (VikToolMouseFunc) zoomtool_click,
dc2c040e 1388 (VikToolMouseMoveFunc) zoomtool_move,
f2f2f7bf
GB
1389 (VikToolMouseFunc) zoomtool_release,
1390 NULL,
ef5e8132 1391 FALSE,
f2f2f7bf 1392 GDK_CURSOR_IS_PIXMAP,
5bfafde9 1393 &cursor_zoom_pixbuf };
463f9d07 1394/*** end zoom code ********************************************************/
941aa6e9 1395
576cbd17
GB
1396/********************************************************************************
1397 ** Pan tool code
1398 ********************************************************************************/
1399static gpointer pantool_create (VikWindow *vw, VikViewport *vvp)
1400{
1401 return vw;
1402}
1403
1404static VikLayerToolFuncStatus pantool_click (VikLayer *vl, GdkEventButton *event, VikWindow *vw)
1405{
1406 vw->modified = TRUE;
1407 if ( event->button == 1 )
1408 vik_window_pan_click ( vw, event );
1409 draw_update ( vw );
1410 return VIK_LAYER_TOOL_ACK;
1411}
1412
dc2c040e 1413static VikLayerToolFuncStatus pantool_move (VikLayer *vl, GdkEventMotion *event, VikWindow *vw)
576cbd17
GB
1414{
1415 vik_window_pan_move ( vw, event );
1416 return VIK_LAYER_TOOL_ACK;
1417}
1418
1419static VikLayerToolFuncStatus pantool_release (VikLayer *vl, GdkEventButton *event, VikWindow *vw)
1420{
1421 if ( event->button == 1 )
1422 vik_window_pan_release ( vw, event );
1423 return VIK_LAYER_TOOL_ACK;
1424}
1425
1426static VikToolInterface pan_tool =
79dce0cb 1427 { { "Pan", "vik-icon-pan", N_("_Pan"), "<control><shift>P", N_("Pan Tool"), 0 },
576cbd17
GB
1428 (VikToolConstructorFunc) pantool_create,
1429 (VikToolDestructorFunc) NULL,
1430 (VikToolActivationFunc) NULL,
1431 (VikToolActivationFunc) NULL,
1432 (VikToolMouseFunc) pantool_click,
dc2c040e 1433 (VikToolMouseMoveFunc) pantool_move,
f2f2f7bf
GB
1434 (VikToolMouseFunc) pantool_release,
1435 NULL,
ef5e8132 1436 FALSE,
f2f2f7bf 1437 GDK_FLEUR };
576cbd17
GB
1438/*** end pan code ********************************************************/
1439
a47bfefa
RN
1440/********************************************************************************
1441 ** Select tool code
1442 ********************************************************************************/
1443static gpointer selecttool_create (VikWindow *vw, VikViewport *vvp)
1444{
08f14055
RN
1445 tool_ed_t *t = g_new(tool_ed_t, 1);
1446 t->vw = vw;
1447 t->vvp = vvp;
1448 t->vtl = NULL;
1449 t->is_waypoint = FALSE;
1450 return t;
1451}
1452
1453static void selecttool_destroy (tool_ed_t *t)
1454{
1455 g_free(t);
a47bfefa
RN
1456}
1457
1458typedef struct {
1459 gboolean cont;
1460 VikViewport *vvp;
1461 GdkEventButton *event;
08f14055 1462 tool_ed_t *tool_edit;
a47bfefa
RN
1463} clicker;
1464
1465static void click_layer_selected (VikLayer *vl, clicker *ck)
1466{
1467 /* Do nothing when function call returns true; */
1468 /* i.e. stop on first found item */
1469 if ( ck->cont )
1470 if ( vl->visible )
08f14055
RN
1471 if ( vik_layer_get_interface(vl->type)->select_click )
1472 ck->cont = !vik_layer_get_interface(vl->type)->select_click ( vl, ck->event, ck->vvp, ck->tool_edit );
a47bfefa
RN
1473}
1474
08f14055 1475static VikLayerToolFuncStatus selecttool_click (VikLayer *vl, GdkEventButton *event, tool_ed_t *t)
a47bfefa
RN
1476{
1477 /* Only allow selection on primary button */
1478 if ( event->button == 1 ) {
1479 /* Enable click to apply callback to potentially all track/waypoint layers */
1480 /* Useful as we can find things that aren't necessarily in the currently selected layer */
aa7ed888 1481 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
1482 clicker ck;
1483 ck.cont = TRUE;
08f14055 1484 ck.vvp = t->vw->viking_vvp;
a47bfefa 1485 ck.event = event;
08f14055 1486 ck.tool_edit = t;
a47bfefa
RN
1487 g_list_foreach ( gl, (GFunc) click_layer_selected, &ck );
1488 g_list_free ( gl );
1489
1490 // If nothing found then deselect & redraw screen if necessary to remove the highlight
1491 if ( ck.cont ) {
1492 GtkTreeIter iter;
08f14055 1493 VikTreeview *vtv = vik_layers_panel_get_treeview ( t->vw->viking_vlp );
a47bfefa
RN
1494
1495 if ( vik_treeview_get_selected_iter ( vtv, &iter ) ) {
1496 // Only clear if selected thing is a TrackWaypoint layer or a sublayer
1497 gint type = vik_treeview_item_get_type ( vtv, &iter );
1498 if ( type == VIK_TREEVIEW_TYPE_SUBLAYER ||
1499 VIK_LAYER(vik_treeview_item_get_pointer ( vtv, &iter ))->type == VIK_LAYER_TRW ) {
1500
1501 vik_treeview_item_unselect ( vtv, &iter );
08f14055
RN
1502 if ( vik_window_clear_highlight ( t->vw ) )
1503 draw_update ( t->vw );
a47bfefa
RN
1504 }
1505 }
1506 }
1507 }
1508 else if ( ( event->button == 3 ) && ( vl && ( vl->type == VIK_LAYER_TRW ) ) ) {
1509 if ( vl->visible )
1510 /* Act on currently selected item to show menu */
60a69560 1511 if ( t->vw->selected_track || t->vw->selected_waypoint )
a47bfefa 1512 if ( vik_layer_get_interface(vl->type)->show_viewport_menu )
08f14055 1513 vik_layer_get_interface(vl->type)->show_viewport_menu ( vl, event, t->vw->viking_vvp );
a47bfefa
RN
1514 }
1515
1516 return VIK_LAYER_TOOL_ACK;
1517}
1518
08f14055
RN
1519static VikLayerToolFuncStatus selecttool_move (VikLayer *vl, GdkEventButton *event, tool_ed_t *t)
1520{
1521 /* Only allow selection on primary button */
1522 if ( event->button == 1 ) {
1523 // Don't care about vl here
1524 if ( t->vtl )
1525 if ( vik_layer_get_interface(VIK_LAYER_TRW)->select_move )
1526 vik_layer_get_interface(VIK_LAYER_TRW)->select_move ( vl, event, t->vvp, t );
1527 }
1528 return VIK_LAYER_TOOL_ACK;
1529}
1530
1531static VikLayerToolFuncStatus selecttool_release (VikLayer *vl, GdkEventButton *event, tool_ed_t *t)
1532{
1533 /* Only allow selection on primary button */
1534 if ( event->button == 1 ) {
1535 // Don't care about vl here
1536 if ( t->vtl )
1537 if ( vik_layer_get_interface(VIK_LAYER_TRW)->select_release )
1538 vik_layer_get_interface(VIK_LAYER_TRW)->select_release ( (VikLayer*)t->vtl, event, t->vvp, t );
1539 }
1540 return VIK_LAYER_TOOL_ACK;
1541}
1542
a47bfefa 1543static VikToolInterface select_tool =
79dce0cb 1544 { { "Select", "vik-icon-select", N_("_Select"), "<control><shift>S", N_("Select Tool"), 3 },
a47bfefa 1545 (VikToolConstructorFunc) selecttool_create,
08f14055 1546 (VikToolDestructorFunc) selecttool_destroy,
a47bfefa
RN
1547 (VikToolActivationFunc) NULL,
1548 (VikToolActivationFunc) NULL,
1549 (VikToolMouseFunc) selecttool_click,
08f14055
RN
1550 (VikToolMouseMoveFunc) selecttool_move,
1551 (VikToolMouseFunc) selecttool_release,
a47bfefa 1552 (VikToolKeyFunc) NULL,
ef5e8132 1553 FALSE,
a47bfefa
RN
1554 GDK_LEFT_PTR,
1555 NULL,
1556 NULL };
1557/*** end select tool code ********************************************************/
1558
8c721f83
EB
1559static void draw_pan_cb ( GtkAction *a, VikWindow *vw )
1560{
1561 if (!strcmp(gtk_action_get_name(a), "PanNorth")) {
1562 vik_viewport_set_center_screen ( vw->viking_vvp, vik_viewport_get_width(vw->viking_vvp)/2, 0 );
1563 } else if (!strcmp(gtk_action_get_name(a), "PanEast")) {
1564 vik_viewport_set_center_screen ( vw->viking_vvp, vik_viewport_get_width(vw->viking_vvp), vik_viewport_get_height(vw->viking_vvp)/2 );
1565 } else if (!strcmp(gtk_action_get_name(a), "PanSouth")) {
1566 vik_viewport_set_center_screen ( vw->viking_vvp, vik_viewport_get_width(vw->viking_vvp)/2, vik_viewport_get_height(vw->viking_vvp) );
1567 } else if (!strcmp(gtk_action_get_name(a), "PanWest")) {
1568 vik_viewport_set_center_screen ( vw->viking_vvp, 0, vik_viewport_get_height(vw->viking_vvp)/2 );
1569 }
1570 draw_update ( vw );
1571}
941aa6e9 1572
7de42638
EB
1573static void full_screen_cb ( GtkAction *a, VikWindow *vw )
1574{
1575 GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/FullScreen" );
1576 g_assert(check_box);
1577 gboolean state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box));
1578 if ( state )
1579 gtk_window_fullscreen ( GTK_WINDOW(vw) );
1580 else
1581 gtk_window_unfullscreen ( GTK_WINDOW(vw) );
1582}
941aa6e9 1583
e4afc73a 1584static void draw_zoom_cb ( GtkAction *a, VikWindow *vw )
50a14534 1585{
e4afc73a
EB
1586 guint what = 128;
1587
1588 if (!strcmp(gtk_action_get_name(a), "ZoomIn")) {
1589 what = -3;
1590 }
1591 else if (!strcmp(gtk_action_get_name(a), "ZoomOut")) {
1592 what = -4;
1593 }
1594 else if (!strcmp(gtk_action_get_name(a), "Zoom0.25")) {
1595 what = -2;
1596 }
1597 else if (!strcmp(gtk_action_get_name(a), "Zoom0.5")) {
1598 what = -1;
1599 }
1600 else {
1601 gchar *s = (gchar *)gtk_action_get_name(a);
1602 what = atoi(s+4);
1603 }
1604
50a14534
EB
1605 switch (what)
1606 {
1607 case -3: vik_viewport_zoom_in ( vw->viking_vvp ); break;
1608 case -4: vik_viewport_zoom_out ( vw->viking_vvp ); break;
1609 case -1: vik_viewport_set_zoom ( vw->viking_vvp, 0.5 ); break;
1610 case -2: vik_viewport_set_zoom ( vw->viking_vvp, 0.25 ); break;
1611 default: vik_viewport_set_zoom ( vw->viking_vvp, what );
1612 }
1613 draw_update ( vw );
1614}
1615
e4afc73a 1616void draw_goto_cb ( GtkAction *a, VikWindow *vw )
50a14534
EB
1617{
1618 VikCoord new_center;
e4afc73a
EB
1619
1620 if (!strcmp(gtk_action_get_name(a), "GotoLL")) {
50a14534
EB
1621 struct LatLon ll, llold;
1622 vik_coord_to_latlon ( vik_viewport_get_center ( vw->viking_vvp ), &llold );
1623 if ( a_dialog_goto_latlon ( GTK_WINDOW(vw), &ll, &llold ) )
1624 vik_coord_load_from_latlon ( &new_center, vik_viewport_get_coord_mode(vw->viking_vvp), &ll );
1625 else
1626 return;
1627 }
e4afc73a 1628 else if (!strcmp(gtk_action_get_name(a), "GotoUTM")) {
50a14534
EB
1629 struct UTM utm, utmold;
1630 vik_coord_to_utm ( vik_viewport_get_center ( vw->viking_vvp ), &utmold );
1631 if ( a_dialog_goto_utm ( GTK_WINDOW(vw), &utm, &utmold ) )
1632 vik_coord_load_from_utm ( &new_center, vik_viewport_get_coord_mode(vw->viking_vvp), &utm );
1633 else
1634 return;
1635 }
e4afc73a 1636 else {
8dc8da82 1637 g_critical("Houston, we've had a problem.");
e4afc73a
EB
1638 return;
1639 }
50a14534
EB
1640
1641 vik_viewport_set_center_coord ( vw->viking_vvp, &new_center );
1642 draw_update ( vw );
1643}
1644
e4afc73a 1645static void menu_addlayer_cb ( GtkAction *a, VikWindow *vw )
50a14534 1646{
e4afc73a
EB
1647 gint type;
1648 for ( type = 0; type < VIK_LAYER_NUM_TYPES; type++ ) {
1649 if (!strcmp(vik_layer_get_interface(type)->name, gtk_action_get_name(a))) {
1650 if ( vik_layers_panel_new_layer ( vw->viking_vlp, type ) ) {
1651 draw_update ( vw );
1652 vw->modified = TRUE;
1653 }
1654 }
50a14534
EB
1655 }
1656}
1657
e4afc73a 1658static void menu_copy_layer_cb ( GtkAction *a, VikWindow *vw )
50a14534 1659{
2cebc318 1660 a_clipboard_copy_selected ( vw->viking_vlp );
50a14534
EB
1661}
1662
e4afc73a 1663static void menu_cut_layer_cb ( GtkAction *a, VikWindow *vw )
50a14534 1664{
169acf64 1665 vik_layers_panel_cut_selected ( vw->viking_vlp );
169acf64 1666 vw->modified = TRUE;
50a14534
EB
1667}
1668
e4afc73a 1669static void menu_paste_layer_cb ( GtkAction *a, VikWindow *vw )
50a14534
EB
1670{
1671 if ( a_clipboard_paste ( vw->viking_vlp ) )
1672 {
50a14534
EB
1673 vw->modified = TRUE;
1674 }
1675}
1676
e4afc73a 1677static void menu_properties_cb ( GtkAction *a, VikWindow *vw )
50a14534
EB
1678{
1679 if ( ! vik_layers_panel_properties ( vw->viking_vlp ) )
4c77d5e0 1680 a_dialog_info_msg ( GTK_WINDOW(vw), _("You must select a layer to show its properties.") );
50a14534
EB
1681}
1682
5ff75d1e
GB
1683static void help_help_cb ( GtkAction *a, VikWindow *vw )
1684{
6ace3182
MA
1685#ifdef WINDOWS
1686 ShellExecute(NULL, "open", ""PACKAGE".pdf", NULL, NULL, SW_SHOWNORMAL);
1687#else /* WINDOWS */
5ff75d1e
GB
1688#if GTK_CHECK_VERSION (2, 14, 0)
1689 gchar *uri;
1690 uri = g_strdup_printf("ghelp:%s", PACKAGE);
1691 gtk_show_uri(NULL, uri, GDK_CURRENT_TIME, NULL);
1692 g_free(uri);
1693#endif
6ace3182 1694#endif /* WINDOWS */
5ff75d1e
GB
1695}
1696
d0a5f320
AF
1697static void help_about_cb ( GtkAction *a, VikWindow *vw )
1698{
1699 a_dialog_about(GTK_WINDOW(vw));
1700}
1701
e4afc73a 1702static void menu_delete_layer_cb ( GtkAction *a, VikWindow *vw )
50a14534
EB
1703{
1704 if ( vik_layers_panel_get_selected ( vw->viking_vlp ) )
1705 {
1706 vik_layers_panel_delete_selected ( vw->viking_vlp );
1707 vw->modified = TRUE;
1708 }
1709 else
4c77d5e0 1710 a_dialog_info_msg ( GTK_WINDOW(vw), _("You must select a layer to delete.") );
50a14534
EB
1711}
1712
181f5d0c
MA
1713static void view_side_panel_cb ( GtkAction *a, VikWindow *vw )
1714{
48df6aa3 1715 GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ViewSidePanel" );
181f5d0c
MA
1716 g_assert(check_box);
1717 gboolean state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box));
1718 if ( state )
1719 gtk_widget_show(GTK_WIDGET(vw->viking_vlp));
1720 else
1721 gtk_widget_hide(GTK_WIDGET(vw->viking_vlp));
1722}
1723
a459ee10
RN
1724static void view_statusbar_cb ( GtkAction *a, VikWindow *vw )
1725{
48df6aa3 1726 GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ViewStatusBar" );
a459ee10
RN
1727 if ( !check_box )
1728 return;
1729 gboolean state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box) );
1730 if ( state )
1731 gtk_widget_show ( GTK_WIDGET(vw->viking_vs) );
1732 else
1733 gtk_widget_hide ( GTK_WIDGET(vw->viking_vs) );
1734}
1735
e7591765
RN
1736static void view_toolbar_cb ( GtkAction *a, VikWindow *vw )
1737{
48df6aa3 1738 GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ViewToolbar" );
e7591765
RN
1739 if ( !check_box )
1740 return;
1741 gboolean state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box) );
1742 if ( state )
1743 gtk_widget_show ( GTK_WIDGET(vw->toolbar) );
1744 else
1745 gtk_widget_hide ( GTK_WIDGET(vw->toolbar) );
1746}
1747
7622022f
RN
1748static void view_main_menu_cb ( GtkAction *a, VikWindow *vw )
1749{
48df6aa3 1750 GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ViewMainMenu" );
7622022f
RN
1751 if ( !check_box )
1752 return;
1753 gboolean state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box) );
1754 if ( !state )
1755 gtk_widget_hide ( gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu" ) );
1756 else
1757 gtk_widget_show ( gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu" ) );
1758}
1759
941aa6e9
AF
1760/***************************************
1761 ** tool management routines
1762 **
1763 ***************************************/
1764
1765static toolbox_tools_t* toolbox_create(VikWindow *vw)
1766{
1767 toolbox_tools_t *vt = g_new(toolbox_tools_t, 1);
1768 vt->tools = NULL;
1769 vt->n_tools = 0;
1770 vt->active_tool = -1;
1771 vt->vw = vw;
1772 if (!vw->viking_vvp) {
7742da66 1773 g_critical("no viewport found.");
941aa6e9
AF
1774 exit(1);
1775 }
1776 return vt;
1777}
1778
9593a4c9 1779static void toolbox_add_tool(toolbox_tools_t *vt, VikToolInterface *vti, gint layer_type )
941aa6e9
AF
1780{
1781 vt->tools = g_renew(toolbox_tool_t, vt->tools, vt->n_tools+1);
1782 vt->tools[vt->n_tools].ti = *vti;
9593a4c9 1783 vt->tools[vt->n_tools].layer_type = layer_type;
941aa6e9
AF
1784 if (vti->create) {
1785 vt->tools[vt->n_tools].state = vti->create(vt->vw, vt->vw->viking_vvp);
1786 }
1787 else {
1788 vt->tools[vt->n_tools].state = NULL;
1789 }
1790 vt->n_tools++;
1791}
1792
1793static int toolbox_get_tool(toolbox_tools_t *vt, const gchar *tool_name)
1794{
1795 int i;
1796 for (i=0; i<vt->n_tools; i++) {
79dce0cb 1797 if (!strcmp(tool_name, vt->tools[i].ti.radioActionEntry.name)) {
941aa6e9
AF
1798 break;
1799 }
1800 }
1801 return i;
1802}
1803
1804static void toolbox_activate(toolbox_tools_t *vt, const gchar *tool_name)
1805{
1806 int tool = toolbox_get_tool(vt, tool_name);
1807 toolbox_tool_t *t = &vt->tools[tool];
1808 VikLayer *vl = vik_layers_panel_get_selected ( vt->vw->viking_vlp );
1809
1810 if (tool == vt->n_tools) {
7742da66 1811 g_critical("trying to activate a non-existent tool...");
941aa6e9
AF
1812 exit(1);
1813 }
1814 /* is the tool already active? */
1815 if (vt->active_tool == tool) {
1816 return;
1817 }
1818
1819 if (vt->active_tool != -1) {
1820 if (vt->tools[vt->active_tool].ti.deactivate) {
1821 vt->tools[vt->active_tool].ti.deactivate(NULL, vt->tools[vt->active_tool].state);
1822 }
1823 }
1824 if (t->ti.activate) {
1825 t->ti.activate(vl, t->state);
1826 }
1827 vt->active_tool = tool;
1828}
1829
f2f2f7bf
GB
1830static const GdkCursor *toolbox_get_cursor(toolbox_tools_t *vt, const gchar *tool_name)
1831{
1832 int tool = toolbox_get_tool(vt, tool_name);
1833 toolbox_tool_t *t = &vt->tools[tool];
1834 if (t->ti.cursor == NULL) {
1835 if (t->ti.cursor_type == GDK_CURSOR_IS_PIXMAP && t->ti.cursor_data != NULL) {
1836 GError *cursor_load_err = NULL;
1837 GdkPixbuf *cursor_pixbuf = gdk_pixbuf_from_pixdata (t->ti.cursor_data, FALSE, &cursor_load_err);
1838 /* TODO: settable offeset */
1839 t->ti.cursor = gdk_cursor_new_from_pixbuf ( gdk_display_get_default(), cursor_pixbuf, 3, 3 );
1840 g_object_unref ( G_OBJECT(cursor_pixbuf) );
1841 } else {
1842 t->ti.cursor = gdk_cursor_new ( t->ti.cursor_type );
1843 }
1844 }
1845 return t->ti.cursor;
1846}
1847
941aa6e9
AF
1848static void toolbox_click (toolbox_tools_t *vt, GdkEventButton *event)
1849{
1850 VikLayer *vl = vik_layers_panel_get_selected ( vt->vw->viking_vlp );
1851 if (vt->active_tool != -1 && vt->tools[vt->active_tool].ti.click) {
9593a4c9
EB
1852 gint ltype = vt->tools[vt->active_tool].layer_type;
1853 if ( ltype == TOOL_LAYER_TYPE_NONE || (vl && ltype == vl->type) )
1854 vt->tools[vt->active_tool].ti.click(vl, event, vt->tools[vt->active_tool].state);
941aa6e9
AF
1855 }
1856}
1857
dc2c040e 1858static void toolbox_move (toolbox_tools_t *vt, GdkEventMotion *event)
941aa6e9
AF
1859{
1860 VikLayer *vl = vik_layers_panel_get_selected ( vt->vw->viking_vlp );
1861 if (vt->active_tool != -1 && vt->tools[vt->active_tool].ti.move) {
9593a4c9
EB
1862 gint ltype = vt->tools[vt->active_tool].layer_type;
1863 if ( ltype == TOOL_LAYER_TYPE_NONE || (vl && ltype == vl->type) )
165d30aa
EB
1864 if ( VIK_LAYER_TOOL_ACK_GRAB_FOCUS == vt->tools[vt->active_tool].ti.move(vl, event, vt->tools[vt->active_tool].state) )
1865 gtk_widget_grab_focus ( GTK_WIDGET(vt->vw->viking_vvp) );
941aa6e9
AF
1866 }
1867}
1868
1869static void toolbox_release (toolbox_tools_t *vt, GdkEventButton *event)
1870{
1871 VikLayer *vl = vik_layers_panel_get_selected ( vt->vw->viking_vlp );
9593a4c9
EB
1872 if (vt->active_tool != -1 && vt->tools[vt->active_tool].ti.release ) {
1873 gint ltype = vt->tools[vt->active_tool].layer_type;
1874 if ( ltype == TOOL_LAYER_TYPE_NONE || (vl && ltype == vl->type) )
1875 vt->tools[vt->active_tool].ti.release(vl, event, vt->tools[vt->active_tool].state);
941aa6e9
AF
1876 }
1877}
1878/** End tool management ************************************/
1879
8fb71d6c
EB
1880void vik_window_enable_layer_tool ( VikWindow *vw, gint layer_id, gint tool_id )
1881{
79dce0cb 1882 gtk_action_activate ( gtk_action_group_get_action ( vw->action_group, vik_layer_get_interface(layer_id)->tools[tool_id].radioActionEntry.name ) );
8fb71d6c 1883}
941aa6e9
AF
1884
1885/* this function gets called whenever a toolbar tool is clicked */
e4afc73a 1886static void menu_tool_cb ( GtkAction *old, GtkAction *a, VikWindow *vw )
50a14534
EB
1887{
1888 /* White Magic, my friends ... White Magic... */
8fb71d6c 1889 int layer_id, tool_id;
f2f2f7bf 1890 const GdkCursor *cursor = NULL;
e4afc73a 1891
941aa6e9
AF
1892 toolbox_activate(vw->vt, gtk_action_get_name(a));
1893
f2f2f7bf 1894 cursor = toolbox_get_cursor(vw->vt, gtk_action_get_name(a));
33bc7c1b
RN
1895
1896 if ( GTK_WIDGET(vw->viking_vvp)->window )
1897 /* We set cursor, even if it is NULL: it resets to default */
1898 gdk_window_set_cursor ( GTK_WIDGET(vw->viking_vvp)->window, (GdkCursor *)cursor );
f2f2f7bf 1899
576cbd17
GB
1900 if (!strcmp(gtk_action_get_name(a), "Pan")) {
1901 vw->current_tool = TOOL_PAN;
576cbd17
GB
1902 }
1903 else if (!strcmp(gtk_action_get_name(a), "Zoom")) {
e4afc73a
EB
1904 vw->current_tool = TOOL_ZOOM;
1905 }
1906 else if (!strcmp(gtk_action_get_name(a), "Ruler")) {
1907 vw->current_tool = TOOL_RULER;
1908 }
a47bfefa
RN
1909 else if (!strcmp(gtk_action_get_name(a), "Select")) {
1910 vw->current_tool = TOOL_SELECT;
1911 }
e4afc73a 1912 else {
79845167 1913 /* TODO: only enable tools from active layer */
8fb71d6c
EB
1914 for (layer_id=0; layer_id<VIK_LAYER_NUM_TYPES; layer_id++) {
1915 for ( tool_id = 0; tool_id < vik_layer_get_interface(layer_id)->tools_count; tool_id++ ) {
79dce0cb 1916 if (!strcmp(vik_layer_get_interface(layer_id)->tools[tool_id].radioActionEntry.name, gtk_action_get_name(a))) {
8fb71d6c
EB
1917 vw->current_tool = TOOL_LAYER;
1918 vw->tool_layer_id = layer_id;
1919 vw->tool_tool_id = tool_id;
e4afc73a
EB
1920 }
1921 }
1922 }
1923 }
50a14534
EB
1924 draw_status ( vw );
1925}
1926
1927static void window_set_filename ( VikWindow *vw, const gchar *filename )
1928{
1929 gchar *title;
4c77d5e0 1930 const gchar *file;
50a14534
EB
1931 if ( vw->filename )
1932 g_free ( vw->filename );
1933 if ( filename == NULL )
1934 {
1935 vw->filename = NULL;
4c77d5e0 1936 file = _("Untitled");
50a14534
EB
1937 }
1938 else
1939 {
1940 vw->filename = g_strdup(filename);
4c77d5e0 1941 file = a_file_basename ( filename );
50a14534 1942 }
4c77d5e0
GB
1943 title = g_strdup_printf( "%s - Viking", file );
1944 gtk_window_set_title ( GTK_WINDOW(vw), title );
1945 g_free ( title );
50a14534
EB
1946}
1947
7bc965c0
GB
1948GtkWidget *vik_window_get_drawmode_button ( VikWindow *vw, VikViewportDrawMode mode )
1949{
1950 GtkWidget *mode_button;
1951 gchar *buttonname;
1952 switch ( mode ) {
794c8f18 1953#ifdef VIK_CONFIG_EXPEDIA
7bc965c0 1954 case VIK_VIEWPORT_DRAWMODE_EXPEDIA: buttonname = "/ui/MainMenu/View/ModeExpedia"; break;
794c8f18 1955#endif
7bc965c0 1956 case VIK_VIEWPORT_DRAWMODE_MERCATOR: buttonname = "/ui/MainMenu/View/ModeMercator"; break;
d587678a 1957 case VIK_VIEWPORT_DRAWMODE_LATLON: buttonname = "/ui/MainMenu/View/ModeLatLon"; break;
794c8f18 1958 default: buttonname = "/ui/MainMenu/View/ModeUTM";
7bc965c0
GB
1959 }
1960 mode_button = gtk_ui_manager_get_widget ( vw->uim, buttonname );
1961 g_assert ( mode_button );
1962 return mode_button;
1963}
1964
01da6b4d
GB
1965/**
1966 * vik_window_get_pan_move:
1967 * @vw: some VikWindow
1968 *
1969 * Retrieves @vw's pan_move.
1970 *
1971 * Should be removed as soon as possible.
1972 *
1973 * Returns: @vw's pan_move
1974 *
1975 * Since: 0.9.96
1976 **/
1c6a6010
GB
1977gboolean vik_window_get_pan_move ( VikWindow *vw )
1978{
1979 return vw->pan_move;
1980}
1981
13505702
GB
1982static void on_activate_recent_item (GtkRecentChooser *chooser,
1983 VikWindow *self)
1984{
1985 gchar *filename;
1986
1987 filename = gtk_recent_chooser_get_current_uri (chooser);
1988 if (filename != NULL)
1989 {
1990 GFile *file = g_file_new_for_uri ( filename );
1991 gchar *path = g_file_get_path ( file );
1992 g_object_unref ( file );
1993 if ( self->filename )
1994 {
d8ff1421
RN
1995 GSList *filenames = NULL;
1996 filenames = g_slist_append ( filenames, path );
13505702 1997 g_signal_emit ( G_OBJECT(self), window_signals[VW_OPENWINDOW_SIGNAL], 0, filenames );
d8ff1421 1998 // NB: GSList & contents are freed by main.open_window
13505702 1999 }
d8ff1421 2000 else {
756d53f5 2001 vik_window_open_file ( self, path, TRUE );
d8ff1421
RN
2002 g_free ( path );
2003 }
13505702
GB
2004 }
2005
2006 g_free (filename);
2007}
2008
2009static void setup_recent_files (VikWindow *self)
2010{
2011 GtkRecentManager *manager;
2012 GtkRecentFilter *filter;
2013 GtkWidget *menu, *menu_item;
2014
2015 filter = gtk_recent_filter_new ();
2016 /* gtk_recent_filter_add_application (filter, g_get_application_name()); */
2017 gtk_recent_filter_add_group(filter, "viking");
2018
2019 manager = gtk_recent_manager_get_default ();
2020 menu = gtk_recent_chooser_menu_new_for_manager (manager);
2021 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu), GTK_RECENT_SORT_MRU);
2022 gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu), filter);
2023
2024 menu_item = gtk_ui_manager_get_widget (self->uim, "/ui/MainMenu/File/OpenRecentFile");
2025 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), menu);
2026
2027 g_signal_connect (G_OBJECT (menu), "item-activated",
2028 G_CALLBACK (on_activate_recent_item), (gpointer) self);
2029}
2030
2031static void update_recently_used_document(const gchar *filename)
2032{
2033 /* Update Recently Used Document framework */
2034 GtkRecentManager *manager = gtk_recent_manager_get_default();
2035 GtkRecentData *recent_data = g_slice_new (GtkRecentData);
2036 gchar *groups[] = {"viking", NULL};
2037 GFile *file = g_file_new_for_commandline_arg(filename);
2038 gchar *uri = g_file_get_uri(file);
2039 gchar *basename = g_path_get_basename(filename);
2040 g_object_unref(file);
2041 file = NULL;
2042
2043 recent_data->display_name = basename;
2044 recent_data->description = NULL;
2045 recent_data->mime_type = "text/x-gps-data";
2046 recent_data->app_name = (gchar *) g_get_application_name ();
2047 recent_data->app_exec = g_strjoin (" ", g_get_prgname (), "%f", NULL);
2048 recent_data->groups = groups;
2049 recent_data->is_private = FALSE;
2050 if (!gtk_recent_manager_add_full (manager, uri, recent_data))
2051 {
2052 g_warning (_("Unable to add '%s' to the list of recently used documents"), uri);
2053 }
2054
2055 g_free (uri);
2056 g_free (basename);
2057 g_free (recent_data->app_exec);
2058 g_slice_free (GtkRecentData, recent_data);
2059}
2060
50a14534
EB
2061void vik_window_open_file ( VikWindow *vw, const gchar *filename, gboolean change_filename )
2062{
2063 switch ( a_file_load ( vik_layers_panel_get_top_layer(vw->viking_vlp), vw->viking_vvp, filename ) )
2064 {
ba9d0a00 2065 case LOAD_TYPE_READ_FAILURE:
4c77d5e0 2066 a_dialog_error_msg ( GTK_WINDOW(vw), _("The file you requested could not be opened.") );
50a14534 2067 break;
ba9d0a00
RN
2068 case LOAD_TYPE_GPSBABEL_FAILURE:
2069 a_dialog_error_msg ( GTK_WINDOW(vw), _("GPSBabel is required to load files of this type or GPSBabel encountered problems.") );
2070 break;
54b84792
RN
2071 case LOAD_TYPE_GPX_FAILURE:
2072 a_dialog_error_msg_extra ( GTK_WINDOW(vw), _("Unable to load malformed GPX file %s"), filename );
2073 break;
cb5ec7a8
RN
2074 case LOAD_TYPE_UNSUPPORTED_FAILURE:
2075 a_dialog_error_msg_extra ( GTK_WINDOW(vw), _("Unsupported file type for %s"), filename );
2076 break;
ba9d0a00 2077 case LOAD_TYPE_VIK_SUCCESS:
50a14534
EB
2078 {
2079 GtkWidget *mode_button;
13505702 2080 /* Update UI */
50a14534
EB
2081 if ( change_filename )
2082 window_set_filename ( vw, filename );
7bc965c0 2083 mode_button = vik_window_get_drawmode_button ( vw, vik_viewport_get_drawmode ( vw->viking_vvp ) );
50a14534
EB
2084 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. */
2085 gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(mode_button), TRUE );
2086 vw->only_updating_coord_mode_ui = FALSE;
2087
2088 vik_layers_panel_change_coord_mode ( vw->viking_vlp, vik_viewport_get_coord_mode ( vw->viking_vvp ) );
2afcef36 2089
48df6aa3 2090 mode_button = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ShowScale" );
1657065a
QT
2091 g_assert ( mode_button );
2092 gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(mode_button),vik_viewport_get_draw_scale(vw->viking_vvp) );
2093
48df6aa3 2094 mode_button = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ShowCenterMark" );
1657065a
QT
2095 g_assert ( mode_button );
2096 gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(mode_button),vik_viewport_get_draw_centermark(vw->viking_vvp) );
2afcef36
RN
2097
2098 mode_button = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ShowHighlight" );
2099 g_assert ( mode_button );
2100 gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(mode_button),vik_viewport_get_draw_highlight (vw->viking_vvp) );
50a14534 2101 }
ba9d0a00 2102 //case LOAD_TYPE_OTHER_SUCCESS:
13505702
GB
2103 default:
2104 update_recently_used_document(filename);
2105 draw_update ( vw );
ba9d0a00 2106 break;
50a14534
EB
2107 }
2108}
e4afc73a 2109static void load_file ( GtkAction *a, VikWindow *vw )
50a14534 2110{
6e4a49aa
MA
2111 GSList *files = NULL;
2112 GSList *cur_file = NULL;
e4afc73a
EB
2113 gboolean newwindow;
2114 if (!strcmp(gtk_action_get_name(a), "Open")) {
2115 newwindow = TRUE;
2116 }
2117 else if (!strcmp(gtk_action_get_name(a), "Append")) {
2118 newwindow = FALSE;
2119 }
2120 else {
8dc8da82 2121 g_critical("Houston, we've had a problem.");
e4afc73a
EB
2122 return;
2123 }
2124
50a14534
EB
2125 if ( ! vw->open_dia )
2126 {
6e4a49aa
MA
2127 vw->open_dia = gtk_file_chooser_dialog_new (_("Please select a GPS data file to open. "),
2128 GTK_WINDOW(vw),
2129 GTK_FILE_CHOOSER_ACTION_OPEN,
2130 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
2131 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
2132 NULL);
269fe4da
RN
2133 GtkFileFilter *filter;
2134 // NB file filters are listed this way for alphabetical ordering
2135#ifdef VIK_CONFIG_GEOCACHES
2136 filter = gtk_file_filter_new ();
2137 gtk_file_filter_set_name( filter, _("Geocaching") );
2138 gtk_file_filter_add_pattern ( filter, "*.loc" ); // No MIME type available
2139 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(vw->open_dia), filter);
2140#endif
2141
2142 filter = gtk_file_filter_new ();
2143 gtk_file_filter_set_name( filter, _("Google Earth") );
2144 gtk_file_filter_add_mime_type ( filter, "application/vnd.google-earth.kml+xml");
2145 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(vw->open_dia), filter);
2146
2147 filter = gtk_file_filter_new ();
2148 gtk_file_filter_set_name( filter, _("GPX") );
2149 gtk_file_filter_add_pattern ( filter, "*.gpx" ); // No MIME type available
2150 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(vw->open_dia), filter);
2151
2152 filter = gtk_file_filter_new ();
2153 gtk_file_filter_set_name( filter, _("Viking") );
2154 gtk_file_filter_add_pattern ( filter, "*.vik" );
2155 gtk_file_filter_add_pattern ( filter, "*.viking" );
2156 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(vw->open_dia), filter);
2157
2158 // NB could have filters for gpspoint (*.gps,*.gpsoint?) + gpsmapper (*.gsm,*.gpsmapper?)
2159 // However assume this are barely used and thus not worthy of inclusion
2160 // as they'll just make the options too many and have no clear file pattern
2161 // one can always use the all option
2162 filter = gtk_file_filter_new ();
2163 gtk_file_filter_set_name( filter, _("All") );
2164 gtk_file_filter_add_pattern ( filter, "*" );
2165 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(vw->open_dia), filter);
2166 // Default to any file - same as before open filters were added
2167 gtk_file_chooser_set_filter (GTK_FILE_CHOOSER(vw->open_dia), filter);
2168
6e4a49aa 2169 gtk_file_chooser_set_select_multiple ( GTK_FILE_CHOOSER(vw->open_dia), TRUE );
50a14534
EB
2170 gtk_window_set_transient_for ( GTK_WINDOW(vw->open_dia), GTK_WINDOW(vw) );
2171 gtk_window_set_destroy_with_parent ( GTK_WINDOW(vw->open_dia), TRUE );
2172 }
6e4a49aa 2173 if ( gtk_dialog_run ( GTK_DIALOG(vw->open_dia) ) == GTK_RESPONSE_ACCEPT )
50a14534
EB
2174 {
2175 gtk_widget_hide ( vw->open_dia );
a5fd2196 2176#ifdef VIKING_PROMPT_IF_MODIFIED
50a14534 2177 if ( (vw->modified || vw->filename) && newwindow )
a5fd2196
QT
2178#else
2179 if ( vw->filename && newwindow )
2180#endif
6e4a49aa 2181 g_signal_emit ( G_OBJECT(vw), window_signals[VW_OPENWINDOW_SIGNAL], 0, gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER(vw->open_dia) ) );
50a14534 2182 else {
6e4a49aa
MA
2183 files = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER(vw->open_dia) );
2184 gboolean change_fn = newwindow && (g_slist_length(files)==1); /* only change fn if one file */
2185
2186 cur_file = files;
2187 while ( cur_file ) {
2188 gchar *file_name = cur_file->data;
2189 vik_window_open_file ( vw, file_name, change_fn );
2190 g_free (file_name);
2191 cur_file = g_slist_next (cur_file);
50a14534 2192 }
6e4a49aa 2193 g_slist_free (files);
50a14534
EB
2194 }
2195 }
2196 else
2197 gtk_widget_hide ( vw->open_dia );
2198}
2199
e4afc73a 2200static gboolean save_file_as ( GtkAction *a, VikWindow *vw )
50a14534
EB
2201{
2202 gboolean rv = FALSE;
2203 const gchar *fn;
2204 if ( ! vw->save_dia )
2205 {
6e4a49aa
MA
2206 vw->save_dia = gtk_file_chooser_dialog_new (_("Save as Viking File."),
2207 GTK_WINDOW(vw),
2208 GTK_FILE_CHOOSER_ACTION_SAVE,
2209 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
2210 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
2211 NULL);
50a14534
EB
2212 gtk_window_set_transient_for ( GTK_WINDOW(vw->save_dia), GTK_WINDOW(vw) );
2213 gtk_window_set_destroy_with_parent ( GTK_WINDOW(vw->save_dia), TRUE );
2214 }
2215
6e4a49aa 2216 while ( gtk_dialog_run ( GTK_DIALOG(vw->save_dia) ) == GTK_RESPONSE_ACCEPT )
50a14534 2217 {
6e4a49aa 2218 fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(vw->save_dia) );
d91e5f2b 2219 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
2220 {
2221 window_set_filename ( vw, fn );
2222 rv = window_save ( vw );
2223 vw->modified = FALSE;
2224 break;
2225 }
2226 }
2227 gtk_widget_hide ( vw->save_dia );
2228 return rv;
2229}
2230
2231static gboolean window_save ( VikWindow *vw )
2232{
2233 if ( a_file_save ( vik_layers_panel_get_top_layer ( vw->viking_vlp ), vw->viking_vvp, vw->filename ) )
13505702
GB
2234 {
2235 update_recently_used_document ( vw->filename );
50a14534 2236 return TRUE;
13505702 2237 }
50a14534
EB
2238 else
2239 {
4c77d5e0 2240 a_dialog_error_msg ( GTK_WINDOW(vw), _("The filename you requested could not be opened for writing.") );
50a14534
EB
2241 return FALSE;
2242 }
2243}
2244
e4afc73a 2245static gboolean save_file ( GtkAction *a, VikWindow *vw )
50a14534
EB
2246{
2247 if ( ! vw->filename )
e4afc73a 2248 return save_file_as ( NULL, vw );
50a14534
EB
2249 else
2250 {
2251 vw->modified = FALSE;
2252 return window_save ( vw );
2253 }
2254}
2255
1d1bc3c1
EB
2256static void acquire_from_gps ( GtkAction *a, VikWindow *vw )
2257{
16fc32f6
RN
2258 // Via the file menu, acquiring from a GPS makes a new layer
2259 // this has always been the way (not entirely sure if this was the real intention!)
2260 // thus maintain the behaviour ATM.
2261 // Hence explicit setting here (as the value may be changed elsewhere)
2262 vik_datasource_gps_interface.mode = VIK_DATASOURCE_CREATENEWLAYER;
7b3479e3
EB
2263 a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_gps_interface );
2264}
2265
31349009
GB
2266static void acquire_from_file ( GtkAction *a, VikWindow *vw )
2267{
2268 a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_file_interface );
2269}
2270
ebf1bd39 2271#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS
7b3479e3
EB
2272static void acquire_from_google ( GtkAction *a, VikWindow *vw )
2273{
2274 a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_google_interface );
1d1bc3c1 2275}
ebf1bd39 2276#endif
1d1bc3c1 2277
9c4555df
GB
2278#ifdef VIK_CONFIG_OPENSTREETMAP
2279static void acquire_from_osm ( GtkAction *a, VikWindow *vw )
2280{
2281 a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_osm_interface );
2282}
2283#endif
2284
1ef9e637 2285#ifdef VIK_CONFIG_GEOCACHES
3333c069
EB
2286static void acquire_from_gc ( GtkAction *a, VikWindow *vw )
2287{
2288 a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_gc_interface );
2289}
1ef9e637 2290#endif
3333c069 2291
f75d0233
RN
2292#ifdef VIK_CONFIG_GEOTAG
2293static void acquire_from_geotag ( GtkAction *a, VikWindow *vw )
2294{
2295 vik_datasource_geotag_interface.mode = VIK_DATASOURCE_CREATENEWLAYER;
2296 a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_geotag_interface );
2297}
2298#endif
2299
5210c3d3
GB
2300static void goto_default_location( GtkAction *a, VikWindow *vw)
2301{
2302 struct LatLon ll;
2303 ll.lat = a_vik_get_default_lat();
2304 ll.lon = a_vik_get_default_long();
2305 vik_viewport_set_center_latlon(vw->viking_vvp, &ll);
2306 vik_layers_panel_emit_update(vw->viking_vlp);
2307}
2308
2309
369126f3
QT
2310static void goto_address( GtkAction *a, VikWindow *vw)
2311{
34e71b99 2312 a_vik_goto(vw, vw->viking_vlp, vw->viking_vvp);
369126f3
QT
2313}
2314
7c259702
JJ
2315static void mapcache_flush_cb ( GtkAction *a, VikWindow *vw )
2316{
2317 a_mapcache_flush();
2318}
2319
17a1f8f9
EB
2320static void preferences_cb ( GtkAction *a, VikWindow *vw )
2321{
9be0449f
RN
2322 gboolean wp_icon_size = a_vik_get_use_large_waypoint_icons();
2323
17a1f8f9 2324 a_preferences_show_window ( GTK_WINDOW(vw) );
9be0449f
RN
2325
2326 // Delete icon indexing 'cache' and so automatically regenerates with the new setting when changed
2327 if (wp_icon_size != a_vik_get_use_large_waypoint_icons())
2328 clear_garmin_icon_syms ();
2329
6f9336aa 2330 draw_update ( vw );
17a1f8f9
EB
2331}
2332
5210c3d3
GB
2333static void default_location_cb ( GtkAction *a, VikWindow *vw )
2334{
2335 /* Simplistic repeat of preference setting
2336 Only the name & type are important for setting the preference via this 'external' way */
2337 VikLayerParam pref_lat[] = {
2338 { VIKING_PREFERENCES_NAMESPACE "default_latitude",
2339 VIK_LAYER_PARAM_DOUBLE,
2340 VIK_LOCATION_LAT,
2341 NULL,
2342 VIK_LAYER_WIDGET_SPINBUTTON,
2343 NULL,
2344 NULL },
2345 };
2346 VikLayerParam pref_lon[] = {
2347 { VIKING_PREFERENCES_NAMESPACE "default_longitude",
2348 VIK_LAYER_PARAM_DOUBLE,
2349 VIK_LOCATION_LONG,
2350 NULL,
2351 VIK_LAYER_WIDGET_SPINBUTTON,
2352 NULL,
2353 NULL },
2354 };
2355
2356 /* Get current center */
2357 struct LatLon ll;
2358 vik_coord_to_latlon ( vik_viewport_get_center ( vw->viking_vvp ), &ll );
2359
2360 /* Apply to preferences */
2361 VikLayerParamData vlp_data;
2362 vlp_data.d = ll.lat;
2363 a_preferences_run_setparam (vlp_data, pref_lat);
2364 vlp_data.d = ll.lon;
2365 a_preferences_run_setparam (vlp_data, pref_lon);
2366 /* Remember to save */
2367 a_preferences_save_to_file();
2368}
2369
e4afc73a 2370static void clear_cb ( GtkAction *a, VikWindow *vw )
50a14534
EB
2371{
2372 vik_layers_panel_clear ( vw->viking_vlp );
2373 window_set_filename ( vw, NULL );
2374 draw_update ( vw );
2375}
2376
e4afc73a 2377static void window_close ( GtkAction *a, VikWindow *vw )
50a14534
EB
2378{
2379 if ( ! delete_event ( vw ) )
2380 gtk_widget_destroy ( GTK_WIDGET(vw) );
2381}
2382
2bf7cadd
QT
2383static gboolean save_file_and_exit ( GtkAction *a, VikWindow *vw )
2384{
7bb60307 2385 if (save_file( NULL, vw)) {
2bf7cadd 2386 window_close( NULL, vw);
7bb60307
QT
2387 return(TRUE);
2388 }
2bf7cadd
QT
2389 else
2390 return(FALSE);
2391}
2392
e4afc73a 2393static void zoom_to_cb ( GtkAction *a, VikWindow *vw )
50a14534
EB
2394{
2395 gdouble xmpp = vik_viewport_get_xmpp ( vw->viking_vvp ), ympp = vik_viewport_get_ympp ( vw->viking_vvp );
2396 if ( a_dialog_custom_zoom ( GTK_WINDOW(vw), &xmpp, &ympp ) )
2397 {
2398 vik_viewport_set_xmpp ( vw->viking_vvp, xmpp );
2399 vik_viewport_set_ympp ( vw->viking_vvp, ympp );
2400 draw_update ( vw );
2401 }
2402}
2403
2404static void save_image_file ( VikWindow *vw, const gchar *fn, guint w, guint h, gdouble zoom, gboolean save_as_png )
2405{
2406 /* more efficient way: stuff draws directly to pixbuf (fork viewport) */
2407 GdkPixbuf *pixbuf_to_save;
2408 gdouble old_xmpp, old_ympp;
2409 GError *error = NULL;
2410
2411 /* backup old zoom & set new */
2412 old_xmpp = vik_viewport_get_xmpp ( vw->viking_vvp );
2413 old_ympp = vik_viewport_get_ympp ( vw->viking_vvp );
2414 vik_viewport_set_zoom ( vw->viking_vvp, zoom );
2415
2416 /* reset width and height: */
2417 vik_viewport_configure_manually ( vw->viking_vvp, w, h );
2418
2419 /* draw all layers */
2420 draw_redraw ( vw );
2421
2422 /* save buffer as file. */
2423 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);
2424 gdk_pixbuf_save ( pixbuf_to_save, fn, save_as_png ? "png" : "jpeg", &error, NULL );
2425 if (error)
2426 {
7742da66 2427 g_warning("Unable to write to file %s: %s", fn, error->message );
50a14534
EB
2428 g_error_free (error);
2429 }
2430 g_object_unref ( G_OBJECT(pixbuf_to_save) );
2431
2432 /* pretend like nothing happened ;) */
2433 vik_viewport_set_xmpp ( vw->viking_vvp, old_xmpp );
2434 vik_viewport_set_ympp ( vw->viking_vvp, old_ympp );
2435 vik_viewport_configure ( vw->viking_vvp );
2436 draw_update ( vw );
2437}
2438
2439static 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 )
2440{
2441 gulong size = sizeof(gchar) * (strlen(fn) + 15);
2442 gchar *name_of_file = g_malloc ( size );
2443 guint x = 1, y = 1;
2444 struct UTM utm_orig, utm;
2445
2446 /* *** copied from above *** */
2447 GdkPixbuf *pixbuf_to_save;
2448 gdouble old_xmpp, old_ympp;
2449 GError *error = NULL;
2450
2451 /* backup old zoom & set new */
2452 old_xmpp = vik_viewport_get_xmpp ( vw->viking_vvp );
2453 old_ympp = vik_viewport_get_ympp ( vw->viking_vvp );
2454 vik_viewport_set_zoom ( vw->viking_vvp, zoom );
2455
2456 /* reset width and height: do this only once for all images (same size) */
2457 vik_viewport_configure_manually ( vw->viking_vvp, w, h );
2458 /* *** end copy from above *** */
2459
2460 g_assert ( vik_viewport_get_coord_mode ( vw->viking_vvp ) == VIK_COORD_UTM );
2461
f83131b9 2462 g_mkdir(fn,0777);
50a14534
EB
2463
2464 utm_orig = *((const struct UTM *)vik_viewport_get_center ( vw->viking_vvp ));
2465
2466 for ( y = 1; y <= tiles_h; y++ )
2467 {
2468 for ( x = 1; x <= tiles_w; x++ )
2469 {
3d9454e6 2470 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
2471 utm = utm_orig;
2472 if ( tiles_w & 0x1 )
2473 utm.easting += ((gdouble)x - ceil(((gdouble)tiles_w)/2)) * (w*zoom);
2474 else
2475 utm.easting += ((gdouble)x - (((gdouble)tiles_w)+1)/2) * (w*zoom);
2476 if ( tiles_h & 0x1 ) /* odd */
2477 utm.northing -= ((gdouble)y - ceil(((gdouble)tiles_h)/2)) * (h*zoom);
2478 else /* even */
2479 utm.northing -= ((gdouble)y - (((gdouble)tiles_h)+1)/2) * (h*zoom);
2480
2481 /* move to correct place. */
2482 vik_viewport_set_center_utm ( vw->viking_vvp, &utm );
2483
2484 draw_redraw ( vw );
2485
2486 /* save buffer as file. */
2487 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);
2488 gdk_pixbuf_save ( pixbuf_to_save, name_of_file, save_as_png ? "png" : "jpeg", &error, NULL );
2489 if (error)
2490 {
7742da66 2491 g_warning("Unable to write to file %s: %s", name_of_file, error->message );
50a14534
EB
2492 g_error_free (error);
2493 }
2494
2495 g_object_unref ( G_OBJECT(pixbuf_to_save) );
2496 }
2497 }
2498
2499 vik_viewport_set_center_utm ( vw->viking_vvp, &utm_orig );
2500 vik_viewport_set_xmpp ( vw->viking_vvp, old_xmpp );
2501 vik_viewport_set_ympp ( vw->viking_vvp, old_ympp );
2502 vik_viewport_configure ( vw->viking_vvp );
2503 draw_update ( vw );
2504
2505 g_free ( name_of_file );
2506}
2507
2508static void draw_to_image_file_current_window_cb(GtkWidget* widget,GdkEventButton *event,gpointer *pass_along)
2509{
2510 VikWindow *vw = VIK_WINDOW(pass_along[0]);
2511 GtkSpinButton *width_spin = GTK_SPIN_BUTTON(pass_along[1]), *height_spin = GTK_SPIN_BUTTON(pass_along[2]);
2512 GtkSpinButton *zoom_spin = GTK_SPIN_BUTTON(pass_along[3]);
2513 gdouble width_min, width_max, height_min, height_max;
2514 gint width, height;
2515
2516 gtk_spin_button_get_range ( width_spin, &width_min, &width_max );
2517 gtk_spin_button_get_range ( height_spin, &height_min, &height_max );
2518
2519 /* TODO: support for xzoom and yzoom values */
2520 width = vik_viewport_get_width ( vw->viking_vvp ) * vik_viewport_get_xmpp ( vw->viking_vvp ) / gtk_spin_button_get_value ( zoom_spin );
2521 height = vik_viewport_get_height ( vw->viking_vvp ) * vik_viewport_get_xmpp ( vw->viking_vvp ) / gtk_spin_button_get_value ( zoom_spin );
2522
2523 if ( width > width_max || width < width_min || height > height_max || height < height_min )
4c77d5e0 2524 a_dialog_info_msg ( GTK_WINDOW(vw), _("Viewable region outside allowable pixel size bounds for image. Clipping width/height values.") );
50a14534
EB
2525
2526 gtk_spin_button_set_value ( width_spin, width );
2527 gtk_spin_button_set_value ( height_spin, height );
2528}
2529
2530static void draw_to_image_file_total_area_cb (GtkSpinButton *spinbutton, gpointer *pass_along)
2531{
2532 GtkSpinButton *width_spin = GTK_SPIN_BUTTON(pass_along[1]), *height_spin = GTK_SPIN_BUTTON(pass_along[2]);
2533 GtkSpinButton *zoom_spin = GTK_SPIN_BUTTON(pass_along[3]);
2534 gchar *label_text;
2535 gdouble w, h;
2536 w = gtk_spin_button_get_value(width_spin) * gtk_spin_button_get_value(zoom_spin);
2537 h = gtk_spin_button_get_value(height_spin) * gtk_spin_button_get_value(zoom_spin);
2538 if (pass_along[4]) /* save many images; find TOTAL area covered */
2539 {
2540 w *= gtk_spin_button_get_value(GTK_SPIN_BUTTON(pass_along[4]));
2541 h *= gtk_spin_button_get_value(GTK_SPIN_BUTTON(pass_along[5]));
2542 }
6f9336aa
RN
2543 vik_units_distance_t dist_units = a_vik_get_units_distance ();
2544 switch (dist_units) {
2545 case VIK_UNITS_DISTANCE_KILOMETRES:
2546 label_text = g_strdup_printf ( _("Total area: %ldm x %ldm (%.3f sq. km)"), (glong)w, (glong)h, (w*h/1000000));
2547 break;
2548 case VIK_UNITS_DISTANCE_MILES:
2549 label_text = g_strdup_printf ( _("Total area: %ldm x %ldm (%.3f sq. miles)"), (glong)w, (glong)h, (w*h/2589988.11));
2550 break;
2551 default:
2552 label_text = g_strdup_printf ("Just to keep the compiler happy");
2553 g_critical("Houston, we've had a problem. distance=%d", dist_units);
2554 }
2555
50a14534
EB
2556 gtk_label_set_text(GTK_LABEL(pass_along[6]), label_text);
2557 g_free ( label_text );
2558}
2559
2560static void draw_to_image_file ( VikWindow *vw, const gchar *fn, gboolean one_image_only )
2561{
2562 /* todo: default for answers inside VikWindow or static (thruout instance) */
4c77d5e0 2563 GtkWidget *dialog = gtk_dialog_new_with_buttons ( _("Save to Image File"), GTK_WINDOW(vw),
50a14534
EB
2564 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
2565 GTK_STOCK_CANCEL,
2566 GTK_RESPONSE_REJECT,
2567 GTK_STOCK_OK,
2568 GTK_RESPONSE_ACCEPT,
10888930 2569 NULL );
50a14534
EB
2570 GtkWidget *width_label, *width_spin, *height_label, *height_spin;
2571 GtkWidget *png_radio, *jpeg_radio;
2572 GtkWidget *current_window_button;
2573 gpointer current_window_pass_along[7];
2574 GtkWidget *zoom_label, *zoom_spin;
2575 GtkWidget *total_size_label;
2576
2577 /* only used if (!one_image_only) */
886031df 2578 GtkWidget *tiles_width_spin = NULL, *tiles_height_spin = NULL;
50a14534
EB
2579
2580
4c77d5e0 2581 width_label = gtk_label_new ( _("Width (pixels):") );
50a14534 2582 width_spin = gtk_spin_button_new ( GTK_ADJUSTMENT(gtk_adjustment_new ( vw->draw_image_width, 10, 5000, 10, 100, 0 )), 10, 0 );
4c77d5e0 2583 height_label = gtk_label_new ( _("Height (pixels):") );
50a14534
EB
2584 height_spin = gtk_spin_button_new ( GTK_ADJUSTMENT(gtk_adjustment_new ( vw->draw_image_height, 10, 5000, 10, 100, 0 )), 10, 0 );
2585
4c77d5e0 2586 zoom_label = gtk_label_new ( _("Zoom (meters per pixel):") );
50a14534 2587 /* TODO: separate xzoom and yzoom factors */
ac33062d 2588 zoom_spin = gtk_spin_button_new ( GTK_ADJUSTMENT(gtk_adjustment_new ( vik_viewport_get_xmpp(vw->viking_vvp), VIK_VIEWPORT_MIN_ZOOM, VIK_VIEWPORT_MAX_ZOOM/2.0, 1, 100, 0 )), 16, 0);
50a14534
EB
2589
2590 total_size_label = gtk_label_new ( NULL );
2591
4c77d5e0 2592 current_window_button = gtk_button_new_with_label ( _("Area in current viewable window") );
50a14534
EB
2593 current_window_pass_along [0] = vw;
2594 current_window_pass_along [1] = width_spin;
2595 current_window_pass_along [2] = height_spin;
2596 current_window_pass_along [3] = zoom_spin;
2597 current_window_pass_along [4] = NULL; /* used for one_image_only != 1 */
2598 current_window_pass_along [5] = NULL;
2599 current_window_pass_along [6] = total_size_label;
2600 g_signal_connect ( G_OBJECT(current_window_button), "button_press_event", G_CALLBACK(draw_to_image_file_current_window_cb), current_window_pass_along );
2601
4c77d5e0
GB
2602 png_radio = gtk_radio_button_new_with_label ( NULL, _("Save as PNG") );
2603 jpeg_radio = gtk_radio_button_new_with_label_from_widget ( GTK_RADIO_BUTTON(png_radio), _("Save as JPEG") );
50a14534
EB
2604
2605 if ( ! vw->draw_image_save_as_png )
2606 gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON(jpeg_radio), TRUE );
2607
2608 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), width_label, FALSE, FALSE, 0);
2609 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), width_spin, FALSE, FALSE, 0);
2610 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), height_label, FALSE, FALSE, 0);
2611 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), height_spin, FALSE, FALSE, 0);
2612 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), current_window_button, FALSE, FALSE, 0);
2613 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), png_radio, FALSE, FALSE, 0);
2614 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), jpeg_radio, FALSE, FALSE, 0);
2615 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), zoom_label, FALSE, FALSE, 0);
2616 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), zoom_spin, FALSE, FALSE, 0);
2617
2618 if ( ! one_image_only )
2619 {
2620 GtkWidget *tiles_width_label, *tiles_height_label;
2621
2622
4c77d5e0 2623 tiles_width_label = gtk_label_new ( _("East-west image tiles:") );
50a14534 2624 tiles_width_spin = gtk_spin_button_new ( GTK_ADJUSTMENT(gtk_adjustment_new ( 5, 1, 10, 1, 100, 0 )), 1, 0 );
4c77d5e0 2625 tiles_height_label = gtk_label_new ( _("North-south image tiles:") );
50a14534
EB
2626 tiles_height_spin = gtk_spin_button_new ( GTK_ADJUSTMENT(gtk_adjustment_new ( 5, 1, 10, 1, 100, 0 )), 1, 0 );
2627 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), tiles_width_label, FALSE, FALSE, 0);
2628 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), tiles_width_spin, FALSE, FALSE, 0);
2629 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), tiles_height_label, FALSE, FALSE, 0);
2630 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), tiles_height_spin, FALSE, FALSE, 0);
2631
2632 current_window_pass_along [4] = tiles_width_spin;
2633 current_window_pass_along [5] = tiles_height_spin;
2634 g_signal_connect ( G_OBJECT(tiles_width_spin), "value-changed", G_CALLBACK(draw_to_image_file_total_area_cb), current_window_pass_along );
2635 g_signal_connect ( G_OBJECT(tiles_height_spin), "value-changed", G_CALLBACK(draw_to_image_file_total_area_cb), current_window_pass_along );
2636 }
2637 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), total_size_label, FALSE, FALSE, 0);
2638 g_signal_connect ( G_OBJECT(width_spin), "value-changed", G_CALLBACK(draw_to_image_file_total_area_cb), current_window_pass_along );
2639 g_signal_connect ( G_OBJECT(height_spin), "value-changed", G_CALLBACK(draw_to_image_file_total_area_cb), current_window_pass_along );
2640 g_signal_connect ( G_OBJECT(zoom_spin), "value-changed", G_CALLBACK(draw_to_image_file_total_area_cb), current_window_pass_along );
2641
2642 draw_to_image_file_total_area_cb ( NULL, current_window_pass_along ); /* set correct size info now */
2643
1fb999d3
RN
2644 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
2645
50a14534
EB
2646 gtk_widget_show_all ( GTK_DIALOG(dialog)->vbox );
2647
2648 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
2649 {
2650 gtk_widget_hide ( GTK_WIDGET(dialog) );
2651 if ( one_image_only )
2652 save_image_file ( vw, fn,
2653 vw->draw_image_width = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(width_spin) ),
2654 vw->draw_image_height = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(height_spin) ),
2655 gtk_spin_button_get_value ( GTK_SPIN_BUTTON(zoom_spin) ), /* do not save this value, default is current zoom */
2656 vw->draw_image_save_as_png = gtk_toggle_button_get_active ( GTK_TOGGLE_BUTTON(png_radio) ) );
2657 else {
e5657444
RN
2658 // NB is in UTM mode ATM
2659 save_image_dir ( vw, fn,
50a14534
EB
2660 vw->draw_image_width = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(width_spin) ),
2661 vw->draw_image_height = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(height_spin) ),
2662 gtk_spin_button_get_value ( GTK_SPIN_BUTTON(zoom_spin) ), /* do not save this value, default is current zoom */
2663 vw->draw_image_save_as_png = gtk_toggle_button_get_active ( GTK_TOGGLE_BUTTON(png_radio) ),
2664 gtk_spin_button_get_value ( GTK_SPIN_BUTTON(tiles_width_spin) ),
2665 gtk_spin_button_get_value ( GTK_SPIN_BUTTON(tiles_height_spin) ) );
50a14534
EB
2666 }
2667 }
2668 gtk_widget_destroy ( GTK_WIDGET(dialog) );
2669}
2670
2671
e4afc73a 2672static void draw_to_image_file_cb ( GtkAction *a, VikWindow *vw )
50a14534 2673{
ca9e25af 2674 gchar *fn;
f2a1ca71 2675 if (!vw->save_img_dia) {
6e4a49aa
MA
2676 vw->save_img_dia = gtk_file_chooser_dialog_new (_("Save Image"),
2677 GTK_WINDOW(vw),
2678 GTK_FILE_CHOOSER_ACTION_SAVE,
2679 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
2680 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
2681 NULL);
f2a1ca71
QT
2682 gtk_window_set_transient_for ( GTK_WINDOW(vw->save_img_dia), GTK_WINDOW(vw) );
2683 gtk_window_set_destroy_with_parent ( GTK_WINDOW(vw->save_img_dia), TRUE );
2684 }
50a14534 2685
6e4a49aa 2686 while ( gtk_dialog_run ( GTK_DIALOG(vw->save_img_dia) ) == GTK_RESPONSE_ACCEPT )
50a14534 2687 {
6e4a49aa 2688 fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(vw->save_img_dia) );
d91e5f2b 2689 if ( g_file_test ( fn, G_FILE_TEST_EXISTS ) == FALSE || 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 ) ) )
50a14534 2690 {
50a14534
EB
2691 draw_to_image_file ( vw, fn, TRUE );
2692 break;
2693 }
fc759827
GB
2694 g_free(fn);
2695 fn = NULL;
50a14534 2696 }
f2a1ca71 2697 gtk_widget_hide ( vw->save_img_dia );
50a14534
EB
2698}
2699
e4afc73a 2700static void draw_to_image_dir_cb ( GtkAction *a, VikWindow *vw )
50a14534 2701{
6e4a49aa
MA
2702 gchar *fn = NULL;
2703
e5657444
RN
2704 if ( vik_viewport_get_coord_mode(vw->viking_vvp) != VIK_COORD_UTM ) {
2705 a_dialog_error_msg ( GTK_WINDOW(vw), _("You must be in UTM mode to use this feature") );
2706 return;
2707 }
2708
f2a1ca71 2709 if (!vw->save_img_dir_dia) {
6e4a49aa
MA
2710 vw->save_img_dir_dia = gtk_file_chooser_dialog_new (_("Choose a directory to hold images"),
2711 GTK_WINDOW(vw),
2712 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
2713 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
2714 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2715 NULL);
f2a1ca71
QT
2716 gtk_window_set_transient_for ( GTK_WINDOW(vw->save_img_dir_dia), GTK_WINDOW(vw) );
2717 gtk_window_set_destroy_with_parent ( GTK_WINDOW(vw->save_img_dir_dia), TRUE );
2718 }
6e4a49aa
MA
2719
2720 while ( gtk_dialog_run ( GTK_DIALOG(vw->save_img_dir_dia) ) == GTK_RESPONSE_ACCEPT )
50a14534 2721 {
6e4a49aa
MA
2722 fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(vw->save_img_dir_dia) );
2723 if ( fn )
50a14534 2724 {
50a14534 2725 draw_to_image_file ( vw, fn, FALSE );
6e4a49aa
MA
2726 g_free(fn);
2727 fn = NULL;
50a14534
EB
2728 break;
2729 }
2730 }
f2a1ca71 2731 gtk_widget_hide ( vw->save_img_dir_dia );
50a14534
EB
2732}
2733
9a995996 2734#if GTK_CHECK_VERSION(2,10,0)
42f34743
QT
2735static void print_cb ( GtkAction *a, VikWindow *vw )
2736{
2737 a_print(vw, vw->viking_vvp);
2738}
9a995996 2739#endif
42f34743 2740
50a14534 2741/* really a misnomer: changes coord mode (actual coordinates) AND/OR draw mode (viewport only) */
e4afc73a 2742static void window_change_coord_mode_cb ( GtkAction *old_a, GtkAction *a, VikWindow *vw )
50a14534 2743{
e4afc73a
EB
2744 VikViewportDrawMode drawmode;
2745 if (!strcmp(gtk_action_get_name(a), "ModeUTM")) {
2746 drawmode = VIK_VIEWPORT_DRAWMODE_UTM;
2747 }
d587678a
GB
2748 else if (!strcmp(gtk_action_get_name(a), "ModeLatLon")) {
2749 drawmode = VIK_VIEWPORT_DRAWMODE_LATLON;
2750 }
e4afc73a
EB
2751 else if (!strcmp(gtk_action_get_name(a), "ModeExpedia")) {
2752 drawmode = VIK_VIEWPORT_DRAWMODE_EXPEDIA;
2753 }
e4afc73a
EB
2754 else if (!strcmp(gtk_action_get_name(a), "ModeMercator")) {
2755 drawmode = VIK_VIEWPORT_DRAWMODE_MERCATOR;
2756 }
2757 else {
8dc8da82 2758 g_critical("Houston, we've had a problem.");
e4afc73a
EB
2759 return;
2760 }
2761
50a14534
EB
2762 if ( !vw->only_updating_coord_mode_ui )
2763 {
2764 VikViewportDrawMode olddrawmode = vik_viewport_get_drawmode ( vw->viking_vvp );
2765 if ( olddrawmode != drawmode )
2766 {
2767 /* this takes care of coord mode too */
2768 vik_viewport_set_drawmode ( vw->viking_vvp, drawmode );
2769 if ( drawmode == VIK_VIEWPORT_DRAWMODE_UTM ) {
2770 vik_layers_panel_change_coord_mode ( vw->viking_vlp, VIK_COORD_UTM );
2771 } else if ( olddrawmode == VIK_VIEWPORT_DRAWMODE_UTM ) {
2772 vik_layers_panel_change_coord_mode ( vw->viking_vlp, VIK_COORD_LATLON );
2773 }
2774 draw_update ( vw );
2775 }
2776 }
2777}
2778
35c7c0ba
EB
2779static void set_draw_scale ( GtkAction *a, VikWindow *vw )
2780{
48df6aa3 2781 GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ShowScale" );
1657065a
QT
2782 g_assert(check_box);
2783 gboolean state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box));
2784 vik_viewport_set_draw_scale ( vw->viking_vvp, state );
35c7c0ba
EB
2785 draw_update ( vw );
2786}
2787
c933487f
QT
2788static void set_draw_centermark ( GtkAction *a, VikWindow *vw )
2789{
48df6aa3 2790 GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ShowCenterMark" );
1657065a
QT
2791 g_assert(check_box);
2792 gboolean state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box));
2793 vik_viewport_set_draw_centermark ( vw->viking_vvp, state );
c933487f
QT
2794 draw_update ( vw );
2795}
2796
2afcef36
RN
2797static void set_draw_highlight ( GtkAction *a, VikWindow *vw )
2798{
2799 GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ShowHighlight" );
2800 g_assert(check_box);
2801 gboolean state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box));
2802 vik_viewport_set_draw_highlight ( vw->viking_vvp, state );
2803 draw_update ( vw );
2804}
2805
e4afc73a 2806static void set_bg_color ( GtkAction *a, VikWindow *vw )
50a14534 2807{
4c77d5e0 2808 GtkWidget *colorsd = gtk_color_selection_dialog_new ( _("Choose a background color") );
50a14534
EB
2809 GdkColor *color = vik_viewport_get_background_gdkcolor ( vw->viking_vvp );
2810 gtk_color_selection_set_previous_color ( GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(colorsd)->colorsel), color );
2811 gtk_color_selection_set_current_color ( GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(colorsd)->colorsel), color );
2812 if ( gtk_dialog_run ( GTK_DIALOG(colorsd) ) == GTK_RESPONSE_OK )
2813 {
2814 gtk_color_selection_get_current_color ( GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(colorsd)->colorsel), color );
2815 vik_viewport_set_background_gdkcolor ( vw->viking_vvp, color );
2816 draw_update ( vw );
2817 }
2818 g_free ( color );
2819 gtk_widget_destroy ( colorsd );
2820}
2821
480fb7e1
RN
2822static void set_highlight_color ( GtkAction *a, VikWindow *vw )
2823{
2824 GtkWidget *colorsd = gtk_color_selection_dialog_new ( _("Choose a track highlight color") );
2825 GdkColor *color = vik_viewport_get_highlight_gdkcolor ( vw->viking_vvp );
2826 gtk_color_selection_set_previous_color ( GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(colorsd)->colorsel), color );
2827 gtk_color_selection_set_current_color ( GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(colorsd)->colorsel), color );
2828 if ( gtk_dialog_run ( GTK_DIALOG(colorsd) ) == GTK_RESPONSE_OK )
2829 {
2830 gtk_color_selection_get_current_color ( GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(colorsd)->colorsel), color );
2831 vik_viewport_set_highlight_gdkcolor ( vw->viking_vvp, color );
2832 draw_update ( vw );
2833 }
2834 g_free ( color );
2835 gtk_widget_destroy ( colorsd );
2836}
2837
941aa6e9
AF
2838
2839
2840/***********************************************************************************************
2841 ** GUI Creation
2842 ***********************************************************************************************/
2843
e4afc73a 2844static GtkActionEntry entries[] = {
5515e2d3
JJ
2845 { "File", NULL, N_("_File"), 0, 0, 0 },
2846 { "Edit", NULL, N_("_Edit"), 0, 0, 0 },
2847 { "View", NULL, N_("_View"), 0, 0, 0 },
48df6aa3 2848 { "SetShow", NULL, N_("_Show"), 0, 0, 0 },
5515e2d3
JJ
2849 { "SetZoom", NULL, N_("_Zoom"), 0, 0, 0 },
2850 { "SetPan", NULL, N_("_Pan"), 0, 0, 0 },
2851 { "Layers", NULL, N_("_Layers"), 0, 0, 0 },
2852 { "Tools", NULL, N_("_Tools"), 0, 0, 0 },
92806042 2853 { "Exttools", NULL, N_("_Webtools"), 0, 0, 0 },
5515e2d3
JJ
2854 { "Help", NULL, N_("_Help"), 0, 0, 0 },
2855
2856 { "New", GTK_STOCK_NEW, N_("_New"), "<control>N", N_("New file"), (GCallback)newwindow_cb },
06526f88
RN
2857 { "Open", GTK_STOCK_OPEN, N_("_Open..."), "<control>O", N_("Open a file"), (GCallback)load_file },
2858 { "OpenRecentFile", NULL, N_("Open _Recent File"), NULL, NULL, (GCallback)NULL },
2859 { "Append", GTK_STOCK_ADD, N_("Append _File..."), NULL, N_("Append data from a different file"), (GCallback)load_file },
d6de71f9 2860 { "Acquire", GTK_STOCK_GO_DOWN, N_("A_cquire"), NULL, NULL, (GCallback)NULL },
06526f88 2861 { "AcquireGPS", NULL, N_("From _GPS..."), NULL, N_("Transfer data from a GPS device"), (GCallback)acquire_from_gps },
31349009 2862 { "AcquireGPSBabel", NULL, N_("Import File With GPS_Babel..."), NULL, N_("Import file via GPSBabel converter"), (GCallback)acquire_from_file },
ebf1bd39 2863#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS
06526f88 2864 { "AcquireGoogle", NULL, N_("Google _Directions..."), NULL, N_("Get driving directions from Google"), (GCallback)acquire_from_google },
ebf1bd39 2865#endif
9c4555df
GB
2866#ifdef VIK_CONFIG_OPENSTREETMAP
2867 { "AcquireOSM", NULL, N_("_OSM Traces..."), NULL, N_("Get traces from OpenStreetMap"), (GCallback)acquire_from_osm },
2868#endif
1ef9e637 2869#ifdef VIK_CONFIG_GEOCACHES
06526f88 2870 { "AcquireGC", NULL, N_("Geo_caches..."), NULL, N_("Get Geocaches from geocaching.com"), (GCallback)acquire_from_gc },
f75d0233
RN
2871#endif
2872#ifdef VIK_CONFIG_GEOTAG
2873 { "AcquireGeotag", NULL, N_("From Geotagged _Images..."), NULL, N_("Create waypoints from geotagged images"), (GCallback)acquire_from_geotag },
1ef9e637 2874#endif
5515e2d3 2875 { "Save", GTK_STOCK_SAVE, N_("_Save"), "<control>S", N_("Save the file"), (GCallback)save_file },
06526f88
RN
2876 { "SaveAs", GTK_STOCK_SAVE_AS, N_("Save _As..."), NULL, N_("Save the file under different name"), (GCallback)save_file_as },
2877 { "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 },
2878 { "GenImgDir", GTK_STOCK_DND_MULTIPLE, N_("Generate _Directory of Images..."), NULL, N_("FIXME:IMGDIR"), (GCallback)draw_to_image_dir_cb },
9a995996
EB
2879
2880#if GTK_CHECK_VERSION(2,10,0)
5515e2d3 2881 { "Print", GTK_STOCK_PRINT, N_("_Print..."), NULL, N_("Print maps"), (GCallback)print_cb },
9a995996
EB
2882#endif
2883
5515e2d3
JJ
2884 { "Exit", GTK_STOCK_QUIT, N_("E_xit"), "<control>W", N_("Exit the program"), (GCallback)window_close },
2885 { "SaveExit", GTK_STOCK_QUIT, N_("Save and Exit"), NULL, N_("Save and Exit the program"), (GCallback)save_file_and_exit },
2886
5210c3d3 2887 { "GotoDefaultLocation", GTK_STOCK_HOME, N_("Go to the _Default Location"), NULL, N_("Go to the default location"), (GCallback)goto_default_location },
cbd293bb 2888 { "GotoSearch", GTK_STOCK_JUMP_TO, N_("Go to _Location..."), NULL, N_("Go to address/place using text search"), (GCallback)goto_address },
402fee6c 2889 { "GotoLL", GTK_STOCK_JUMP_TO, N_("_Go to Lat/Lon..."), NULL, N_("Go to arbitrary lat/lon coordinate"), (GCallback)draw_goto_cb },
150618fe 2890 { "GotoUTM", GTK_STOCK_JUMP_TO, N_("Go to UTM..."), NULL, N_("Go to arbitrary UTM coordinate"), (GCallback)draw_goto_cb },
480fb7e1 2891 { "SetHLColor",GTK_STOCK_SELECT_COLOR, N_("Set _Highlight Color..."), NULL, NULL, (GCallback)set_highlight_color },
cbd293bb 2892 { "SetBGColor",GTK_STOCK_SELECT_COLOR, N_("Set Bac_kground Color..."), NULL, NULL, (GCallback)set_bg_color },
5515e2d3
JJ
2893 { "ZoomIn", GTK_STOCK_ZOOM_IN, N_("Zoom _In"), "<control>plus", NULL, (GCallback)draw_zoom_cb },
2894 { "ZoomOut", GTK_STOCK_ZOOM_OUT, N_("Zoom _Out"), "<control>minus", NULL, (GCallback)draw_zoom_cb },
22c15481 2895 { "ZoomTo", GTK_STOCK_ZOOM_FIT, N_("Zoom _To..."), "<control>Z", NULL, (GCallback)zoom_to_cb },
5515e2d3
JJ
2896 { "Zoom0.25", NULL, N_("0.25"), NULL, NULL, (GCallback)draw_zoom_cb },
2897 { "Zoom0.5", NULL, N_("0.5"), NULL, NULL, (GCallback)draw_zoom_cb },
2898 { "Zoom1", NULL, N_("1"), NULL, NULL, (GCallback)draw_zoom_cb },
2899 { "Zoom2", NULL, N_("2"), NULL, NULL, (GCallback)draw_zoom_cb },
2900 { "Zoom4", NULL, N_("4"), NULL, NULL, (GCallback)draw_zoom_cb },
2901 { "Zoom8", NULL, N_("8"), NULL, NULL, (GCallback)draw_zoom_cb },
2902 { "Zoom16", NULL, N_("16"), NULL, NULL, (GCallback)draw_zoom_cb },
2903 { "Zoom32", NULL, N_("32"), NULL, NULL, (GCallback)draw_zoom_cb },
2904 { "Zoom64", NULL, N_("64"), NULL, NULL, (GCallback)draw_zoom_cb },
2905 { "Zoom128", NULL, N_("128"), NULL, NULL, (GCallback)draw_zoom_cb },
4344546e
RN
2906 { "Zoom256", NULL, N_("256"), NULL, NULL, (GCallback)draw_zoom_cb },
2907 { "Zoom512", NULL, N_("512"), NULL, NULL, (GCallback)draw_zoom_cb },
2908 { "Zoom1024", NULL, N_("1024"), NULL, NULL, (GCallback)draw_zoom_cb },
2909 { "Zoom2048", NULL, N_("2048"), NULL, NULL, (GCallback)draw_zoom_cb },
2910 { "Zoom4096", NULL, N_("4096"), NULL, NULL, (GCallback)draw_zoom_cb },
2911 { "Zoom8192", NULL, N_("8192"), NULL, NULL, (GCallback)draw_zoom_cb },
2912 { "Zoom16384", NULL, N_("16384"), NULL, NULL, (GCallback)draw_zoom_cb },
2913 { "Zoom32768", NULL, N_("32768"), NULL, NULL, (GCallback)draw_zoom_cb },
cbd293bb
RN
2914 { "PanNorth", NULL, N_("Pan _North"), "<control>Up", NULL, (GCallback)draw_pan_cb },
2915 { "PanEast", NULL, N_("Pan _East"), "<control>Right", NULL, (GCallback)draw_pan_cb },
2916 { "PanSouth", NULL, N_("Pan _South"), "<control>Down", NULL, (GCallback)draw_pan_cb },
2917 { "PanWest", NULL, N_("Pan _West"), "<control>Left", NULL, (GCallback)draw_pan_cb },
5515e2d3
JJ
2918 { "BGJobs", GTK_STOCK_EXECUTE, N_("Background _Jobs"), NULL, NULL, (GCallback)a_background_show_window },
2919
2920 { "Cut", GTK_STOCK_CUT, N_("Cu_t"), NULL, NULL, (GCallback)menu_cut_layer_cb },
2921 { "Copy", GTK_STOCK_COPY, N_("_Copy"), NULL, NULL, (GCallback)menu_copy_layer_cb },
2922 { "Paste", GTK_STOCK_PASTE, N_("_Paste"), NULL, NULL, (GCallback)menu_paste_layer_cb },
2923 { "Delete", GTK_STOCK_DELETE, N_("_Delete"), NULL, NULL, (GCallback)menu_delete_layer_cb },
2924 { "DeleteAll", NULL, N_("Delete All"), NULL, NULL, (GCallback)clear_cb },
06526f88 2925 { "MapCacheFlush",NULL, N_("_Flush Map Cache"), NULL, NULL, (GCallback)mapcache_flush_cb },
5210c3d3 2926 { "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 2927 { "Preferences",GTK_STOCK_PREFERENCES, N_("_Preferences"), NULL, NULL, (GCallback)preferences_cb },
5515e2d3
JJ
2928 { "Properties",GTK_STOCK_PROPERTIES, N_("_Properties"), NULL, NULL, (GCallback)menu_properties_cb },
2929
5ff75d1e 2930 { "HelpEntry", GTK_STOCK_HELP, N_("_Help"), "F1", NULL, (GCallback)help_help_cb },
5515e2d3 2931 { "About", GTK_STOCK_ABOUT, N_("_About"), NULL, NULL, (GCallback)help_about_cb },
e4afc73a
EB
2932};
2933
2934/* Radio items */
d587678a 2935/* FIXME use VIEWPORT_DRAWMODE values */
e4afc73a 2936static GtkRadioActionEntry mode_entries[] = {
5515e2d3
JJ
2937 { "ModeUTM", NULL, N_("_UTM Mode"), "<control>u", NULL, 0 },
2938 { "ModeExpedia", NULL, N_("_Expedia Mode"), "<control>e", NULL, 1 },
ac16c140 2939 { "ModeMercator", NULL, N_("_Mercator Mode"), "<control>m", NULL, 4 },
bd5e571a 2940 { "ModeLatLon", NULL, N_("Lat_/Lon Mode"), "<control>l", NULL, 5 },
50a14534
EB
2941};
2942
35c7c0ba 2943static GtkToggleActionEntry toggle_entries[] = {
48df6aa3 2944 { "ShowScale", NULL, N_("Show _Scale"), "F5", N_("Show Scale"), (GCallback)set_draw_scale, TRUE },
cbd293bb 2945 { "ShowCenterMark", NULL, N_("Show _Center Mark"), "F6", N_("Show Center Mark"), (GCallback)set_draw_centermark, TRUE },
2afcef36 2946 { "ShowHighlight", GTK_STOCK_UNDERLINE, N_("Show _Highlight"), "F7", N_("Show Highlight"), (GCallback)set_draw_highlight, TRUE },
cbd293bb 2947 { "FullScreen", GTK_STOCK_FULLSCREEN, N_("_Full Screen"), "F11", N_("Activate full screen mode"), (GCallback)full_screen_cb, FALSE },
48df6aa3 2948 { "ViewSidePanel", GTK_STOCK_INDEX, N_("Show Side _Panel"), "F9", N_("Show Side Panel"), (GCallback)view_side_panel_cb, TRUE },
a459ee10 2949 { "ViewStatusBar", NULL, N_("Show Status_bar"), "F12", N_("Show Statusbar"), (GCallback)view_statusbar_cb, TRUE },
48df6aa3
RN
2950 { "ViewToolbar", NULL, N_("Show _Toolbar"), "F3", N_("Show Toolbar"), (GCallback)view_toolbar_cb, TRUE },
2951 { "ViewMainMenu", NULL, N_("Show _Menu"), "F4", N_("Show Menu"), (GCallback)view_main_menu_cb, TRUE },
35c7c0ba
EB
2952};
2953
a527cfff 2954#include "menu.xml.h"
e4afc73a 2955static void window_create_ui( VikWindow *window )
50a14534 2956{
e4afc73a
EB
2957 GtkUIManager *uim;
2958 GtkActionGroup *action_group;
50a14534 2959 GtkAccelGroup *accel_group;
e4afc73a 2960 GError *error;
e4afc73a
EB
2961 guint i, j, mid;
2962 GtkIconFactory *icon_factory;
2963 GtkIconSet *icon_set;
e4afc73a
EB
2964 GtkRadioActionEntry *tools = NULL, *radio;
2965 guint ntools;
2966
2967 uim = gtk_ui_manager_new ();
2968 window->uim = uim;
2969
9593a4c9
EB
2970 toolbox_add_tool(window->vt, &ruler_tool, TOOL_LAYER_TYPE_NONE);
2971 toolbox_add_tool(window->vt, &zoom_tool, TOOL_LAYER_TYPE_NONE);
576cbd17 2972 toolbox_add_tool(window->vt, &pan_tool, TOOL_LAYER_TYPE_NONE);
a47bfefa 2973 toolbox_add_tool(window->vt, &select_tool, TOOL_LAYER_TYPE_NONE);
941aa6e9 2974
e4afc73a 2975 error = NULL;
a527cfff 2976 if (!(mid = gtk_ui_manager_add_ui_from_string (uim, menu_xml, -1, &error))) {
e4afc73a
EB
2977 g_error_free (error);
2978 exit (1);
2979 }
2980
2981 action_group = gtk_action_group_new ("MenuActions");
5515e2d3 2982 gtk_action_group_set_translation_domain(action_group, PACKAGE_NAME);
e4afc73a 2983 gtk_action_group_add_actions (action_group, entries, G_N_ELEMENTS (entries), window);
35c7c0ba 2984 gtk_action_group_add_toggle_actions (action_group, toggle_entries, G_N_ELEMENTS (toggle_entries), window);
6a9ff0ee 2985 gtk_action_group_add_radio_actions (action_group, mode_entries, G_N_ELEMENTS (mode_entries), 4, (GCallback)window_change_coord_mode_cb, window);
e4afc73a
EB
2986
2987 icon_factory = gtk_icon_factory_new ();
ee36ac4f 2988 gtk_icon_factory_add_default (icon_factory);
e4afc73a
EB
2989
2990 register_vik_icons(icon_factory);
2991
79dce0cb
RN
2992 // Copy the tool RadioActionEntries out of the main Window structure into an extending array 'tools'
2993 // so that it can be applied to the UI in one action group add function call below
e4afc73a 2994 ntools = 0;
79dce0cb 2995 for (i=0; i<window->vt->n_tools; i++) {
e4afc73a
EB
2996 tools = g_renew(GtkRadioActionEntry, tools, ntools+1);
2997 radio = &tools[ntools];
2998 ntools++;
79dce0cb 2999 *radio = window->vt->tools[i].ti.radioActionEntry;
e4afc73a 3000 radio->value = ntools;
79dce0cb 3001 }
e4afc73a
EB
3002
3003 for (i=0; i<VIK_LAYER_NUM_TYPES; i++) {
3004 GtkActionEntry action;
3005 gtk_ui_manager_add_ui(uim, mid, "/ui/MainMenu/Layers/",
3006 vik_layer_get_interface(i)->name,
3007 vik_layer_get_interface(i)->name,
3008 GTK_UI_MANAGER_MENUITEM, FALSE);
3009
3010 icon_set = gtk_icon_set_new_from_pixbuf (gdk_pixbuf_from_pixdata (vik_layer_get_interface(i)->icon, FALSE, NULL ));
3011 gtk_icon_factory_add (icon_factory, vik_layer_get_interface(i)->name, icon_set);
3012 gtk_icon_set_unref (icon_set);
3013
3014 action.name = vik_layer_get_interface(i)->name;
3015 action.stock_id = vik_layer_get_interface(i)->name;
da12e3d1 3016 action.label = g_strdup_printf( _("New _%s Layer"), vik_layer_get_interface(i)->name);
75078768 3017 action.accelerator = vik_layer_get_interface(i)->accelerator;
e4afc73a
EB
3018 action.tooltip = NULL;
3019 action.callback = (GCallback)menu_addlayer_cb;
3020 gtk_action_group_add_actions(action_group, &action, 1, window);
3021
3022 if ( vik_layer_get_interface(i)->tools_count ) {
3023 gtk_ui_manager_add_ui(uim, mid, "/ui/MainMenu/Tools/", vik_layer_get_interface(i)->name, NULL, GTK_UI_MANAGER_SEPARATOR, FALSE);
3024 gtk_ui_manager_add_ui(uim, mid, "/ui/MainToolbar/ToolItems/", vik_layer_get_interface(i)->name, NULL, GTK_UI_MANAGER_SEPARATOR, FALSE);
3025 }
3026
79dce0cb 3027 // Further tool copying for to apply to the UI, also apply menu UI setup
e4afc73a
EB
3028 for ( j = 0; j < vik_layer_get_interface(i)->tools_count; j++ ) {
3029 tools = g_renew(GtkRadioActionEntry, tools, ntools+1);
3030 radio = &tools[ntools];
3031 ntools++;
3032
e4afc73a 3033 gtk_ui_manager_add_ui(uim, mid, "/ui/MainMenu/Tools",
79dce0cb
RN
3034 vik_layer_get_interface(i)->tools[j].radioActionEntry.label,
3035 vik_layer_get_interface(i)->tools[j].radioActionEntry.name,
e4afc73a
EB
3036 GTK_UI_MANAGER_MENUITEM, FALSE);
3037 gtk_ui_manager_add_ui(uim, mid, "/ui/MainToolbar/ToolItems",
79dce0cb
RN
3038 vik_layer_get_interface(i)->tools[j].radioActionEntry.label,
3039 vik_layer_get_interface(i)->tools[j].radioActionEntry.name,
e4afc73a
EB
3040 GTK_UI_MANAGER_TOOLITEM, FALSE);
3041
9593a4c9 3042 toolbox_add_tool(window->vt, &(vik_layer_get_interface(i)->tools[j]), i);
941aa6e9 3043
79dce0cb
RN
3044 *radio = vik_layer_get_interface(i)->tools[j].radioActionEntry;
3045 // Overwrite with actual number to use
e4afc73a
EB
3046 radio->value = ntools;
3047 }
3048 }
ee36ac4f 3049 g_object_unref (icon_factory);
50a14534 3050
e4afc73a
EB
3051 gtk_action_group_add_radio_actions(action_group, tools, ntools, 0, (GCallback)menu_tool_cb, window);
3052 g_free(tools);
50a14534 3053
e4afc73a 3054 gtk_ui_manager_insert_action_group (uim, action_group, 0);
50a14534 3055
79845167
QT
3056 for (i=0; i<VIK_LAYER_NUM_TYPES; i++) {
3057 for ( j = 0; j < vik_layer_get_interface(i)->tools_count; j++ ) {
3058 GtkAction *action = gtk_action_group_get_action(action_group,
79dce0cb 3059 vik_layer_get_interface(i)->tools[j].radioActionEntry.name);
79845167
QT
3060 g_object_set(action, "sensitive", FALSE, NULL);
3061 }
3062 }
3063 window->action_group = action_group;
3064
e4afc73a
EB
3065 accel_group = gtk_ui_manager_get_accel_group (uim);
3066 gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
3067 gtk_ui_manager_ensure_update (uim);
13505702
GB
3068
3069 setup_recent_files(window);
e4afc73a 3070}
50a14534 3071
50a14534 3072
79dce0cb
RN
3073// TODO - add method to add tool icons defined from outside this file
3074// and remove the reverse dependency on icon definition from this file
e4afc73a 3075static struct {
4bd45256 3076 const GdkPixdata *data;
e4afc73a
EB
3077 gchar *stock_id;
3078} stock_icons[] = {
79dce0cb 3079 { &mover_22_pixbuf, "vik-icon-pan" },
5bfafde9
GB
3080 { &zoom_18_pixbuf, "vik-icon-zoom" },
3081 { &ruler_18_pixbuf, "vik-icon-ruler" },
a47bfefa 3082 { &select_18_pixbuf, "vik-icon-select" },
79dce0cb
RN
3083 { &begintr_18_pixbuf, "vik-icon-Begin Track" },
3084 { &route_finder_18_pixbuf, "vik-icon-Route Finder" },
06a6af5b 3085 { &demdl_18_pixbuf, "vik-icon-DEM Download" },
79dce0cb
RN
3086 { &showpic_18_pixbuf, "vik-icon-Show Picture" },
3087 { &addtr_18_pixbuf, "vik-icon-Create Track" },
3088 { &edtr_18_pixbuf, "vik-icon-Edit Trackpoint" },
3089 { &addwp_18_pixbuf, "vik-icon-Create Waypoint" },
3090 { &edwp_18_pixbuf, "vik-icon-Edit Waypoint" },
3091 { &geozoom_18_pixbuf, "vik-icon-Georef Zoom Tool" },
3092 { &geomove_18_pixbuf, "vik-icon-Georef Move Map" },
3093 { &mapdl_18_pixbuf, "vik-icon-Maps Download" },
e4afc73a
EB
3094};
3095
e4afc73a
EB
3096static gint n_stock_icons = G_N_ELEMENTS (stock_icons);
3097
3098static void
3099register_vik_icons (GtkIconFactory *icon_factory)
3100{
3101 GtkIconSet *icon_set;
e4afc73a 3102 gint i;
e4afc73a
EB
3103
3104 for (i = 0; i < n_stock_icons; i++) {
4bd45256
EB
3105 icon_set = gtk_icon_set_new_from_pixbuf (gdk_pixbuf_from_pixdata (
3106 stock_icons[i].data, FALSE, NULL ));
e4afc73a
EB
3107 gtk_icon_factory_add (icon_factory, stock_icons[i].stock_id, icon_set);
3108 gtk_icon_set_unref (icon_set);
3109 }
50a14534 3110}
bce3a7b0 3111
9d7c24ed
RN
3112gpointer vik_window_get_selected_trw_layer ( VikWindow *vw )
3113{
3114 return vw->selected_vtl;
3115}
3116
3117void vik_window_set_selected_trw_layer ( VikWindow *vw, gpointer vtl )
3118{
113c74f6
RN
3119 vw->selected_vtl = vtl;
3120 vw->containing_vtl = vtl;
9d7c24ed
RN
3121 /* Clear others */
3122 vw->selected_track = NULL;
3123 vw->selected_tracks = NULL;
3124 vw->selected_waypoint = NULL;
3125 vw->selected_waypoints = NULL;
04f36d92
RN
3126 // Set highlight thickness
3127 vik_viewport_set_highlight_thickness ( vw->viking_vvp, vik_trw_layer_get_property_tracks_line_thickness (vw->containing_vtl) );
9d7c24ed
RN
3128}
3129
3130gpointer vik_window_get_selected_tracks ( VikWindow *vw )
3131{
3132 return vw->selected_tracks;
3133}
3134
113c74f6 3135void vik_window_set_selected_tracks ( VikWindow *vw, gpointer gl, gpointer vtl )
9d7c24ed
RN
3136{
3137 vw->selected_tracks = gl;
113c74f6 3138 vw->containing_vtl = vtl;
9d7c24ed
RN
3139 /* Clear others */
3140 vw->selected_vtl = NULL;
3141 vw->selected_track = NULL;
3142 vw->selected_waypoint = NULL;
3143 vw->selected_waypoints = NULL;
04f36d92
RN
3144 // Set highlight thickness
3145 vik_viewport_set_highlight_thickness ( vw->viking_vvp, vik_trw_layer_get_property_tracks_line_thickness (vw->containing_vtl) );
9d7c24ed
RN
3146}
3147
3148gpointer vik_window_get_selected_track ( VikWindow *vw )
3149{
3150 return vw->selected_track;
3151}
3152
43f2e1da 3153void vik_window_set_selected_track ( VikWindow *vw, gpointer *vt, gpointer vtl, gpointer name )
9d7c24ed
RN
3154{
3155 vw->selected_track = vt;
113c74f6 3156 vw->containing_vtl = vtl;
9d7c24ed
RN
3157 /* Clear others */
3158 vw->selected_vtl = NULL;
3159 vw->selected_tracks = NULL;
3160 vw->selected_waypoint = NULL;
3161 vw->selected_waypoints = NULL;
04f36d92
RN
3162 // Set highlight thickness
3163 vik_viewport_set_highlight_thickness ( vw->viking_vvp, vik_trw_layer_get_property_tracks_line_thickness (vw->containing_vtl) );
9d7c24ed 3164}
04f36d92 3165
9d7c24ed
RN
3166gpointer vik_window_get_selected_waypoints ( VikWindow *vw )
3167{
3168 return vw->selected_waypoints;
3169}
3170
113c74f6 3171void vik_window_set_selected_waypoints ( VikWindow *vw, gpointer gl, gpointer vtl )
9d7c24ed
RN
3172{
3173 vw->selected_waypoints = gl;
113c74f6 3174 vw->containing_vtl = vtl;
9d7c24ed
RN
3175 /* Clear others */
3176 vw->selected_vtl = NULL;
3177 vw->selected_track = NULL;
3178 vw->selected_tracks = NULL;
3179 vw->selected_waypoint = NULL;
3180}
3181
3182gpointer vik_window_get_selected_waypoint ( VikWindow *vw )
3183{
3184 return vw->selected_waypoint;
3185}
3186
43f2e1da 3187void vik_window_set_selected_waypoint ( VikWindow *vw, gpointer *vwp, gpointer vtl, gpointer name )
9d7c24ed
RN
3188{
3189 vw->selected_waypoint = vwp;
113c74f6 3190 vw->containing_vtl = vtl;
9d7c24ed
RN
3191 /* Clear others */
3192 vw->selected_vtl = NULL;
3193 vw->selected_track = NULL;
3194 vw->selected_tracks = NULL;
3195 vw->selected_waypoints = NULL;
3196}
3197
3198gboolean vik_window_clear_highlight ( VikWindow *vw )
3199{
3200 gboolean need_redraw = FALSE;
3201 if ( vw->selected_vtl != NULL ) {
3202 vw->selected_vtl = NULL;
3203 need_redraw = TRUE;
3204 }
3205 if ( vw->selected_track != NULL ) {
3206 vw->selected_track = NULL;
3207 need_redraw = TRUE;
3208 }
3209 if ( vw->selected_tracks != NULL ) {
3210 vw->selected_tracks = NULL;
3211 need_redraw = TRUE;
3212 }
3213 if ( vw->selected_waypoint != NULL ) {
3214 vw->selected_waypoint = NULL;
3215 need_redraw = TRUE;
3216 }
3217 if ( vw->selected_waypoints != NULL ) {
3218 vw->selected_waypoints = NULL;
3219 need_redraw = TRUE;
3220 }
3221 return need_redraw;
3222}