]> git.street.me.uk Git - andy/viking.git/blame - src/vikwindow.c
Disable direction finding via Google services as they no longer support KML output.
[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
ebf1bd39 2197#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS
7b3479e3
EB
2198static void acquire_from_google ( GtkAction *a, VikWindow *vw )
2199{
2200 a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_google_interface );
1d1bc3c1 2201}
ebf1bd39 2202#endif
1d1bc3c1 2203
9c4555df
GB
2204#ifdef VIK_CONFIG_OPENSTREETMAP
2205static void acquire_from_osm ( GtkAction *a, VikWindow *vw )
2206{
2207 a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_osm_interface );
2208}
2209#endif
2210
1ef9e637 2211#ifdef VIK_CONFIG_GEOCACHES
3333c069
EB
2212static void acquire_from_gc ( GtkAction *a, VikWindow *vw )
2213{
2214 a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_gc_interface );
2215}
1ef9e637 2216#endif
3333c069 2217
f75d0233
RN
2218#ifdef VIK_CONFIG_GEOTAG
2219static void acquire_from_geotag ( GtkAction *a, VikWindow *vw )
2220{
2221 vik_datasource_geotag_interface.mode = VIK_DATASOURCE_CREATENEWLAYER;
2222 a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_geotag_interface );
2223}
2224#endif
2225
5210c3d3
GB
2226static void goto_default_location( GtkAction *a, VikWindow *vw)
2227{
2228 struct LatLon ll;
2229 ll.lat = a_vik_get_default_lat();
2230 ll.lon = a_vik_get_default_long();
2231 vik_viewport_set_center_latlon(vw->viking_vvp, &ll);
2232 vik_layers_panel_emit_update(vw->viking_vlp);
2233}
2234
2235
369126f3
QT
2236static void goto_address( GtkAction *a, VikWindow *vw)
2237{
34e71b99 2238 a_vik_goto(vw, vw->viking_vlp, vw->viking_vvp);
369126f3
QT
2239}
2240
7c259702
JJ
2241static void mapcache_flush_cb ( GtkAction *a, VikWindow *vw )
2242{
2243 a_mapcache_flush();
2244}
2245
17a1f8f9
EB
2246static void preferences_cb ( GtkAction *a, VikWindow *vw )
2247{
9be0449f
RN
2248 gboolean wp_icon_size = a_vik_get_use_large_waypoint_icons();
2249
17a1f8f9 2250 a_preferences_show_window ( GTK_WINDOW(vw) );
9be0449f
RN
2251
2252 // Delete icon indexing 'cache' and so automatically regenerates with the new setting when changed
2253 if (wp_icon_size != a_vik_get_use_large_waypoint_icons())
2254 clear_garmin_icon_syms ();
2255
6f9336aa 2256 draw_update ( vw );
17a1f8f9
EB
2257}
2258
5210c3d3
GB
2259static void default_location_cb ( GtkAction *a, VikWindow *vw )
2260{
2261 /* Simplistic repeat of preference setting
2262 Only the name & type are important for setting the preference via this 'external' way */
2263 VikLayerParam pref_lat[] = {
2264 { VIKING_PREFERENCES_NAMESPACE "default_latitude",
2265 VIK_LAYER_PARAM_DOUBLE,
2266 VIK_LOCATION_LAT,
2267 NULL,
2268 VIK_LAYER_WIDGET_SPINBUTTON,
2269 NULL,
2270 NULL },
2271 };
2272 VikLayerParam pref_lon[] = {
2273 { VIKING_PREFERENCES_NAMESPACE "default_longitude",
2274 VIK_LAYER_PARAM_DOUBLE,
2275 VIK_LOCATION_LONG,
2276 NULL,
2277 VIK_LAYER_WIDGET_SPINBUTTON,
2278 NULL,
2279 NULL },
2280 };
2281
2282 /* Get current center */
2283 struct LatLon ll;
2284 vik_coord_to_latlon ( vik_viewport_get_center ( vw->viking_vvp ), &ll );
2285
2286 /* Apply to preferences */
2287 VikLayerParamData vlp_data;
2288 vlp_data.d = ll.lat;
2289 a_preferences_run_setparam (vlp_data, pref_lat);
2290 vlp_data.d = ll.lon;
2291 a_preferences_run_setparam (vlp_data, pref_lon);
2292 /* Remember to save */
2293 a_preferences_save_to_file();
2294}
2295
e4afc73a 2296static void clear_cb ( GtkAction *a, VikWindow *vw )
50a14534
EB
2297{
2298 vik_layers_panel_clear ( vw->viking_vlp );
2299 window_set_filename ( vw, NULL );
2300 draw_update ( vw );
2301}
2302
e4afc73a 2303static void window_close ( GtkAction *a, VikWindow *vw )
50a14534
EB
2304{
2305 if ( ! delete_event ( vw ) )
2306 gtk_widget_destroy ( GTK_WIDGET(vw) );
2307}
2308
2bf7cadd
QT
2309static gboolean save_file_and_exit ( GtkAction *a, VikWindow *vw )
2310{
7bb60307 2311 if (save_file( NULL, vw)) {
2bf7cadd 2312 window_close( NULL, vw);
7bb60307
QT
2313 return(TRUE);
2314 }
2bf7cadd
QT
2315 else
2316 return(FALSE);
2317}
2318
e4afc73a 2319static void zoom_to_cb ( GtkAction *a, VikWindow *vw )
50a14534
EB
2320{
2321 gdouble xmpp = vik_viewport_get_xmpp ( vw->viking_vvp ), ympp = vik_viewport_get_ympp ( vw->viking_vvp );
2322 if ( a_dialog_custom_zoom ( GTK_WINDOW(vw), &xmpp, &ympp ) )
2323 {
2324 vik_viewport_set_xmpp ( vw->viking_vvp, xmpp );
2325 vik_viewport_set_ympp ( vw->viking_vvp, ympp );
2326 draw_update ( vw );
2327 }
2328}
2329
2330static void save_image_file ( VikWindow *vw, const gchar *fn, guint w, guint h, gdouble zoom, gboolean save_as_png )
2331{
2332 /* more efficient way: stuff draws directly to pixbuf (fork viewport) */
2333 GdkPixbuf *pixbuf_to_save;
2334 gdouble old_xmpp, old_ympp;
2335 GError *error = NULL;
2336
2337 /* backup old zoom & set new */
2338 old_xmpp = vik_viewport_get_xmpp ( vw->viking_vvp );
2339 old_ympp = vik_viewport_get_ympp ( vw->viking_vvp );
2340 vik_viewport_set_zoom ( vw->viking_vvp, zoom );
2341
2342 /* reset width and height: */
2343 vik_viewport_configure_manually ( vw->viking_vvp, w, h );
2344
2345 /* draw all layers */
2346 draw_redraw ( vw );
2347
2348 /* save buffer as file. */
2349 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);
2350 gdk_pixbuf_save ( pixbuf_to_save, fn, save_as_png ? "png" : "jpeg", &error, NULL );
2351 if (error)
2352 {
7742da66 2353 g_warning("Unable to write to file %s: %s", fn, error->message );
50a14534
EB
2354 g_error_free (error);
2355 }
2356 g_object_unref ( G_OBJECT(pixbuf_to_save) );
2357
2358 /* pretend like nothing happened ;) */
2359 vik_viewport_set_xmpp ( vw->viking_vvp, old_xmpp );
2360 vik_viewport_set_ympp ( vw->viking_vvp, old_ympp );
2361 vik_viewport_configure ( vw->viking_vvp );
2362 draw_update ( vw );
2363}
2364
2365static 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 )
2366{
2367 gulong size = sizeof(gchar) * (strlen(fn) + 15);
2368 gchar *name_of_file = g_malloc ( size );
2369 guint x = 1, y = 1;
2370 struct UTM utm_orig, utm;
2371
2372 /* *** copied from above *** */
2373 GdkPixbuf *pixbuf_to_save;
2374 gdouble old_xmpp, old_ympp;
2375 GError *error = NULL;
2376
2377 /* backup old zoom & set new */
2378 old_xmpp = vik_viewport_get_xmpp ( vw->viking_vvp );
2379 old_ympp = vik_viewport_get_ympp ( vw->viking_vvp );
2380 vik_viewport_set_zoom ( vw->viking_vvp, zoom );
2381
2382 /* reset width and height: do this only once for all images (same size) */
2383 vik_viewport_configure_manually ( vw->viking_vvp, w, h );
2384 /* *** end copy from above *** */
2385
2386 g_assert ( vik_viewport_get_coord_mode ( vw->viking_vvp ) == VIK_COORD_UTM );
2387
f83131b9 2388 g_mkdir(fn,0777);
50a14534
EB
2389
2390 utm_orig = *((const struct UTM *)vik_viewport_get_center ( vw->viking_vvp ));
2391
2392 for ( y = 1; y <= tiles_h; y++ )
2393 {
2394 for ( x = 1; x <= tiles_w; x++ )
2395 {
3d9454e6 2396 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
2397 utm = utm_orig;
2398 if ( tiles_w & 0x1 )
2399 utm.easting += ((gdouble)x - ceil(((gdouble)tiles_w)/2)) * (w*zoom);
2400 else
2401 utm.easting += ((gdouble)x - (((gdouble)tiles_w)+1)/2) * (w*zoom);
2402 if ( tiles_h & 0x1 ) /* odd */
2403 utm.northing -= ((gdouble)y - ceil(((gdouble)tiles_h)/2)) * (h*zoom);
2404 else /* even */
2405 utm.northing -= ((gdouble)y - (((gdouble)tiles_h)+1)/2) * (h*zoom);
2406
2407 /* move to correct place. */
2408 vik_viewport_set_center_utm ( vw->viking_vvp, &utm );
2409
2410 draw_redraw ( vw );
2411
2412 /* save buffer as file. */
2413 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);
2414 gdk_pixbuf_save ( pixbuf_to_save, name_of_file, save_as_png ? "png" : "jpeg", &error, NULL );
2415 if (error)
2416 {
7742da66 2417 g_warning("Unable to write to file %s: %s", name_of_file, error->message );
50a14534
EB
2418 g_error_free (error);
2419 }
2420
2421 g_object_unref ( G_OBJECT(pixbuf_to_save) );
2422 }
2423 }
2424
2425 vik_viewport_set_center_utm ( vw->viking_vvp, &utm_orig );
2426 vik_viewport_set_xmpp ( vw->viking_vvp, old_xmpp );
2427 vik_viewport_set_ympp ( vw->viking_vvp, old_ympp );
2428 vik_viewport_configure ( vw->viking_vvp );
2429 draw_update ( vw );
2430
2431 g_free ( name_of_file );
2432}
2433
2434static void draw_to_image_file_current_window_cb(GtkWidget* widget,GdkEventButton *event,gpointer *pass_along)
2435{
2436 VikWindow *vw = VIK_WINDOW(pass_along[0]);
2437 GtkSpinButton *width_spin = GTK_SPIN_BUTTON(pass_along[1]), *height_spin = GTK_SPIN_BUTTON(pass_along[2]);
2438 GtkSpinButton *zoom_spin = GTK_SPIN_BUTTON(pass_along[3]);
2439 gdouble width_min, width_max, height_min, height_max;
2440 gint width, height;
2441
2442 gtk_spin_button_get_range ( width_spin, &width_min, &width_max );
2443 gtk_spin_button_get_range ( height_spin, &height_min, &height_max );
2444
2445 /* TODO: support for xzoom and yzoom values */
2446 width = vik_viewport_get_width ( vw->viking_vvp ) * vik_viewport_get_xmpp ( vw->viking_vvp ) / gtk_spin_button_get_value ( zoom_spin );
2447 height = vik_viewport_get_height ( vw->viking_vvp ) * vik_viewport_get_xmpp ( vw->viking_vvp ) / gtk_spin_button_get_value ( zoom_spin );
2448
2449 if ( width > width_max || width < width_min || height > height_max || height < height_min )
4c77d5e0 2450 a_dialog_info_msg ( GTK_WINDOW(vw), _("Viewable region outside allowable pixel size bounds for image. Clipping width/height values.") );
50a14534
EB
2451
2452 gtk_spin_button_set_value ( width_spin, width );
2453 gtk_spin_button_set_value ( height_spin, height );
2454}
2455
2456static void draw_to_image_file_total_area_cb (GtkSpinButton *spinbutton, gpointer *pass_along)
2457{
2458 GtkSpinButton *width_spin = GTK_SPIN_BUTTON(pass_along[1]), *height_spin = GTK_SPIN_BUTTON(pass_along[2]);
2459 GtkSpinButton *zoom_spin = GTK_SPIN_BUTTON(pass_along[3]);
2460 gchar *label_text;
2461 gdouble w, h;
2462 w = gtk_spin_button_get_value(width_spin) * gtk_spin_button_get_value(zoom_spin);
2463 h = gtk_spin_button_get_value(height_spin) * gtk_spin_button_get_value(zoom_spin);
2464 if (pass_along[4]) /* save many images; find TOTAL area covered */
2465 {
2466 w *= gtk_spin_button_get_value(GTK_SPIN_BUTTON(pass_along[4]));
2467 h *= gtk_spin_button_get_value(GTK_SPIN_BUTTON(pass_along[5]));
2468 }
6f9336aa
RN
2469 vik_units_distance_t dist_units = a_vik_get_units_distance ();
2470 switch (dist_units) {
2471 case VIK_UNITS_DISTANCE_KILOMETRES:
2472 label_text = g_strdup_printf ( _("Total area: %ldm x %ldm (%.3f sq. km)"), (glong)w, (glong)h, (w*h/1000000));
2473 break;
2474 case VIK_UNITS_DISTANCE_MILES:
2475 label_text = g_strdup_printf ( _("Total area: %ldm x %ldm (%.3f sq. miles)"), (glong)w, (glong)h, (w*h/2589988.11));
2476 break;
2477 default:
2478 label_text = g_strdup_printf ("Just to keep the compiler happy");
2479 g_critical("Houston, we've had a problem. distance=%d", dist_units);
2480 }
2481
50a14534
EB
2482 gtk_label_set_text(GTK_LABEL(pass_along[6]), label_text);
2483 g_free ( label_text );
2484}
2485
2486static void draw_to_image_file ( VikWindow *vw, const gchar *fn, gboolean one_image_only )
2487{
2488 /* todo: default for answers inside VikWindow or static (thruout instance) */
4c77d5e0 2489 GtkWidget *dialog = gtk_dialog_new_with_buttons ( _("Save to Image File"), GTK_WINDOW(vw),
50a14534
EB
2490 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
2491 GTK_STOCK_CANCEL,
2492 GTK_RESPONSE_REJECT,
2493 GTK_STOCK_OK,
2494 GTK_RESPONSE_ACCEPT,
10888930 2495 NULL );
50a14534
EB
2496 GtkWidget *width_label, *width_spin, *height_label, *height_spin;
2497 GtkWidget *png_radio, *jpeg_radio;
2498 GtkWidget *current_window_button;
2499 gpointer current_window_pass_along[7];
2500 GtkWidget *zoom_label, *zoom_spin;
2501 GtkWidget *total_size_label;
2502
2503 /* only used if (!one_image_only) */
886031df 2504 GtkWidget *tiles_width_spin = NULL, *tiles_height_spin = NULL;
50a14534
EB
2505
2506
4c77d5e0 2507 width_label = gtk_label_new ( _("Width (pixels):") );
50a14534 2508 width_spin = gtk_spin_button_new ( GTK_ADJUSTMENT(gtk_adjustment_new ( vw->draw_image_width, 10, 5000, 10, 100, 0 )), 10, 0 );
4c77d5e0 2509 height_label = gtk_label_new ( _("Height (pixels):") );
50a14534
EB
2510 height_spin = gtk_spin_button_new ( GTK_ADJUSTMENT(gtk_adjustment_new ( vw->draw_image_height, 10, 5000, 10, 100, 0 )), 10, 0 );
2511
4c77d5e0 2512 zoom_label = gtk_label_new ( _("Zoom (meters per pixel):") );
50a14534 2513 /* TODO: separate xzoom and yzoom factors */
ac33062d 2514 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
2515
2516 total_size_label = gtk_label_new ( NULL );
2517
4c77d5e0 2518 current_window_button = gtk_button_new_with_label ( _("Area in current viewable window") );
50a14534
EB
2519 current_window_pass_along [0] = vw;
2520 current_window_pass_along [1] = width_spin;
2521 current_window_pass_along [2] = height_spin;
2522 current_window_pass_along [3] = zoom_spin;
2523 current_window_pass_along [4] = NULL; /* used for one_image_only != 1 */
2524 current_window_pass_along [5] = NULL;
2525 current_window_pass_along [6] = total_size_label;
2526 g_signal_connect ( G_OBJECT(current_window_button), "button_press_event", G_CALLBACK(draw_to_image_file_current_window_cb), current_window_pass_along );
2527
4c77d5e0
GB
2528 png_radio = gtk_radio_button_new_with_label ( NULL, _("Save as PNG") );
2529 jpeg_radio = gtk_radio_button_new_with_label_from_widget ( GTK_RADIO_BUTTON(png_radio), _("Save as JPEG") );
50a14534
EB
2530
2531 if ( ! vw->draw_image_save_as_png )
2532 gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON(jpeg_radio), TRUE );
2533
2534 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), width_label, FALSE, FALSE, 0);
2535 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), width_spin, FALSE, FALSE, 0);
2536 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), height_label, FALSE, FALSE, 0);
2537 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), height_spin, FALSE, FALSE, 0);
2538 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), current_window_button, FALSE, FALSE, 0);
2539 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), png_radio, FALSE, FALSE, 0);
2540 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), jpeg_radio, FALSE, FALSE, 0);
2541 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), zoom_label, FALSE, FALSE, 0);
2542 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), zoom_spin, FALSE, FALSE, 0);
2543
2544 if ( ! one_image_only )
2545 {
2546 GtkWidget *tiles_width_label, *tiles_height_label;
2547
2548
4c77d5e0 2549 tiles_width_label = gtk_label_new ( _("East-west image tiles:") );
50a14534 2550 tiles_width_spin = gtk_spin_button_new ( GTK_ADJUSTMENT(gtk_adjustment_new ( 5, 1, 10, 1, 100, 0 )), 1, 0 );
4c77d5e0 2551 tiles_height_label = gtk_label_new ( _("North-south image tiles:") );
50a14534
EB
2552 tiles_height_spin = gtk_spin_button_new ( GTK_ADJUSTMENT(gtk_adjustment_new ( 5, 1, 10, 1, 100, 0 )), 1, 0 );
2553 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), tiles_width_label, FALSE, FALSE, 0);
2554 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), tiles_width_spin, FALSE, FALSE, 0);
2555 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), tiles_height_label, FALSE, FALSE, 0);
2556 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), tiles_height_spin, FALSE, FALSE, 0);
2557
2558 current_window_pass_along [4] = tiles_width_spin;
2559 current_window_pass_along [5] = tiles_height_spin;
2560 g_signal_connect ( G_OBJECT(tiles_width_spin), "value-changed", G_CALLBACK(draw_to_image_file_total_area_cb), current_window_pass_along );
2561 g_signal_connect ( G_OBJECT(tiles_height_spin), "value-changed", G_CALLBACK(draw_to_image_file_total_area_cb), current_window_pass_along );
2562 }
2563 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), total_size_label, FALSE, FALSE, 0);
2564 g_signal_connect ( G_OBJECT(width_spin), "value-changed", G_CALLBACK(draw_to_image_file_total_area_cb), current_window_pass_along );
2565 g_signal_connect ( G_OBJECT(height_spin), "value-changed", G_CALLBACK(draw_to_image_file_total_area_cb), current_window_pass_along );
2566 g_signal_connect ( G_OBJECT(zoom_spin), "value-changed", G_CALLBACK(draw_to_image_file_total_area_cb), current_window_pass_along );
2567
2568 draw_to_image_file_total_area_cb ( NULL, current_window_pass_along ); /* set correct size info now */
2569
1fb999d3
RN
2570 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
2571
50a14534
EB
2572 gtk_widget_show_all ( GTK_DIALOG(dialog)->vbox );
2573
2574 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
2575 {
2576 gtk_widget_hide ( GTK_WIDGET(dialog) );
2577 if ( one_image_only )
2578 save_image_file ( vw, fn,
2579 vw->draw_image_width = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(width_spin) ),
2580 vw->draw_image_height = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(height_spin) ),
2581 gtk_spin_button_get_value ( GTK_SPIN_BUTTON(zoom_spin) ), /* do not save this value, default is current zoom */
2582 vw->draw_image_save_as_png = gtk_toggle_button_get_active ( GTK_TOGGLE_BUTTON(png_radio) ) );
2583 else {
e5657444
RN
2584 // NB is in UTM mode ATM
2585 save_image_dir ( vw, fn,
50a14534
EB
2586 vw->draw_image_width = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(width_spin) ),
2587 vw->draw_image_height = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(height_spin) ),
2588 gtk_spin_button_get_value ( GTK_SPIN_BUTTON(zoom_spin) ), /* do not save this value, default is current zoom */
2589 vw->draw_image_save_as_png = gtk_toggle_button_get_active ( GTK_TOGGLE_BUTTON(png_radio) ),
2590 gtk_spin_button_get_value ( GTK_SPIN_BUTTON(tiles_width_spin) ),
2591 gtk_spin_button_get_value ( GTK_SPIN_BUTTON(tiles_height_spin) ) );
50a14534
EB
2592 }
2593 }
2594 gtk_widget_destroy ( GTK_WIDGET(dialog) );
2595}
2596
2597
e4afc73a 2598static void draw_to_image_file_cb ( GtkAction *a, VikWindow *vw )
50a14534 2599{
ca9e25af 2600 gchar *fn;
f2a1ca71 2601 if (!vw->save_img_dia) {
6e4a49aa
MA
2602 vw->save_img_dia = gtk_file_chooser_dialog_new (_("Save Image"),
2603 GTK_WINDOW(vw),
2604 GTK_FILE_CHOOSER_ACTION_SAVE,
2605 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
2606 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
2607 NULL);
f2a1ca71
QT
2608 gtk_window_set_transient_for ( GTK_WINDOW(vw->save_img_dia), GTK_WINDOW(vw) );
2609 gtk_window_set_destroy_with_parent ( GTK_WINDOW(vw->save_img_dia), TRUE );
2610 }
50a14534 2611
6e4a49aa 2612 while ( gtk_dialog_run ( GTK_DIALOG(vw->save_img_dia) ) == GTK_RESPONSE_ACCEPT )
50a14534 2613 {
6e4a49aa 2614 fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(vw->save_img_dia) );
d91e5f2b 2615 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 2616 {
50a14534
EB
2617 draw_to_image_file ( vw, fn, TRUE );
2618 break;
2619 }
fc759827
GB
2620 g_free(fn);
2621 fn = NULL;
50a14534 2622 }
f2a1ca71 2623 gtk_widget_hide ( vw->save_img_dia );
50a14534
EB
2624}
2625
e4afc73a 2626static void draw_to_image_dir_cb ( GtkAction *a, VikWindow *vw )
50a14534 2627{
6e4a49aa
MA
2628 gchar *fn = NULL;
2629
e5657444
RN
2630 if ( vik_viewport_get_coord_mode(vw->viking_vvp) != VIK_COORD_UTM ) {
2631 a_dialog_error_msg ( GTK_WINDOW(vw), _("You must be in UTM mode to use this feature") );
2632 return;
2633 }
2634
f2a1ca71 2635 if (!vw->save_img_dir_dia) {
6e4a49aa
MA
2636 vw->save_img_dir_dia = gtk_file_chooser_dialog_new (_("Choose a directory to hold images"),
2637 GTK_WINDOW(vw),
2638 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
2639 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
2640 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2641 NULL);
f2a1ca71
QT
2642 gtk_window_set_transient_for ( GTK_WINDOW(vw->save_img_dir_dia), GTK_WINDOW(vw) );
2643 gtk_window_set_destroy_with_parent ( GTK_WINDOW(vw->save_img_dir_dia), TRUE );
2644 }
6e4a49aa
MA
2645
2646 while ( gtk_dialog_run ( GTK_DIALOG(vw->save_img_dir_dia) ) == GTK_RESPONSE_ACCEPT )
50a14534 2647 {
6e4a49aa
MA
2648 fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(vw->save_img_dir_dia) );
2649 if ( fn )
50a14534 2650 {
50a14534 2651 draw_to_image_file ( vw, fn, FALSE );
6e4a49aa
MA
2652 g_free(fn);
2653 fn = NULL;
50a14534
EB
2654 break;
2655 }
2656 }
f2a1ca71 2657 gtk_widget_hide ( vw->save_img_dir_dia );
50a14534
EB
2658}
2659
9a995996 2660#if GTK_CHECK_VERSION(2,10,0)
42f34743
QT
2661static void print_cb ( GtkAction *a, VikWindow *vw )
2662{
2663 a_print(vw, vw->viking_vvp);
2664}
9a995996 2665#endif
42f34743 2666
50a14534 2667/* really a misnomer: changes coord mode (actual coordinates) AND/OR draw mode (viewport only) */
e4afc73a 2668static void window_change_coord_mode_cb ( GtkAction *old_a, GtkAction *a, VikWindow *vw )
50a14534 2669{
e4afc73a
EB
2670 VikViewportDrawMode drawmode;
2671 if (!strcmp(gtk_action_get_name(a), "ModeUTM")) {
2672 drawmode = VIK_VIEWPORT_DRAWMODE_UTM;
2673 }
d587678a
GB
2674 else if (!strcmp(gtk_action_get_name(a), "ModeLatLon")) {
2675 drawmode = VIK_VIEWPORT_DRAWMODE_LATLON;
2676 }
e4afc73a
EB
2677 else if (!strcmp(gtk_action_get_name(a), "ModeExpedia")) {
2678 drawmode = VIK_VIEWPORT_DRAWMODE_EXPEDIA;
2679 }
e4afc73a
EB
2680 else if (!strcmp(gtk_action_get_name(a), "ModeMercator")) {
2681 drawmode = VIK_VIEWPORT_DRAWMODE_MERCATOR;
2682 }
2683 else {
8dc8da82 2684 g_critical("Houston, we've had a problem.");
e4afc73a
EB
2685 return;
2686 }
2687
50a14534
EB
2688 if ( !vw->only_updating_coord_mode_ui )
2689 {
2690 VikViewportDrawMode olddrawmode = vik_viewport_get_drawmode ( vw->viking_vvp );
2691 if ( olddrawmode != drawmode )
2692 {
2693 /* this takes care of coord mode too */
2694 vik_viewport_set_drawmode ( vw->viking_vvp, drawmode );
2695 if ( drawmode == VIK_VIEWPORT_DRAWMODE_UTM ) {
2696 vik_layers_panel_change_coord_mode ( vw->viking_vlp, VIK_COORD_UTM );
2697 } else if ( olddrawmode == VIK_VIEWPORT_DRAWMODE_UTM ) {
2698 vik_layers_panel_change_coord_mode ( vw->viking_vlp, VIK_COORD_LATLON );
2699 }
2700 draw_update ( vw );
2701 }
2702 }
2703}
2704
35c7c0ba
EB
2705static void set_draw_scale ( GtkAction *a, VikWindow *vw )
2706{
48df6aa3 2707 GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ShowScale" );
1657065a
QT
2708 g_assert(check_box);
2709 gboolean state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box));
2710 vik_viewport_set_draw_scale ( vw->viking_vvp, state );
35c7c0ba
EB
2711 draw_update ( vw );
2712}
2713
c933487f
QT
2714static void set_draw_centermark ( GtkAction *a, VikWindow *vw )
2715{
48df6aa3 2716 GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ShowCenterMark" );
1657065a
QT
2717 g_assert(check_box);
2718 gboolean state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box));
2719 vik_viewport_set_draw_centermark ( vw->viking_vvp, state );
c933487f
QT
2720 draw_update ( vw );
2721}
2722
2afcef36
RN
2723static void set_draw_highlight ( GtkAction *a, VikWindow *vw )
2724{
2725 GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ShowHighlight" );
2726 g_assert(check_box);
2727 gboolean state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box));
2728 vik_viewport_set_draw_highlight ( vw->viking_vvp, state );
2729 draw_update ( vw );
2730}
2731
e4afc73a 2732static void set_bg_color ( GtkAction *a, VikWindow *vw )
50a14534 2733{
4c77d5e0 2734 GtkWidget *colorsd = gtk_color_selection_dialog_new ( _("Choose a background color") );
50a14534
EB
2735 GdkColor *color = vik_viewport_get_background_gdkcolor ( vw->viking_vvp );
2736 gtk_color_selection_set_previous_color ( GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(colorsd)->colorsel), color );
2737 gtk_color_selection_set_current_color ( GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(colorsd)->colorsel), color );
2738 if ( gtk_dialog_run ( GTK_DIALOG(colorsd) ) == GTK_RESPONSE_OK )
2739 {
2740 gtk_color_selection_get_current_color ( GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(colorsd)->colorsel), color );
2741 vik_viewport_set_background_gdkcolor ( vw->viking_vvp, color );
2742 draw_update ( vw );
2743 }
2744 g_free ( color );
2745 gtk_widget_destroy ( colorsd );
2746}
2747
480fb7e1
RN
2748static void set_highlight_color ( GtkAction *a, VikWindow *vw )
2749{
2750 GtkWidget *colorsd = gtk_color_selection_dialog_new ( _("Choose a track highlight color") );
2751 GdkColor *color = vik_viewport_get_highlight_gdkcolor ( vw->viking_vvp );
2752 gtk_color_selection_set_previous_color ( GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(colorsd)->colorsel), color );
2753 gtk_color_selection_set_current_color ( GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(colorsd)->colorsel), color );
2754 if ( gtk_dialog_run ( GTK_DIALOG(colorsd) ) == GTK_RESPONSE_OK )
2755 {
2756 gtk_color_selection_get_current_color ( GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(colorsd)->colorsel), color );
2757 vik_viewport_set_highlight_gdkcolor ( vw->viking_vvp, color );
2758 draw_update ( vw );
2759 }
2760 g_free ( color );
2761 gtk_widget_destroy ( colorsd );
2762}
2763
941aa6e9
AF
2764
2765
2766/***********************************************************************************************
2767 ** GUI Creation
2768 ***********************************************************************************************/
2769
e4afc73a 2770static GtkActionEntry entries[] = {
5515e2d3
JJ
2771 { "File", NULL, N_("_File"), 0, 0, 0 },
2772 { "Edit", NULL, N_("_Edit"), 0, 0, 0 },
2773 { "View", NULL, N_("_View"), 0, 0, 0 },
48df6aa3 2774 { "SetShow", NULL, N_("_Show"), 0, 0, 0 },
5515e2d3
JJ
2775 { "SetZoom", NULL, N_("_Zoom"), 0, 0, 0 },
2776 { "SetPan", NULL, N_("_Pan"), 0, 0, 0 },
2777 { "Layers", NULL, N_("_Layers"), 0, 0, 0 },
2778 { "Tools", NULL, N_("_Tools"), 0, 0, 0 },
92806042 2779 { "Exttools", NULL, N_("_Webtools"), 0, 0, 0 },
5515e2d3
JJ
2780 { "Help", NULL, N_("_Help"), 0, 0, 0 },
2781
2782 { "New", GTK_STOCK_NEW, N_("_New"), "<control>N", N_("New file"), (GCallback)newwindow_cb },
06526f88
RN
2783 { "Open", GTK_STOCK_OPEN, N_("_Open..."), "<control>O", N_("Open a file"), (GCallback)load_file },
2784 { "OpenRecentFile", NULL, N_("Open _Recent File"), NULL, NULL, (GCallback)NULL },
2785 { "Append", GTK_STOCK_ADD, N_("Append _File..."), NULL, N_("Append data from a different file"), (GCallback)load_file },
d6de71f9 2786 { "Acquire", GTK_STOCK_GO_DOWN, N_("A_cquire"), NULL, NULL, (GCallback)NULL },
06526f88 2787 { "AcquireGPS", NULL, N_("From _GPS..."), NULL, N_("Transfer data from a GPS device"), (GCallback)acquire_from_gps },
31349009 2788 { "AcquireGPSBabel", NULL, N_("Import File With GPS_Babel..."), NULL, N_("Import file via GPSBabel converter"), (GCallback)acquire_from_file },
ebf1bd39 2789#ifdef VIK_CONFIG_GOOGLE_DIRECTIONS
06526f88 2790 { "AcquireGoogle", NULL, N_("Google _Directions..."), NULL, N_("Get driving directions from Google"), (GCallback)acquire_from_google },
ebf1bd39 2791#endif
9c4555df
GB
2792#ifdef VIK_CONFIG_OPENSTREETMAP
2793 { "AcquireOSM", NULL, N_("_OSM Traces..."), NULL, N_("Get traces from OpenStreetMap"), (GCallback)acquire_from_osm },
2794#endif
1ef9e637 2795#ifdef VIK_CONFIG_GEOCACHES
06526f88 2796 { "AcquireGC", NULL, N_("Geo_caches..."), NULL, N_("Get Geocaches from geocaching.com"), (GCallback)acquire_from_gc },
f75d0233
RN
2797#endif
2798#ifdef VIK_CONFIG_GEOTAG
2799 { "AcquireGeotag", NULL, N_("From Geotagged _Images..."), NULL, N_("Create waypoints from geotagged images"), (GCallback)acquire_from_geotag },
1ef9e637 2800#endif
5515e2d3 2801 { "Save", GTK_STOCK_SAVE, N_("_Save"), "<control>S", N_("Save the file"), (GCallback)save_file },
06526f88
RN
2802 { "SaveAs", GTK_STOCK_SAVE_AS, N_("Save _As..."), NULL, N_("Save the file under different name"), (GCallback)save_file_as },
2803 { "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 },
2804 { "GenImgDir", GTK_STOCK_DND_MULTIPLE, N_("Generate _Directory of Images..."), NULL, N_("FIXME:IMGDIR"), (GCallback)draw_to_image_dir_cb },
9a995996
EB
2805
2806#if GTK_CHECK_VERSION(2,10,0)
5515e2d3 2807 { "Print", GTK_STOCK_PRINT, N_("_Print..."), NULL, N_("Print maps"), (GCallback)print_cb },
9a995996
EB
2808#endif
2809
5515e2d3
JJ
2810 { "Exit", GTK_STOCK_QUIT, N_("E_xit"), "<control>W", N_("Exit the program"), (GCallback)window_close },
2811 { "SaveExit", GTK_STOCK_QUIT, N_("Save and Exit"), NULL, N_("Save and Exit the program"), (GCallback)save_file_and_exit },
2812
5210c3d3 2813 { "GotoDefaultLocation", GTK_STOCK_HOME, N_("Go to the _Default Location"), NULL, N_("Go to the default location"), (GCallback)goto_default_location },
cbd293bb 2814 { "GotoSearch", GTK_STOCK_JUMP_TO, N_("Go to _Location..."), NULL, N_("Go to address/place using text search"), (GCallback)goto_address },
402fee6c 2815 { "GotoLL", GTK_STOCK_JUMP_TO, N_("_Go to Lat/Lon..."), NULL, N_("Go to arbitrary lat/lon coordinate"), (GCallback)draw_goto_cb },
150618fe 2816 { "GotoUTM", GTK_STOCK_JUMP_TO, N_("Go to UTM..."), NULL, N_("Go to arbitrary UTM coordinate"), (GCallback)draw_goto_cb },
480fb7e1 2817 { "SetHLColor",GTK_STOCK_SELECT_COLOR, N_("Set _Highlight Color..."), NULL, NULL, (GCallback)set_highlight_color },
cbd293bb 2818 { "SetBGColor",GTK_STOCK_SELECT_COLOR, N_("Set Bac_kground Color..."), NULL, NULL, (GCallback)set_bg_color },
5515e2d3
JJ
2819 { "ZoomIn", GTK_STOCK_ZOOM_IN, N_("Zoom _In"), "<control>plus", NULL, (GCallback)draw_zoom_cb },
2820 { "ZoomOut", GTK_STOCK_ZOOM_OUT, N_("Zoom _Out"), "<control>minus", NULL, (GCallback)draw_zoom_cb },
22c15481 2821 { "ZoomTo", GTK_STOCK_ZOOM_FIT, N_("Zoom _To..."), "<control>Z", NULL, (GCallback)zoom_to_cb },
5515e2d3
JJ
2822 { "Zoom0.25", NULL, N_("0.25"), NULL, NULL, (GCallback)draw_zoom_cb },
2823 { "Zoom0.5", NULL, N_("0.5"), NULL, NULL, (GCallback)draw_zoom_cb },
2824 { "Zoom1", NULL, N_("1"), NULL, NULL, (GCallback)draw_zoom_cb },
2825 { "Zoom2", NULL, N_("2"), NULL, NULL, (GCallback)draw_zoom_cb },
2826 { "Zoom4", NULL, N_("4"), NULL, NULL, (GCallback)draw_zoom_cb },
2827 { "Zoom8", NULL, N_("8"), NULL, NULL, (GCallback)draw_zoom_cb },
2828 { "Zoom16", NULL, N_("16"), NULL, NULL, (GCallback)draw_zoom_cb },
2829 { "Zoom32", NULL, N_("32"), NULL, NULL, (GCallback)draw_zoom_cb },
2830 { "Zoom64", NULL, N_("64"), NULL, NULL, (GCallback)draw_zoom_cb },
2831 { "Zoom128", NULL, N_("128"), NULL, NULL, (GCallback)draw_zoom_cb },
4344546e
RN
2832 { "Zoom256", NULL, N_("256"), NULL, NULL, (GCallback)draw_zoom_cb },
2833 { "Zoom512", NULL, N_("512"), NULL, NULL, (GCallback)draw_zoom_cb },
2834 { "Zoom1024", NULL, N_("1024"), NULL, NULL, (GCallback)draw_zoom_cb },
2835 { "Zoom2048", NULL, N_("2048"), NULL, NULL, (GCallback)draw_zoom_cb },
2836 { "Zoom4096", NULL, N_("4096"), NULL, NULL, (GCallback)draw_zoom_cb },
2837 { "Zoom8192", NULL, N_("8192"), NULL, NULL, (GCallback)draw_zoom_cb },
2838 { "Zoom16384", NULL, N_("16384"), NULL, NULL, (GCallback)draw_zoom_cb },
2839 { "Zoom32768", NULL, N_("32768"), NULL, NULL, (GCallback)draw_zoom_cb },
cbd293bb
RN
2840 { "PanNorth", NULL, N_("Pan _North"), "<control>Up", NULL, (GCallback)draw_pan_cb },
2841 { "PanEast", NULL, N_("Pan _East"), "<control>Right", NULL, (GCallback)draw_pan_cb },
2842 { "PanSouth", NULL, N_("Pan _South"), "<control>Down", NULL, (GCallback)draw_pan_cb },
2843 { "PanWest", NULL, N_("Pan _West"), "<control>Left", NULL, (GCallback)draw_pan_cb },
5515e2d3
JJ
2844 { "BGJobs", GTK_STOCK_EXECUTE, N_("Background _Jobs"), NULL, NULL, (GCallback)a_background_show_window },
2845
2846 { "Cut", GTK_STOCK_CUT, N_("Cu_t"), NULL, NULL, (GCallback)menu_cut_layer_cb },
2847 { "Copy", GTK_STOCK_COPY, N_("_Copy"), NULL, NULL, (GCallback)menu_copy_layer_cb },
2848 { "Paste", GTK_STOCK_PASTE, N_("_Paste"), NULL, NULL, (GCallback)menu_paste_layer_cb },
2849 { "Delete", GTK_STOCK_DELETE, N_("_Delete"), NULL, NULL, (GCallback)menu_delete_layer_cb },
2850 { "DeleteAll", NULL, N_("Delete All"), NULL, NULL, (GCallback)clear_cb },
06526f88 2851 { "MapCacheFlush",NULL, N_("_Flush Map Cache"), NULL, NULL, (GCallback)mapcache_flush_cb },
5210c3d3 2852 { "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 2853 { "Preferences",GTK_STOCK_PREFERENCES, N_("_Preferences"), NULL, NULL, (GCallback)preferences_cb },
5515e2d3
JJ
2854 { "Properties",GTK_STOCK_PROPERTIES, N_("_Properties"), NULL, NULL, (GCallback)menu_properties_cb },
2855
5ff75d1e 2856 { "HelpEntry", GTK_STOCK_HELP, N_("_Help"), "F1", NULL, (GCallback)help_help_cb },
5515e2d3 2857 { "About", GTK_STOCK_ABOUT, N_("_About"), NULL, NULL, (GCallback)help_about_cb },
e4afc73a
EB
2858};
2859
2860/* Radio items */
d587678a 2861/* FIXME use VIEWPORT_DRAWMODE values */
e4afc73a 2862static GtkRadioActionEntry mode_entries[] = {
5515e2d3
JJ
2863 { "ModeUTM", NULL, N_("_UTM Mode"), "<control>u", NULL, 0 },
2864 { "ModeExpedia", NULL, N_("_Expedia Mode"), "<control>e", NULL, 1 },
ac16c140 2865 { "ModeMercator", NULL, N_("_Mercator Mode"), "<control>m", NULL, 4 },
bd5e571a 2866 { "ModeLatLon", NULL, N_("Lat_/Lon Mode"), "<control>l", NULL, 5 },
50a14534
EB
2867};
2868
35c7c0ba 2869static GtkToggleActionEntry toggle_entries[] = {
48df6aa3 2870 { "ShowScale", NULL, N_("Show _Scale"), "F5", N_("Show Scale"), (GCallback)set_draw_scale, TRUE },
cbd293bb 2871 { "ShowCenterMark", NULL, N_("Show _Center Mark"), "F6", N_("Show Center Mark"), (GCallback)set_draw_centermark, TRUE },
2afcef36 2872 { "ShowHighlight", GTK_STOCK_UNDERLINE, N_("Show _Highlight"), "F7", N_("Show Highlight"), (GCallback)set_draw_highlight, TRUE },
cbd293bb 2873 { "FullScreen", GTK_STOCK_FULLSCREEN, N_("_Full Screen"), "F11", N_("Activate full screen mode"), (GCallback)full_screen_cb, FALSE },
48df6aa3 2874 { "ViewSidePanel", GTK_STOCK_INDEX, N_("Show Side _Panel"), "F9", N_("Show Side Panel"), (GCallback)view_side_panel_cb, TRUE },
a459ee10 2875 { "ViewStatusBar", NULL, N_("Show Status_bar"), "F12", N_("Show Statusbar"), (GCallback)view_statusbar_cb, TRUE },
48df6aa3
RN
2876 { "ViewToolbar", NULL, N_("Show _Toolbar"), "F3", N_("Show Toolbar"), (GCallback)view_toolbar_cb, TRUE },
2877 { "ViewMainMenu", NULL, N_("Show _Menu"), "F4", N_("Show Menu"), (GCallback)view_main_menu_cb, TRUE },
35c7c0ba
EB
2878};
2879
a527cfff 2880#include "menu.xml.h"
e4afc73a 2881static void window_create_ui( VikWindow *window )
50a14534 2882{
e4afc73a
EB
2883 GtkUIManager *uim;
2884 GtkActionGroup *action_group;
50a14534 2885 GtkAccelGroup *accel_group;
e4afc73a 2886 GError *error;
e4afc73a
EB
2887 guint i, j, mid;
2888 GtkIconFactory *icon_factory;
2889 GtkIconSet *icon_set;
e4afc73a
EB
2890 GtkRadioActionEntry *tools = NULL, *radio;
2891 guint ntools;
2892
2893 uim = gtk_ui_manager_new ();
2894 window->uim = uim;
2895
9593a4c9
EB
2896 toolbox_add_tool(window->vt, &ruler_tool, TOOL_LAYER_TYPE_NONE);
2897 toolbox_add_tool(window->vt, &zoom_tool, TOOL_LAYER_TYPE_NONE);
576cbd17 2898 toolbox_add_tool(window->vt, &pan_tool, TOOL_LAYER_TYPE_NONE);
a47bfefa 2899 toolbox_add_tool(window->vt, &select_tool, TOOL_LAYER_TYPE_NONE);
941aa6e9 2900
e4afc73a 2901 error = NULL;
a527cfff 2902 if (!(mid = gtk_ui_manager_add_ui_from_string (uim, menu_xml, -1, &error))) {
e4afc73a
EB
2903 g_error_free (error);
2904 exit (1);
2905 }
2906
2907 action_group = gtk_action_group_new ("MenuActions");
5515e2d3 2908 gtk_action_group_set_translation_domain(action_group, PACKAGE_NAME);
e4afc73a 2909 gtk_action_group_add_actions (action_group, entries, G_N_ELEMENTS (entries), window);
35c7c0ba 2910 gtk_action_group_add_toggle_actions (action_group, toggle_entries, G_N_ELEMENTS (toggle_entries), window);
6a9ff0ee 2911 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
2912
2913 icon_factory = gtk_icon_factory_new ();
ee36ac4f 2914 gtk_icon_factory_add_default (icon_factory);
e4afc73a
EB
2915
2916 register_vik_icons(icon_factory);
2917
79dce0cb
RN
2918 // Copy the tool RadioActionEntries out of the main Window structure into an extending array 'tools'
2919 // so that it can be applied to the UI in one action group add function call below
e4afc73a 2920 ntools = 0;
79dce0cb 2921 for (i=0; i<window->vt->n_tools; i++) {
e4afc73a
EB
2922 tools = g_renew(GtkRadioActionEntry, tools, ntools+1);
2923 radio = &tools[ntools];
2924 ntools++;
79dce0cb 2925 *radio = window->vt->tools[i].ti.radioActionEntry;
e4afc73a 2926 radio->value = ntools;
79dce0cb 2927 }
e4afc73a
EB
2928
2929 for (i=0; i<VIK_LAYER_NUM_TYPES; i++) {
2930 GtkActionEntry action;
2931 gtk_ui_manager_add_ui(uim, mid, "/ui/MainMenu/Layers/",
2932 vik_layer_get_interface(i)->name,
2933 vik_layer_get_interface(i)->name,
2934 GTK_UI_MANAGER_MENUITEM, FALSE);
2935
2936 icon_set = gtk_icon_set_new_from_pixbuf (gdk_pixbuf_from_pixdata (vik_layer_get_interface(i)->icon, FALSE, NULL ));
2937 gtk_icon_factory_add (icon_factory, vik_layer_get_interface(i)->name, icon_set);
2938 gtk_icon_set_unref (icon_set);
2939
2940 action.name = vik_layer_get_interface(i)->name;
2941 action.stock_id = vik_layer_get_interface(i)->name;
da12e3d1 2942 action.label = g_strdup_printf( _("New _%s Layer"), vik_layer_get_interface(i)->name);
75078768 2943 action.accelerator = vik_layer_get_interface(i)->accelerator;
e4afc73a
EB
2944 action.tooltip = NULL;
2945 action.callback = (GCallback)menu_addlayer_cb;
2946 gtk_action_group_add_actions(action_group, &action, 1, window);
2947
2948 if ( vik_layer_get_interface(i)->tools_count ) {
2949 gtk_ui_manager_add_ui(uim, mid, "/ui/MainMenu/Tools/", vik_layer_get_interface(i)->name, NULL, GTK_UI_MANAGER_SEPARATOR, FALSE);
2950 gtk_ui_manager_add_ui(uim, mid, "/ui/MainToolbar/ToolItems/", vik_layer_get_interface(i)->name, NULL, GTK_UI_MANAGER_SEPARATOR, FALSE);
2951 }
2952
79dce0cb 2953 // Further tool copying for to apply to the UI, also apply menu UI setup
e4afc73a
EB
2954 for ( j = 0; j < vik_layer_get_interface(i)->tools_count; j++ ) {
2955 tools = g_renew(GtkRadioActionEntry, tools, ntools+1);
2956 radio = &tools[ntools];
2957 ntools++;
2958
e4afc73a 2959 gtk_ui_manager_add_ui(uim, mid, "/ui/MainMenu/Tools",
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_MENUITEM, FALSE);
2963 gtk_ui_manager_add_ui(uim, mid, "/ui/MainToolbar/ToolItems",
79dce0cb
RN
2964 vik_layer_get_interface(i)->tools[j].radioActionEntry.label,
2965 vik_layer_get_interface(i)->tools[j].radioActionEntry.name,
e4afc73a
EB
2966 GTK_UI_MANAGER_TOOLITEM, FALSE);
2967
9593a4c9 2968 toolbox_add_tool(window->vt, &(vik_layer_get_interface(i)->tools[j]), i);
941aa6e9 2969
79dce0cb
RN
2970 *radio = vik_layer_get_interface(i)->tools[j].radioActionEntry;
2971 // Overwrite with actual number to use
e4afc73a
EB
2972 radio->value = ntools;
2973 }
2974 }
ee36ac4f 2975 g_object_unref (icon_factory);
50a14534 2976
e4afc73a
EB
2977 gtk_action_group_add_radio_actions(action_group, tools, ntools, 0, (GCallback)menu_tool_cb, window);
2978 g_free(tools);
50a14534 2979
e4afc73a 2980 gtk_ui_manager_insert_action_group (uim, action_group, 0);
50a14534 2981
79845167
QT
2982 for (i=0; i<VIK_LAYER_NUM_TYPES; i++) {
2983 for ( j = 0; j < vik_layer_get_interface(i)->tools_count; j++ ) {
2984 GtkAction *action = gtk_action_group_get_action(action_group,
79dce0cb 2985 vik_layer_get_interface(i)->tools[j].radioActionEntry.name);
79845167
QT
2986 g_object_set(action, "sensitive", FALSE, NULL);
2987 }
2988 }
2989 window->action_group = action_group;
2990
e4afc73a
EB
2991 accel_group = gtk_ui_manager_get_accel_group (uim);
2992 gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
2993 gtk_ui_manager_ensure_update (uim);
13505702
GB
2994
2995 setup_recent_files(window);
e4afc73a 2996}
50a14534 2997
50a14534 2998
79dce0cb
RN
2999// TODO - add method to add tool icons defined from outside this file
3000// and remove the reverse dependency on icon definition from this file
e4afc73a 3001static struct {
4bd45256 3002 const GdkPixdata *data;
e4afc73a
EB
3003 gchar *stock_id;
3004} stock_icons[] = {
79dce0cb 3005 { &mover_22_pixbuf, "vik-icon-pan" },
5bfafde9
GB
3006 { &zoom_18_pixbuf, "vik-icon-zoom" },
3007 { &ruler_18_pixbuf, "vik-icon-ruler" },
a47bfefa 3008 { &select_18_pixbuf, "vik-icon-select" },
79dce0cb
RN
3009 { &begintr_18_pixbuf, "vik-icon-Begin Track" },
3010 { &route_finder_18_pixbuf, "vik-icon-Route Finder" },
06a6af5b 3011 { &demdl_18_pixbuf, "vik-icon-DEM Download" },
79dce0cb
RN
3012 { &showpic_18_pixbuf, "vik-icon-Show Picture" },
3013 { &addtr_18_pixbuf, "vik-icon-Create Track" },
3014 { &edtr_18_pixbuf, "vik-icon-Edit Trackpoint" },
3015 { &addwp_18_pixbuf, "vik-icon-Create Waypoint" },
3016 { &edwp_18_pixbuf, "vik-icon-Edit Waypoint" },
3017 { &geozoom_18_pixbuf, "vik-icon-Georef Zoom Tool" },
3018 { &geomove_18_pixbuf, "vik-icon-Georef Move Map" },
3019 { &mapdl_18_pixbuf, "vik-icon-Maps Download" },
e4afc73a
EB
3020};
3021
e4afc73a
EB
3022static gint n_stock_icons = G_N_ELEMENTS (stock_icons);
3023
3024static void
3025register_vik_icons (GtkIconFactory *icon_factory)
3026{
3027 GtkIconSet *icon_set;
e4afc73a 3028 gint i;
e4afc73a
EB
3029
3030 for (i = 0; i < n_stock_icons; i++) {
4bd45256
EB
3031 icon_set = gtk_icon_set_new_from_pixbuf (gdk_pixbuf_from_pixdata (
3032 stock_icons[i].data, FALSE, NULL ));
e4afc73a
EB
3033 gtk_icon_factory_add (icon_factory, stock_icons[i].stock_id, icon_set);
3034 gtk_icon_set_unref (icon_set);
3035 }
50a14534 3036}
bce3a7b0 3037
9d7c24ed
RN
3038gpointer vik_window_get_selected_trw_layer ( VikWindow *vw )
3039{
3040 return vw->selected_vtl;
3041}
3042
3043void vik_window_set_selected_trw_layer ( VikWindow *vw, gpointer vtl )
3044{
113c74f6
RN
3045 vw->selected_vtl = vtl;
3046 vw->containing_vtl = vtl;
9d7c24ed
RN
3047 /* Clear others */
3048 vw->selected_track = NULL;
3049 vw->selected_tracks = NULL;
3050 vw->selected_waypoint = NULL;
3051 vw->selected_waypoints = NULL;
04f36d92
RN
3052 // Set highlight thickness
3053 vik_viewport_set_highlight_thickness ( vw->viking_vvp, vik_trw_layer_get_property_tracks_line_thickness (vw->containing_vtl) );
9d7c24ed
RN
3054}
3055
3056gpointer vik_window_get_selected_tracks ( VikWindow *vw )
3057{
3058 return vw->selected_tracks;
3059}
3060
113c74f6 3061void vik_window_set_selected_tracks ( VikWindow *vw, gpointer gl, gpointer vtl )
9d7c24ed
RN
3062{
3063 vw->selected_tracks = gl;
113c74f6 3064 vw->containing_vtl = vtl;
9d7c24ed
RN
3065 /* Clear others */
3066 vw->selected_vtl = NULL;
3067 vw->selected_track = NULL;
3068 vw->selected_waypoint = NULL;
3069 vw->selected_waypoints = NULL;
04f36d92
RN
3070 // Set highlight thickness
3071 vik_viewport_set_highlight_thickness ( vw->viking_vvp, vik_trw_layer_get_property_tracks_line_thickness (vw->containing_vtl) );
9d7c24ed
RN
3072}
3073
3074gpointer vik_window_get_selected_track ( VikWindow *vw )
3075{
3076 return vw->selected_track;
3077}
3078
43f2e1da 3079void vik_window_set_selected_track ( VikWindow *vw, gpointer *vt, gpointer vtl, gpointer name )
9d7c24ed
RN
3080{
3081 vw->selected_track = vt;
113c74f6 3082 vw->containing_vtl = vtl;
9d7c24ed
RN
3083 /* Clear others */
3084 vw->selected_vtl = NULL;
3085 vw->selected_tracks = NULL;
3086 vw->selected_waypoint = NULL;
3087 vw->selected_waypoints = NULL;
04f36d92
RN
3088 // Set highlight thickness
3089 vik_viewport_set_highlight_thickness ( vw->viking_vvp, vik_trw_layer_get_property_tracks_line_thickness (vw->containing_vtl) );
9d7c24ed 3090}
04f36d92 3091
9d7c24ed
RN
3092gpointer vik_window_get_selected_waypoints ( VikWindow *vw )
3093{
3094 return vw->selected_waypoints;
3095}
3096
113c74f6 3097void vik_window_set_selected_waypoints ( VikWindow *vw, gpointer gl, gpointer vtl )
9d7c24ed
RN
3098{
3099 vw->selected_waypoints = gl;
113c74f6 3100 vw->containing_vtl = vtl;
9d7c24ed
RN
3101 /* Clear others */
3102 vw->selected_vtl = NULL;
3103 vw->selected_track = NULL;
3104 vw->selected_tracks = NULL;
3105 vw->selected_waypoint = NULL;
3106}
3107
3108gpointer vik_window_get_selected_waypoint ( VikWindow *vw )
3109{
3110 return vw->selected_waypoint;
3111}
3112
43f2e1da 3113void vik_window_set_selected_waypoint ( VikWindow *vw, gpointer *vwp, gpointer vtl, gpointer name )
9d7c24ed
RN
3114{
3115 vw->selected_waypoint = vwp;
113c74f6 3116 vw->containing_vtl = vtl;
9d7c24ed
RN
3117 /* Clear others */
3118 vw->selected_vtl = NULL;
3119 vw->selected_track = NULL;
3120 vw->selected_tracks = NULL;
3121 vw->selected_waypoints = NULL;
3122}
3123
3124gboolean vik_window_clear_highlight ( VikWindow *vw )
3125{
3126 gboolean need_redraw = FALSE;
3127 if ( vw->selected_vtl != NULL ) {
3128 vw->selected_vtl = NULL;
3129 need_redraw = TRUE;
3130 }
3131 if ( vw->selected_track != NULL ) {
3132 vw->selected_track = NULL;
3133 need_redraw = TRUE;
3134 }
3135 if ( vw->selected_tracks != NULL ) {
3136 vw->selected_tracks = NULL;
3137 need_redraw = TRUE;
3138 }
3139 if ( vw->selected_waypoint != NULL ) {
3140 vw->selected_waypoint = NULL;
3141 need_redraw = TRUE;
3142 }
3143 if ( vw->selected_waypoints != NULL ) {
3144 vw->selected_waypoints = NULL;
3145 need_redraw = TRUE;
3146 }
3147 return need_redraw;
3148}