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