]> git.street.me.uk Git - andy/viking.git/blame - src/vikwindow.c
Add conditional compilation for geonames
[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>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
4c77d5e0
GB
21
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
25
50a14534
EB
26#include "viking.h"
27#include "background.h"
1d1bc3c1 28#include "acquire.h"
7b3479e3 29#include "datasources.h"
93c47137 30#include "geonamessearch.h"
071da616 31#include "dems.h"
42f34743 32#include "print.h"
17a1f8f9 33#include "preferences.h"
f2f2f7bf 34#include "icons/icons.h"
92806042 35#include "vikexttools.h"
50a14534 36
8c00358d 37#ifdef HAVE_STDLIB_H
e4afc73a 38#include <stdlib.h>
8c00358d
GB
39#endif
40#ifdef HAVE_MATH_H
50a14534 41#include <math.h>
8c00358d
GB
42#endif
43#ifdef HAVE_STRING_H
50a14534 44#include <string.h>
8c00358d 45#endif
50a14534 46#include <ctype.h>
f83131b9
MA
47#include <glib.h>
48#include <glib/gstdio.h>
1d1bc3c1 49#include <glib/gprintf.h>
4c77d5e0 50#include <glib/gi18n.h>
50a14534 51
3570ad57
QT
52#define VIKING_WINDOW_WIDTH 1000
53#define VIKING_WINDOW_HEIGHT 800
50a14534
EB
54#define DRAW_IMAGE_DEFAULT_WIDTH 1280
55#define DRAW_IMAGE_DEFAULT_HEIGHT 1024
56#define DRAW_IMAGE_DEFAULT_SAVE_AS_PNG TRUE
57
58static void window_finalize ( GObject *gob );
59static GObjectClass *parent_class;
60
61static void window_init ( VikWindow *vw );
62static void window_class_init ( VikWindowClass *klass );
4c77d5e0 63static void window_set_filename ( VikWindow *vw, const gchar *filename );
50a14534
EB
64
65static void draw_update ( VikWindow *vw );
66
e4afc73a 67static void newwindow_cb ( GtkAction *a, VikWindow *vw );
50a14534
EB
68
69/* Drawing & stuff */
70
71static gboolean delete_event( VikWindow *vw );
72
777e2d4d
EB
73static gboolean key_press_event( VikWindow *vw, GdkEventKey *event, gpointer data );
74
bce3a7b0 75static void window_configure_event ( VikWindow *vw );
50a14534
EB
76static void draw_sync ( VikWindow *vw );
77static void draw_redraw ( VikWindow *vw );
941aa6e9 78static void draw_scroll ( VikWindow *vw, GdkEventScroll *event );
50a14534
EB
79static void draw_click ( VikWindow *vw, GdkEventButton *event );
80static void draw_release ( VikWindow *vw, GdkEventButton *event );
81static void draw_mouse_motion ( VikWindow *vw, GdkEventMotion *event );
e4afc73a
EB
82static void draw_zoom_cb ( GtkAction *a, VikWindow *vw );
83static void draw_goto_cb ( GtkAction *a, VikWindow *vw );
50a14534
EB
84
85static void draw_status ();
86
87/* End Drawing Functions */
88
e4afc73a
EB
89static void menu_addlayer_cb ( GtkAction *a, VikWindow *vw );
90static void menu_properties_cb ( GtkAction *a, VikWindow *vw );
91static void menu_delete_layer_cb ( GtkAction *a, VikWindow *vw );
941aa6e9
AF
92
93/* tool management */
94typedef struct {
95 VikToolInterface ti;
96 gpointer state;
9593a4c9 97 gint layer_type;
941aa6e9 98} toolbox_tool_t;
9593a4c9 99#define TOOL_LAYER_TYPE_NONE -1
941aa6e9
AF
100
101typedef struct {
102 int active_tool;
103 int n_tools;
104 toolbox_tool_t *tools;
105 VikWindow *vw;
106} toolbox_tools_t;
107
e4afc73a 108static void menu_tool_cb ( GtkAction *old, GtkAction *a, VikWindow *vw );
941aa6e9 109static toolbox_tools_t* toolbox_create(VikWindow *vw);
9593a4c9 110static void toolbox_add_tool(toolbox_tools_t *vt, VikToolInterface *vti, gint layer_type );
941aa6e9
AF
111static int toolbox_get_tool(toolbox_tools_t *vt, const gchar *tool_name);
112static void toolbox_activate(toolbox_tools_t *vt, const gchar *tool_name);
f2f2f7bf 113static const GdkCursor *toolbox_get_cursor(toolbox_tools_t *vt, const gchar *tool_name);
941aa6e9 114static void toolbox_click (toolbox_tools_t *vt, GdkEventButton *event);
dc2c040e 115static void toolbox_move (toolbox_tools_t *vt, GdkEventMotion *event);
941aa6e9
AF
116static void toolbox_release (toolbox_tools_t *vt, GdkEventButton *event);
117
50a14534 118
941aa6e9 119/* ui creation */
e4afc73a 120static void window_create_ui( VikWindow *window );
941aa6e9 121static void register_vik_icons (GtkIconFactory *icon_factory);
50a14534 122
941aa6e9 123/* i/o */
e4afc73a
EB
124static void load_file ( GtkAction *a, VikWindow *vw );
125static gboolean save_file_as ( GtkAction *a, VikWindow *vw );
126static gboolean save_file ( GtkAction *a, VikWindow *vw );
2bf7cadd 127static gboolean save_file_and_exit ( GtkAction *a, VikWindow *vw );
50a14534
EB
128static gboolean window_save ( VikWindow *vw );
129
130struct _VikWindow {
131 GtkWindow gtkwindow;
132 VikViewport *viking_vvp;
133 VikLayersPanel *viking_vlp;
134 VikStatusbar *viking_vs;
135
e4afc73a
EB
136 GtkToolbar *toolbar;
137
50a14534
EB
138 GtkItemFactory *item_factory;
139
941aa6e9 140 /* tool management state */
50a14534 141 guint current_tool;
941aa6e9 142 toolbox_tools_t *vt;
50a14534
EB
143 guint16 tool_layer_id;
144 guint16 tool_tool_id;
145
79845167
QT
146 GtkActionGroup *action_group;
147
50a14534
EB
148 gint pan_x, pan_y;
149
150 guint draw_image_width, draw_image_height;
151 gboolean draw_image_save_as_png;
152
153 gchar *filename;
154 gboolean modified;
155
156 GtkWidget *open_dia, *save_dia;
f2a1ca71 157 GtkWidget *save_img_dia, *save_img_dir_dia;
50a14534
EB
158
159 gboolean only_updating_coord_mode_ui; /* hack for a bug in GTK */
e4afc73a 160 GtkUIManager *uim;
c9177aae
QT
161
162 /* half-drawn update */
163 VikLayer *trigger;
164 VikCoord trigger_center;
50a14534
EB
165};
166
167enum {
576cbd17
GB
168 TOOL_PAN = 0,
169 TOOL_ZOOM,
50a14534
EB
170 TOOL_RULER,
171 TOOL_LAYER,
172 NUMBER_OF_TOOLS
173};
174
175enum {
176 VW_NEWWINDOW_SIGNAL,
177 VW_OPENWINDOW_SIGNAL,
178 VW_LAST_SIGNAL
179};
180
181static guint window_signals[VW_LAST_SIGNAL] = { 0 };
182
576cbd17 183static gchar *tool_names[NUMBER_OF_TOOLS] = { N_("Pan"), N_("Zoom"), N_("Ruler") };
50a14534
EB
184
185GType vik_window_get_type (void)
186{
187 static GType vw_type = 0;
188
189 if (!vw_type)
190 {
191 static const GTypeInfo vw_info =
192 {
193 sizeof (VikWindowClass),
194 NULL, /* base_init */
195 NULL, /* base_finalize */
196 (GClassInitFunc) window_class_init, /* class_init */
197 NULL, /* class_finalize */
198 NULL, /* class_data */
199 sizeof (VikWindow),
200 0,
201 (GInstanceInitFunc) window_init,
202 };
203 vw_type = g_type_register_static ( GTK_TYPE_WINDOW, "VikWindow", &vw_info, 0 );
204 }
205
206 return vw_type;
207}
208
014128f6
QT
209VikViewport * vik_window_viewport(VikWindow *vw)
210{
211 return(vw->viking_vvp);
212}
213
79845167
QT
214void vik_window_selected_layer(VikWindow *vw, VikLayer *vl)
215{
216 int i, j, tool_count;
217 VikLayerInterface *layer_interface;
218
219 if (!vw->action_group) return;
220
221 for (i=0; i<VIK_LAYER_NUM_TYPES; i++) {
222 GtkAction *action;
223 layer_interface = vik_layer_get_interface(i);
224 tool_count = layer_interface->tools_count;
225
226 for (j = 0; j < tool_count; j++) {
227 action = gtk_action_group_get_action(vw->action_group,
228 layer_interface->tools[j].name);
229 g_object_set(action, "sensitive", i == vl->type, NULL);
230 }
231 }
232}
233
50a14534
EB
234static void window_finalize ( GObject *gob )
235{
236 VikWindow *vw = VIK_WINDOW(gob);
237 g_return_if_fail ( vw != NULL );
238
239 a_background_remove_status ( vw->viking_vs );
240
241 G_OBJECT_CLASS(parent_class)->finalize(gob);
242}
243
bce3a7b0 244
50a14534
EB
245static void window_class_init ( VikWindowClass *klass )
246{
247 /* destructor */
248 GObjectClass *object_class;
249
250 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 251 window_signals[VW_OPENWINDOW_SIGNAL] = g_signal_new ( "openwindow", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (VikWindowClass, openwindow), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);
50a14534
EB
252
253 object_class = G_OBJECT_CLASS (klass);
254
255 object_class->finalize = window_finalize;
256
257 parent_class = g_type_class_peek_parent (klass);
258
259}
260
261static void window_init ( VikWindow *vw )
262{
263 GtkWidget *main_vbox;
264 GtkWidget *hpaned;
265
79845167 266 vw->action_group = NULL;
50a14534 267
24277274 268 vw->viking_vvp = vik_viewport_new();
50a14534
EB
269 vw->viking_vlp = vik_layers_panel_new();
270 vik_layers_panel_set_viewport ( vw->viking_vlp, vw->viking_vvp );
271 vw->viking_vs = vik_statusbar_new();
272
941aa6e9
AF
273 vw->vt = toolbox_create(vw);
274 window_create_ui(vw);
4c77d5e0 275 window_set_filename (vw, NULL);
941aa6e9 276
576cbd17 277 toolbox_activate(vw->vt, "Pan");
941aa6e9 278
50a14534 279 vw->filename = NULL;
e4afc73a 280 vw->item_factory = NULL;
50a14534 281
50a14534
EB
282 vw->modified = FALSE;
283 vw->only_updating_coord_mode_ui = FALSE;
941aa6e9 284
50a14534
EB
285 vw->pan_x = vw->pan_y = -1;
286 vw->draw_image_width = DRAW_IMAGE_DEFAULT_WIDTH;
287 vw->draw_image_height = DRAW_IMAGE_DEFAULT_HEIGHT;
288 vw->draw_image_save_as_png = DRAW_IMAGE_DEFAULT_SAVE_AS_PNG;
289
290 main_vbox = gtk_vbox_new(FALSE, 1);
291 gtk_container_add (GTK_CONTAINER (vw), main_vbox);
292
e4afc73a
EB
293 gtk_box_pack_start (GTK_BOX(main_vbox), gtk_ui_manager_get_widget (vw->uim, "/MainMenu"), FALSE, TRUE, 0);
294 gtk_box_pack_start (GTK_BOX(main_vbox), gtk_ui_manager_get_widget (vw->uim, "/MainToolbar"), FALSE, TRUE, 0);
886031df
AF
295 gtk_toolbar_set_icon_size(GTK_TOOLBAR(gtk_ui_manager_get_widget (vw->uim, "/MainToolbar")), GTK_ICON_SIZE_SMALL_TOOLBAR);
296 gtk_toolbar_set_style (GTK_TOOLBAR(gtk_ui_manager_get_widget (vw->uim, "/MainToolbar")), GTK_TOOLBAR_ICONS);
50a14534 297
92806042 298 vik_ext_tools_add_menu_items ( vw, vw->uim );
777e2d4d 299
50a14534
EB
300 g_signal_connect (G_OBJECT (vw), "delete_event", G_CALLBACK (delete_event), NULL);
301
302 g_signal_connect_swapped (G_OBJECT(vw->viking_vvp), "expose_event", G_CALLBACK(draw_sync), vw);
bce3a7b0 303 g_signal_connect_swapped (G_OBJECT(vw->viking_vvp), "configure_event", G_CALLBACK(window_configure_event), vw);
777e2d4d 304 gtk_widget_add_events ( GTK_WIDGET(vw->viking_vvp), GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK );
50a14534
EB
305 g_signal_connect_swapped (G_OBJECT(vw->viking_vvp), "scroll_event", G_CALLBACK(draw_scroll), vw);
306 g_signal_connect_swapped (G_OBJECT(vw->viking_vvp), "button_press_event", G_CALLBACK(draw_click), vw);
307 g_signal_connect_swapped (G_OBJECT(vw->viking_vvp), "button_release_event", G_CALLBACK(draw_release), vw);
308 g_signal_connect_swapped (G_OBJECT(vw->viking_vvp), "motion_notify_event", G_CALLBACK(draw_mouse_motion), vw);
309 g_signal_connect_swapped (G_OBJECT(vw->viking_vlp), "update", G_CALLBACK(draw_update), vw);
310
165d30aa 311 g_signal_connect_swapped (G_OBJECT (vw->viking_vvp), "key_press_event", G_CALLBACK (key_press_event), vw);
777e2d4d 312
9a3cdf12 313 gtk_window_set_default_size ( GTK_WINDOW(vw), VIKING_WINDOW_WIDTH, VIKING_WINDOW_HEIGHT);
50a14534
EB
314
315 hpaned = gtk_hpaned_new ();
181f5d0c
MA
316 gtk_paned_pack1 ( GTK_PANED(hpaned), GTK_WIDGET (vw->viking_vlp), FALSE, FALSE );
317 gtk_paned_pack2 ( GTK_PANED(hpaned), GTK_WIDGET (vw->viking_vvp), TRUE, TRUE );
50a14534
EB
318
319 /* This packs the button into the window (a gtk container). */
320 gtk_box_pack_start (GTK_BOX(main_vbox), hpaned, TRUE, TRUE, 0);
321
322 gtk_box_pack_end (GTK_BOX(main_vbox), GTK_WIDGET(vw->viking_vs), FALSE, TRUE, 0);
323
324 a_background_add_status(vw->viking_vs);
325
326 vw->open_dia = NULL;
327 vw->save_dia = NULL;
f2a1ca71
QT
328 vw->save_img_dia = NULL;
329 vw->save_img_dir_dia = NULL;
50a14534
EB
330}
331
332VikWindow *vik_window_new ()
333{
334 return VIK_WINDOW ( g_object_new ( VIK_WINDOW_TYPE, NULL ) );
335}
336
777e2d4d
EB
337static gboolean key_press_event( VikWindow *vw, GdkEventKey *event, gpointer data )
338{
339 VikLayer *vl = vik_layers_panel_get_selected ( vw->viking_vlp );
340 if (vl && vw->vt->active_tool != -1 && vw->vt->tools[vw->vt->active_tool].ti.key_press ) {
341 gint ltype = vw->vt->tools[vw->vt->active_tool].layer_type;
342 if ( vl && ltype == vl->type )
343 return vw->vt->tools[vw->vt->active_tool].ti.key_press(vl, event, vw->vt->tools[vw->vt->active_tool].state);
344 }
345 return FALSE; /* don't handle the keypress */
346}
347
50a14534
EB
348static gboolean delete_event( VikWindow *vw )
349{
a5fd2196 350#ifdef VIKING_PROMPT_IF_MODIFIED
50a14534 351 if ( vw->modified )
a5fd2196
QT
352#else
353 if (0)
354#endif
50a14534
EB
355 {
356 GtkDialog *dia;
357 dia = GTK_DIALOG ( gtk_message_dialog_new ( GTK_WINDOW(vw), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
4c77d5e0
GB
358 _("Do you want to save the changes you made to the document \"%s\"?\n"
359 "\n"
360 "Your changes will be lost if you don't save them."),
361 vw->filename ? a_file_basename ( vw->filename ) : _("Untitled") ) );
362 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
363 switch ( gtk_dialog_run ( dia ) )
364 {
365 case GTK_RESPONSE_NO: gtk_widget_destroy ( GTK_WIDGET(dia) ); return FALSE;
366 case GTK_RESPONSE_CANCEL: gtk_widget_destroy ( GTK_WIDGET(dia) ); return TRUE;
e4afc73a 367 default: gtk_widget_destroy ( GTK_WIDGET(dia) ); return ! save_file(NULL, vw);
50a14534
EB
368 }
369 }
370 return FALSE;
371}
372
373/* Drawing stuff */
e4afc73a 374static void newwindow_cb ( GtkAction *a, VikWindow *vw )
50a14534
EB
375{
376 g_signal_emit ( G_OBJECT(vw), window_signals[VW_NEWWINDOW_SIGNAL], 0 );
377}
378
379static void draw_update ( VikWindow *vw )
380{
381 draw_redraw (vw);
382 draw_sync (vw);
383}
384
385static void draw_sync ( VikWindow *vw )
386{
387 vik_viewport_sync(vw->viking_vvp);
388 draw_status ( vw );
389 /* other things may be necc here later. */
390}
391
392static void draw_status ( VikWindow *vw )
393{
394 static gchar zoom_level[22];
4c77d5e0 395 g_snprintf ( zoom_level, 22, "%.3f/%.3f %s", vik_viewport_get_xmpp (vw->viking_vvp), vik_viewport_get_ympp(vw->viking_vvp), vik_viewport_get_coord_mode(vw->viking_vvp) == VIK_COORD_UTM ? _("mpp") : _("pixelfact") );
50a14534
EB
396 if ( vw->current_tool == TOOL_LAYER )
397 vik_statusbar_set_message ( vw->viking_vs, 0, vik_layer_get_interface(vw->tool_layer_id)->tools[vw->tool_tool_id].name );
398 else
4c77d5e0 399 vik_statusbar_set_message ( vw->viking_vs, 0, _(tool_names[vw->current_tool]) );
50a14534
EB
400
401 vik_statusbar_set_message ( vw->viking_vs, 2, zoom_level );
402}
403
c9177aae
QT
404void vik_window_set_redraw_trigger(VikLayer *vl)
405{
730a38c1 406 VikWindow *vw = VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vl));
be3b5803
GB
407 if (NULL != vw)
408 vw->trigger = vl;
c9177aae
QT
409}
410
bce3a7b0
EB
411static void window_configure_event ( VikWindow *vw )
412{
f2f2f7bf 413 static int first = 1;
bce3a7b0 414 draw_redraw ( vw );
372132a6
GB
415 if (first) {
416 // This is a hack to set the cursor corresponding to the first tool
417 // FIXME find the correct way to initialize both tool and its cursor
f2f2f7bf 418 const GdkCursor *cursor = NULL;
372132a6 419 first = 0;
f2f2f7bf
GB
420 cursor = toolbox_get_cursor(vw->vt, "Pan");
421 /* We set cursor, even if it is NULL: it resets to default */
422 gdk_window_set_cursor ( GTK_WIDGET(vw->viking_vvp)->window, cursor );
372132a6 423 }
bce3a7b0
EB
424}
425
50a14534
EB
426static void draw_redraw ( VikWindow *vw )
427{
c9177aae
QT
428 VikCoord old_center = vw->trigger_center;
429 vw->trigger_center = *(vik_viewport_get_center(vw->viking_vvp));
430 VikLayer *new_trigger = vw->trigger;
431 vw->trigger = NULL;
0df66d57
EB
432 VikLayer *old_trigger = VIK_LAYER(vik_viewport_get_trigger(vw->viking_vvp));
433
434 if ( ! new_trigger )
435 ; /* do nothing -- have to redraw everything. */
c9177aae 436 else if ( (old_trigger != new_trigger) || !vik_coord_equals(&old_center, &vw->trigger_center) )
0df66d57
EB
437 vik_viewport_set_trigger ( vw->viking_vvp, new_trigger ); /* todo: set to half_drawn mode if new trigger is above old */
438 else
439 vik_viewport_set_half_drawn ( vw->viking_vvp, TRUE );
440
441 /* actually draw */
50a14534 442 vik_viewport_clear ( vw->viking_vvp);
50a14534 443 vik_layers_panel_draw_all ( vw->viking_vlp );
acaf7113 444 vik_viewport_draw_scale ( vw->viking_vvp );
c933487f 445 vik_viewport_draw_centermark ( vw->viking_vvp );
0df66d57
EB
446
447 vik_viewport_set_half_drawn ( vw->viking_vvp, FALSE ); /* just in case. */
50a14534
EB
448}
449
941aa6e9
AF
450gboolean draw_buf_done = TRUE;
451
452static gboolean draw_buf(gpointer data)
453{
454 gpointer *pass_along = data;
455 gdk_threads_enter();
456 gdk_draw_drawable (pass_along[0], pass_along[1],
457 pass_along[2], 0, 0, 0, 0, -1, -1);
458 draw_buf_done = TRUE;
459 gdk_threads_leave();
460 return FALSE;
461}
462
463
464/* Mouse event handlers ************************************************************************/
465
b57126a3
GB
466static void vik_window_pan_click (VikWindow *vw, GdkEventButton *event)
467{
468 /* set panning origin */
469 vw->pan_x = (gint) event->x;
470 vw->pan_y = (gint) event->y;
471}
472
941aa6e9
AF
473static void draw_click (VikWindow *vw, GdkEventButton *event)
474{
165d30aa 475 gtk_widget_grab_focus ( GTK_WIDGET(vw->viking_vvp) );
941aa6e9
AF
476
477 /* middle button pressed. we reserve all middle button and scroll events
478 * for panning and zooming; tools only get left/right/movement
479 */
480 if ( event->button == 2) {
b57126a3 481 vik_window_pan_click ( vw, event );
941aa6e9
AF
482 }
483 else {
484 toolbox_click(vw->vt, event);
485 }
486}
487
b57126a3
GB
488static void vik_window_pan_move (VikWindow *vw, GdkEventMotion *event)
489{
490 if ( vw->pan_x != -1 ) {
491 vik_viewport_pan_sync ( vw->viking_vvp, event->x - vw->pan_x, event->y - vw->pan_y );
492 }
493}
494
941aa6e9
AF
495static void draw_mouse_motion (VikWindow *vw, GdkEventMotion *event)
496{
497 static VikCoord coord;
498 static struct UTM utm;
499 static struct LatLon ll;
a58aaed4
GB
500 #define BUFFER_SIZE 50
501 static char pointer_buf[BUFFER_SIZE];
502 gchar *lat = NULL, *lon = NULL;
071da616 503 gint16 alt;
228213c5
QT
504 gdouble zoom;
505 VikDemInterpol interpol_method;
941aa6e9 506
576cbd17 507 toolbox_move(vw->vt, event);
941aa6e9
AF
508
509 vik_viewport_screen_to_coord ( vw->viking_vvp, event->x, event->y, &coord );
510 vik_coord_to_utm ( &coord, &utm );
511 a_coords_utm_to_latlon ( &utm, &ll );
a58aaed4 512 a_coords_latlon_to_string ( &ll, &lat, &lon );
228213c5
QT
513 /* Change interpolate method according to scale */
514 zoom = vik_viewport_get_zoom(vw->viking_vvp);
515 if (zoom > 2.0)
516 interpol_method = VIK_DEM_INTERPOL_NONE;
517 else if (zoom >= 1.0)
518 interpol_method = VIK_DEM_INTERPOL_SIMPLE;
519 else
520 interpol_method = VIK_DEM_INTERPOL_BEST;
521 if ((alt = a_dems_get_elev_by_coord(&coord, interpol_method)) != VIK_DEM_INVALID_ELEVATION)
a58aaed4 522 g_snprintf ( pointer_buf, BUFFER_SIZE, _("%s %s %dm"), lat, lon, alt );
071da616 523 else
a58aaed4
GB
524 g_snprintf ( pointer_buf, BUFFER_SIZE, _("%s %s"), lat, lon );
525 g_free (lat);
526 lat = NULL;
527 g_free (lon);
528 lon = NULL;
941aa6e9
AF
529 vik_statusbar_set_message ( vw->viking_vs, 4, pointer_buf );
530
b57126a3
GB
531 vik_window_pan_move ( vw, event );
532}
533
534static void vik_window_pan_release ( VikWindow *vw, GdkEventButton *event )
535{
536 if ( ABS(vw->pan_x - event->x) <= 1 && ABS(vw->pan_y - event->y) <= 1 )
537 vik_viewport_set_center_screen ( vw->viking_vvp, vw->pan_x, vw->pan_y );
538 else
539 vik_viewport_set_center_screen ( vw->viking_vvp, vik_viewport_get_width(vw->viking_vvp)/2 - event->x + vw->pan_x,
540 vik_viewport_get_height(vw->viking_vvp)/2 - event->y + vw->pan_y );
541 draw_update ( vw );
542 vw->pan_x = vw->pan_y = -1;
941aa6e9
AF
543}
544
545static void draw_release ( VikWindow *vw, GdkEventButton *event )
546{
165d30aa
EB
547 gtk_widget_grab_focus ( GTK_WIDGET(vw->viking_vvp) );
548
941aa6e9 549 if ( event->button == 2 ) { /* move / pan */
b57126a3 550 vik_window_pan_release(vw, event);
941aa6e9
AF
551 }
552 else {
553 toolbox_release(vw->vt, event);
554 }
555}
556
557static void draw_scroll (VikWindow *vw, GdkEventScroll *event)
558{
bddd2056 559 if ( event->state == GDK_CONTROL_MASK ) {
8c721f83
EB
560 /* control == pan up & down */
561 if ( event->direction == GDK_SCROLL_UP )
562 vik_viewport_set_center_screen ( vw->viking_vvp, vik_viewport_get_width(vw->viking_vvp)/2, vik_viewport_get_height(vw->viking_vvp)/3 );
563 else
564 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 );
e086b16d 565 } else if ( event->state == GDK_SHIFT_MASK ) {
8c721f83
EB
566 /* control-shift == pan left & right */
567 if ( event->direction == GDK_SCROLL_UP )
568 vik_viewport_set_center_screen ( vw->viking_vvp, vik_viewport_get_width(vw->viking_vvp)/3, vik_viewport_get_height(vw->viking_vvp)/2 );
569 else
570 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 );
e086b16d 571 } else if ( event->state == (GDK_CONTROL_MASK | GDK_SHIFT_MASK) ) {
9a30122d
EB
572 if ( event->direction == GDK_SCROLL_UP ) {
573 /* make sure mouse is still over the same point on the map when we zoom */
574 VikCoord coord;
575 gint x, y;
576 gint center_x = vik_viewport_get_width ( vw->viking_vvp ) / 2;
577 gint center_y = vik_viewport_get_height ( vw->viking_vvp ) / 2;
578 vik_viewport_screen_to_coord ( vw->viking_vvp, event->x, event->y, &coord );
8c721f83 579 vik_viewport_zoom_in (vw->viking_vvp);
9a30122d
EB
580 vik_viewport_coord_to_screen ( vw->viking_vvp, &coord, &x, &y );
581 vik_viewport_set_center_screen ( vw->viking_vvp, center_x + (x - event->x),
582 center_y + (y - event->y) );
583 }
584 else {
585 VikCoord coord;
586 gint x, y;
587 gint center_x = vik_viewport_get_width ( vw->viking_vvp ) / 2;
588 gint center_y = vik_viewport_get_height ( vw->viking_vvp ) / 2;
589 vik_viewport_screen_to_coord ( vw->viking_vvp, event->x, event->y, &coord );
8c721f83 590 vik_viewport_zoom_out(vw->viking_vvp);
9a30122d
EB
591 vik_viewport_coord_to_screen ( vw->viking_vvp, &coord, &x, &y );
592 vik_viewport_set_center_screen ( vw->viking_vvp, center_x + (x - event->x),
593 center_y + (y - event->y) );
594 }
e086b16d
EB
595 } else {
596 if ( event->direction == GDK_SCROLL_UP )
597 vik_viewport_zoom_in (vw->viking_vvp);
598 else
599 vik_viewport_zoom_out (vw->viking_vvp);
8c721f83
EB
600 }
601
941aa6e9
AF
602 draw_update(vw);
603}
604
605
606
607/********************************************************************************
608 ** Ruler tool code
609 ********************************************************************************/
e4847ce9
AF
610static void draw_ruler(VikViewport *vvp, GdkDrawable *d, GdkGC *gc, gint x1, gint y1, gint x2, gint y2, gdouble distance)
611{
612 PangoFontDescription *pfd;
613 PangoLayout *pl;
614 gchar str[128];
0dff88ea
AF
615 GdkGC *labgc = vik_viewport_new_gc ( vvp, "#cccccc", 1);
616 GdkGC *thickgc = gdk_gc_new(d);
617
e4847ce9
AF
618 gdouble len = sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
619 gdouble dx = (x2-x1)/len*10;
620 gdouble dy = (y2-y1)/len*10;
621 gdouble c = cos(15.0 * M_PI/180.0);
622 gdouble s = sin(15.0 * M_PI/180.0);
0dff88ea 623 gdouble angle;
15614495 624 gdouble baseangle = 0;
0dff88ea 625 gint i;
e4847ce9 626
0dff88ea 627 /* draw line with arrow ends */
d9ffd267
EB
628 {
629 gint tmp_x1=x1, tmp_y1=y1, tmp_x2=x2, tmp_y2=y2;
630 a_viewport_clip_line(&tmp_x1, &tmp_y1, &tmp_x2, &tmp_y2);
631 gdk_draw_line(d, gc, tmp_x1, tmp_y1, tmp_x2, tmp_y2);
632 }
633
15614495
AF
634 a_viewport_clip_line(&x1, &y1, &x2, &y2);
635 gdk_draw_line(d, gc, x1, y1, x2, y2);
d9ffd267 636
e4847ce9
AF
637 gdk_draw_line(d, gc, x1 - dy, y1 + dx, x1 + dy, y1 - dx);
638 gdk_draw_line(d, gc, x2 - dy, y2 + dx, x2 + dy, y2 - dx);
639 gdk_draw_line(d, gc, x2, y2, x2 - (dx * c + dy * s), y2 - (dy * c - dx * s));
640 gdk_draw_line(d, gc, x2, y2, x2 - (dx * c - dy * s), y2 - (dy * c + dx * s));
641 gdk_draw_line(d, gc, x1, y1, x1 + (dx * c + dy * s), y1 + (dy * c - dx * s));
642 gdk_draw_line(d, gc, x1, y1, x1 + (dx * c - dy * s), y1 + (dy * c + dx * s));
643
0dff88ea
AF
644 /* draw compass */
645#define CR 80
646#define CW 4
15614495
AF
647 angle = atan2(dy, dx) + M_PI_2;
648
649 if ( vik_viewport_get_drawmode ( vvp ) == VIK_VIEWPORT_DRAWMODE_UTM) {
650 VikCoord test;
651 struct LatLon ll;
652 struct UTM u;
653 gint tx, ty;
654
655 vik_viewport_screen_to_coord ( vvp, x1, y1, &test );
656 vik_coord_to_latlon ( &test, &ll );
657 ll.lat += vik_viewport_get_ympp ( vvp ) * vik_viewport_get_height ( vvp ) / 11000.0; // about 11km per degree latitude
658 a_coords_latlon_to_utm ( &ll, &u );
659 vik_coord_load_from_utm ( &test, VIK_VIEWPORT_DRAWMODE_UTM, &u );
660 vik_viewport_coord_to_screen ( vvp, &test, &tx, &ty );
661
662 baseangle = M_PI - atan2(tx-x1, ty-y1);
663 angle -= baseangle;
664 }
665
0dff88ea
AF
666 if (angle<0)
667 angle+=2*M_PI;
668 if (angle>2*M_PI)
669 angle-=2*M_PI;
670
671 {
672 GdkColor color;
673 gdk_gc_copy(thickgc, gc);
674 gdk_gc_set_line_attributes(thickgc, CW, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
675 gdk_color_parse("#2255cc", &color);
676 gdk_gc_set_rgb_fg_color(thickgc, &color);
677 }
15614495 678 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 679
e4847ce9 680
0dff88ea
AF
681 gdk_gc_copy(thickgc, gc);
682 gdk_gc_set_line_attributes(thickgc, 2, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
683 for (i=0; i<180; i++) {
15614495
AF
684 c = cos(i*M_PI/90.0 + baseangle);
685 s = sin(i*M_PI/90.0 + baseangle);
e4847ce9 686
0dff88ea
AF
687 if (i%5) {
688 gdk_draw_line (d, gc, x1 + CR*c, y1 + CR*s, x1 + (CR+CW)*c, y1 + (CR+CW)*s);
689 } else {
690 gdouble ticksize = 2*CW;
691 gdk_draw_line (d, thickgc, x1 + (CR-CW)*c, y1 + (CR-CW)*s, x1 + (CR+ticksize)*c, y1 + (CR+ticksize)*s);
692 }
e4847ce9 693 }
0dff88ea
AF
694
695 gdk_draw_arc (d, gc, FALSE, x1-CR, y1-CR, 2*CR, 2*CR, 0, 64*360);
696 gdk_draw_arc (d, gc, FALSE, x1-CR-CW, y1-CR-CW, 2*(CR+CW), 2*(CR+CW), 0, 64*360);
697 gdk_draw_arc (d, gc, FALSE, x1-CR+CW, y1-CR+CW, 2*(CR-CW), 2*(CR-CW), 0, 64*360);
15614495
AF
698 c = (CR+CW*2)*cos(baseangle);
699 s = (CR+CW*2)*sin(baseangle);
700 gdk_draw_line (d, gc, x1-c, y1-s, x1+c, y1+s);
701 gdk_draw_line (d, gc, x1+s, y1-c, x1-s, y1+c);
0dff88ea
AF
702
703 /* draw labels */
704#define LABEL(x, y, w, h) { \
705 gdk_draw_rectangle(d, labgc, TRUE, (x)-2, (y)-1, (w)+4, (h)+1); \
706 gdk_draw_rectangle(d, gc, FALSE, (x)-2, (y)-1, (w)+4, (h)+1); \
707 gdk_draw_layout(d, gc, (x), (y), pl); }
708 {
709 gint wd, hd, xd, yd;
710 gint wb, hb, xb, yb;
711
712 pl = gtk_widget_create_pango_layout (GTK_WIDGET(vvp), NULL);
713
714 pfd = pango_font_description_from_string ("Sans 8"); // FIXME: settable option? global variable?
715 pango_layout_set_font_description (pl, pfd);
716 pango_font_description_free (pfd);
717
718 pango_layout_set_text(pl, "N", -1);
719 gdk_draw_layout(d, gc, x1-5, y1-CR-3*CW-8, pl);
720
721 /* draw label with distance */
722 if (distance >= 1000 && distance < 100000) {
15614495 723 g_sprintf(str, "%3.2f km", distance/1000.0);
0dff88ea 724 } else if (distance < 1000) {
15614495 725 g_sprintf(str, "%d m", (int)distance);
0dff88ea 726 } else {
15614495 727 g_sprintf(str, "%d km", (int)distance/1000);
0dff88ea
AF
728 }
729 pango_layout_set_text(pl, str, -1);
730
731 pango_layout_get_pixel_size ( pl, &wd, &hd );
732 if (dy>0) {
733 xd = (x1+x2)/2 + dy;
734 yd = (y1+y2)/2 - hd/2 - dx;
735 } else {
736 xd = (x1+x2)/2 - dy;
737 yd = (y1+y2)/2 - hd/2 + dx;
738 }
024f32c1
EB
739
740 if ( xd < -5 || yd < -5 || xd > vik_viewport_get_width(vvp)+5 || yd > vik_viewport_get_height(vvp)+5 ) {
741 xd = x2 + 10;
742 yd = y2 - 5;
743 }
744
0dff88ea
AF
745 LABEL(xd, yd, wd, hd);
746
747 /* draw label with bearing */
15614495 748 g_sprintf(str, "%3.1f°", angle*180.0/M_PI);
0dff88ea
AF
749 pango_layout_set_text(pl, str, -1);
750 pango_layout_get_pixel_size ( pl, &wb, &hb );
751 xb = x1 + CR*cos(angle-M_PI_2);
752 yb = y1 + CR*sin(angle-M_PI_2);
753
024f32c1
EB
754 if ( xb < -5 || yb < -5 || xb > vik_viewport_get_width(vvp)+5 || yb > vik_viewport_get_height(vvp)+5 ) {
755 xb = x2 + 10;
756 yb = y2 + 10;
757 }
758
0dff88ea
AF
759 {
760 GdkRectangle r1 = {xd-2, yd-1, wd+4, hd+1}, r2 = {xb-2, yb-1, wb+4, hb+1};
761 if (gdk_rectangle_intersect(&r1, &r2, &r2)) {
762 xb = xd + wd + 5;
763 }
764 }
765 LABEL(xb, yb, wb, hb);
e4847ce9 766 }
03d62e57 767#undef LABEL
e4847ce9 768
024f32c1 769 g_object_unref ( G_OBJECT ( pl ) );
0dff88ea
AF
770 g_object_unref ( G_OBJECT ( labgc ) );
771 g_object_unref ( G_OBJECT ( thickgc ) );
e4847ce9
AF
772}
773
941aa6e9
AF
774typedef struct {
775 VikWindow *vw;
776 VikViewport *vvp;
777 gboolean has_oldcoord;
778 VikCoord oldcoord;
779} ruler_tool_state_t;
03d62e57 780
941aa6e9 781static gpointer ruler_create (VikWindow *vw, VikViewport *vvp)
03d62e57 782{
941aa6e9
AF
783 ruler_tool_state_t *s = g_new(ruler_tool_state_t, 1);
784 s->vw = vw;
785 s->vvp = vvp;
786 s->has_oldcoord = FALSE;
787 return s;
03d62e57
AF
788}
789
941aa6e9 790static void ruler_destroy (ruler_tool_state_t *s)
50a14534 791{
941aa6e9
AF
792 g_free(s);
793}
50a14534 794
941aa6e9
AF
795static VikLayerToolFuncStatus ruler_click (VikLayer *vl, GdkEventButton *event, ruler_tool_state_t *s)
796{
797 struct LatLon ll;
798 VikCoord coord;
799 gchar *temp;
800 if ( event->button == 1 ) {
a58aaed4 801 gchar *lat=NULL, *lon=NULL;
941aa6e9
AF
802 vik_viewport_screen_to_coord ( s->vvp, (gint) event->x, (gint) event->y, &coord );
803 vik_coord_to_latlon ( &coord, &ll );
a58aaed4 804 a_coords_latlon_to_string ( &ll, &lat, &lon );
941aa6e9 805 if ( s->has_oldcoord ) {
a58aaed4 806 temp = g_strdup_printf ( "%s %s DIFF %f meters", lat, lon, vik_coord_diff( &coord, &(s->oldcoord) ) );
941aa6e9
AF
807 s->has_oldcoord = FALSE;
808 }
809 else {
a58aaed4 810 temp = g_strdup_printf ( "%s %s", lat, lon );
941aa6e9
AF
811 s->has_oldcoord = TRUE;
812 }
50a14534 813
941aa6e9
AF
814 vik_statusbar_set_message ( s->vw->viking_vs, 3, temp );
815 g_free ( temp );
e4847ce9 816
941aa6e9
AF
817 s->oldcoord = coord;
818 }
819 else {
820 vik_viewport_set_center_screen ( s->vvp, (gint) event->x, (gint) event->y );
821 draw_update ( s->vw );
822 }
823 return VIK_LAYER_TOOL_ACK;
824}
e4847ce9 825
dc2c040e 826static VikLayerToolFuncStatus ruler_move (VikLayer *vl, GdkEventMotion *event, ruler_tool_state_t *s)
941aa6e9
AF
827{
828 VikViewport *vvp = s->vvp;
829 VikWindow *vw = s->vw;
830
831 struct LatLon ll;
832 VikCoord coord;
833 gchar *temp;
834
835 if ( s->has_oldcoord ) {
836 int oldx, oldy, w1, h1, w2, h2;
837 static GdkPixmap *buf = NULL;
a58aaed4 838 gchar *lat=NULL, *lon=NULL;
941aa6e9
AF
839 w1 = vik_viewport_get_width(vvp);
840 h1 = vik_viewport_get_height(vvp);
841 if (!buf) {
842 buf = gdk_pixmap_new ( GTK_WIDGET(vvp)->window, w1, h1, -1 );
843 }
844 gdk_drawable_get_size(buf, &w2, &h2);
845 if (w1 != w2 || h1 != h2) {
846 g_object_unref ( G_OBJECT ( buf ) );
847 buf = gdk_pixmap_new ( GTK_WIDGET(vvp)->window, w1, h1, -1 );
e4847ce9 848 }
e4847ce9 849
941aa6e9
AF
850 vik_viewport_screen_to_coord ( vvp, (gint) event->x, (gint) event->y, &coord );
851 vik_coord_to_latlon ( &coord, &ll );
852 vik_viewport_coord_to_screen ( vvp, &s->oldcoord, &oldx, &oldy );
853
854 gdk_draw_drawable (buf, GTK_WIDGET(vvp)->style->black_gc,
855 vik_viewport_get_pixmap(vvp), 0, 0, 0, 0, -1, -1);
856 draw_ruler(vvp, buf, GTK_WIDGET(vvp)->style->black_gc, oldx, oldy, event->x, event->y, vik_coord_diff( &coord, &(s->oldcoord)) );
857 if (draw_buf_done) {
858 static gpointer pass_along[3];
859 pass_along[0] = GTK_WIDGET(vvp)->window;
860 pass_along[1] = GTK_WIDGET(vvp)->style->black_gc;
861 pass_along[2] = buf;
862 g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, draw_buf, pass_along, NULL);
863 draw_buf_done = FALSE;
864 }
a58aaed4
GB
865 a_coords_latlon_to_string(&ll, &lat, &lon);
866 temp = g_strdup_printf ( "%s %s DIFF %f meters", lat, lon, vik_coord_diff( &coord, &(s->oldcoord) ) );
941aa6e9
AF
867 vik_statusbar_set_message ( vw->viking_vs, 3, temp );
868 g_free ( temp );
acaf7113 869 }
941aa6e9
AF
870 return VIK_LAYER_TOOL_ACK;
871}
50a14534 872
941aa6e9
AF
873static VikLayerToolFuncStatus ruler_release (VikLayer *vl, GdkEventButton *event, ruler_tool_state_t *s)
874{
875 return VIK_LAYER_TOOL_ACK;
50a14534
EB
876}
877
941aa6e9 878static void ruler_deactivate (VikLayer *vl, ruler_tool_state_t *s)
50a14534 879{
941aa6e9 880 draw_update ( s->vw );
50a14534
EB
881}
882
941aa6e9
AF
883static VikToolInterface ruler_tool =
884 { "Ruler",
885 (VikToolConstructorFunc) ruler_create,
886 (VikToolDestructorFunc) ruler_destroy,
887 (VikToolActivationFunc) NULL,
888 (VikToolActivationFunc) ruler_deactivate,
889 (VikToolMouseFunc) ruler_click,
dc2c040e 890 (VikToolMouseMoveFunc) ruler_move,
f2f2f7bf
GB
891 (VikToolMouseFunc) ruler_release,
892 NULL,
893 GDK_CURSOR_IS_PIXMAP,
5bfafde9 894 &cursor_ruler_pixbuf };
941aa6e9
AF
895/*** end ruler code ********************************************************/
896
897
898
899/********************************************************************************
900 ** Zoom tool code
901 ********************************************************************************/
902static gpointer zoomtool_create (VikWindow *vw, VikViewport *vvp)
50a14534 903{
941aa6e9 904 return vw;
50a14534
EB
905}
906
941aa6e9 907static VikLayerToolFuncStatus zoomtool_click (VikLayer *vl, GdkEventButton *event, VikWindow *vw)
50a14534 908{
941aa6e9
AF
909 vw->modified = TRUE;
910 vik_viewport_set_center_screen ( vw->viking_vvp, (gint) event->x, (gint) event->y );
911 if ( event->button == 1 )
912 vik_viewport_zoom_in (vw->viking_vvp);
913 else if ( event->button == 3 )
914 vik_viewport_zoom_out (vw->viking_vvp);
915 draw_update ( vw );
916 return VIK_LAYER_TOOL_ACK;
917}
50a14534 918
dc2c040e 919static VikLayerToolFuncStatus zoomtool_move (VikLayer *vl, GdkEventMotion *event, VikViewport *vvp)
941aa6e9
AF
920{
921 return VIK_LAYER_TOOL_ACK;
922}
50a14534 923
941aa6e9
AF
924static VikLayerToolFuncStatus zoomtool_release (VikLayer *vl, GdkEventButton *event, VikViewport *vvp)
925{
926 return VIK_LAYER_TOOL_ACK;
50a14534
EB
927}
928
941aa6e9
AF
929static VikToolInterface zoom_tool =
930 { "Zoom",
931 (VikToolConstructorFunc) zoomtool_create,
932 (VikToolDestructorFunc) NULL,
933 (VikToolActivationFunc) NULL,
934 (VikToolActivationFunc) NULL,
935 (VikToolMouseFunc) zoomtool_click,
dc2c040e 936 (VikToolMouseMoveFunc) zoomtool_move,
f2f2f7bf
GB
937 (VikToolMouseFunc) zoomtool_release,
938 NULL,
939 GDK_CURSOR_IS_PIXMAP,
5bfafde9 940 &cursor_zoom_pixbuf };
463f9d07 941/*** end zoom code ********************************************************/
941aa6e9 942
576cbd17
GB
943/********************************************************************************
944 ** Pan tool code
945 ********************************************************************************/
946static gpointer pantool_create (VikWindow *vw, VikViewport *vvp)
947{
948 return vw;
949}
950
951static VikLayerToolFuncStatus pantool_click (VikLayer *vl, GdkEventButton *event, VikWindow *vw)
952{
953 vw->modified = TRUE;
954 if ( event->button == 1 )
955 vik_window_pan_click ( vw, event );
956 draw_update ( vw );
957 return VIK_LAYER_TOOL_ACK;
958}
959
dc2c040e 960static VikLayerToolFuncStatus pantool_move (VikLayer *vl, GdkEventMotion *event, VikWindow *vw)
576cbd17
GB
961{
962 vik_window_pan_move ( vw, event );
963 return VIK_LAYER_TOOL_ACK;
964}
965
966static VikLayerToolFuncStatus pantool_release (VikLayer *vl, GdkEventButton *event, VikWindow *vw)
967{
968 if ( event->button == 1 )
969 vik_window_pan_release ( vw, event );
970 return VIK_LAYER_TOOL_ACK;
971}
972
973static VikToolInterface pan_tool =
974 { "Pan",
975 (VikToolConstructorFunc) pantool_create,
976 (VikToolDestructorFunc) NULL,
977 (VikToolActivationFunc) NULL,
978 (VikToolActivationFunc) NULL,
979 (VikToolMouseFunc) pantool_click,
dc2c040e 980 (VikToolMouseMoveFunc) pantool_move,
f2f2f7bf
GB
981 (VikToolMouseFunc) pantool_release,
982 NULL,
983 GDK_FLEUR };
576cbd17
GB
984/*** end pan code ********************************************************/
985
8c721f83
EB
986static void draw_pan_cb ( GtkAction *a, VikWindow *vw )
987{
988 if (!strcmp(gtk_action_get_name(a), "PanNorth")) {
989 vik_viewport_set_center_screen ( vw->viking_vvp, vik_viewport_get_width(vw->viking_vvp)/2, 0 );
990 } else if (!strcmp(gtk_action_get_name(a), "PanEast")) {
991 vik_viewport_set_center_screen ( vw->viking_vvp, vik_viewport_get_width(vw->viking_vvp), vik_viewport_get_height(vw->viking_vvp)/2 );
992 } else if (!strcmp(gtk_action_get_name(a), "PanSouth")) {
993 vik_viewport_set_center_screen ( vw->viking_vvp, vik_viewport_get_width(vw->viking_vvp)/2, vik_viewport_get_height(vw->viking_vvp) );
994 } else if (!strcmp(gtk_action_get_name(a), "PanWest")) {
995 vik_viewport_set_center_screen ( vw->viking_vvp, 0, vik_viewport_get_height(vw->viking_vvp)/2 );
996 }
997 draw_update ( vw );
998}
941aa6e9 999
7de42638
EB
1000static void full_screen_cb ( GtkAction *a, VikWindow *vw )
1001{
1002 GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/FullScreen" );
1003 g_assert(check_box);
1004 gboolean state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box));
1005 if ( state )
1006 gtk_window_fullscreen ( GTK_WINDOW(vw) );
1007 else
1008 gtk_window_unfullscreen ( GTK_WINDOW(vw) );
1009}
941aa6e9 1010
e4afc73a 1011static void draw_zoom_cb ( GtkAction *a, VikWindow *vw )
50a14534 1012{
e4afc73a
EB
1013 guint what = 128;
1014
1015 if (!strcmp(gtk_action_get_name(a), "ZoomIn")) {
1016 what = -3;
1017 }
1018 else if (!strcmp(gtk_action_get_name(a), "ZoomOut")) {
1019 what = -4;
1020 }
1021 else if (!strcmp(gtk_action_get_name(a), "Zoom0.25")) {
1022 what = -2;
1023 }
1024 else if (!strcmp(gtk_action_get_name(a), "Zoom0.5")) {
1025 what = -1;
1026 }
1027 else {
1028 gchar *s = (gchar *)gtk_action_get_name(a);
1029 what = atoi(s+4);
1030 }
1031
50a14534
EB
1032 switch (what)
1033 {
1034 case -3: vik_viewport_zoom_in ( vw->viking_vvp ); break;
1035 case -4: vik_viewport_zoom_out ( vw->viking_vvp ); break;
1036 case -1: vik_viewport_set_zoom ( vw->viking_vvp, 0.5 ); break;
1037 case -2: vik_viewport_set_zoom ( vw->viking_vvp, 0.25 ); break;
1038 default: vik_viewport_set_zoom ( vw->viking_vvp, what );
1039 }
1040 draw_update ( vw );
1041}
1042
e4afc73a 1043void draw_goto_cb ( GtkAction *a, VikWindow *vw )
50a14534
EB
1044{
1045 VikCoord new_center;
e4afc73a
EB
1046
1047 if (!strcmp(gtk_action_get_name(a), "GotoLL")) {
50a14534
EB
1048 struct LatLon ll, llold;
1049 vik_coord_to_latlon ( vik_viewport_get_center ( vw->viking_vvp ), &llold );
1050 if ( a_dialog_goto_latlon ( GTK_WINDOW(vw), &ll, &llold ) )
1051 vik_coord_load_from_latlon ( &new_center, vik_viewport_get_coord_mode(vw->viking_vvp), &ll );
1052 else
1053 return;
1054 }
e4afc73a 1055 else if (!strcmp(gtk_action_get_name(a), "GotoUTM")) {
50a14534
EB
1056 struct UTM utm, utmold;
1057 vik_coord_to_utm ( vik_viewport_get_center ( vw->viking_vvp ), &utmold );
1058 if ( a_dialog_goto_utm ( GTK_WINDOW(vw), &utm, &utmold ) )
1059 vik_coord_load_from_utm ( &new_center, vik_viewport_get_coord_mode(vw->viking_vvp), &utm );
1060 else
1061 return;
1062 }
e4afc73a 1063 else {
8dc8da82 1064 g_critical("Houston, we've had a problem.");
e4afc73a
EB
1065 return;
1066 }
50a14534
EB
1067
1068 vik_viewport_set_center_coord ( vw->viking_vvp, &new_center );
1069 draw_update ( vw );
1070}
1071
e4afc73a 1072static void menu_addlayer_cb ( GtkAction *a, VikWindow *vw )
50a14534 1073{
e4afc73a
EB
1074 gint type;
1075 for ( type = 0; type < VIK_LAYER_NUM_TYPES; type++ ) {
1076 if (!strcmp(vik_layer_get_interface(type)->name, gtk_action_get_name(a))) {
1077 if ( vik_layers_panel_new_layer ( vw->viking_vlp, type ) ) {
1078 draw_update ( vw );
1079 vw->modified = TRUE;
1080 }
1081 }
50a14534
EB
1082 }
1083}
1084
e4afc73a 1085static void menu_copy_layer_cb ( GtkAction *a, VikWindow *vw )
50a14534 1086{
2cebc318 1087 a_clipboard_copy_selected ( vw->viking_vlp );
50a14534
EB
1088}
1089
e4afc73a 1090static void menu_cut_layer_cb ( GtkAction *a, VikWindow *vw )
50a14534 1091{
2cebc318 1092 a_clipboard_copy_selected ( vw->viking_vlp );
e4afc73a 1093 menu_delete_layer_cb ( a, vw );
50a14534
EB
1094}
1095
e4afc73a 1096static void menu_paste_layer_cb ( GtkAction *a, VikWindow *vw )
50a14534
EB
1097{
1098 if ( a_clipboard_paste ( vw->viking_vlp ) )
1099 {
1100 draw_update ( vw );
1101 vw->modified = TRUE;
1102 }
1103}
1104
e4afc73a 1105static void menu_properties_cb ( GtkAction *a, VikWindow *vw )
50a14534
EB
1106{
1107 if ( ! vik_layers_panel_properties ( vw->viking_vlp ) )
4c77d5e0 1108 a_dialog_info_msg ( GTK_WINDOW(vw), _("You must select a layer to show its properties.") );
50a14534
EB
1109}
1110
d0a5f320
AF
1111static void help_about_cb ( GtkAction *a, VikWindow *vw )
1112{
1113 a_dialog_about(GTK_WINDOW(vw));
1114}
1115
e4afc73a 1116static void menu_delete_layer_cb ( GtkAction *a, VikWindow *vw )
50a14534
EB
1117{
1118 if ( vik_layers_panel_get_selected ( vw->viking_vlp ) )
1119 {
1120 vik_layers_panel_delete_selected ( vw->viking_vlp );
1121 vw->modified = TRUE;
1122 }
1123 else
4c77d5e0 1124 a_dialog_info_msg ( GTK_WINDOW(vw), _("You must select a layer to delete.") );
50a14534
EB
1125}
1126
181f5d0c
MA
1127static void view_side_panel_cb ( GtkAction *a, VikWindow *vw )
1128{
1129 GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/ViewSidePanel" );
1130 g_assert(check_box);
1131 gboolean state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box));
1132 if ( state )
1133 gtk_widget_show(GTK_WIDGET(vw->viking_vlp));
1134 else
1135 gtk_widget_hide(GTK_WIDGET(vw->viking_vlp));
1136}
1137
941aa6e9
AF
1138/***************************************
1139 ** tool management routines
1140 **
1141 ***************************************/
1142
1143static toolbox_tools_t* toolbox_create(VikWindow *vw)
1144{
1145 toolbox_tools_t *vt = g_new(toolbox_tools_t, 1);
1146 vt->tools = NULL;
1147 vt->n_tools = 0;
1148 vt->active_tool = -1;
1149 vt->vw = vw;
1150 if (!vw->viking_vvp) {
7742da66 1151 g_critical("no viewport found.");
941aa6e9
AF
1152 exit(1);
1153 }
1154 return vt;
1155}
1156
9593a4c9 1157static void toolbox_add_tool(toolbox_tools_t *vt, VikToolInterface *vti, gint layer_type )
941aa6e9
AF
1158{
1159 vt->tools = g_renew(toolbox_tool_t, vt->tools, vt->n_tools+1);
1160 vt->tools[vt->n_tools].ti = *vti;
9593a4c9 1161 vt->tools[vt->n_tools].layer_type = layer_type;
941aa6e9
AF
1162 if (vti->create) {
1163 vt->tools[vt->n_tools].state = vti->create(vt->vw, vt->vw->viking_vvp);
1164 }
1165 else {
1166 vt->tools[vt->n_tools].state = NULL;
1167 }
1168 vt->n_tools++;
1169}
1170
1171static int toolbox_get_tool(toolbox_tools_t *vt, const gchar *tool_name)
1172{
1173 int i;
1174 for (i=0; i<vt->n_tools; i++) {
1175 if (!strcmp(tool_name, vt->tools[i].ti.name)) {
1176 break;
1177 }
1178 }
1179 return i;
1180}
1181
1182static void toolbox_activate(toolbox_tools_t *vt, const gchar *tool_name)
1183{
1184 int tool = toolbox_get_tool(vt, tool_name);
1185 toolbox_tool_t *t = &vt->tools[tool];
1186 VikLayer *vl = vik_layers_panel_get_selected ( vt->vw->viking_vlp );
1187
1188 if (tool == vt->n_tools) {
7742da66 1189 g_critical("trying to activate a non-existent tool...");
941aa6e9
AF
1190 exit(1);
1191 }
1192 /* is the tool already active? */
1193 if (vt->active_tool == tool) {
1194 return;
1195 }
1196
1197 if (vt->active_tool != -1) {
1198 if (vt->tools[vt->active_tool].ti.deactivate) {
1199 vt->tools[vt->active_tool].ti.deactivate(NULL, vt->tools[vt->active_tool].state);
1200 }
1201 }
1202 if (t->ti.activate) {
1203 t->ti.activate(vl, t->state);
1204 }
1205 vt->active_tool = tool;
1206}
1207
f2f2f7bf
GB
1208static const GdkCursor *toolbox_get_cursor(toolbox_tools_t *vt, const gchar *tool_name)
1209{
1210 int tool = toolbox_get_tool(vt, tool_name);
1211 toolbox_tool_t *t = &vt->tools[tool];
1212 if (t->ti.cursor == NULL) {
1213 if (t->ti.cursor_type == GDK_CURSOR_IS_PIXMAP && t->ti.cursor_data != NULL) {
1214 GError *cursor_load_err = NULL;
1215 GdkPixbuf *cursor_pixbuf = gdk_pixbuf_from_pixdata (t->ti.cursor_data, FALSE, &cursor_load_err);
1216 /* TODO: settable offeset */
1217 t->ti.cursor = gdk_cursor_new_from_pixbuf ( gdk_display_get_default(), cursor_pixbuf, 3, 3 );
1218 g_object_unref ( G_OBJECT(cursor_pixbuf) );
1219 } else {
1220 t->ti.cursor = gdk_cursor_new ( t->ti.cursor_type );
1221 }
1222 }
1223 return t->ti.cursor;
1224}
1225
941aa6e9
AF
1226static void toolbox_click (toolbox_tools_t *vt, GdkEventButton *event)
1227{
1228 VikLayer *vl = vik_layers_panel_get_selected ( vt->vw->viking_vlp );
1229 if (vt->active_tool != -1 && vt->tools[vt->active_tool].ti.click) {
9593a4c9
EB
1230 gint ltype = vt->tools[vt->active_tool].layer_type;
1231 if ( ltype == TOOL_LAYER_TYPE_NONE || (vl && ltype == vl->type) )
1232 vt->tools[vt->active_tool].ti.click(vl, event, vt->tools[vt->active_tool].state);
941aa6e9
AF
1233 }
1234}
1235
dc2c040e 1236static void toolbox_move (toolbox_tools_t *vt, GdkEventMotion *event)
941aa6e9
AF
1237{
1238 VikLayer *vl = vik_layers_panel_get_selected ( vt->vw->viking_vlp );
1239 if (vt->active_tool != -1 && vt->tools[vt->active_tool].ti.move) {
9593a4c9
EB
1240 gint ltype = vt->tools[vt->active_tool].layer_type;
1241 if ( ltype == TOOL_LAYER_TYPE_NONE || (vl && ltype == vl->type) )
165d30aa
EB
1242 if ( VIK_LAYER_TOOL_ACK_GRAB_FOCUS == vt->tools[vt->active_tool].ti.move(vl, event, vt->tools[vt->active_tool].state) )
1243 gtk_widget_grab_focus ( GTK_WIDGET(vt->vw->viking_vvp) );
941aa6e9
AF
1244 }
1245}
1246
1247static void toolbox_release (toolbox_tools_t *vt, GdkEventButton *event)
1248{
1249 VikLayer *vl = vik_layers_panel_get_selected ( vt->vw->viking_vlp );
9593a4c9
EB
1250 if (vt->active_tool != -1 && vt->tools[vt->active_tool].ti.release ) {
1251 gint ltype = vt->tools[vt->active_tool].layer_type;
1252 if ( ltype == TOOL_LAYER_TYPE_NONE || (vl && ltype == vl->type) )
1253 vt->tools[vt->active_tool].ti.release(vl, event, vt->tools[vt->active_tool].state);
941aa6e9
AF
1254 }
1255}
1256/** End tool management ************************************/
1257
8fb71d6c
EB
1258void vik_window_enable_layer_tool ( VikWindow *vw, gint layer_id, gint tool_id )
1259{
1260 gtk_action_activate ( gtk_action_group_get_action ( vw->action_group, vik_layer_get_interface(layer_id)->tools[tool_id].name ) );
1261}
941aa6e9
AF
1262
1263/* this function gets called whenever a toolbar tool is clicked */
e4afc73a 1264static void menu_tool_cb ( GtkAction *old, GtkAction *a, VikWindow *vw )
50a14534
EB
1265{
1266 /* White Magic, my friends ... White Magic... */
8fb71d6c 1267 int layer_id, tool_id;
f2f2f7bf 1268 const GdkCursor *cursor = NULL;
e4afc73a 1269
941aa6e9
AF
1270 toolbox_activate(vw->vt, gtk_action_get_name(a));
1271
f2f2f7bf
GB
1272 cursor = toolbox_get_cursor(vw->vt, gtk_action_get_name(a));
1273 /* We set cursor, even if it is NULL: it resets to default */
1274 gdk_window_set_cursor ( GTK_WIDGET(vw->viking_vvp)->window, cursor );
1275
576cbd17
GB
1276 if (!strcmp(gtk_action_get_name(a), "Pan")) {
1277 vw->current_tool = TOOL_PAN;
576cbd17
GB
1278 }
1279 else if (!strcmp(gtk_action_get_name(a), "Zoom")) {
e4afc73a
EB
1280 vw->current_tool = TOOL_ZOOM;
1281 }
1282 else if (!strcmp(gtk_action_get_name(a), "Ruler")) {
1283 vw->current_tool = TOOL_RULER;
1284 }
1285 else {
79845167 1286 /* TODO: only enable tools from active layer */
8fb71d6c
EB
1287 for (layer_id=0; layer_id<VIK_LAYER_NUM_TYPES; layer_id++) {
1288 for ( tool_id = 0; tool_id < vik_layer_get_interface(layer_id)->tools_count; tool_id++ ) {
1289 if (!strcmp(vik_layer_get_interface(layer_id)->tools[tool_id].name, gtk_action_get_name(a))) {
1290 vw->current_tool = TOOL_LAYER;
1291 vw->tool_layer_id = layer_id;
1292 vw->tool_tool_id = tool_id;
e4afc73a
EB
1293 }
1294 }
1295 }
1296 }
50a14534
EB
1297 draw_status ( vw );
1298}
1299
1300static void window_set_filename ( VikWindow *vw, const gchar *filename )
1301{
1302 gchar *title;
4c77d5e0 1303 const gchar *file;
50a14534
EB
1304 if ( vw->filename )
1305 g_free ( vw->filename );
1306 if ( filename == NULL )
1307 {
1308 vw->filename = NULL;
4c77d5e0 1309 file = _("Untitled");
50a14534
EB
1310 }
1311 else
1312 {
1313 vw->filename = g_strdup(filename);
4c77d5e0 1314 file = a_file_basename ( filename );
50a14534 1315 }
4c77d5e0
GB
1316 title = g_strdup_printf( "%s - Viking", file );
1317 gtk_window_set_title ( GTK_WINDOW(vw), title );
1318 g_free ( title );
50a14534
EB
1319}
1320
7bc965c0
GB
1321GtkWidget *vik_window_get_drawmode_button ( VikWindow *vw, VikViewportDrawMode mode )
1322{
1323 GtkWidget *mode_button;
1324 gchar *buttonname;
1325 switch ( mode ) {
794c8f18 1326#ifdef VIK_CONFIG_EXPEDIA
7bc965c0 1327 case VIK_VIEWPORT_DRAWMODE_EXPEDIA: buttonname = "/ui/MainMenu/View/ModeExpedia"; break;
794c8f18 1328#endif
7bc965c0 1329 case VIK_VIEWPORT_DRAWMODE_MERCATOR: buttonname = "/ui/MainMenu/View/ModeMercator"; break;
794c8f18 1330 default: buttonname = "/ui/MainMenu/View/ModeUTM";
7bc965c0
GB
1331 }
1332 mode_button = gtk_ui_manager_get_widget ( vw->uim, buttonname );
1333 g_assert ( mode_button );
1334 return mode_button;
1335}
1336
50a14534
EB
1337void vik_window_open_file ( VikWindow *vw, const gchar *filename, gboolean change_filename )
1338{
1339 switch ( a_file_load ( vik_layers_panel_get_top_layer(vw->viking_vlp), vw->viking_vvp, filename ) )
1340 {
1341 case 0:
4c77d5e0 1342 a_dialog_error_msg ( GTK_WINDOW(vw), _("The file you requested could not be opened.") );
50a14534
EB
1343 break;
1344 case 1:
1345 {
1346 GtkWidget *mode_button;
50a14534
EB
1347 if ( change_filename )
1348 window_set_filename ( vw, filename );
7bc965c0 1349 mode_button = vik_window_get_drawmode_button ( vw, vik_viewport_get_drawmode ( vw->viking_vvp ) );
50a14534
EB
1350 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. */
1351 gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(mode_button), TRUE );
1352 vw->only_updating_coord_mode_ui = FALSE;
1353
1354 vik_layers_panel_change_coord_mode ( vw->viking_vlp, vik_viewport_get_coord_mode ( vw->viking_vvp ) );
1657065a
QT
1355
1356 mode_button = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/ShowScale" );
1357 g_assert ( mode_button );
1358 gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(mode_button),vik_viewport_get_draw_scale(vw->viking_vvp) );
1359
1360 mode_button = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/ShowCenterMark" );
1361 g_assert ( mode_button );
1362 gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(mode_button),vik_viewport_get_draw_centermark(vw->viking_vvp) );
50a14534
EB
1363 }
1364 default: draw_update ( vw );
1365 }
1366}
e4afc73a 1367static void load_file ( GtkAction *a, VikWindow *vw )
50a14534 1368{
6e4a49aa
MA
1369 GSList *files = NULL;
1370 GSList *cur_file = NULL;
e4afc73a
EB
1371 gboolean newwindow;
1372 if (!strcmp(gtk_action_get_name(a), "Open")) {
1373 newwindow = TRUE;
1374 }
1375 else if (!strcmp(gtk_action_get_name(a), "Append")) {
1376 newwindow = FALSE;
1377 }
1378 else {
8dc8da82 1379 g_critical("Houston, we've had a problem.");
e4afc73a
EB
1380 return;
1381 }
1382
50a14534
EB
1383 if ( ! vw->open_dia )
1384 {
6e4a49aa
MA
1385 vw->open_dia = gtk_file_chooser_dialog_new (_("Please select a GPS data file to open. "),
1386 GTK_WINDOW(vw),
1387 GTK_FILE_CHOOSER_ACTION_OPEN,
1388 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1389 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1390 NULL);
1391 gtk_file_chooser_set_select_multiple ( GTK_FILE_CHOOSER(vw->open_dia), TRUE );
50a14534
EB
1392 gtk_window_set_transient_for ( GTK_WINDOW(vw->open_dia), GTK_WINDOW(vw) );
1393 gtk_window_set_destroy_with_parent ( GTK_WINDOW(vw->open_dia), TRUE );
1394 }
6e4a49aa 1395 if ( gtk_dialog_run ( GTK_DIALOG(vw->open_dia) ) == GTK_RESPONSE_ACCEPT )
50a14534
EB
1396 {
1397 gtk_widget_hide ( vw->open_dia );
a5fd2196 1398#ifdef VIKING_PROMPT_IF_MODIFIED
50a14534 1399 if ( (vw->modified || vw->filename) && newwindow )
a5fd2196
QT
1400#else
1401 if ( vw->filename && newwindow )
1402#endif
6e4a49aa 1403 g_signal_emit ( G_OBJECT(vw), window_signals[VW_OPENWINDOW_SIGNAL], 0, gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER(vw->open_dia) ) );
50a14534 1404 else {
6e4a49aa
MA
1405 files = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER(vw->open_dia) );
1406 gboolean change_fn = newwindow && (g_slist_length(files)==1); /* only change fn if one file */
1407
1408 cur_file = files;
1409 while ( cur_file ) {
1410 gchar *file_name = cur_file->data;
1411 vik_window_open_file ( vw, file_name, change_fn );
1412 g_free (file_name);
1413 cur_file = g_slist_next (cur_file);
50a14534 1414 }
6e4a49aa 1415 g_slist_free (files);
50a14534
EB
1416 }
1417 }
1418 else
1419 gtk_widget_hide ( vw->open_dia );
1420}
1421
e4afc73a 1422static gboolean save_file_as ( GtkAction *a, VikWindow *vw )
50a14534
EB
1423{
1424 gboolean rv = FALSE;
1425 const gchar *fn;
1426 if ( ! vw->save_dia )
1427 {
6e4a49aa
MA
1428 vw->save_dia = gtk_file_chooser_dialog_new (_("Save as Viking File."),
1429 GTK_WINDOW(vw),
1430 GTK_FILE_CHOOSER_ACTION_SAVE,
1431 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1432 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
1433 NULL);
50a14534
EB
1434 gtk_window_set_transient_for ( GTK_WINDOW(vw->save_dia), GTK_WINDOW(vw) );
1435 gtk_window_set_destroy_with_parent ( GTK_WINDOW(vw->save_dia), TRUE );
1436 }
1437
6e4a49aa 1438 while ( gtk_dialog_run ( GTK_DIALOG(vw->save_dia) ) == GTK_RESPONSE_ACCEPT )
50a14534 1439 {
6e4a49aa 1440 fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(vw->save_dia) );
45acf79e 1441 if ( g_file_test ( fn, G_FILE_TEST_EXISTS ) == FALSE || a_dialog_overwrite ( GTK_WINDOW(vw->save_dia), _("The file \"%s\" exists, do you wish to overwrite it?"), a_file_basename ( fn ) ) )
50a14534
EB
1442 {
1443 window_set_filename ( vw, fn );
1444 rv = window_save ( vw );
1445 vw->modified = FALSE;
1446 break;
1447 }
1448 }
1449 gtk_widget_hide ( vw->save_dia );
1450 return rv;
1451}
1452
1453static gboolean window_save ( VikWindow *vw )
1454{
1455 if ( a_file_save ( vik_layers_panel_get_top_layer ( vw->viking_vlp ), vw->viking_vvp, vw->filename ) )
1456 return TRUE;
1457 else
1458 {
4c77d5e0 1459 a_dialog_error_msg ( GTK_WINDOW(vw), _("The filename you requested could not be opened for writing.") );
50a14534
EB
1460 return FALSE;
1461 }
1462}
1463
e4afc73a 1464static gboolean save_file ( GtkAction *a, VikWindow *vw )
50a14534
EB
1465{
1466 if ( ! vw->filename )
e4afc73a 1467 return save_file_as ( NULL, vw );
50a14534
EB
1468 else
1469 {
1470 vw->modified = FALSE;
1471 return window_save ( vw );
1472 }
1473}
1474
1d1bc3c1
EB
1475static void acquire_from_gps ( GtkAction *a, VikWindow *vw )
1476{
7b3479e3
EB
1477 a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_gps_interface );
1478}
1479
1480static void acquire_from_google ( GtkAction *a, VikWindow *vw )
1481{
1482 a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_google_interface );
1d1bc3c1
EB
1483}
1484
1ef9e637 1485#ifdef VIK_CONFIG_GEOCACHES
3333c069
EB
1486static void acquire_from_gc ( GtkAction *a, VikWindow *vw )
1487{
1488 a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_gc_interface );
1489}
1ef9e637 1490#endif
3333c069 1491
369126f3
QT
1492static void goto_address( GtkAction *a, VikWindow *vw)
1493{
93c47137 1494 a_geonames_search(vw, vw->viking_vlp, vw->viking_vvp);
369126f3
QT
1495}
1496
17a1f8f9
EB
1497static void preferences_cb ( GtkAction *a, VikWindow *vw )
1498{
1499 a_preferences_show_window ( GTK_WINDOW(vw) );
1500}
1501
e4afc73a 1502static void clear_cb ( GtkAction *a, VikWindow *vw )
50a14534
EB
1503{
1504 vik_layers_panel_clear ( vw->viking_vlp );
1505 window_set_filename ( vw, NULL );
1506 draw_update ( vw );
1507}
1508
e4afc73a 1509static void window_close ( GtkAction *a, VikWindow *vw )
50a14534
EB
1510{
1511 if ( ! delete_event ( vw ) )
1512 gtk_widget_destroy ( GTK_WIDGET(vw) );
1513}
1514
2bf7cadd
QT
1515static gboolean save_file_and_exit ( GtkAction *a, VikWindow *vw )
1516{
7bb60307 1517 if (save_file( NULL, vw)) {
2bf7cadd 1518 window_close( NULL, vw);
7bb60307
QT
1519 return(TRUE);
1520 }
2bf7cadd
QT
1521 else
1522 return(FALSE);
1523}
1524
e4afc73a 1525static void zoom_to_cb ( GtkAction *a, VikWindow *vw )
50a14534
EB
1526{
1527 gdouble xmpp = vik_viewport_get_xmpp ( vw->viking_vvp ), ympp = vik_viewport_get_ympp ( vw->viking_vvp );
1528 if ( a_dialog_custom_zoom ( GTK_WINDOW(vw), &xmpp, &ympp ) )
1529 {
1530 vik_viewport_set_xmpp ( vw->viking_vvp, xmpp );
1531 vik_viewport_set_ympp ( vw->viking_vvp, ympp );
1532 draw_update ( vw );
1533 }
1534}
1535
1536static void save_image_file ( VikWindow *vw, const gchar *fn, guint w, guint h, gdouble zoom, gboolean save_as_png )
1537{
1538 /* more efficient way: stuff draws directly to pixbuf (fork viewport) */
1539 GdkPixbuf *pixbuf_to_save;
1540 gdouble old_xmpp, old_ympp;
1541 GError *error = NULL;
1542
1543 /* backup old zoom & set new */
1544 old_xmpp = vik_viewport_get_xmpp ( vw->viking_vvp );
1545 old_ympp = vik_viewport_get_ympp ( vw->viking_vvp );
1546 vik_viewport_set_zoom ( vw->viking_vvp, zoom );
1547
1548 /* reset width and height: */
1549 vik_viewport_configure_manually ( vw->viking_vvp, w, h );
1550
1551 /* draw all layers */
1552 draw_redraw ( vw );
1553
1554 /* save buffer as file. */
1555 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);
1556 gdk_pixbuf_save ( pixbuf_to_save, fn, save_as_png ? "png" : "jpeg", &error, NULL );
1557 if (error)
1558 {
7742da66 1559 g_warning("Unable to write to file %s: %s", fn, error->message );
50a14534
EB
1560 g_error_free (error);
1561 }
1562 g_object_unref ( G_OBJECT(pixbuf_to_save) );
1563
1564 /* pretend like nothing happened ;) */
1565 vik_viewport_set_xmpp ( vw->viking_vvp, old_xmpp );
1566 vik_viewport_set_ympp ( vw->viking_vvp, old_ympp );
1567 vik_viewport_configure ( vw->viking_vvp );
1568 draw_update ( vw );
1569}
1570
1571static 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 )
1572{
1573 gulong size = sizeof(gchar) * (strlen(fn) + 15);
1574 gchar *name_of_file = g_malloc ( size );
1575 guint x = 1, y = 1;
1576 struct UTM utm_orig, utm;
1577
1578 /* *** copied from above *** */
1579 GdkPixbuf *pixbuf_to_save;
1580 gdouble old_xmpp, old_ympp;
1581 GError *error = NULL;
1582
1583 /* backup old zoom & set new */
1584 old_xmpp = vik_viewport_get_xmpp ( vw->viking_vvp );
1585 old_ympp = vik_viewport_get_ympp ( vw->viking_vvp );
1586 vik_viewport_set_zoom ( vw->viking_vvp, zoom );
1587
1588 /* reset width and height: do this only once for all images (same size) */
1589 vik_viewport_configure_manually ( vw->viking_vvp, w, h );
1590 /* *** end copy from above *** */
1591
1592 g_assert ( vik_viewport_get_coord_mode ( vw->viking_vvp ) == VIK_COORD_UTM );
1593
f83131b9 1594 g_mkdir(fn,0777);
50a14534
EB
1595
1596 utm_orig = *((const struct UTM *)vik_viewport_get_center ( vw->viking_vvp ));
1597
1598 for ( y = 1; y <= tiles_h; y++ )
1599 {
1600 for ( x = 1; x <= tiles_w; x++ )
1601 {
3d9454e6 1602 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
1603 utm = utm_orig;
1604 if ( tiles_w & 0x1 )
1605 utm.easting += ((gdouble)x - ceil(((gdouble)tiles_w)/2)) * (w*zoom);
1606 else
1607 utm.easting += ((gdouble)x - (((gdouble)tiles_w)+1)/2) * (w*zoom);
1608 if ( tiles_h & 0x1 ) /* odd */
1609 utm.northing -= ((gdouble)y - ceil(((gdouble)tiles_h)/2)) * (h*zoom);
1610 else /* even */
1611 utm.northing -= ((gdouble)y - (((gdouble)tiles_h)+1)/2) * (h*zoom);
1612
1613 /* move to correct place. */
1614 vik_viewport_set_center_utm ( vw->viking_vvp, &utm );
1615
1616 draw_redraw ( vw );
1617
1618 /* save buffer as file. */
1619 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);
1620 gdk_pixbuf_save ( pixbuf_to_save, name_of_file, save_as_png ? "png" : "jpeg", &error, NULL );
1621 if (error)
1622 {
7742da66 1623 g_warning("Unable to write to file %s: %s", name_of_file, error->message );
50a14534
EB
1624 g_error_free (error);
1625 }
1626
1627 g_object_unref ( G_OBJECT(pixbuf_to_save) );
1628 }
1629 }
1630
1631 vik_viewport_set_center_utm ( vw->viking_vvp, &utm_orig );
1632 vik_viewport_set_xmpp ( vw->viking_vvp, old_xmpp );
1633 vik_viewport_set_ympp ( vw->viking_vvp, old_ympp );
1634 vik_viewport_configure ( vw->viking_vvp );
1635 draw_update ( vw );
1636
1637 g_free ( name_of_file );
1638}
1639
1640static void draw_to_image_file_current_window_cb(GtkWidget* widget,GdkEventButton *event,gpointer *pass_along)
1641{
1642 VikWindow *vw = VIK_WINDOW(pass_along[0]);
1643 GtkSpinButton *width_spin = GTK_SPIN_BUTTON(pass_along[1]), *height_spin = GTK_SPIN_BUTTON(pass_along[2]);
1644 GtkSpinButton *zoom_spin = GTK_SPIN_BUTTON(pass_along[3]);
1645 gdouble width_min, width_max, height_min, height_max;
1646 gint width, height;
1647
1648 gtk_spin_button_get_range ( width_spin, &width_min, &width_max );
1649 gtk_spin_button_get_range ( height_spin, &height_min, &height_max );
1650
1651 /* TODO: support for xzoom and yzoom values */
1652 width = vik_viewport_get_width ( vw->viking_vvp ) * vik_viewport_get_xmpp ( vw->viking_vvp ) / gtk_spin_button_get_value ( zoom_spin );
1653 height = vik_viewport_get_height ( vw->viking_vvp ) * vik_viewport_get_xmpp ( vw->viking_vvp ) / gtk_spin_button_get_value ( zoom_spin );
1654
1655 if ( width > width_max || width < width_min || height > height_max || height < height_min )
4c77d5e0 1656 a_dialog_info_msg ( GTK_WINDOW(vw), _("Viewable region outside allowable pixel size bounds for image. Clipping width/height values.") );
50a14534
EB
1657
1658 gtk_spin_button_set_value ( width_spin, width );
1659 gtk_spin_button_set_value ( height_spin, height );
1660}
1661
1662static void draw_to_image_file_total_area_cb (GtkSpinButton *spinbutton, gpointer *pass_along)
1663{
1664 GtkSpinButton *width_spin = GTK_SPIN_BUTTON(pass_along[1]), *height_spin = GTK_SPIN_BUTTON(pass_along[2]);
1665 GtkSpinButton *zoom_spin = GTK_SPIN_BUTTON(pass_along[3]);
1666 gchar *label_text;
1667 gdouble w, h;
1668 w = gtk_spin_button_get_value(width_spin) * gtk_spin_button_get_value(zoom_spin);
1669 h = gtk_spin_button_get_value(height_spin) * gtk_spin_button_get_value(zoom_spin);
1670 if (pass_along[4]) /* save many images; find TOTAL area covered */
1671 {
1672 w *= gtk_spin_button_get_value(GTK_SPIN_BUTTON(pass_along[4]));
1673 h *= gtk_spin_button_get_value(GTK_SPIN_BUTTON(pass_along[5]));
1674 }
4c77d5e0 1675 label_text = g_strdup_printf ( _("Total area: %ldm x %ldm (%.3f sq. km)"), (glong)w, (glong)h, (w*h/1000000));
50a14534
EB
1676 gtk_label_set_text(GTK_LABEL(pass_along[6]), label_text);
1677 g_free ( label_text );
1678}
1679
1680static void draw_to_image_file ( VikWindow *vw, const gchar *fn, gboolean one_image_only )
1681{
1682 /* todo: default for answers inside VikWindow or static (thruout instance) */
4c77d5e0 1683 GtkWidget *dialog = gtk_dialog_new_with_buttons ( _("Save to Image File"), GTK_WINDOW(vw),
50a14534
EB
1684 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1685 GTK_STOCK_CANCEL,
1686 GTK_RESPONSE_REJECT,
1687 GTK_STOCK_OK,
1688 GTK_RESPONSE_ACCEPT,
10888930 1689 NULL );
50a14534
EB
1690 GtkWidget *width_label, *width_spin, *height_label, *height_spin;
1691 GtkWidget *png_radio, *jpeg_radio;
1692 GtkWidget *current_window_button;
1693 gpointer current_window_pass_along[7];
1694 GtkWidget *zoom_label, *zoom_spin;
1695 GtkWidget *total_size_label;
1696
1697 /* only used if (!one_image_only) */
886031df 1698 GtkWidget *tiles_width_spin = NULL, *tiles_height_spin = NULL;
50a14534
EB
1699
1700
4c77d5e0 1701 width_label = gtk_label_new ( _("Width (pixels):") );
50a14534 1702 width_spin = gtk_spin_button_new ( GTK_ADJUSTMENT(gtk_adjustment_new ( vw->draw_image_width, 10, 5000, 10, 100, 0 )), 10, 0 );
4c77d5e0 1703 height_label = gtk_label_new ( _("Height (pixels):") );
50a14534
EB
1704 height_spin = gtk_spin_button_new ( GTK_ADJUSTMENT(gtk_adjustment_new ( vw->draw_image_height, 10, 5000, 10, 100, 0 )), 10, 0 );
1705
4c77d5e0 1706 zoom_label = gtk_label_new ( _("Zoom (meters per pixel):") );
50a14534
EB
1707 /* TODO: separate xzoom and yzoom factors */
1708 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, 3 )), 16, 3);
1709
1710 total_size_label = gtk_label_new ( NULL );
1711
4c77d5e0 1712 current_window_button = gtk_button_new_with_label ( _("Area in current viewable window") );
50a14534
EB
1713 current_window_pass_along [0] = vw;
1714 current_window_pass_along [1] = width_spin;
1715 current_window_pass_along [2] = height_spin;
1716 current_window_pass_along [3] = zoom_spin;
1717 current_window_pass_along [4] = NULL; /* used for one_image_only != 1 */
1718 current_window_pass_along [5] = NULL;
1719 current_window_pass_along [6] = total_size_label;
1720 g_signal_connect ( G_OBJECT(current_window_button), "button_press_event", G_CALLBACK(draw_to_image_file_current_window_cb), current_window_pass_along );
1721
4c77d5e0
GB
1722 png_radio = gtk_radio_button_new_with_label ( NULL, _("Save as PNG") );
1723 jpeg_radio = gtk_radio_button_new_with_label_from_widget ( GTK_RADIO_BUTTON(png_radio), _("Save as JPEG") );
50a14534
EB
1724
1725 if ( ! vw->draw_image_save_as_png )
1726 gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON(jpeg_radio), TRUE );
1727
1728 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), width_label, FALSE, FALSE, 0);
1729 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), width_spin, FALSE, FALSE, 0);
1730 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), height_label, FALSE, FALSE, 0);
1731 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), height_spin, FALSE, FALSE, 0);
1732 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), current_window_button, FALSE, FALSE, 0);
1733 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), png_radio, FALSE, FALSE, 0);
1734 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), jpeg_radio, FALSE, FALSE, 0);
1735 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), zoom_label, FALSE, FALSE, 0);
1736 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), zoom_spin, FALSE, FALSE, 0);
1737
1738 if ( ! one_image_only )
1739 {
1740 GtkWidget *tiles_width_label, *tiles_height_label;
1741
1742
4c77d5e0 1743 tiles_width_label = gtk_label_new ( _("East-west image tiles:") );
50a14534 1744 tiles_width_spin = gtk_spin_button_new ( GTK_ADJUSTMENT(gtk_adjustment_new ( 5, 1, 10, 1, 100, 0 )), 1, 0 );
4c77d5e0 1745 tiles_height_label = gtk_label_new ( _("North-south image tiles:") );
50a14534
EB
1746 tiles_height_spin = gtk_spin_button_new ( GTK_ADJUSTMENT(gtk_adjustment_new ( 5, 1, 10, 1, 100, 0 )), 1, 0 );
1747 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), tiles_width_label, FALSE, FALSE, 0);
1748 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), tiles_width_spin, FALSE, FALSE, 0);
1749 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), tiles_height_label, FALSE, FALSE, 0);
1750 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), tiles_height_spin, FALSE, FALSE, 0);
1751
1752 current_window_pass_along [4] = tiles_width_spin;
1753 current_window_pass_along [5] = tiles_height_spin;
1754 g_signal_connect ( G_OBJECT(tiles_width_spin), "value-changed", G_CALLBACK(draw_to_image_file_total_area_cb), current_window_pass_along );
1755 g_signal_connect ( G_OBJECT(tiles_height_spin), "value-changed", G_CALLBACK(draw_to_image_file_total_area_cb), current_window_pass_along );
1756 }
1757 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), total_size_label, FALSE, FALSE, 0);
1758 g_signal_connect ( G_OBJECT(width_spin), "value-changed", G_CALLBACK(draw_to_image_file_total_area_cb), current_window_pass_along );
1759 g_signal_connect ( G_OBJECT(height_spin), "value-changed", G_CALLBACK(draw_to_image_file_total_area_cb), current_window_pass_along );
1760 g_signal_connect ( G_OBJECT(zoom_spin), "value-changed", G_CALLBACK(draw_to_image_file_total_area_cb), current_window_pass_along );
1761
1762 draw_to_image_file_total_area_cb ( NULL, current_window_pass_along ); /* set correct size info now */
1763
1764 gtk_widget_show_all ( GTK_DIALOG(dialog)->vbox );
1765
1766 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
1767 {
1768 gtk_widget_hide ( GTK_WIDGET(dialog) );
1769 if ( one_image_only )
1770 save_image_file ( vw, fn,
1771 vw->draw_image_width = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(width_spin) ),
1772 vw->draw_image_height = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(height_spin) ),
1773 gtk_spin_button_get_value ( GTK_SPIN_BUTTON(zoom_spin) ), /* do not save this value, default is current zoom */
1774 vw->draw_image_save_as_png = gtk_toggle_button_get_active ( GTK_TOGGLE_BUTTON(png_radio) ) );
1775 else {
1776 if ( vik_viewport_get_coord_mode(vw->viking_vvp) == VIK_COORD_UTM )
1777 save_image_dir ( vw, fn,
1778 vw->draw_image_width = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(width_spin) ),
1779 vw->draw_image_height = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(height_spin) ),
1780 gtk_spin_button_get_value ( GTK_SPIN_BUTTON(zoom_spin) ), /* do not save this value, default is current zoom */
1781 vw->draw_image_save_as_png = gtk_toggle_button_get_active ( GTK_TOGGLE_BUTTON(png_radio) ),
1782 gtk_spin_button_get_value ( GTK_SPIN_BUTTON(tiles_width_spin) ),
1783 gtk_spin_button_get_value ( GTK_SPIN_BUTTON(tiles_height_spin) ) );
1784 else
4c77d5e0 1785 a_dialog_error_msg ( GTK_WINDOW(vw), _("You must be in UTM mode to use this feature") );
50a14534
EB
1786 }
1787 }
1788 gtk_widget_destroy ( GTK_WIDGET(dialog) );
1789}
1790
1791
e4afc73a 1792static void draw_to_image_file_cb ( GtkAction *a, VikWindow *vw )
50a14534 1793{
50a14534 1794 const gchar *fn;
f2a1ca71 1795 if (!vw->save_img_dia) {
6e4a49aa
MA
1796 vw->save_img_dia = gtk_file_chooser_dialog_new (_("Save Image"),
1797 GTK_WINDOW(vw),
1798 GTK_FILE_CHOOSER_ACTION_SAVE,
1799 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1800 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
1801 NULL);
f2a1ca71
QT
1802 gtk_window_set_transient_for ( GTK_WINDOW(vw->save_img_dia), GTK_WINDOW(vw) );
1803 gtk_window_set_destroy_with_parent ( GTK_WINDOW(vw->save_img_dia), TRUE );
1804 }
50a14534 1805
6e4a49aa 1806 while ( gtk_dialog_run ( GTK_DIALOG(vw->save_img_dia) ) == GTK_RESPONSE_ACCEPT )
50a14534 1807 {
6e4a49aa 1808 fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(vw->save_img_dia) );
45acf79e 1809 if ( g_file_test ( fn, G_FILE_TEST_EXISTS ) == FALSE || a_dialog_overwrite ( GTK_WINDOW(vw->save_img_dia), _("The file \"%s\" exists, do you wish to overwrite it?"), a_file_basename ( fn ) ) )
50a14534 1810 {
50a14534
EB
1811 draw_to_image_file ( vw, fn, TRUE );
1812 break;
1813 }
1814 }
f2a1ca71 1815 gtk_widget_hide ( vw->save_img_dia );
50a14534
EB
1816}
1817
e4afc73a 1818static void draw_to_image_dir_cb ( GtkAction *a, VikWindow *vw )
50a14534 1819{
6e4a49aa
MA
1820 gchar *fn = NULL;
1821
f2a1ca71 1822 if (!vw->save_img_dir_dia) {
6e4a49aa
MA
1823 vw->save_img_dir_dia = gtk_file_chooser_dialog_new (_("Choose a directory to hold images"),
1824 GTK_WINDOW(vw),
1825 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
1826 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1827 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1828 NULL);
f2a1ca71
QT
1829 gtk_window_set_transient_for ( GTK_WINDOW(vw->save_img_dir_dia), GTK_WINDOW(vw) );
1830 gtk_window_set_destroy_with_parent ( GTK_WINDOW(vw->save_img_dir_dia), TRUE );
1831 }
6e4a49aa
MA
1832
1833 while ( gtk_dialog_run ( GTK_DIALOG(vw->save_img_dir_dia) ) == GTK_RESPONSE_ACCEPT )
50a14534 1834 {
6e4a49aa
MA
1835 fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(vw->save_img_dir_dia) );
1836 if ( fn )
50a14534 1837 {
50a14534 1838 draw_to_image_file ( vw, fn, FALSE );
6e4a49aa
MA
1839 g_free(fn);
1840 fn = NULL;
50a14534
EB
1841 break;
1842 }
1843 }
f2a1ca71 1844 gtk_widget_hide ( vw->save_img_dir_dia );
50a14534
EB
1845}
1846
9a995996 1847#if GTK_CHECK_VERSION(2,10,0)
42f34743
QT
1848static void print_cb ( GtkAction *a, VikWindow *vw )
1849{
1850 a_print(vw, vw->viking_vvp);
1851}
9a995996 1852#endif
42f34743 1853
50a14534 1854/* really a misnomer: changes coord mode (actual coordinates) AND/OR draw mode (viewport only) */
e4afc73a 1855static void window_change_coord_mode_cb ( GtkAction *old_a, GtkAction *a, VikWindow *vw )
50a14534 1856{
e4afc73a
EB
1857 VikViewportDrawMode drawmode;
1858 if (!strcmp(gtk_action_get_name(a), "ModeUTM")) {
1859 drawmode = VIK_VIEWPORT_DRAWMODE_UTM;
1860 }
1861 else if (!strcmp(gtk_action_get_name(a), "ModeExpedia")) {
1862 drawmode = VIK_VIEWPORT_DRAWMODE_EXPEDIA;
1863 }
e4afc73a
EB
1864 else if (!strcmp(gtk_action_get_name(a), "ModeMercator")) {
1865 drawmode = VIK_VIEWPORT_DRAWMODE_MERCATOR;
1866 }
1867 else {
8dc8da82 1868 g_critical("Houston, we've had a problem.");
e4afc73a
EB
1869 return;
1870 }
1871
50a14534
EB
1872 if ( !vw->only_updating_coord_mode_ui )
1873 {
1874 VikViewportDrawMode olddrawmode = vik_viewport_get_drawmode ( vw->viking_vvp );
1875 if ( olddrawmode != drawmode )
1876 {
1877 /* this takes care of coord mode too */
1878 vik_viewport_set_drawmode ( vw->viking_vvp, drawmode );
1879 if ( drawmode == VIK_VIEWPORT_DRAWMODE_UTM ) {
1880 vik_layers_panel_change_coord_mode ( vw->viking_vlp, VIK_COORD_UTM );
1881 } else if ( olddrawmode == VIK_VIEWPORT_DRAWMODE_UTM ) {
1882 vik_layers_panel_change_coord_mode ( vw->viking_vlp, VIK_COORD_LATLON );
1883 }
1884 draw_update ( vw );
1885 }
1886 }
1887}
1888
35c7c0ba
EB
1889static void set_draw_scale ( GtkAction *a, VikWindow *vw )
1890{
1657065a
QT
1891 GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/ShowScale" );
1892 g_assert(check_box);
1893 gboolean state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box));
1894 vik_viewport_set_draw_scale ( vw->viking_vvp, state );
35c7c0ba
EB
1895 draw_update ( vw );
1896}
1897
c933487f
QT
1898static void set_draw_centermark ( GtkAction *a, VikWindow *vw )
1899{
1657065a
QT
1900 GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/ShowCenterMark" );
1901 g_assert(check_box);
1902 gboolean state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box));
1903 vik_viewport_set_draw_centermark ( vw->viking_vvp, state );
c933487f
QT
1904 draw_update ( vw );
1905}
1906
e4afc73a 1907static void set_bg_color ( GtkAction *a, VikWindow *vw )
50a14534 1908{
4c77d5e0 1909 GtkWidget *colorsd = gtk_color_selection_dialog_new ( _("Choose a background color") );
50a14534
EB
1910 GdkColor *color = vik_viewport_get_background_gdkcolor ( vw->viking_vvp );
1911 gtk_color_selection_set_previous_color ( GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(colorsd)->colorsel), color );
1912 gtk_color_selection_set_current_color ( GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(colorsd)->colorsel), color );
1913 if ( gtk_dialog_run ( GTK_DIALOG(colorsd) ) == GTK_RESPONSE_OK )
1914 {
1915 gtk_color_selection_get_current_color ( GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(colorsd)->colorsel), color );
1916 vik_viewport_set_background_gdkcolor ( vw->viking_vvp, color );
1917 draw_update ( vw );
1918 }
1919 g_free ( color );
1920 gtk_widget_destroy ( colorsd );
1921}
1922
941aa6e9
AF
1923
1924
1925/***********************************************************************************************
1926 ** GUI Creation
1927 ***********************************************************************************************/
1928
e4afc73a 1929static GtkActionEntry entries[] = {
5515e2d3
JJ
1930 { "File", NULL, N_("_File"), 0, 0, 0 },
1931 { "Edit", NULL, N_("_Edit"), 0, 0, 0 },
1932 { "View", NULL, N_("_View"), 0, 0, 0 },
1933 { "SetZoom", NULL, N_("_Zoom"), 0, 0, 0 },
1934 { "SetPan", NULL, N_("_Pan"), 0, 0, 0 },
1935 { "Layers", NULL, N_("_Layers"), 0, 0, 0 },
1936 { "Tools", NULL, N_("_Tools"), 0, 0, 0 },
92806042 1937 { "Exttools", NULL, N_("_Webtools"), 0, 0, 0 },
5515e2d3
JJ
1938 { "Help", NULL, N_("_Help"), 0, 0, 0 },
1939
1940 { "New", GTK_STOCK_NEW, N_("_New"), "<control>N", N_("New file"), (GCallback)newwindow_cb },
1941 { "Open", GTK_STOCK_OPEN, N_("_Open"), "<control>O", N_("Open a file"), (GCallback)load_file },
1942 { "Append", GTK_STOCK_ADD, N_("A_ppend File"), NULL, N_("Append data from a different file"), (GCallback)load_file },
1943 { "Acquire", NULL, N_("A_cquire"), 0, 0, 0 },
1944 { "AcquireGPS", NULL, N_("From _GPS"), NULL, N_("Transfer data from a GPS device"), (GCallback)acquire_from_gps },
1945 { "AcquireGoogle", NULL, N_("Google _Directions"), NULL, N_("Get driving directions from Google"), (GCallback)acquire_from_google },
1ef9e637 1946#ifdef VIK_CONFIG_GEOCACHES
5515e2d3 1947 { "AcquireGC", NULL, N_("Geo_caches"), NULL, N_("Get Geocaches from geocaching.com"), (GCallback)acquire_from_gc },
1ef9e637 1948#endif
5515e2d3
JJ
1949 { "Save", GTK_STOCK_SAVE, N_("_Save"), "<control>S", N_("Save the file"), (GCallback)save_file },
1950 { "SaveAs", GTK_STOCK_SAVE_AS, N_("Save _As"), NULL, N_("Save the file under different name"), (GCallback)save_file_as },
1951 { "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 },
1952 { "GenImgDir", GTK_STOCK_DND_MULTIPLE, N_("Generate _Directory of Images"), NULL, N_("FIXME:IMGDIR"), (GCallback)draw_to_image_dir_cb },
9a995996
EB
1953
1954#if GTK_CHECK_VERSION(2,10,0)
5515e2d3 1955 { "Print", GTK_STOCK_PRINT, N_("_Print..."), NULL, N_("Print maps"), (GCallback)print_cb },
9a995996
EB
1956#endif
1957
5515e2d3
JJ
1958 { "Exit", GTK_STOCK_QUIT, N_("E_xit"), "<control>W", N_("Exit the program"), (GCallback)window_close },
1959 { "SaveExit", GTK_STOCK_QUIT, N_("Save and Exit"), NULL, N_("Save and Exit the program"), (GCallback)save_file_and_exit },
1960
93c47137 1961 { "GeoNamesSearch", GTK_STOCK_JUMP_TO, N_("Go To GeoNames location"), NULL, N_("Go to address/place using GeoNames search"), (GCallback)goto_address },
5515e2d3
JJ
1962 { "GotoLL", GTK_STOCK_QUIT, N_("_Go to Lat\\/Lon..."), NULL, N_("Go to arbitrary lat\\/lon coordinate"), (GCallback)draw_goto_cb },
1963 { "GotoUTM", GTK_STOCK_QUIT, N_("Go to UTM..."), NULL, N_("Go to arbitrary UTM coordinate"), (GCallback)draw_goto_cb },
1964 { "SetBGColor",GTK_STOCK_SELECT_COLOR, N_("Set Background Color..."), NULL, NULL, (GCallback)set_bg_color },
1965 { "ZoomIn", GTK_STOCK_ZOOM_IN, N_("Zoom _In"), "<control>plus", NULL, (GCallback)draw_zoom_cb },
1966 { "ZoomOut", GTK_STOCK_ZOOM_OUT, N_("Zoom _Out"), "<control>minus", NULL, (GCallback)draw_zoom_cb },
7f9f736d 1967 { "ZoomTo", GTK_STOCK_ZOOM_FIT, N_("Zoom _To"), "<control>Z", NULL, (GCallback)zoom_to_cb },
5515e2d3
JJ
1968 { "Zoom0.25", NULL, N_("0.25"), NULL, NULL, (GCallback)draw_zoom_cb },
1969 { "Zoom0.5", NULL, N_("0.5"), NULL, NULL, (GCallback)draw_zoom_cb },
1970 { "Zoom1", NULL, N_("1"), NULL, NULL, (GCallback)draw_zoom_cb },
1971 { "Zoom2", NULL, N_("2"), NULL, NULL, (GCallback)draw_zoom_cb },
1972 { "Zoom4", NULL, N_("4"), NULL, NULL, (GCallback)draw_zoom_cb },
1973 { "Zoom8", NULL, N_("8"), NULL, NULL, (GCallback)draw_zoom_cb },
1974 { "Zoom16", NULL, N_("16"), NULL, NULL, (GCallback)draw_zoom_cb },
1975 { "Zoom32", NULL, N_("32"), NULL, NULL, (GCallback)draw_zoom_cb },
1976 { "Zoom64", NULL, N_("64"), NULL, NULL, (GCallback)draw_zoom_cb },
1977 { "Zoom128", NULL, N_("128"), NULL, NULL, (GCallback)draw_zoom_cb },
1978 { "PanNorth", NULL, N_("Pan North"), "<control>Up", NULL, (GCallback)draw_pan_cb },
1979 { "PanEast", NULL, N_("Pan East"), "<control>Right", NULL, (GCallback)draw_pan_cb },
1980 { "PanSouth", NULL, N_("Pan South"), "<control>Down", NULL, (GCallback)draw_pan_cb },
1981 { "PanWest", NULL, N_("Pan West"), "<control>Left", NULL, (GCallback)draw_pan_cb },
1982 { "BGJobs", GTK_STOCK_EXECUTE, N_("Background _Jobs"), NULL, NULL, (GCallback)a_background_show_window },
1983
1984 { "Cut", GTK_STOCK_CUT, N_("Cu_t"), NULL, NULL, (GCallback)menu_cut_layer_cb },
1985 { "Copy", GTK_STOCK_COPY, N_("_Copy"), NULL, NULL, (GCallback)menu_copy_layer_cb },
1986 { "Paste", GTK_STOCK_PASTE, N_("_Paste"), NULL, NULL, (GCallback)menu_paste_layer_cb },
1987 { "Delete", GTK_STOCK_DELETE, N_("_Delete"), NULL, NULL, (GCallback)menu_delete_layer_cb },
1988 { "DeleteAll", NULL, N_("Delete All"), NULL, NULL, (GCallback)clear_cb },
17a1f8f9 1989 { "Preferences",GTK_STOCK_PREFERENCES, N_("_Preferences..."), NULL, NULL, (GCallback)preferences_cb },
5515e2d3
JJ
1990 { "Properties",GTK_STOCK_PROPERTIES, N_("_Properties"), NULL, NULL, (GCallback)menu_properties_cb },
1991
1992 { "About", GTK_STOCK_ABOUT, N_("_About"), NULL, NULL, (GCallback)help_about_cb },
e4afc73a
EB
1993};
1994
1995/* Radio items */
1996static GtkRadioActionEntry mode_entries[] = {
5515e2d3
JJ
1997 { "ModeUTM", NULL, N_("_UTM Mode"), "<control>u", NULL, 0 },
1998 { "ModeExpedia", NULL, N_("_Expedia Mode"), "<control>e", NULL, 1 },
5515e2d3 1999 { "ModeMercator", NULL, N_("_Google Mode"), "<control>g", NULL, 4 }
50a14534
EB
2000};
2001
e4afc73a 2002static GtkRadioActionEntry tool_entries[] = {
576cbd17
GB
2003 { "Pan", "vik-icon-pan", N_("_Pan"), "<control><shift>P", N_("Pan Tool"), 0 },
2004 { "Zoom", "vik-icon-zoom", N_("_Zoom"), "<control><shift>Z", N_("Zoom Tool"), 1 },
2005 { "Ruler", "vik-icon-ruler", N_("_Ruler"), "<control><shift>R", N_("Ruler Tool"), 2 }
e4afc73a 2006};
50a14534 2007
35c7c0ba 2008static GtkToggleActionEntry toggle_entries[] = {
94807fab
GB
2009 { "ShowScale", NULL, N_("Show Scale"), NULL, N_("Show Scale"), (GCallback)set_draw_scale, TRUE },
2010 { "ShowCenterMark", NULL, N_("Show Center Mark"), NULL, N_("Show Center Mark"), (GCallback)set_draw_centermark, TRUE },
2011 { "FullScreen", GTK_STOCK_FULLSCREEN, N_("Full Screen"), "F11", N_("Activate full screen mode"), (GCallback)full_screen_cb, FALSE },
2012 { "ViewSidePanel", GTK_STOCK_INDEX, N_("Show Side Panel"), "F9", N_("Show Side Panel"), (GCallback)view_side_panel_cb, TRUE },
35c7c0ba
EB
2013};
2014
a527cfff 2015#include "menu.xml.h"
e4afc73a 2016static void window_create_ui( VikWindow *window )
50a14534 2017{
e4afc73a
EB
2018 GtkUIManager *uim;
2019 GtkActionGroup *action_group;
50a14534 2020 GtkAccelGroup *accel_group;
e4afc73a 2021 GError *error;
e4afc73a
EB
2022 guint i, j, mid;
2023 GtkIconFactory *icon_factory;
2024 GtkIconSet *icon_set;
e4afc73a
EB
2025 GtkRadioActionEntry *tools = NULL, *radio;
2026 guint ntools;
2027
2028 uim = gtk_ui_manager_new ();
2029 window->uim = uim;
2030
9593a4c9
EB
2031 toolbox_add_tool(window->vt, &ruler_tool, TOOL_LAYER_TYPE_NONE);
2032 toolbox_add_tool(window->vt, &zoom_tool, TOOL_LAYER_TYPE_NONE);
576cbd17 2033 toolbox_add_tool(window->vt, &pan_tool, TOOL_LAYER_TYPE_NONE);
941aa6e9 2034
e4afc73a 2035 error = NULL;
a527cfff 2036 if (!(mid = gtk_ui_manager_add_ui_from_string (uim, menu_xml, -1, &error))) {
e4afc73a
EB
2037 g_error_free (error);
2038 exit (1);
2039 }
2040
2041 action_group = gtk_action_group_new ("MenuActions");
5515e2d3 2042 gtk_action_group_set_translation_domain(action_group, PACKAGE_NAME);
e4afc73a 2043 gtk_action_group_add_actions (action_group, entries, G_N_ELEMENTS (entries), window);
35c7c0ba 2044 gtk_action_group_add_toggle_actions (action_group, toggle_entries, G_N_ELEMENTS (toggle_entries), window);
6a9ff0ee 2045 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
2046
2047 icon_factory = gtk_icon_factory_new ();
ee36ac4f 2048 gtk_icon_factory_add_default (icon_factory);
e4afc73a
EB
2049
2050 register_vik_icons(icon_factory);
2051
2052 ntools = 0;
2053 for (i=0; i<G_N_ELEMENTS(tool_entries); i++) {
2054 tools = g_renew(GtkRadioActionEntry, tools, ntools+1);
2055 radio = &tools[ntools];
2056 ntools++;
2057 *radio = tool_entries[i];
2058 radio->value = ntools;
2059 }
2060
2061 for (i=0; i<VIK_LAYER_NUM_TYPES; i++) {
2062 GtkActionEntry action;
2063 gtk_ui_manager_add_ui(uim, mid, "/ui/MainMenu/Layers/",
2064 vik_layer_get_interface(i)->name,
2065 vik_layer_get_interface(i)->name,
2066 GTK_UI_MANAGER_MENUITEM, FALSE);
2067
2068 icon_set = gtk_icon_set_new_from_pixbuf (gdk_pixbuf_from_pixdata (vik_layer_get_interface(i)->icon, FALSE, NULL ));
2069 gtk_icon_factory_add (icon_factory, vik_layer_get_interface(i)->name, icon_set);
2070 gtk_icon_set_unref (icon_set);
2071
2072 action.name = vik_layer_get_interface(i)->name;
2073 action.stock_id = vik_layer_get_interface(i)->name;
4c77d5e0 2074 action.label = g_strdup_printf( _("New %s Layer"), vik_layer_get_interface(i)->name);
e4afc73a
EB
2075 action.accelerator = NULL;
2076 action.tooltip = NULL;
2077 action.callback = (GCallback)menu_addlayer_cb;
2078 gtk_action_group_add_actions(action_group, &action, 1, window);
2079
2080 if ( vik_layer_get_interface(i)->tools_count ) {
2081 gtk_ui_manager_add_ui(uim, mid, "/ui/MainMenu/Tools/", vik_layer_get_interface(i)->name, NULL, GTK_UI_MANAGER_SEPARATOR, FALSE);
2082 gtk_ui_manager_add_ui(uim, mid, "/ui/MainToolbar/ToolItems/", vik_layer_get_interface(i)->name, NULL, GTK_UI_MANAGER_SEPARATOR, FALSE);
2083 }
2084
2085 for ( j = 0; j < vik_layer_get_interface(i)->tools_count; j++ ) {
2086 tools = g_renew(GtkRadioActionEntry, tools, ntools+1);
2087 radio = &tools[ntools];
2088 ntools++;
2089
e4afc73a 2090 gtk_ui_manager_add_ui(uim, mid, "/ui/MainMenu/Tools",
4c77d5e0 2091 _(vik_layer_get_interface(i)->tools[j].name),
e4afc73a
EB
2092 vik_layer_get_interface(i)->tools[j].name,
2093 GTK_UI_MANAGER_MENUITEM, FALSE);
2094 gtk_ui_manager_add_ui(uim, mid, "/ui/MainToolbar/ToolItems",
4c77d5e0 2095 _(vik_layer_get_interface(i)->tools[j].name),
e4afc73a
EB
2096 vik_layer_get_interface(i)->tools[j].name,
2097 GTK_UI_MANAGER_TOOLITEM, FALSE);
2098
9593a4c9 2099 toolbox_add_tool(window->vt, &(vik_layer_get_interface(i)->tools[j]), i);
941aa6e9 2100
e4afc73a
EB
2101 radio->name = vik_layer_get_interface(i)->tools[j].name;
2102 radio->stock_id = vik_layer_get_interface(i)->tools[j].name,
4c77d5e0 2103 radio->label = _(vik_layer_get_interface(i)->tools[j].name);
e4afc73a 2104 radio->accelerator = NULL;
4c77d5e0 2105 radio->tooltip = _(vik_layer_get_interface(i)->tools[j].name);
e4afc73a
EB
2106 radio->value = ntools;
2107 }
2108 }
ee36ac4f 2109 g_object_unref (icon_factory);
50a14534 2110
e4afc73a
EB
2111 gtk_action_group_add_radio_actions(action_group, tools, ntools, 0, (GCallback)menu_tool_cb, window);
2112 g_free(tools);
50a14534 2113
e4afc73a 2114 gtk_ui_manager_insert_action_group (uim, action_group, 0);
50a14534 2115
79845167
QT
2116 for (i=0; i<VIK_LAYER_NUM_TYPES; i++) {
2117 for ( j = 0; j < vik_layer_get_interface(i)->tools_count; j++ ) {
2118 GtkAction *action = gtk_action_group_get_action(action_group,
2119 vik_layer_get_interface(i)->tools[j].name);
2120 g_object_set(action, "sensitive", FALSE, NULL);
2121 }
2122 }
2123 window->action_group = action_group;
2124
e4afc73a
EB
2125 accel_group = gtk_ui_manager_get_accel_group (uim);
2126 gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
2127 gtk_ui_manager_ensure_update (uim);
e4afc73a 2128}
50a14534 2129
50a14534 2130
941aa6e9 2131
e4afc73a 2132static struct {
4bd45256 2133 const GdkPixdata *data;
e4afc73a
EB
2134 gchar *stock_id;
2135} stock_icons[] = {
5bfafde9
GB
2136 { &begintr_18_pixbuf, "Begin Track" },
2137 { &iscissors_18_pixbuf, "Magic Scissors" },
2138 { &mover_22_pixbuf, "vik-icon-pan" },
2139 { &demdl_18_pixbuf, "DEM Download/Import" },
2140 { &showpic_18_pixbuf, "Show Picture" },
2141 { &addtr_18_pixbuf, "Create Track" },
2142 { &edtr_18_pixbuf, "Edit Trackpoint" },
2143 { &addwp_18_pixbuf, "Create Waypoint" },
2144 { &edwp_18_pixbuf, "Edit Waypoint" },
2145 { &zoom_18_pixbuf, "vik-icon-zoom" },
2146 { &ruler_18_pixbuf, "vik-icon-ruler" },
2147 { &geozoom_18_pixbuf, "Georef Zoom Tool" },
2148 { &geomove_18_pixbuf, "Georef Move Map" },
2149 { &mapdl_18_pixbuf, "Maps Download" },
2150 { &showpic_18_pixbuf, "Show Picture" },
e4afc73a
EB
2151};
2152
e4afc73a
EB
2153static gint n_stock_icons = G_N_ELEMENTS (stock_icons);
2154
2155static void
2156register_vik_icons (GtkIconFactory *icon_factory)
2157{
2158 GtkIconSet *icon_set;
e4afc73a 2159 gint i;
e4afc73a
EB
2160
2161 for (i = 0; i < n_stock_icons; i++) {
4bd45256
EB
2162 icon_set = gtk_icon_set_new_from_pixbuf (gdk_pixbuf_from_pixdata (
2163 stock_icons[i].data, FALSE, NULL ));
e4afc73a
EB
2164 gtk_icon_factory_add (icon_factory, stock_icons[i].stock_id, icon_set);
2165 gtk_icon_set_unref (icon_set);
2166 }
50a14534 2167}
bce3a7b0 2168