X-Git-Url: https://git.street.me.uk/andy/viking.git/blobdiff_plain/beb9d63a39b01fad2c4126b695a9935443634eab..5eb031a0b26eeb000f445a12b8ce337286dac8a6:/src/vikwindow.c diff --git a/src/vikwindow.c b/src/vikwindow.c index a1f49abe..b89791fb 100644 --- a/src/vikwindow.c +++ b/src/vikwindow.c @@ -3,7 +3,7 @@ * * Copyright (C) 2003-2005, Evan Battaglia * Copyright (C) 2005-2006, Alex Foobarian - * Copyright (C) 2012-2013, Rob Norris + * Copyright (C) 2012-2015, Rob Norris * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,11 +29,13 @@ #include "background.h" #include "acquire.h" #include "datasources.h" +#include "geojson.h" #include "vikgoto.h" #include "dems.h" #include "mapcache.h" #include "print.h" #include "preferences.h" +#include "toolbar.h" #include "viklayer_defaults.h" #include "icons/icons.h" #include "vikexttools.h" @@ -41,6 +43,9 @@ #include "garminsymbols.h" #include "vikmapslayer.h" #include "geonamessearch.h" +#include "vikutils.h" +#include "dir.h" +#include "kmz.h" #ifdef HAVE_STDLIB_H #include @@ -72,6 +77,10 @@ static GSList *window_list = NULL; #define DRAW_IMAGE_DEFAULT_HEIGHT 1024 #define DRAW_IMAGE_DEFAULT_SAVE_AS_PNG TRUE +// The last used directories +static gchar *last_folder_files_uri = NULL; +static gchar *last_folder_images_uri = NULL; + static void window_finalize ( GObject *gob ); static GObjectClass *parent_class; @@ -111,6 +120,10 @@ static void draw_status ( VikWindow *vw ); /* End Drawing Functions */ +static void toggle_draw_scale ( GtkAction *a, VikWindow *vw ); +static void toggle_draw_centermark ( GtkAction *a, VikWindow *vw ); +static void toggle_draw_highlight ( GtkAction *a, VikWindow *vw ); + static void menu_addlayer_cb ( GtkAction *a, VikWindow *vw ); static void menu_properties_cb ( GtkAction *a, VikWindow *vw ); static void menu_delete_layer_cb ( GtkAction *a, VikWindow *vw ); @@ -130,7 +143,8 @@ typedef struct { VikWindow *vw; } toolbox_tools_t; -static void menu_tool_cb ( GtkAction *old, GtkAction *a, VikWindow *vw ); +static void menu_cb ( GtkAction *old, GtkAction *a, VikWindow *vw ); +static void window_change_coord_mode_cb ( GtkAction *old, GtkAction *a, VikWindow *vw ); static toolbox_tools_t* toolbox_create(VikWindow *vw); static void toolbox_add_tool(toolbox_tools_t *vt, VikToolInterface *vti, gint layer_type ); static int toolbox_get_tool(toolbox_tools_t *vt, const gchar *tool_name); @@ -154,11 +168,14 @@ static gboolean window_save ( VikWindow *vw ); struct _VikWindow { GtkWindow gtkwindow; + GtkWidget *hpaned; VikViewport *viking_vvp; VikLayersPanel *viking_vlp; VikStatusbar *viking_vs; + VikToolbar *viking_vtb; - GtkToolbar *toolbar; + GtkWidget *main_vbox; + GtkWidget *menu_hbox; GdkCursor *busy_cursor; GdkCursor *viewport_cursor; // only a reference @@ -171,6 +188,15 @@ struct _VikWindow { GtkActionGroup *action_group; + // Display controls + // NB scale, centermark and highlight are in viewport. + gboolean show_full_screen; + gboolean show_side_panel; + gboolean show_statusbar; + gboolean show_toolbar; + gboolean show_main_menu; + + gboolean select_move; gboolean pan_move; gint pan_x, pan_y; gint delayed_pan_x, delayed_pan_y; // Temporary storage @@ -183,9 +209,6 @@ struct _VikWindow { gboolean modified; VikLoadType_t loaded_type; - GtkWidget *open_dia, *save_dia; - GtkWidget *save_img_dia, *save_img_dir_dia; - gboolean only_updating_coord_mode_ui; /* hack for a bug in GTK */ GtkUIManager *uim; @@ -284,12 +307,17 @@ static gboolean statusbar_idle_update ( statusbar_idle_data *sid ) */ void vik_window_statusbar_update ( VikWindow *vw, const gchar* message, vik_statusbar_type_t vs_type ) { + GThread *thread = vik_window_get_thread ( vw ); + if ( !thread ) + // Do nothing + return; + statusbar_idle_data *sid = g_malloc ( sizeof (statusbar_idle_data) ); sid->vs = vw->viking_vs; sid->vs_type = vs_type; sid->message = g_strdup ( message ); - if ( g_thread_self() == vik_window_get_thread ( vw ) ) { + if ( g_thread_self() == thread ) { g_idle_add ( (GSourceFunc) statusbar_idle_update, sid ); } else { @@ -302,8 +330,11 @@ void vik_window_statusbar_update ( VikWindow *vw, const gchar* message, vik_stat static void destroy_window ( GtkWidget *widget, gpointer data ) { - if ( ! --window_count ) + if ( ! --window_count ) { + g_free ( last_folder_files_uri ); + g_free ( last_folder_images_uri ); gtk_main_quit (); + } } #define VIK_SETTINGS_WIN_SIDEPANEL "window_sidepanel" @@ -350,7 +381,7 @@ VikWindow *vik_window_new_window () gboolean toolbar; if ( a_settings_get_boolean ( VIK_SETTINGS_WIN_TOOLBAR, &toolbar ) ) if ( ! toolbar ) { - gtk_widget_hide ( GTK_WIDGET(vw->toolbar) ); + gtk_widget_hide ( toolbar_get_widget (vw->viking_vtb) ); GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ViewToolBar" ); gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), FALSE ); } @@ -453,7 +484,8 @@ void vik_window_new_window_finish ( VikWindow *vw ) vik_statusbar_set_message ( vw->viking_vs, VIK_STATUSBAR_INFO, _("Trying to determine location...") ); - a_background_thread ( GTK_WINDOW(vw), + a_background_thread ( BACKGROUND_POOL_REMOTE, + GTK_WINDOW(vw), _("Determining location"), (vik_thr_func) determine_location_thread, vw, @@ -466,12 +498,14 @@ void vik_window_new_window_finish ( VikWindow *vw ) static void open_window ( VikWindow *vw, GSList *files ) { + if ( !vw ) + return; gboolean change_fn = (g_slist_length(files) == 1); /* only change fn if one file */ GSList *cur_file = files; while ( cur_file ) { // Only open a new window if a viking file gchar *file_name = cur_file->data; - if (vw != NULL && vw->filename && check_file_magic_vik ( file_name ) ) { + if (vw->filename && check_file_magic_vik ( file_name ) ) { VikWindow *newvw = vik_window_new_window (); if (newvw) vik_window_open_file ( newvw, file_name, TRUE ); @@ -502,6 +536,7 @@ void vik_window_selected_layer(VikWindow *vw, VikLayer *vl) action = gtk_action_group_get_action(vw->action_group, layer_interface->tools[j].radioActionEntry.name); g_object_set(action, "sensitive", i == vl->type, NULL); + toolbar_action_set_sensitive ( vw->viking_vtb, vik_layer_get_interface(i)->tools[j].radioActionEntry.name, i == vl->type ); } } } @@ -523,6 +558,8 @@ static void window_finalize ( GObject *gob ) g_free ( vw->vt->tools ); g_free ( vw->vt ); + vik_toolbar_finalize ( vw->viking_vtb ); + G_OBJECT_CLASS(parent_class)->finalize(gob); } @@ -551,7 +588,7 @@ static void zoom_changed (GtkMenuShell *menushell, GtkWidget *aw = gtk_menu_get_active ( GTK_MENU (menushell) ); gint active = GPOINTER_TO_INT(g_object_get_data ( G_OBJECT (aw), "position" )); - gdouble zoom_request = pow (2, active-2 ); + gdouble zoom_request = pow (2, active-5 ); // But has it really changed? gdouble current_zoom = vik_viewport_get_zoom ( vw->viking_vvp ); @@ -568,7 +605,7 @@ static void zoom_changed (GtkMenuShell *menushell, static GtkWidget *create_zoom_menu_all_levels ( gdouble mpp ) { GtkWidget *menu = gtk_menu_new (); - char *itemLabels[] = { "0.25", "0.5", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", "2048", "4096", "8192", "16384", "32768" }; + char *itemLabels[] = { "0.031", "0.063", "0.125", "0.25", "0.5", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", "2048", "4096", "8192", "16384", "32768" }; int i; for (i = 0 ; i < G_N_ELEMENTS(itemLabels) ; i++) @@ -579,7 +616,7 @@ static GtkWidget *create_zoom_menu_all_levels ( gdouble mpp ) g_object_set_data (G_OBJECT (item), "position", GINT_TO_POINTER(i)); } - gint active = 2 + round ( log (mpp) / log (2) ); + gint active = 5 + round ( log (mpp) / log (2) ); // Ensure value derived from mpp is in bounds of the menu if ( active >= G_N_ELEMENTS(itemLabels) ) active = G_N_ELEMENTS(itemLabels) - 1; @@ -685,19 +722,34 @@ static void drag_data_received_cb ( GtkWidget *widget, gtk_drag_finish ( context, success, FALSE, time ); } +static void toolbar_tool_cb ( GtkAction *old, GtkAction *current, gpointer gp ) +{ + VikWindow *vw = (VikWindow*)gp; + GtkAction *action = gtk_action_group_get_action ( vw->action_group, gtk_action_get_name(current) ); + if ( action ) + gtk_action_activate ( action ); +} + +static void toolbar_reload_cb ( GtkActionGroup *grp, gpointer gp ) +{ + VikWindow *vw = (VikWindow*)gp; + center_changed_cb ( vw ); +} + #define VIK_SETTINGS_WIN_MAX "window_maximized" #define VIK_SETTINGS_WIN_FULLSCREEN "window_fullscreen" #define VIK_SETTINGS_WIN_WIDTH "window_width" #define VIK_SETTINGS_WIN_HEIGHT "window_height" +#define VIK_SETTINGS_WIN_PANE_POSITION "window_horizontal_pane_position" #define VIK_SETTINGS_WIN_SAVE_IMAGE_WIDTH "window_save_image_width" #define VIK_SETTINGS_WIN_SAVE_IMAGE_HEIGHT "window_save_image_height" #define VIK_SETTINGS_WIN_SAVE_IMAGE_PNG "window_save_image_as_png" +#define VIK_SETTINGS_WIN_COPY_CENTRE_FULL_FORMAT "window_copy_centre_full_format" + +#define VIKING_ACCELERATOR_KEY_FILE "keys.rc" static void vik_window_init ( VikWindow *vw ) { - GtkWidget *main_vbox; - GtkWidget *hpaned; - vw->action_group = NULL; vw->viking_vvp = vik_viewport_new(); @@ -706,20 +758,18 @@ static void vik_window_init ( VikWindow *vw ) vw->viking_vs = vik_statusbar_new(); vw->vt = toolbox_create(vw); + vw->viking_vtb = vik_toolbar_new (); window_create_ui(vw); window_set_filename (vw, NULL); - vw->toolbar = GTK_TOOLBAR(gtk_ui_manager_get_widget (vw->uim, "/MainToolbar")); vw->busy_cursor = gdk_cursor_new ( GDK_WATCH ); - // Set the default tool - gtk_action_activate ( gtk_action_group_get_action ( vw->action_group, "Pan" ) ); - vw->filename = NULL; vw->loaded_type = LOAD_TYPE_READ_FAILURE; //AKA none vw->modified = FALSE; vw->only_updating_coord_mode_ui = FALSE; - + + vw->select_move = FALSE; vw->pan_move = FALSE; vw->pan_x = vw->pan_y = -1; vw->single_click_pending = FALSE; @@ -740,13 +790,27 @@ static void vik_window_init ( VikWindow *vw ) else vw->draw_image_save_as_png = DRAW_IMAGE_DEFAULT_SAVE_AS_PNG; - main_vbox = gtk_vbox_new(FALSE, 1); - gtk_container_add (GTK_CONTAINER (vw), main_vbox); - - gtk_box_pack_start (GTK_BOX(main_vbox), gtk_ui_manager_get_widget (vw->uim, "/MainMenu"), FALSE, TRUE, 0); - gtk_box_pack_start (GTK_BOX(main_vbox), GTK_WIDGET(vw->toolbar), FALSE, TRUE, 0); - gtk_toolbar_set_icon_size (vw->toolbar, GTK_ICON_SIZE_SMALL_TOOLBAR); - gtk_toolbar_set_style (vw->toolbar, GTK_TOOLBAR_ICONS); + vw->main_vbox = gtk_vbox_new(FALSE, 1); + gtk_container_add (GTK_CONTAINER (vw), vw->main_vbox); + vw->menu_hbox = gtk_hbox_new(FALSE, 1); + GtkWidget *menu_bar = gtk_ui_manager_get_widget (vw->uim, "/MainMenu"); + gtk_box_pack_start (GTK_BOX(vw->menu_hbox), menu_bar, FALSE, TRUE, 0); + gtk_box_pack_start (GTK_BOX(vw->main_vbox), vw->menu_hbox, FALSE, TRUE, 0); + + toolbar_init(vw->viking_vtb, + &vw->gtkwindow, + vw->main_vbox, + vw->menu_hbox, + toolbar_tool_cb, + toolbar_reload_cb, + (gpointer)vw); // This auto packs toolbar into the vbox + // Must be performed post toolbar init + gint i,j; + for (i=0; itools_count; j++ ) { + toolbar_action_set_sensitive ( vw->viking_vtb, vik_layer_get_interface(i)->tools[j].radioActionEntry.name, FALSE ); + } + } vik_ext_tool_datasources_add_menu_items ( vw, vw->uim ); @@ -778,14 +842,14 @@ static void vik_window_init ( VikWindow *vw ) // Set initial button sensitivity center_changed_cb ( vw ); - hpaned = gtk_hpaned_new (); - gtk_paned_pack1 ( GTK_PANED(hpaned), GTK_WIDGET (vw->viking_vlp), FALSE, FALSE ); - gtk_paned_pack2 ( GTK_PANED(hpaned), GTK_WIDGET (vw->viking_vvp), TRUE, TRUE ); + vw->hpaned = gtk_hpaned_new (); + gtk_paned_pack1 ( GTK_PANED(vw->hpaned), GTK_WIDGET (vw->viking_vlp), FALSE, TRUE ); + gtk_paned_pack2 ( GTK_PANED(vw->hpaned), GTK_WIDGET (vw->viking_vvp), TRUE, TRUE ); /* This packs the button into the window (a gtk container). */ - gtk_box_pack_start (GTK_BOX(main_vbox), hpaned, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX(vw->main_vbox), vw->hpaned, TRUE, TRUE, 0); - gtk_box_pack_end (GTK_BOX(main_vbox), GTK_WIDGET(vw->viking_vs), FALSE, TRUE, 0); + gtk_box_pack_end (GTK_BOX(vw->main_vbox), GTK_WIDGET(vw->viking_vs), FALSE, TRUE, 0); a_background_add_window ( vw ); @@ -821,19 +885,27 @@ static void vik_window_init ( VikWindow *vw ) gboolean full; if ( a_settings_get_boolean ( VIK_SETTINGS_WIN_FULLSCREEN, &full ) ) { if ( full ) { + vw->show_full_screen = TRUE; gtk_window_fullscreen ( GTK_WINDOW(vw) ); GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/FullScreen" ); - gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), TRUE ); + if ( check_box ) + gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), TRUE ); } } + + gint position = -1; // Let GTK determine default positioning + if ( !a_settings_get_integer ( VIK_SETTINGS_WIN_PANE_POSITION, &position ) ) { + position = -1; + } + gtk_paned_set_position ( GTK_PANED(vw->hpaned), position ); } gtk_window_set_default_size ( GTK_WINDOW(vw), width, height ); - vw->open_dia = NULL; - vw->save_dia = NULL; - vw->save_img_dia = NULL; - vw->save_img_dir_dia = NULL; + vw->show_side_panel = TRUE; + vw->show_statusbar = TRUE; + vw->show_toolbar = TRUE; + vw->show_main_menu = TRUE; // Only accept Drag and Drop of files onto the viewport gtk_drag_dest_set ( GTK_WIDGET(vw->viking_vvp), GTK_DEST_DEFAULT_ALL, NULL, 0, GDK_ACTION_COPY ); @@ -844,6 +916,14 @@ static void vik_window_init ( VikWindow *vw ) // Hopefully we are storing the main thread value here :) // [ATM any window initialization is always be performed by the main thread] vw->thread = g_thread_self(); + + // Set the default tool + mode + gtk_action_activate ( gtk_action_group_get_action ( vw->action_group, "Pan" ) ); + gtk_action_activate ( gtk_action_group_get_action ( vw->action_group, "ModeMercator" ) ); + + gchar *accel_file_name = g_build_filename ( a_get_viking_dir(), VIKING_ACCELERATOR_KEY_FILE, NULL ); + gtk_accel_map_load ( accel_file_name ); + g_free ( accel_file_name ); } static VikWindow *window_new () @@ -897,9 +977,21 @@ static gboolean key_press_event( VikWindow *vw, GdkEventKey *event, gpointer dat map_download = TRUE; map_download_only_new = FALSE; } + // Standard Ctrl+KP+ / Ctrl+KP- to zoom in/out respectively + else if ( event->keyval == GDK_KEY_KP_Add && (event->state & modifiers) == GDK_CONTROL_MASK ) { + vik_viewport_zoom_in ( vw->viking_vvp ); + draw_update(vw); + return TRUE; // handled keypress + } + else if ( event->keyval == GDK_KEY_KP_Subtract && (event->state & modifiers) == GDK_CONTROL_MASK ) { + vik_viewport_zoom_out ( vw->viking_vvp ); + draw_update(vw); + return TRUE; // handled keypress + } if ( map_download ) { simple_map_update ( vw, map_download_only_new ); + return TRUE; // handled keypress } VikLayer *vl = vik_layers_panel_get_selected ( vw->viking_vlp ); @@ -971,7 +1063,7 @@ static gboolean delete_event( VikWindow *vw ) a_settings_set_boolean ( VIK_SETTINGS_WIN_STATUSBAR, GTK_WIDGET_VISIBLE (GTK_WIDGET(vw->viking_vs)) ); - a_settings_set_boolean ( VIK_SETTINGS_WIN_TOOLBAR, GTK_WIDGET_VISIBLE (GTK_WIDGET(vw->toolbar)) ); + a_settings_set_boolean ( VIK_SETTINGS_WIN_TOOLBAR, GTK_WIDGET_VISIBLE (toolbar_get_widget(vw->viking_vtb)) ); // If supersized - no need to save the enlarged width+height values if ( ! (state_fullscreen || state_max) ) { @@ -980,11 +1072,17 @@ static gboolean delete_event( VikWindow *vw ) a_settings_set_integer ( VIK_SETTINGS_WIN_WIDTH, width ); a_settings_set_integer ( VIK_SETTINGS_WIN_HEIGHT, height ); } + + a_settings_set_integer ( VIK_SETTINGS_WIN_PANE_POSITION, gtk_paned_get_position (GTK_PANED(vw->hpaned)) ); } a_settings_set_integer ( VIK_SETTINGS_WIN_SAVE_IMAGE_WIDTH, vw->draw_image_width ); a_settings_set_integer ( VIK_SETTINGS_WIN_SAVE_IMAGE_HEIGHT, vw->draw_image_height ); a_settings_set_boolean ( VIK_SETTINGS_WIN_SAVE_IMAGE_PNG, vw->draw_image_save_as_png ); + + gchar *accel_file_name = g_build_filename ( a_get_viking_dir(), VIKING_ACCELERATOR_KEY_FILE, NULL ); + gtk_accel_map_save ( accel_file_name ); + g_free ( accel_file_name ); } return FALSE; @@ -1156,11 +1254,34 @@ static void vik_window_pan_move (VikWindow *vw, GdkEventMotion *event) } } +/** + * get_location_strings: + * + * Utility function to get positional strings for the given location + * lat and lon strings will get allocated and so need to be freed after use + */ +static void get_location_strings ( VikWindow *vw, struct UTM utm, gchar **lat, gchar **lon ) +{ + if ( vik_viewport_get_drawmode ( vw->viking_vvp ) == VIK_VIEWPORT_DRAWMODE_UTM ) { + // Reuse lat for the first part (Zone + N or S, and lon for the second part (easting and northing) of a UTM format: + // ZONE[N|S] EASTING NORTHING + *lat = g_malloc(4*sizeof(gchar)); + // NB zone is stored in a char but is an actual number + g_snprintf (*lat, 4, "%d%c", utm.zone, utm.letter); + *lon = g_malloc(16*sizeof(gchar)); + g_snprintf (*lon, 16, "%d %d", (gint)utm.easting, (gint)utm.northing); + } + else { + struct LatLon ll; + a_coords_utm_to_latlon ( &utm, &ll ); + a_coords_latlon_to_string ( &ll, lat, lon ); + } +} + static void draw_mouse_motion (VikWindow *vw, GdkEventMotion *event) { static VikCoord coord; static struct UTM utm; - static struct LatLon ll; #define BUFFER_SIZE 50 static char pointer_buf[BUFFER_SIZE]; gchar *lat = NULL, *lon = NULL; @@ -1180,19 +1301,7 @@ static void draw_mouse_motion (VikWindow *vw, GdkEventMotion *event) vik_viewport_screen_to_coord ( vw->viking_vvp, event->x, event->y, &coord ); vik_coord_to_utm ( &coord, &utm ); - if ( vik_viewport_get_drawmode ( vw->viking_vvp ) == VIK_VIEWPORT_DRAWMODE_UTM ) { - // Reuse lat for the first part (Zone + N or S, and lon for the second part (easting and northing) of a UTM format: - // ZONE[N|S] EASTING NORTHING - lat = g_malloc(4*sizeof(gchar)); - // NB zone is stored in a char but is an actual number - g_snprintf (lat, 4, "%d%c", utm.zone, utm.letter); - lon = g_malloc(16*sizeof(gchar)); - g_snprintf (lon, 16, "%d %d", (gint)utm.easting, (gint)utm.northing); - } - else { - a_coords_utm_to_latlon ( &utm, &ll ); - a_coords_latlon_to_string ( &ll, &lat, &lon ); - } + get_location_strings ( vw, utm, &lat, &lon ); /* Change interpolate method according to scale */ zoom = vik_viewport_get_zoom(vw->viking_vvp); @@ -1249,6 +1358,8 @@ static gboolean vik_window_pan_timeout (VikWindow *vw) static void vik_window_pan_release ( VikWindow *vw, GdkEventButton *event ) { + gboolean do_draw = TRUE; + if ( vw->pan_move == FALSE ) { vw->single_click_pending = !vw->single_click_pending; @@ -1258,13 +1369,13 @@ static void vik_window_pan_release ( VikWindow *vw, GdkEventButton *event ) vw->delayed_pan_y = vw->pan_y; // Get double click time GtkSettings *gs = gtk_widget_get_settings ( GTK_WIDGET(vw) ); - GValue dct = G_VALUE_INIT; + GValue dct = { 0 }; // = G_VALUE_INIT; // GLIB 2.30+ only g_value_init ( &dct, G_TYPE_INT ); g_object_get_property ( G_OBJECT(gs), "gtk-double-click-time", &dct ); // Give chance for a double click to occur gint timer = g_value_get_int ( &dct ) + 50; g_timeout_add ( timer, (GSourceFunc)vik_window_pan_timeout, vw ); - goto skip_draw; + do_draw = FALSE; } else { vik_viewport_set_center_screen ( vw->viking_vvp, vw->pan_x, vw->pan_y ); @@ -1275,11 +1386,10 @@ static void vik_window_pan_release ( VikWindow *vw, GdkEventButton *event ) vik_viewport_get_height(vw->viking_vvp)/2 - event->y + vw->pan_y ); } - draw_update ( vw ); - - skip_draw: vw->pan_move = FALSE; vw->pan_x = vw->pan_y = -1; + if ( do_draw ) + draw_update ( vw ); } static void draw_release ( VikWindow *vw, GdkEventButton *event ) @@ -1432,20 +1542,29 @@ static void draw_ruler(VikViewport *vvp, GdkDrawable *d, GdkGC *gc, gint x1, gin switch (dist_units) { case VIK_UNITS_DISTANCE_KILOMETRES: if (distance >= 1000 && distance < 100000) { - g_sprintf(str, "%3.2f km", distance/1000.0); + g_sprintf(str, "%3.2f km", distance/1000.0); } else if (distance < 1000) { - g_sprintf(str, "%d m", (int)distance); + g_sprintf(str, "%d m", (int)distance); } else { - g_sprintf(str, "%d km", (int)distance/1000); + g_sprintf(str, "%d km", (int)distance/1000); } break; case VIK_UNITS_DISTANCE_MILES: if (distance >= VIK_MILES_TO_METERS(1) && distance < VIK_MILES_TO_METERS(100)) { - g_sprintf(str, "%3.2f miles", VIK_METERS_TO_MILES(distance)); + g_sprintf(str, "%3.2f miles", VIK_METERS_TO_MILES(distance)); } else if (distance < VIK_MILES_TO_METERS(1)) { - g_sprintf(str, "%d yards", (int)(distance*1.0936133)); + g_sprintf(str, "%d yards", (int)(distance*1.0936133)); + } else { + g_sprintf(str, "%d miles", (int)VIK_METERS_TO_MILES(distance)); + } + break; + case VIK_UNITS_DISTANCE_NAUTICAL_MILES: + if (distance >= VIK_NAUTICAL_MILES_TO_METERS(1) && distance < VIK_NAUTICAL_MILES_TO_METERS(100)) { + g_sprintf(str, "%3.2f NM", VIK_METERS_TO_NAUTICAL_MILES(distance)); + } else if (distance < VIK_NAUTICAL_MILES_TO_METERS(1)) { + g_sprintf(str, "%d yards", (int)(distance*1.0936133)); } else { - g_sprintf(str, "%d miles", (int)VIK_METERS_TO_MILES(distance)); + g_sprintf(str, "%d NM", (int)VIK_METERS_TO_NAUTICAL_MILES(distance)); } break; default: @@ -1532,14 +1651,17 @@ static VikLayerToolFuncStatus ruler_click (VikLayer *vl, GdkEventButton *event, vik_units_distance_t dist_units = a_vik_get_units_distance (); switch (dist_units) { case VIK_UNITS_DISTANCE_KILOMETRES: - temp = g_strdup_printf ( "%s %s DIFF %f meters", lat, lon, vik_coord_diff( &coord, &(s->oldcoord) ) ); - break; + temp = g_strdup_printf ( "%s %s DIFF %f meters", lat, lon, vik_coord_diff( &coord, &(s->oldcoord) ) ); + break; case VIK_UNITS_DISTANCE_MILES: - temp = g_strdup_printf ( "%s %s DIFF %f miles", lat, lon, VIK_METERS_TO_MILES(vik_coord_diff( &coord, &(s->oldcoord) )) ); - break; + temp = g_strdup_printf ( "%s %s DIFF %f miles", lat, lon, VIK_METERS_TO_MILES(vik_coord_diff( &coord, &(s->oldcoord) )) ); + break; + case VIK_UNITS_DISTANCE_NAUTICAL_MILES: + temp = g_strdup_printf ( "%s %s DIFF %f NM", lat, lon, VIK_METERS_TO_NAUTICAL_MILES(vik_coord_diff( &coord, &(s->oldcoord) )) ); + break; default: - temp = g_strdup_printf ("Just to keep the compiler happy"); - g_critical("Houston, we've had a problem. distance=%d", dist_units); + temp = g_strdup_printf ("Just to keep the compiler happy"); + g_critical("Houston, we've had a problem. distance=%d", dist_units); } s->has_oldcoord = FALSE; @@ -1609,6 +1731,9 @@ static VikLayerToolFuncStatus ruler_move (VikLayer *vl, GdkEventMotion *event, r case VIK_UNITS_DISTANCE_MILES: temp = g_strdup_printf ( "%s %s DIFF %f miles", lat, lon, VIK_METERS_TO_MILES (vik_coord_diff( &coord, &(s->oldcoord) )) ); break; + case VIK_UNITS_DISTANCE_NAUTICAL_MILES: + temp = g_strdup_printf ( "%s %s DIFF %f NM", lat, lon, VIK_METERS_TO_NAUTICAL_MILES (vik_coord_diff( &coord, &(s->oldcoord) )) ); + break; default: temp = g_strdup_printf ("Just to keep the compiler happy"); g_critical("Houston, we've had a problem. distance=%d", dist_units); @@ -1653,7 +1778,8 @@ static VikToolInterface ruler_tool = (VikToolKeyFunc) ruler_key_press, FALSE, GDK_CURSOR_IS_PIXMAP, - &cursor_ruler_pixbuf }; + &cursor_ruler_pixbuf, + NULL }; /*** end ruler code ********************************************************/ @@ -1817,6 +1943,9 @@ static VikLayerToolFuncStatus zoomtool_move (VikLayer *vl, GdkEventMotion *event draw_buf_done = FALSE; } } + else + zts->bounds_active = FALSE; + return VIK_LAYER_TOOL_ACK; } @@ -1824,11 +1953,11 @@ static VikLayerToolFuncStatus zoomtool_release (VikLayer *vl, GdkEventButton *ev { guint modifiers = event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK); - zts->bounds_active = FALSE; - // Ensure haven't just released on the exact same position // i.e. probably haven't moved the mouse at all - if ( modifiers == GDK_SHIFT_MASK && !( ( event->x == zts->start_x ) && ( event->y == zts->start_y )) ) { + if ( zts->bounds_active && modifiers == GDK_SHIFT_MASK && + ( event->x < zts->start_x-5 || event->x > zts->start_x+5 ) && + ( event->y < zts->start_y-5 || event->y > zts->start_y+5 ) ) { VikCoord coord1, coord2; vik_viewport_screen_to_coord ( zts->vw->viking_vvp, zts->start_x, zts->start_y, &coord1); @@ -1883,9 +2012,30 @@ static VikLayerToolFuncStatus zoomtool_release (VikLayer *vl, GdkEventButton *ev zoom = zoom * 2; vik_viewport_set_zoom ( zts->vw->viking_vvp, zoom ); } - - draw_update ( zts->vw ); } + else { + // When pressing shift and clicking for zoom, then jump three levels + if ( modifiers == GDK_SHIFT_MASK ) { + // Zoom in/out by three if possible + vik_viewport_set_center_screen ( zts->vw->viking_vvp, event->x, event->y ); + if ( event->button == 1 ) { + vik_viewport_zoom_in ( zts->vw->viking_vvp ); + vik_viewport_zoom_in ( zts->vw->viking_vvp ); + vik_viewport_zoom_in ( zts->vw->viking_vvp ); + } + else if ( event->button == 3 ) { + vik_viewport_zoom_out ( zts->vw->viking_vvp ); + vik_viewport_zoom_out ( zts->vw->viking_vvp ); + vik_viewport_zoom_out ( zts->vw->viking_vvp ); + } + } + } + + draw_update ( zts->vw ); + + // Reset + zts->bounds_active = FALSE; + return VIK_LAYER_TOOL_ACK; } @@ -1901,7 +2051,8 @@ static VikToolInterface zoom_tool = NULL, FALSE, GDK_CURSOR_IS_PIXMAP, - &cursor_zoom_pixbuf }; + &cursor_zoom_pixbuf, + NULL }; /*** end zoom code ********************************************************/ /******************************************************************************** @@ -1964,7 +2115,9 @@ static VikToolInterface pan_tool = (VikToolMouseFunc) pantool_release, NULL, FALSE, - GDK_FLEUR }; + GDK_FLEUR, + NULL, + NULL }; /*** end pan code ********************************************************/ /******************************************************************************** @@ -2002,36 +2155,55 @@ static void click_layer_selected (VikLayer *vl, clicker *ck) ck->cont = !vik_layer_get_interface(vl->type)->select_click ( vl, ck->event, ck->vvp, ck->tool_edit ); } +#ifdef WINDOWS +// Hopefully Alt keys by default +#define VIK_MOVE_MODIFIER GDK_MOD1_MASK +#else +// Alt+mouse on Linux desktops tend to be used by the desktop manager +// Thus use an alternate modifier - you may need to set something into this group +#define VIK_MOVE_MODIFIER GDK_MOD5_MASK +#endif + static VikLayerToolFuncStatus selecttool_click (VikLayer *vl, GdkEventButton *event, tool_ed_t *t) { + t->vw->select_move = FALSE; /* Only allow selection on primary button */ if ( event->button == 1 ) { - /* Enable click to apply callback to potentially all track/waypoint layers */ - /* Useful as we can find things that aren't necessarily in the currently selected layer */ - GList* gl = vik_layers_panel_get_all_layers_of_type ( t->vw->viking_vlp, VIK_LAYER_TRW, FALSE ); // Don't get invisible layers - clicker ck; - ck.cont = TRUE; - ck.vvp = t->vw->viking_vvp; - ck.event = event; - ck.tool_edit = t; - g_list_foreach ( gl, (GFunc) click_layer_selected, &ck ); - g_list_free ( gl ); - - // If nothing found then deselect & redraw screen if necessary to remove the highlight - if ( ck.cont ) { - GtkTreeIter iter; - VikTreeview *vtv = vik_layers_panel_get_treeview ( t->vw->viking_vlp ); - - if ( vik_treeview_get_selected_iter ( vtv, &iter ) ) { - // Only clear if selected thing is a TrackWaypoint layer or a sublayer - gint type = vik_treeview_item_get_type ( vtv, &iter ); - if ( type == VIK_TREEVIEW_TYPE_SUBLAYER || - VIK_LAYER(vik_treeview_item_get_pointer ( vtv, &iter ))->type == VIK_LAYER_TRW ) { + + if ( event->state & VIK_MOVE_MODIFIER ) + vik_window_pan_click ( t->vw, event ); + else { + /* Enable click to apply callback to potentially all track/waypoint layers */ + /* Useful as we can find things that aren't necessarily in the currently selected layer */ + GList* gl = vik_layers_panel_get_all_layers_of_type ( t->vw->viking_vlp, VIK_LAYER_TRW, FALSE ); // Don't get invisible layers + clicker ck; + ck.cont = TRUE; + ck.vvp = t->vw->viking_vvp; + ck.event = event; + ck.tool_edit = t; + g_list_foreach ( gl, (GFunc) click_layer_selected, &ck ); + g_list_free ( gl ); + + // If nothing found then deselect & redraw screen if necessary to remove the highlight + if ( ck.cont ) { + GtkTreeIter iter; + VikTreeview *vtv = vik_layers_panel_get_treeview ( t->vw->viking_vlp ); + + if ( vik_treeview_get_selected_iter ( vtv, &iter ) ) { + // Only clear if selected thing is a TrackWaypoint layer or a sublayer + gint type = vik_treeview_item_get_type ( vtv, &iter ); + if ( type == VIK_TREEVIEW_TYPE_SUBLAYER || + VIK_LAYER(vik_treeview_item_get_pointer ( vtv, &iter ))->type == VIK_LAYER_TRW ) { - vik_treeview_item_unselect ( vtv, &iter ); - if ( vik_window_clear_highlight ( t->vw ) ) - draw_update ( t->vw ); - } + vik_treeview_item_unselect ( vtv, &iter ); + if ( vik_window_clear_highlight ( t->vw ) ) + draw_update ( t->vw ); + } + } + } + else { + // Something found - so enable movement + t->vw->select_move = TRUE; } } } @@ -2046,27 +2218,41 @@ static VikLayerToolFuncStatus selecttool_click (VikLayer *vl, GdkEventButton *ev return VIK_LAYER_TOOL_ACK; } -static VikLayerToolFuncStatus selecttool_move (VikLayer *vl, GdkEventButton *event, tool_ed_t *t) +static VikLayerToolFuncStatus selecttool_move (VikLayer *vl, GdkEventMotion *event, tool_ed_t *t) { - /* Only allow selection on primary button */ - if ( event->button == 1 ) { + if ( t->vw->select_move ) { // Don't care about vl here if ( t->vtl ) if ( vik_layer_get_interface(VIK_LAYER_TRW)->select_move ) - vik_layer_get_interface(VIK_LAYER_TRW)->select_move ( vl, event, t->vvp, t ); + vik_layer_get_interface(VIK_LAYER_TRW)->select_move ( vl, event, t->vvp, t ); } + else + // Optional Panning + if ( event->state & VIK_MOVE_MODIFIER ) + vik_window_pan_move ( t->vw, event ); + return VIK_LAYER_TOOL_ACK; } static VikLayerToolFuncStatus selecttool_release (VikLayer *vl, GdkEventButton *event, tool_ed_t *t) { - /* Only allow selection on primary button */ - if ( event->button == 1 ) { + if ( t->vw->select_move ) { // Don't care about vl here if ( t->vtl ) if ( vik_layer_get_interface(VIK_LAYER_TRW)->select_release ) - vik_layer_get_interface(VIK_LAYER_TRW)->select_release ( (VikLayer*)t->vtl, event, t->vvp, t ); + vik_layer_get_interface(VIK_LAYER_TRW)->select_release ( (VikLayer*)t->vtl, event, t->vvp, t ); } + + if ( event->button == 1 && (event->state & VIK_MOVE_MODIFIER) ) + vik_window_pan_release ( t->vw, event ); + + // Force pan off incase it was on + t->vw->pan_move = FALSE; + t->vw->pan_x = t->vw->pan_y = -1; + + // End of this select movement + t->vw->select_move = FALSE; + return VIK_LAYER_TOOL_ACK; } @@ -2106,17 +2292,6 @@ static void draw_pan_cb ( GtkAction *a, VikWindow *vw ) draw_update ( vw ); } -static void full_screen_cb ( GtkAction *a, VikWindow *vw ) -{ - GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/FullScreen" ); - g_assert(check_box); - gboolean state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box)); - if ( state ) - gtk_window_fullscreen ( GTK_WINDOW(vw) ); - else - gtk_window_unfullscreen ( GTK_WINDOW(vw) ); -} - static void draw_zoom_cb ( GtkAction *a, VikWindow *vw ) { guint what = 128; @@ -2194,6 +2369,8 @@ static void center_changed_cb ( VikWindow *vw ) if ( action_forward ) { gtk_action_set_sensitive ( action_forward, vik_viewport_forward_available(vw->viking_vvp) ); } + + toolbar_action_set_sensitive ( vw->viking_vtb, "GoForward", vik_viewport_forward_available(vw->viking_vvp) ); } /** @@ -2288,11 +2465,190 @@ static void help_help_cb ( GtkAction *a, VikWindow *vw ) #endif /* WINDOWS */ } +static void toggle_side_panel ( VikWindow *vw ) +{ + vw->show_side_panel = !vw->show_side_panel; + if ( vw->show_side_panel ) + gtk_widget_show(GTK_WIDGET(vw->viking_vlp)); + else + gtk_widget_hide(GTK_WIDGET(vw->viking_vlp)); +} + +static void toggle_full_screen ( VikWindow *vw ) +{ + vw->show_full_screen = !vw->show_full_screen; + if ( vw->show_full_screen ) + gtk_window_fullscreen ( GTK_WINDOW(vw) ); + else + gtk_window_unfullscreen ( GTK_WINDOW(vw) ); +} + +static void toggle_statusbar ( VikWindow *vw ) +{ + vw->show_statusbar = !vw->show_statusbar; + if ( vw->show_statusbar ) + gtk_widget_show ( GTK_WIDGET(vw->viking_vs) ); + else + gtk_widget_hide ( GTK_WIDGET(vw->viking_vs) ); +} + +static void toggle_toolbar ( VikWindow *vw ) +{ + vw->show_toolbar = !vw->show_toolbar; + if ( vw->show_toolbar ) + gtk_widget_show ( toolbar_get_widget (vw->viking_vtb) ); + else + gtk_widget_hide ( toolbar_get_widget (vw->viking_vtb) ); +} + +static void toggle_main_menu ( VikWindow *vw ) +{ + vw->show_main_menu = !vw->show_main_menu; + if ( vw->show_main_menu ) + gtk_widget_show ( gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu" ) ); + else + gtk_widget_hide ( gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu" ) ); +} + +// Only for 'view' toggle menu widgets ATM. +GtkWidget *get_show_widget_by_name(VikWindow *vw, const gchar *name) +{ + g_return_val_if_fail(name != NULL, NULL); + + // ATM only FullScreen is *not* in SetShow path + gchar *path; + if ( g_strcmp0 ("FullScreen", name ) ) + path = g_strconcat("/ui/MainMenu/View/SetShow/", name, NULL); + else + path = g_strconcat("/ui/MainMenu/View/", name, NULL); + + GtkWidget *widget = gtk_ui_manager_get_widget(vw->uim, path); + g_free(path); + + return widget; +} + +static void tb_view_side_panel_cb ( GtkAction *a, VikWindow *vw ) +{ + gboolean next_state = !vw->show_side_panel; + GtkWidget *check_box = get_show_widget_by_name ( vw, gtk_action_get_name(a) ); + gboolean menu_state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box) ); + if ( next_state != menu_state ) + gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), next_state ); + else + toggle_side_panel ( vw ); +} + +static void tb_full_screen_cb ( GtkAction *a, VikWindow *vw ) +{ + gboolean next_state = !vw->show_full_screen; + GtkWidget *check_box = get_show_widget_by_name ( vw, gtk_action_get_name(a) ); + gboolean menu_state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box) ); + if ( next_state != menu_state ) + gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), next_state ); + else + toggle_full_screen ( vw ); +} + +static void tb_view_statusbar_cb ( GtkAction *a, VikWindow *vw ) +{ + gboolean next_state = !vw->show_statusbar; + GtkWidget *check_box = get_show_widget_by_name ( vw, gtk_action_get_name(a) ); + gboolean menu_state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box) ); + if ( next_state != menu_state ) + gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), next_state ); + else + toggle_statusbar ( vw ); +} + +static void tb_view_toolbar_cb ( GtkAction *a, VikWindow *vw ) +{ + gboolean next_state = !vw->show_toolbar; + GtkWidget *check_box = get_show_widget_by_name ( vw, gtk_action_get_name(a) ); + gboolean menu_state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box) ); + if ( next_state != menu_state ) + gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), next_state ); + else + toggle_toolbar ( vw ); +} + +static void tb_view_main_menu_cb ( GtkAction *a, VikWindow *vw ) +{ + gboolean next_state = !vw->show_main_menu; + GtkWidget *check_box = get_show_widget_by_name ( vw, gtk_action_get_name(a) ); + gboolean menu_state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box) ); + if ( next_state != menu_state ) + gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), next_state ); + else + toggle_main_menu ( vw ); +} + +static void tb_set_draw_scale ( GtkAction *a, VikWindow *vw ) +{ + gboolean next_state = !vik_viewport_get_draw_scale ( vw->viking_vvp ); + GtkWidget *check_box = get_show_widget_by_name ( vw, gtk_action_get_name(a) ); + gboolean menu_state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box) ); + if ( next_state != menu_state ) + gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), next_state ); + else { + vik_viewport_set_draw_scale ( vw->viking_vvp, next_state ); + draw_update ( vw ); + } +} + +static void tb_set_draw_centermark ( GtkAction *a, VikWindow *vw ) +{ + gboolean next_state = !vik_viewport_get_draw_centermark ( vw->viking_vvp ); + GtkWidget *check_box = get_show_widget_by_name ( vw, gtk_action_get_name(a) ); + gboolean menu_state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box) ); + if ( next_state != menu_state ) + gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), next_state ); + else { + vik_viewport_set_draw_centermark ( vw->viking_vvp, next_state ); + draw_update ( vw ); + } +} + +static void tb_set_draw_highlight ( GtkAction *a, VikWindow *vw ) +{ + gboolean next_state = !vik_viewport_get_draw_highlight ( vw->viking_vvp ); + GtkWidget *check_box = get_show_widget_by_name ( vw, gtk_action_get_name(a) ); + gboolean menu_state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box) ); + if ( next_state != menu_state ) + gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), next_state ); + else { + vik_viewport_set_draw_highlight ( vw->viking_vvp, next_state ); + draw_update ( vw ); + } +} + static void help_about_cb ( GtkAction *a, VikWindow *vw ) { a_dialog_about(GTK_WINDOW(vw)); } +static void help_cache_info_cb ( GtkAction *a, VikWindow *vw ) +{ + // NB: No i18n as this is just for debug + gint byte_size = a_mapcache_get_size(); + gchar *msg_sz = NULL; + gchar *msg = NULL; +#if GLIB_CHECK_VERSION(2,30,0) + msg_sz = g_format_size_full ( byte_size, G_FORMAT_SIZE_LONG_FORMAT ); +#else + msg_sz = g_format_size_for_display ( byte_size ); +#endif + msg = g_strdup_printf ( "Map Cache size is %s with %d items", msg_sz, a_mapcache_get_count()); + a_dialog_info_msg_extra ( GTK_WINDOW(vw), "%s", msg ); + g_free ( msg_sz ); + g_free ( msg ); +} + +static void back_forward_info_cb ( GtkAction *a, VikWindow *vw ) +{ + vik_viewport_show_centers ( vw->viking_vvp, GTK_WINDOW(vw) ); +} + static void menu_delete_layer_cb ( GtkAction *a, VikWindow *vw ) { if ( vik_layers_panel_get_selected ( vw->viking_vlp ) ) @@ -2304,51 +2660,79 @@ static void menu_delete_layer_cb ( GtkAction *a, VikWindow *vw ) a_dialog_info_msg ( GTK_WINDOW(vw), _("You must select a layer to delete.") ); } +static void full_screen_cb ( GtkAction *a, VikWindow *vw ) +{ + gboolean next_state = !vw->show_full_screen; + GtkToggleToolButton *tbutton = (GtkToggleToolButton *)toolbar_get_widget_by_name ( vw->viking_vtb, gtk_action_get_name(a) ); + if ( tbutton ) { + gboolean tb_state = gtk_toggle_tool_button_get_active ( tbutton ); + if ( next_state != tb_state ) + gtk_toggle_tool_button_set_active ( tbutton, next_state ); + else + toggle_full_screen ( vw ); + } + else + toggle_full_screen ( vw ); +} + static void view_side_panel_cb ( GtkAction *a, VikWindow *vw ) { - GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ViewSidePanel" ); - g_assert(check_box); - gboolean state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box)); - if ( state ) - gtk_widget_show(GTK_WIDGET(vw->viking_vlp)); + gboolean next_state = !vw->show_side_panel; + GtkToggleToolButton *tbutton = (GtkToggleToolButton *)toolbar_get_widget_by_name ( vw->viking_vtb, gtk_action_get_name(a) ); + if ( tbutton ) { + gboolean tb_state = gtk_toggle_tool_button_get_active ( tbutton ); + if ( next_state != tb_state ) + gtk_toggle_tool_button_set_active ( tbutton, next_state ); + else + toggle_side_panel ( vw ); + } else - gtk_widget_hide(GTK_WIDGET(vw->viking_vlp)); + toggle_side_panel ( vw ); } static void view_statusbar_cb ( GtkAction *a, VikWindow *vw ) { - GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ViewStatusBar" ); - if ( !check_box ) - return; - gboolean state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box) ); - if ( state ) - gtk_widget_show ( GTK_WIDGET(vw->viking_vs) ); + gboolean next_state = !vw->show_statusbar; + GtkToggleToolButton *tbutton = (GtkToggleToolButton *)toolbar_get_widget_by_name ( vw->viking_vtb, gtk_action_get_name(a) ); + if ( tbutton ) { + gboolean tb_state = gtk_toggle_tool_button_get_active ( tbutton ); + if ( next_state != tb_state ) + gtk_toggle_tool_button_set_active ( tbutton, next_state ); + else + toggle_statusbar ( vw ); + } else - gtk_widget_hide ( GTK_WIDGET(vw->viking_vs) ); + toggle_statusbar ( vw ); } static void view_toolbar_cb ( GtkAction *a, VikWindow *vw ) { - GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ViewToolbar" ); - if ( !check_box ) - return; - gboolean state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box) ); - if ( state ) - gtk_widget_show ( GTK_WIDGET(vw->toolbar) ); + gboolean next_state = !vw->show_toolbar; + GtkToggleToolButton *tbutton = (GtkToggleToolButton *)toolbar_get_widget_by_name ( vw->viking_vtb, gtk_action_get_name(a) ); + if ( tbutton ) { + gboolean tb_state = gtk_toggle_tool_button_get_active ( tbutton ); + if ( next_state != tb_state ) + gtk_toggle_tool_button_set_active ( tbutton, next_state ); + else + toggle_toolbar ( vw ); + } else - gtk_widget_hide ( GTK_WIDGET(vw->toolbar) ); + toggle_toolbar ( vw ); } static void view_main_menu_cb ( GtkAction *a, VikWindow *vw ) { - GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ViewMainMenu" ); - if ( !check_box ) - return; - gboolean state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box) ); - if ( !state ) - gtk_widget_hide ( gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu" ) ); + gboolean next_state = !vw->show_main_menu; + GtkToggleToolButton *tbutton = (GtkToggleToolButton *)toolbar_get_widget_by_name ( vw->viking_vtb, gtk_action_get_name(a) ); + if ( tbutton ) { + gboolean tb_state = gtk_toggle_tool_button_get_active ( tbutton ); + if ( next_state != tb_state ) + gtk_toggle_tool_button_set_active ( tbutton, next_state ); + else + toggle_main_menu ( vw ); + } else - gtk_widget_show ( gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu" ) ); + toggle_toolbar ( vw ); } /*************************************** @@ -2472,36 +2856,52 @@ void vik_window_enable_layer_tool ( VikWindow *vw, gint layer_id, gint tool_id ) gtk_action_activate ( gtk_action_group_get_action ( vw->action_group, vik_layer_get_interface(layer_id)->tools[tool_id].radioActionEntry.name ) ); } -/* this function gets called whenever a toolbar tool is clicked */ -static void menu_tool_cb ( GtkAction *old, GtkAction *a, VikWindow *vw ) +// Be careful with usage - as it may trigger actions being continually alternately by the menu and toolbar items +// DON'T Use this from menu callback with toggle toolbar items!! +static void toolbar_sync ( VikWindow *vw, const gchar *name, gboolean state ) { + GtkToggleToolButton *tbutton = (GtkToggleToolButton *)toolbar_get_widget_by_name ( vw->viking_vtb, name ); + if ( tbutton ) { + // Causes toggle signal action to be raised. + gtk_toggle_tool_button_set_active ( tbutton, state ); + } +} + +/* this function gets called whenever a menu is clicked */ +// Note old is not used +static void menu_cb ( GtkAction *old, GtkAction *a, VikWindow *vw ) +{ + // Ensure Toolbar kept in sync + const gchar *name = gtk_action_get_name(a); + toolbar_sync ( vw, name, TRUE ); + /* White Magic, my friends ... White Magic... */ gint tool_id; - toolbox_activate(vw->vt, gtk_action_get_name(a)); + toolbox_activate(vw->vt, name); - vw->viewport_cursor = (GdkCursor *)toolbox_get_cursor(vw->vt, gtk_action_get_name(a)); + vw->viewport_cursor = (GdkCursor *)toolbox_get_cursor(vw->vt, name); if ( gtk_widget_get_window(GTK_WIDGET(vw->viking_vvp)) ) /* We set cursor, even if it is NULL: it resets to default */ gdk_window_set_cursor ( gtk_widget_get_window(GTK_WIDGET(vw->viking_vvp)), vw->viewport_cursor ); - if (!strcmp(gtk_action_get_name(a), "Pan")) { + if (!g_strcmp0(name, "Pan")) { vw->current_tool = TOOL_PAN; } - else if (!strcmp(gtk_action_get_name(a), "Zoom")) { + else if (!g_strcmp0(name, "Zoom")) { vw->current_tool = TOOL_ZOOM; } - else if (!strcmp(gtk_action_get_name(a), "Ruler")) { + else if (!g_strcmp0(name, "Ruler")) { vw->current_tool = TOOL_RULER; } - else if (!strcmp(gtk_action_get_name(a), "Select")) { + else if (!g_strcmp0(name, "Select")) { vw->current_tool = TOOL_SELECT; } else { VikLayerTypeEnum layer_id; for (layer_id=0; layer_idtools_count; tool_id++ ) { - if (!strcmp(vik_layer_get_interface(layer_id)->tools[tool_id].radioActionEntry.name, gtk_action_get_name(a))) { + if (!g_strcmp0(vik_layer_get_interface(layer_id)->tools[tool_id].radioActionEntry.name, name)) { vw->current_tool = TOOL_LAYER; vw->tool_layer_id = layer_id; vw->tool_tool_id = tool_id; @@ -2614,6 +3014,7 @@ static void setup_recent_files (VikWindow *self) menu = gtk_recent_chooser_menu_new_for_manager (manager); gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu), GTK_RECENT_SORT_MRU); gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu), filter); + gtk_recent_chooser_set_limit (GTK_RECENT_CHOOSER (menu), a_vik_get_recent_number_files() ); menu_item = gtk_ui_manager_get_widget (self->uim, "/ui/MainMenu/File/OpenRecentFile"); gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), menu); @@ -2622,7 +3023,10 @@ static void setup_recent_files (VikWindow *self) G_CALLBACK (on_activate_recent_item), (gpointer) self); } -static void update_recently_used_document(const gchar *filename) +/* + * + */ +static void update_recently_used_document (VikWindow *vw, const gchar *filename) { /* Update Recently Used Document framework */ GtkRecentManager *manager = gtk_recent_manager_get_default(); @@ -2643,7 +3047,9 @@ static void update_recently_used_document(const gchar *filename) recent_data->is_private = FALSE; if (!gtk_recent_manager_add_full (manager, uri, recent_data)) { - g_warning (_("Unable to add '%s' to the list of recently used documents"), uri); + gchar *msg = g_strdup_printf (_("Unable to add '%s' to the list of recently used documents"), uri); + vik_statusbar_set_message ( vw->viking_vs, VIK_STATUSBAR_INFO, msg ); + g_free ( msg ); } g_free (uri); @@ -2721,18 +3127,30 @@ void vik_window_open_file ( VikWindow *vw, const gchar *filename, gboolean chang vw->only_updating_coord_mode_ui = FALSE; vik_layers_panel_change_coord_mode ( vw->viking_vlp, vik_viewport_get_coord_mode ( vw->viking_vvp ) ); - - mode_button = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ShowScale" ); - g_assert ( mode_button ); - gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(mode_button),vik_viewport_get_draw_scale(vw->viking_vvp) ); - mode_button = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ShowCenterMark" ); - g_assert ( mode_button ); - gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(mode_button),vik_viewport_get_draw_centermark(vw->viking_vvp) ); - - mode_button = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ShowHighlight" ); - g_assert ( mode_button ); - gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(mode_button),vik_viewport_get_draw_highlight (vw->viking_vvp) ); + // Slightly long winded methods to align loaded viewport settings with the UI + // Since the rewrite for toolbar + menu actions + // there no longer exists a simple way to directly change the UI to a value for toggle settings + // it only supports toggling the existing setting (otherwise get infinite loops in trying to align tb+menu elements) + // Thus get state, compare them, if different then invert viewport setting and (re)sync the setting (via toggling) + gboolean vp_state_scale = vik_viewport_get_draw_scale ( vw->viking_vvp ); + gboolean ui_state_scale = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(get_show_widget_by_name(vw, "ShowScale")) ); + if ( vp_state_scale != ui_state_scale ) { + vik_viewport_set_draw_scale ( vw->viking_vvp, !vp_state_scale ); + toggle_draw_scale ( NULL, vw ); + } + gboolean vp_state_centermark = vik_viewport_get_draw_centermark ( vw->viking_vvp ); + gboolean ui_state_centermark = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(get_show_widget_by_name(vw, "ShowCenterMark")) ); + if ( vp_state_centermark != ui_state_centermark ) { + vik_viewport_set_draw_centermark ( vw->viking_vvp, !vp_state_centermark ); + toggle_draw_centermark ( NULL, vw ); + } + gboolean vp_state_highlight = vik_viewport_get_draw_highlight ( vw->viking_vvp ); + gboolean ui_state_highlight = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(get_show_widget_by_name(vw, "ShowHighlight")) ); + if ( vp_state_highlight != ui_state_highlight ) { + vik_viewport_set_draw_highlight ( vw->viking_vvp, !vp_state_highlight ); + toggle_draw_highlight ( NULL, vw ); + } } // NB No break, carry on to redraw //case LOAD_TYPE_OTHER_SUCCESS: @@ -2740,7 +3158,7 @@ void vik_window_open_file ( VikWindow *vw, const gchar *filename, gboolean chang success = TRUE; // When LOAD_TYPE_OTHER_SUCCESS *only*, this will maintain the existing Viking project restore_original_filename = ! restore_original_filename; - update_recently_used_document(filename); + update_recently_used_document (vw, filename); draw_update ( vw ); break; } @@ -2768,72 +3186,75 @@ static void load_file ( GtkAction *a, VikWindow *vw ) g_critical("Houston, we've had a problem."); return; } - - if ( ! vw->open_dia ) - { - vw->open_dia = gtk_file_chooser_dialog_new (_("Please select a GPS data file to open. "), - GTK_WINDOW(vw), - GTK_FILE_CHOOSER_ACTION_OPEN, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, - NULL); - gchar *cwd = g_get_current_dir(); - if ( cwd ) { - gtk_file_chooser_set_current_folder ( GTK_FILE_CHOOSER(vw->open_dia), cwd ); - g_free ( cwd ); - } - GtkFileFilter *filter; - // NB file filters are listed this way for alphabetical ordering + GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Please select a GPS data file to open. "), + GTK_WINDOW(vw), + GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + NULL); + if ( last_folder_files_uri ) + gtk_file_chooser_set_current_folder_uri ( GTK_FILE_CHOOSER(dialog), last_folder_files_uri ); + + GtkFileFilter *filter; + // NB file filters are listed this way for alphabetical ordering #ifdef VIK_CONFIG_GEOCACHES - filter = gtk_file_filter_new (); - gtk_file_filter_set_name( filter, _("Geocaching") ); - gtk_file_filter_add_pattern ( filter, "*.loc" ); // No MIME type available - gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(vw->open_dia), filter); + filter = gtk_file_filter_new (); + gtk_file_filter_set_name( filter, _("Geocaching") ); + gtk_file_filter_add_pattern ( filter, "*.loc" ); // No MIME type available + gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter); #endif - filter = gtk_file_filter_new (); - gtk_file_filter_set_name( filter, _("Google Earth") ); - gtk_file_filter_add_mime_type ( filter, "application/vnd.google-earth.kml+xml"); - gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(vw->open_dia), filter); - - filter = gtk_file_filter_new (); - gtk_file_filter_set_name( filter, _("GPX") ); - gtk_file_filter_add_pattern ( filter, "*.gpx" ); // No MIME type available - gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(vw->open_dia), filter); - - filter = gtk_file_filter_new (); - gtk_file_filter_set_name( filter, _("Viking") ); - gtk_file_filter_add_pattern ( filter, "*.vik" ); - gtk_file_filter_add_pattern ( filter, "*.viking" ); - gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(vw->open_dia), filter); - - // NB could have filters for gpspoint (*.gps,*.gpsoint?) + gpsmapper (*.gsm,*.gpsmapper?) - // However assume this are barely used and thus not worthy of inclusion - // as they'll just make the options too many and have no clear file pattern - // one can always use the all option - filter = gtk_file_filter_new (); - gtk_file_filter_set_name( filter, _("All") ); - gtk_file_filter_add_pattern ( filter, "*" ); - gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(vw->open_dia), filter); - // Default to any file - same as before open filters were added - gtk_file_chooser_set_filter (GTK_FILE_CHOOSER(vw->open_dia), filter); + filter = gtk_file_filter_new (); + gtk_file_filter_set_name( filter, _("Google Earth") ); + gtk_file_filter_add_mime_type ( filter, "application/vnd.google-earth.kml+xml"); + gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter); + + filter = gtk_file_filter_new (); + gtk_file_filter_set_name( filter, _("GPX") ); + gtk_file_filter_add_pattern ( filter, "*.gpx" ); // No MIME type available + gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter); + + filter = gtk_file_filter_new (); + gtk_file_filter_set_name ( filter, _("JPG") ); + gtk_file_filter_add_mime_type ( filter, "image/jpeg"); + gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter); + + filter = gtk_file_filter_new (); + gtk_file_filter_set_name( filter, _("Viking") ); + gtk_file_filter_add_pattern ( filter, "*.vik" ); + gtk_file_filter_add_pattern ( filter, "*.viking" ); + gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter); + + // NB could have filters for gpspoint (*.gps,*.gpsoint?) + gpsmapper (*.gsm,*.gpsmapper?) + // However assume this are barely used and thus not worthy of inclusion + // as they'll just make the options too many and have no clear file pattern + // one can always use the all option + filter = gtk_file_filter_new (); + gtk_file_filter_set_name( filter, _("All") ); + gtk_file_filter_add_pattern ( filter, "*" ); + gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter); + // Default to any file - same as before open filters were added + gtk_file_chooser_set_filter (GTK_FILE_CHOOSER(dialog), filter); + + gtk_file_chooser_set_select_multiple ( GTK_FILE_CHOOSER(dialog), TRUE ); + gtk_window_set_transient_for ( GTK_WINDOW(dialog), GTK_WINDOW(vw) ); + gtk_window_set_destroy_with_parent ( GTK_WINDOW(dialog), TRUE ); - gtk_file_chooser_set_select_multiple ( GTK_FILE_CHOOSER(vw->open_dia), TRUE ); - gtk_window_set_transient_for ( GTK_WINDOW(vw->open_dia), GTK_WINDOW(vw) ); - gtk_window_set_destroy_with_parent ( GTK_WINDOW(vw->open_dia), TRUE ); - } - if ( gtk_dialog_run ( GTK_DIALOG(vw->open_dia) ) == GTK_RESPONSE_ACCEPT ) + if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT ) { - gtk_widget_hide ( vw->open_dia ); + g_free ( last_folder_files_uri ); + last_folder_files_uri = gtk_file_chooser_get_current_folder_uri ( GTK_FILE_CHOOSER(dialog) ); + #ifdef VIKING_PROMPT_IF_MODIFIED if ( (vw->modified || vw->filename) && newwindow ) #else if ( vw->filename && newwindow ) #endif - g_signal_emit ( G_OBJECT(vw), window_signals[VW_OPENWINDOW_SIGNAL], 0, gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER(vw->open_dia) ) ); + g_signal_emit ( G_OBJECT(vw), window_signals[VW_OPENWINDOW_SIGNAL], 0, gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER(dialog) ) ); else { - files = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER(vw->open_dia) ); + + files = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER(dialog) ); gboolean change_fn = newwindow && (g_slist_length(files)==1); /* only change fn if one file */ gboolean first_vik_file = TRUE; cur_file = files; @@ -2863,65 +3284,64 @@ static void load_file ( GtkAction *a, VikWindow *vw ) g_slist_free (files); } } - else - gtk_widget_hide ( vw->open_dia ); + gtk_widget_destroy ( dialog ); } static gboolean save_file_as ( GtkAction *a, VikWindow *vw ) { gboolean rv = FALSE; const gchar *fn; - if ( ! vw->save_dia ) - { - vw->save_dia = gtk_file_chooser_dialog_new (_("Save as Viking File."), - GTK_WINDOW(vw), - GTK_FILE_CHOOSER_ACTION_SAVE, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, - NULL); - gchar *cwd = g_get_current_dir(); - if ( cwd ) { - gtk_file_chooser_set_current_folder ( GTK_FILE_CHOOSER(vw->save_dia), cwd ); - g_free ( cwd ); - } - GtkFileFilter *filter; - filter = gtk_file_filter_new (); - gtk_file_filter_set_name( filter, _("All") ); - gtk_file_filter_add_pattern ( filter, "*" ); - gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(vw->save_dia), filter); + GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Save as Viking File."), + GTK_WINDOW(vw), + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + NULL); + if ( last_folder_files_uri ) + gtk_file_chooser_set_current_folder_uri ( GTK_FILE_CHOOSER(dialog), last_folder_files_uri ); + + GtkFileFilter *filter; + filter = gtk_file_filter_new (); + gtk_file_filter_set_name( filter, _("All") ); + gtk_file_filter_add_pattern ( filter, "*" ); + gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter); + + filter = gtk_file_filter_new (); + gtk_file_filter_set_name( filter, _("Viking") ); + gtk_file_filter_add_pattern ( filter, "*.vik" ); + gtk_file_filter_add_pattern ( filter, "*.viking" ); + gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter); + // Default to a Viking file + gtk_file_chooser_set_filter (GTK_FILE_CHOOSER(dialog), filter); - filter = gtk_file_filter_new (); - gtk_file_filter_set_name( filter, _("Viking") ); - gtk_file_filter_add_pattern ( filter, "*.vik" ); - gtk_file_filter_add_pattern ( filter, "*.viking" ); - gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(vw->save_dia), filter); - // Default to a Viking file - gtk_file_chooser_set_filter (GTK_FILE_CHOOSER(vw->save_dia), filter); + gtk_window_set_transient_for ( GTK_WINDOW(dialog), GTK_WINDOW(vw) ); + gtk_window_set_destroy_with_parent ( GTK_WINDOW(dialog), TRUE ); - gtk_window_set_transient_for ( GTK_WINDOW(vw->save_dia), GTK_WINDOW(vw) ); - gtk_window_set_destroy_with_parent ( GTK_WINDOW(vw->save_dia), TRUE ); - } // Auto append / replace extension with '.vik' to the suggested file name as it's going to be a Viking File gchar* auto_save_name = g_strdup ( window_get_filename ( vw ) ); - if ( ! check_file_ext ( auto_save_name, ".vik" ) ) + if ( ! a_file_check_ext ( auto_save_name, ".vik" ) ) auto_save_name = g_strconcat ( auto_save_name, ".vik", NULL ); - gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER(vw->save_dia), auto_save_name); + gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER(dialog), auto_save_name); - while ( gtk_dialog_run ( GTK_DIALOG(vw->save_dia) ) == GTK_RESPONSE_ACCEPT ) + while ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT ) { - fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(vw->save_dia) ); - 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 ) ) ) + fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(dialog) ); + if ( g_file_test ( fn, G_FILE_TEST_EXISTS ) == FALSE || a_dialog_yes_or_no ( GTK_WINDOW(dialog), _("The file \"%s\" exists, do you wish to overwrite it?"), a_file_basename ( fn ) ) ) { window_set_filename ( vw, fn ); rv = window_save ( vw ); - vw->modified = FALSE; + if ( rv ) { + vw->modified = FALSE; + g_free ( last_folder_files_uri ); + last_folder_files_uri = gtk_file_chooser_get_current_folder_uri ( GTK_FILE_CHOOSER(dialog) ); + } break; } } g_free ( auto_save_name ); - gtk_widget_hide ( vw->save_dia ); + gtk_widget_destroy ( dialog ); return rv; } @@ -2932,7 +3352,7 @@ static gboolean window_save ( VikWindow *vw ) if ( a_file_save ( vik_layers_panel_get_top_layer ( vw->viking_vlp ), vw->viking_vvp, vw->filename ) ) { - update_recently_used_document ( vw->filename ); + update_recently_used_document ( vw, vw->filename ); } else { @@ -3085,19 +3505,15 @@ static void file_properties_cb ( GtkAction *a, VikWindow *vw ) if ( g_stat ( vw->filename, &stat_buf ) == 0 ) { gchar time_buf[64]; strftime ( time_buf, sizeof(time_buf), "%c", gmtime((const time_t *)&stat_buf.st_mtime) ); - gchar *size = NULL; - gint byte_size = stat_buf.st_size; - // See http://en.wikipedia.org/wiki/Megabyte (and Kilobyte) - // hence using 1000 rather than 1024 - // so get output as per 'ls' or the Gtk file open dialog - if ( byte_size < 1000 ) - size = g_strdup_printf ( _("%d bytes"), byte_size ); - else if ( byte_size < 1000*1000 ) - size = g_strdup_printf ( _("%3.1f kB"), (gdouble)byte_size / 1000 ); - else - size = g_strdup_printf ( _("%3.1f MB"), (gdouble)byte_size / (1000*1000) ); - message = g_strdup_printf ( _("%s\n\n%s\n\n%s"), vw->filename, time_buf, size ); - g_free (size); + gchar *size = NULL; + gint byte_size = stat_buf.st_size; +#if GLIB_CHECK_VERSION(2,30,0) + size = g_format_size_full ( byte_size, G_FORMAT_SIZE_DEFAULT ); +#else + size = g_format_size_for_display ( byte_size ); +#endif + message = g_strdup_printf ( "%s\n\n%s\n\n%s", vw->filename, time_buf, size ); + g_free (size); } } else @@ -3111,64 +3527,70 @@ static void file_properties_cb ( GtkAction *a, VikWindow *vw ) g_free ( message ); } +static void my_acquire ( VikWindow *vw, VikDataSourceInterface *datasource ) +{ + vik_datasource_mode_t mode = datasource->mode; + if ( mode == VIK_DATASOURCE_AUTO_LAYER_MANAGEMENT ) + mode = VIK_DATASOURCE_CREATENEWLAYER; + a_acquire ( vw, vw->viking_vlp, vw->viking_vvp, mode, datasource, NULL, NULL ); +} + static void acquire_from_gps ( GtkAction *a, VikWindow *vw ) { - // Via the file menu, acquiring from a GPS makes a new layer - // this has always been the way (not entirely sure if this was the real intention!) - // thus maintain the behaviour ATM. - // Hence explicit setting here (as the value may be changed elsewhere) - vik_datasource_gps_interface.mode = VIK_DATASOURCE_CREATENEWLAYER; - a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_gps_interface, NULL, NULL ); + my_acquire ( vw, &vik_datasource_gps_interface ); } static void acquire_from_file ( GtkAction *a, VikWindow *vw ) { - a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_file_interface, NULL, NULL ); + my_acquire ( vw, &vik_datasource_file_interface ); +} + +static void acquire_from_geojson ( GtkAction *a, VikWindow *vw ) +{ + my_acquire ( vw, &vik_datasource_geojson_interface ); } static void acquire_from_routing ( GtkAction *a, VikWindow *vw ) { - a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_routing_interface, NULL, NULL ); + my_acquire ( vw, &vik_datasource_routing_interface ); } #ifdef VIK_CONFIG_OPENSTREETMAP static void acquire_from_osm ( GtkAction *a, VikWindow *vw ) { - a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_osm_interface, NULL, NULL ); + my_acquire ( vw, &vik_datasource_osm_interface ); } static void acquire_from_my_osm ( GtkAction *a, VikWindow *vw ) { - a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_osm_my_traces_interface, NULL, NULL ); + my_acquire ( vw, &vik_datasource_osm_my_traces_interface ); } #endif #ifdef VIK_CONFIG_GEOCACHES static void acquire_from_gc ( GtkAction *a, VikWindow *vw ) { - a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_gc_interface, NULL, NULL ); + my_acquire ( vw, &vik_datasource_gc_interface ); } #endif #ifdef VIK_CONFIG_GEOTAG static void acquire_from_geotag ( GtkAction *a, VikWindow *vw ) { - vik_datasource_geotag_interface.mode = VIK_DATASOURCE_CREATENEWLAYER; - a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_geotag_interface, NULL, NULL ); + my_acquire ( vw, &vik_datasource_geotag_interface ); } #endif #ifdef VIK_CONFIG_GEONAMES static void acquire_from_wikipedia ( GtkAction *a, VikWindow *vw ) { - a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_wikipedia_interface, NULL, NULL ); + my_acquire ( vw, &vik_datasource_wikipedia_interface ); } #endif static void acquire_from_url ( GtkAction *a, VikWindow *vw ) { - vik_datasource_url_interface.mode = VIK_DATASOURCE_CREATENEWLAYER; - a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_url_interface, NULL, NULL ); + my_acquire ( vw, &vik_datasource_url_interface ); } static void goto_default_location( GtkAction *a, VikWindow *vw) @@ -3192,6 +3614,38 @@ static void mapcache_flush_cb ( GtkAction *a, VikWindow *vw ) a_mapcache_flush(); } +static void menu_copy_centre_cb ( GtkAction *a, VikWindow *vw ) +{ + const VikCoord* coord; + struct UTM utm; + gchar *lat = NULL, *lon = NULL; + + coord = vik_viewport_get_center ( vw->viking_vvp ); + vik_coord_to_utm ( coord, &utm ); + + gboolean full_format = FALSE; + (void)a_settings_get_boolean ( VIK_SETTINGS_WIN_COPY_CENTRE_FULL_FORMAT, &full_format ); + + if ( full_format ) + // Bells & Whistles - may include degrees, minutes and second symbols + get_location_strings ( vw, utm, &lat, &lon ); + else { + // Simple x.xx y.yy format + struct LatLon ll; + a_coords_utm_to_latlon ( &utm, &ll ); + lat = g_strdup_printf ( "%.6f", ll.lat ); + lon = g_strdup_printf ( "%.6f", ll.lon ); + } + + gchar *msg = g_strdup_printf ( "%s %s", lat, lon ); + g_free (lat); + g_free (lon); + + a_clipboard_copy ( VIK_CLIPBOARD_DATA_TEXT, 0, 0, 0, msg, NULL ); + + g_free ( msg ); +} + static void layer_defaults_cb ( GtkAction *a, VikWindow *vw ) { gchar **texts = g_strsplit ( gtk_action_get_name(a), "Layer", 0 ); @@ -3240,6 +3694,12 @@ static void preferences_cb ( GtkAction *a, VikWindow *vw ) // Update all windows g_slist_foreach ( window_list, (GFunc) preferences_change_update, NULL ); } + + // Ensure TZ Lookup initialized + if ( a_vik_get_time_ref_frame() == VIK_TIME_REF_WORLD ) + vu_setup_lat_lon_tz_lookup(); + + toolbar_apply_settings ( vw->viking_vtb, vw->main_vbox, vw->menu_hbox, TRUE ); } static void default_location_cb ( GtkAction *a, VikWindow *vw ) @@ -3258,6 +3718,7 @@ static void default_location_cb ( GtkAction *a, VikWindow *vw ) NULL, NULL, NULL, + NULL, }, }; VikLayerParam pref_lon[] = { @@ -3272,6 +3733,7 @@ static void default_location_cb ( GtkAction *a, VikWindow *vw ) NULL, NULL, NULL, + NULL, }, }; @@ -3323,7 +3785,7 @@ static void zoom_to_cb ( GtkAction *a, VikWindow *vw ) } } -static void save_image_file ( VikWindow *vw, const gchar *fn, guint w, guint h, gdouble zoom, gboolean save_as_png ) +static void save_image_file ( VikWindow *vw, const gchar *fn, guint w, guint h, gdouble zoom, gboolean save_as_png, gboolean save_kmz ) { /* more efficient way: stuff draws directly to pixbuf (fork viewport) */ GdkPixbuf *pixbuf_to_save; @@ -3366,17 +3828,27 @@ static void save_image_file ( VikWindow *vw, const gchar *fn, guint w, guint h, goto cleanup; } - gdk_pixbuf_save ( pixbuf_to_save, fn, save_as_png ? "png" : "jpeg", &error, NULL ); - if (error) - { - g_warning("Unable to write to file %s: %s", fn, error->message ); - gtk_message_dialog_set_markup ( GTK_MESSAGE_DIALOG(msgbox), _("Failed to generate image file.") ); - g_error_free (error); + int ans = 0; // Default to success + + if ( save_kmz ) { + gdouble north, east, south, west; + vik_viewport_get_min_max_lat_lon ( vw->viking_vvp, &south, &north, &west, &east ); + ans = kmz_save_file ( pixbuf_to_save, fn, north, east, south, west ); } else { - // Success - gtk_message_dialog_set_markup ( GTK_MESSAGE_DIALOG(msgbox), _("Image file generated.") ); + gdk_pixbuf_save ( pixbuf_to_save, fn, save_as_png ? "png" : "jpeg", &error, NULL ); + if (error) { + g_warning("Unable to write to file %s: %s", fn, error->message ); + g_error_free (error); + ans = 42; + } } + + if ( ans == 0 ) + gtk_message_dialog_set_markup ( GTK_MESSAGE_DIALOG(msgbox), _("Image file generated.") ); + else + gtk_message_dialog_set_markup ( GTK_MESSAGE_DIALOG(msgbox), _("Failed to generate image file.") ); + g_object_unref ( G_OBJECT(pixbuf_to_save) ); cleanup: @@ -3414,7 +3886,8 @@ static void save_image_dir ( VikWindow *vw, const gchar *fn, guint w, guint h, g g_assert ( vik_viewport_get_coord_mode ( vw->viking_vvp ) == VIK_COORD_UTM ); - g_mkdir(fn,0777); + if ( g_mkdir(fn,0777) != 0 ) + g_warning ( "%s: Failed to create directory %s", __FUNCTION__, fn ); utm_orig = *((const struct UTM *)vik_viewport_get_center ( vw->viking_vvp )); @@ -3443,7 +3916,9 @@ static void save_image_dir ( VikWindow *vw, const gchar *fn, guint w, guint h, g gdk_pixbuf_save ( pixbuf_to_save, name_of_file, save_as_png ? "png" : "jpeg", &error, NULL ); if (error) { - g_warning("Unable to write to file %s: %s", name_of_file, error->message ); + gchar *msg = g_strdup_printf (_("Unable to write to file %s: %s"), name_of_file, error->message ); + vik_statusbar_set_message ( vw->viking_vs, VIK_STATUSBAR_INFO, msg ); + g_free ( msg ); g_error_free (error); } @@ -3509,6 +3984,9 @@ static void draw_to_image_file_total_area_cb (GtkSpinButton *spinbutton, gpointe case VIK_UNITS_DISTANCE_MILES: label_text = g_strdup_printf ( _("Total area: %ldm x %ldm (%.3f sq. miles)"), (glong)w, (glong)h, (w*h/2589988.11)); break; + case VIK_UNITS_DISTANCE_NAUTICAL_MILES: + label_text = g_strdup_printf ( _("Total area: %ldm x %ldm (%.3f sq. NM)"), (glong)w, (glong)h, (w*h/(1852.0*1852.0))); + break; default: label_text = g_strdup_printf ("Just to keep the compiler happy"); g_critical("Houston, we've had a problem. distance=%d", dist_units); @@ -3518,37 +3996,47 @@ static void draw_to_image_file_total_area_cb (GtkSpinButton *spinbutton, gpointe g_free ( label_text ); } +typedef enum { + VW_GEN_SINGLE_IMAGE, + VW_GEN_DIRECTORY_OF_IMAGES, + VW_GEN_KMZ_FILE, +} img_generation_t; + /* * Get an allocated filename (or directory as specified) */ -static gchar* draw_image_filename ( VikWindow *vw, gboolean one_image_only ) +static gchar* draw_image_filename ( VikWindow *vw, img_generation_t img_gen ) { gchar *fn = NULL; - if ( one_image_only ) + if ( img_gen != VW_GEN_DIRECTORY_OF_IMAGES ) { // Single file - if (!vw->save_img_dia) { - vw->save_img_dia = gtk_file_chooser_dialog_new (_("Save Image"), - GTK_WINDOW(vw), - GTK_FILE_CHOOSER_ACTION_SAVE, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, - NULL); - - gchar *cwd = g_get_current_dir(); - if ( cwd ) { - gtk_file_chooser_set_current_folder ( GTK_FILE_CHOOSER(vw->save_img_dia), cwd ); - g_free ( cwd ); - } + GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Save Image"), + GTK_WINDOW(vw), + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + NULL); + if ( last_folder_images_uri ) + gtk_file_chooser_set_current_folder_uri ( GTK_FILE_CHOOSER(dialog), last_folder_images_uri ); + + GtkFileChooser *chooser = GTK_FILE_CHOOSER ( dialog ); + /* Add filters */ + GtkFileFilter *filter; + filter = gtk_file_filter_new (); + gtk_file_filter_set_name ( filter, _("All") ); + gtk_file_filter_add_pattern ( filter, "*" ); + gtk_file_chooser_add_filter ( chooser, filter ); - GtkFileChooser *chooser = GTK_FILE_CHOOSER ( vw->save_img_dia ); - /* Add filters */ - GtkFileFilter *filter; + if ( img_gen == VW_GEN_KMZ_FILE ) { filter = gtk_file_filter_new (); - gtk_file_filter_set_name ( filter, _("All") ); - gtk_file_filter_add_pattern ( filter, "*" ); + gtk_file_filter_set_name ( filter, _("KMZ") ); + gtk_file_filter_add_mime_type ( filter, "vnd.google-earth.kmz"); + gtk_file_filter_add_pattern ( filter, "*.kmz" ); gtk_file_chooser_add_filter ( chooser, filter ); - + gtk_file_chooser_set_filter ( chooser, filter ); + } + else { filter = gtk_file_filter_new (); gtk_file_filter_set_name ( filter, _("JPG") ); gtk_file_filter_add_mime_type ( filter, "image/jpeg"); @@ -3564,18 +4052,21 @@ static gchar* draw_image_filename ( VikWindow *vw, gboolean one_image_only ) if ( vw->draw_image_save_as_png ) gtk_file_chooser_set_filter ( chooser, filter ); - - gtk_window_set_transient_for ( GTK_WINDOW(vw->save_img_dia), GTK_WINDOW(vw) ); - gtk_window_set_destroy_with_parent ( GTK_WINDOW(vw->save_img_dia), TRUE ); } - if ( gtk_dialog_run ( GTK_DIALOG(vw->save_img_dia) ) == GTK_RESPONSE_ACCEPT ) { - fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(vw->save_img_dia) ); + gtk_window_set_transient_for ( GTK_WINDOW(dialog), GTK_WINDOW(vw) ); + gtk_window_set_destroy_with_parent ( GTK_WINDOW(dialog), TRUE ); + + if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT ) { + g_free ( last_folder_images_uri ); + last_folder_images_uri = gtk_file_chooser_get_current_folder_uri ( GTK_FILE_CHOOSER(dialog) ); + + fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(dialog) ); if ( g_file_test ( fn, G_FILE_TEST_EXISTS ) ) - if ( ! a_dialog_yes_or_no ( GTK_WINDOW(vw->save_img_dia), _("The file \"%s\" exists, do you wish to overwrite it?"), a_file_basename ( fn ) ) ) - fn = NULL; + if ( ! a_dialog_yes_or_no ( GTK_WINDOW(dialog), _("The file \"%s\" exists, do you wish to overwrite it?"), a_file_basename ( fn ) ) ) + fn = NULL; } - gtk_widget_hide ( vw->save_img_dia ); + gtk_widget_destroy ( dialog ); } else { // A directory @@ -3585,26 +4076,24 @@ static gchar* draw_image_filename ( VikWindow *vw, gboolean one_image_only ) return fn; } - if (!vw->save_img_dir_dia) { - vw->save_img_dir_dia = gtk_file_chooser_dialog_new (_("Choose a directory to hold images"), - GTK_WINDOW(vw), - GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, - NULL); - gtk_window_set_transient_for ( GTK_WINDOW(vw->save_img_dir_dia), GTK_WINDOW(vw) ); - gtk_window_set_destroy_with_parent ( GTK_WINDOW(vw->save_img_dir_dia), TRUE ); - } - - if ( gtk_dialog_run ( GTK_DIALOG(vw->save_img_dir_dia) ) == GTK_RESPONSE_ACCEPT ) { - fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(vw->save_img_dir_dia) ); + GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Choose a directory to hold images"), + GTK_WINDOW(vw), + GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, + NULL); + gtk_window_set_transient_for ( GTK_WINDOW(dialog), GTK_WINDOW(vw) ); + gtk_window_set_destroy_with_parent ( GTK_WINDOW(dialog), TRUE ); + + if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT ) { + fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(dialog) ); } - gtk_widget_hide ( vw->save_img_dir_dia ); + gtk_widget_destroy ( dialog ); } return fn; } -static void draw_to_image_file ( VikWindow *vw, gboolean one_image_only ) +static void draw_to_image_file ( VikWindow *vw, img_generation_t img_gen ) { /* todo: default for answers inside VikWindow or static (thruout instance) */ GtkWidget *dialog = gtk_dialog_new_with_buttons ( _("Save to Image File"), GTK_WINDOW(vw), @@ -3615,13 +4104,12 @@ static void draw_to_image_file ( VikWindow *vw, gboolean one_image_only ) GTK_RESPONSE_ACCEPT, NULL ); GtkWidget *width_label, *width_spin, *height_label, *height_spin; - GtkWidget *png_radio, *jpeg_radio; GtkWidget *current_window_button; gpointer current_window_pass_along[7]; GtkWidget *zoom_label, *zoom_combo; GtkWidget *total_size_label; - /* only used if (!one_image_only) */ + // only used for VW_GEN_DIRECTORY_OF_IMAGES GtkWidget *tiles_width_spin = NULL, *tiles_height_spin = NULL; width_label = gtk_label_new ( _("Width (pixels):") ); @@ -3652,16 +4140,22 @@ static void draw_to_image_file ( VikWindow *vw, gboolean one_image_only ) current_window_pass_along [1] = width_spin; current_window_pass_along [2] = height_spin; current_window_pass_along [3] = zoom_combo; - current_window_pass_along [4] = NULL; /* used for one_image_only != 1 */ - current_window_pass_along [5] = NULL; + current_window_pass_along [4] = NULL; // Only for directory of tiles: width + current_window_pass_along [5] = NULL; // Only for directory of tiles: height current_window_pass_along [6] = total_size_label; g_signal_connect ( G_OBJECT(current_window_button), "button_press_event", G_CALLBACK(draw_to_image_file_current_window_cb), current_window_pass_along ); - png_radio = gtk_radio_button_new_with_label ( NULL, _("Save as PNG") ); - jpeg_radio = gtk_radio_button_new_with_label_from_widget ( GTK_RADIO_BUTTON(png_radio), _("Save as JPEG") ); + GtkWidget *png_radio = gtk_radio_button_new_with_label ( NULL, _("Save as PNG") ); + GtkWidget *jpeg_radio = gtk_radio_button_new_with_label_from_widget ( GTK_RADIO_BUTTON(png_radio), _("Save as JPEG") ); - gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), png_radio, FALSE, FALSE, 0); - gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), jpeg_radio, FALSE, FALSE, 0); + if ( img_gen == VW_GEN_KMZ_FILE ) { + // Don't show image type selection if creating a KMZ (always JPG internally) + // Start with viewable area by default + draw_to_image_file_current_window_cb ( current_window_button, NULL, current_window_pass_along ); + } else { + gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), jpeg_radio, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), png_radio, FALSE, FALSE, 0); + } if ( ! vw->draw_image_save_as_png ) gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON(jpeg_radio), TRUE ); @@ -3677,7 +4171,7 @@ static void draw_to_image_file ( VikWindow *vw, gboolean one_image_only ) gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), zoom_label, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), zoom_combo, FALSE, FALSE, 0); - if ( ! one_image_only ) + if ( img_gen == VW_GEN_DIRECTORY_OF_IMAGES ) { GtkWidget *tiles_width_label, *tiles_height_label; @@ -3710,19 +4204,44 @@ static void draw_to_image_file ( VikWindow *vw, gboolean one_image_only ) { gtk_widget_hide ( GTK_WIDGET(dialog) ); - gchar *fn = draw_image_filename ( vw, one_image_only ); + gchar *fn = draw_image_filename ( vw, img_gen ); if ( !fn ) return; - gint active = gtk_combo_box_get_active ( GTK_COMBO_BOX(zoom_combo) ); - gdouble zoom = pow (2, active-2 ); + gint active_z = gtk_combo_box_get_active ( GTK_COMBO_BOX(zoom_combo) ); + gdouble zoom = pow (2, active_z-2 ); - if ( one_image_only ) + if ( img_gen == VW_GEN_SINGLE_IMAGE ) save_image_file ( vw, fn, vw->draw_image_width = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(width_spin) ), vw->draw_image_height = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(height_spin) ), zoom, - vw->draw_image_save_as_png = gtk_toggle_button_get_active ( GTK_TOGGLE_BUTTON(png_radio) ) ); + vw->draw_image_save_as_png = gtk_toggle_button_get_active ( GTK_TOGGLE_BUTTON(png_radio) ), + FALSE ); + else if ( img_gen == VW_GEN_KMZ_FILE ) { + // Remove some viewport overlays as these aren't useful in KMZ file. + gboolean restore_xhair = vik_viewport_get_draw_centermark ( vw->viking_vvp ); + if ( restore_xhair ) + vik_viewport_set_draw_centermark ( vw->viking_vvp, FALSE ); + gboolean restore_scale = vik_viewport_get_draw_scale ( vw->viking_vvp ); + if ( restore_scale ) + vik_viewport_set_draw_scale ( vw->viking_vvp, FALSE ); + + save_image_file ( vw, + fn, + gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(width_spin) ), + gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(height_spin) ), + zoom, + FALSE, // JPG + TRUE ); + + if ( restore_xhair ) + vik_viewport_set_draw_centermark ( vw->viking_vvp, TRUE ); + if ( restore_scale ) + vik_viewport_set_draw_scale ( vw->viking_vvp, TRUE ); + if ( restore_xhair || restore_scale ) + draw_update ( vw ); + } else { // NB is in UTM mode ATM save_image_dir ( vw, fn, @@ -3739,15 +4258,64 @@ static void draw_to_image_file ( VikWindow *vw, gboolean one_image_only ) gtk_widget_destroy ( GTK_WIDGET(dialog) ); } +static void draw_to_kmz_file_cb ( GtkAction *a, VikWindow *vw ) +{ + if ( vik_viewport_get_coord_mode(vw->viking_vvp) == VIK_COORD_UTM ) { + a_dialog_error_msg ( GTK_WINDOW(vw), _("This feature is not available in UTM mode") ); + return; + } + // NB ATM This only generates a KMZ file with the current viewport image - intended mostly for map images [but will include any lines/icons from track & waypoints that are drawn] + // (it does *not* include a full KML dump of every track, waypoint etc...) + draw_to_image_file ( vw, VW_GEN_KMZ_FILE ); +} static void draw_to_image_file_cb ( GtkAction *a, VikWindow *vw ) { - draw_to_image_file ( vw, TRUE ); + draw_to_image_file ( vw, VW_GEN_SINGLE_IMAGE ); } static void draw_to_image_dir_cb ( GtkAction *a, VikWindow *vw ) { - draw_to_image_file ( vw, FALSE ); + draw_to_image_file ( vw, VW_GEN_DIRECTORY_OF_IMAGES ); +} + +/** + * + */ +static void import_kmz_file_cb ( GtkAction *a, VikWindow *vw ) +{ + GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Open File"), + GTK_WINDOW(vw), + GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + NULL); + + GtkFileFilter *filter; + filter = gtk_file_filter_new (); + gtk_file_filter_set_name ( filter, _("KMZ") ); + gtk_file_filter_add_mime_type ( filter, "vnd.google-earth.kmz"); + gtk_file_filter_add_pattern ( filter, "*.kmz" ); + gtk_file_chooser_add_filter ( GTK_FILE_CHOOSER(dialog), filter ); + gtk_file_chooser_set_filter ( GTK_FILE_CHOOSER(dialog), filter ); + + filter = gtk_file_filter_new (); + gtk_file_filter_set_name( filter, _("All") ); + gtk_file_filter_add_pattern ( filter, "*" ); + gtk_file_chooser_add_filter ( GTK_FILE_CHOOSER(dialog), filter ); + // Default to any file - same as before open filters were added + gtk_file_chooser_set_filter ( GTK_FILE_CHOOSER(dialog), filter ); + + if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT ) { + gchar *fn = gtk_file_chooser_get_filename ( GTK_FILE_CHOOSER(dialog) ); + // TODO convert ans value into readable explaination of failure... + int ans = kmz_open_file ( fn, vw->viking_vvp, vw->viking_vlp ); + if ( ans ) + a_dialog_error_msg_extra ( GTK_WINDOW(vw), _("Unable to import %s."), fn ); + + draw_update ( vw ); + } + gtk_widget_destroy ( dialog ); } static void print_cb ( GtkAction *a, VikWindow *vw ) @@ -3758,17 +4326,22 @@ static void print_cb ( GtkAction *a, VikWindow *vw ) /* really a misnomer: changes coord mode (actual coordinates) AND/OR draw mode (viewport only) */ static void window_change_coord_mode_cb ( GtkAction *old_a, GtkAction *a, VikWindow *vw ) { + const gchar *name = gtk_action_get_name(a); + GtkToggleToolButton *tbutton = (GtkToggleToolButton *)toolbar_get_widget_by_name ( vw->viking_vtb, name ); + if ( tbutton ) + gtk_toggle_tool_button_set_active ( tbutton, TRUE ); + VikViewportDrawMode drawmode; - if (!strcmp(gtk_action_get_name(a), "ModeUTM")) { + if (!g_strcmp0(name, "ModeUTM")) { drawmode = VIK_VIEWPORT_DRAWMODE_UTM; } - else if (!strcmp(gtk_action_get_name(a), "ModeLatLon")) { + else if (!g_strcmp0(name, "ModeLatLon")) { drawmode = VIK_VIEWPORT_DRAWMODE_LATLON; } - else if (!strcmp(gtk_action_get_name(a), "ModeExpedia")) { + else if (!g_strcmp0(name, "ModeExpedia")) { drawmode = VIK_VIEWPORT_DRAWMODE_EXPEDIA; } - else if (!strcmp(gtk_action_get_name(a), "ModeMercator")) { + else if (!g_strcmp0(name, "ModeMercator")) { drawmode = VIK_VIEWPORT_DRAWMODE_MERCATOR; } else { @@ -3793,30 +4366,36 @@ static void window_change_coord_mode_cb ( GtkAction *old_a, GtkAction *a, VikWin } } -static void set_draw_scale ( GtkAction *a, VikWindow *vw ) +static void toggle_draw_scale ( GtkAction *a, VikWindow *vw ) { + gboolean state = !vik_viewport_get_draw_scale ( vw->viking_vvp ); GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ShowScale" ); - g_assert(check_box); - gboolean state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box)); + if ( !check_box ) + return; + gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), state ); vik_viewport_set_draw_scale ( vw->viking_vvp, state ); draw_update ( vw ); } -static void set_draw_centermark ( GtkAction *a, VikWindow *vw ) +static void toggle_draw_centermark ( GtkAction *a, VikWindow *vw ) { + gboolean state = !vik_viewport_get_draw_centermark ( vw->viking_vvp ); GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ShowCenterMark" ); - g_assert(check_box); - gboolean state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box)); + if ( !check_box ) + return; + gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), state ); vik_viewport_set_draw_centermark ( vw->viking_vvp, state ); draw_update ( vw ); } -static void set_draw_highlight ( GtkAction *a, VikWindow *vw ) +static void toggle_draw_highlight ( GtkAction *a, VikWindow *vw ) { + gboolean state = !vik_viewport_get_draw_highlight ( vw->viking_vvp ); GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ShowHighlight" ); - g_assert(check_box); - gboolean state = gtk_check_menu_item_get_active ( GTK_CHECK_MENU_ITEM(check_box)); - vik_viewport_set_draw_highlight ( vw->viking_vvp, state ); + if ( !check_box ) + return; + gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), state ); + vik_viewport_set_draw_highlight ( vw->viking_vvp, state ); draw_update ( vw ); } @@ -3853,7 +4432,6 @@ static void set_highlight_color ( GtkAction *a, VikWindow *vw ) } - /*********************************************************************************************** ** GUI Creation ***********************************************************************************************/ @@ -3897,8 +4475,12 @@ static GtkActionEntry entries[] = { { "Save", GTK_STOCK_SAVE, N_("_Save"), "S", N_("Save the file"), (GCallback)save_file }, { "SaveAs", GTK_STOCK_SAVE_AS, N_("Save _As..."), NULL, N_("Save the file under different name"), (GCallback)save_file_as }, { "FileProperties", NULL, N_("Properties..."), NULL, N_("File Properties"), (GCallback)file_properties_cb }, - { "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 }, - { "GenImgDir", GTK_STOCK_DND_MULTIPLE, N_("Generate _Directory of Images..."), NULL, N_("FIXME:IMGDIR"), (GCallback)draw_to_image_dir_cb }, +#ifdef HAVE_ZIP_H + { "ImportKMZ", GTK_STOCK_CONVERT, N_("Import KMZ _Map File..."), NULL, N_("Import a KMZ file"), (GCallback)import_kmz_file_cb }, + { "GenKMZ", GTK_STOCK_DND, N_("Generate _KMZ Map File..."), NULL, N_("Generate a KMZ file with an overlay of the current view"), (GCallback)draw_to_kmz_file_cb }, +#endif + { "GenImg", GTK_STOCK_FILE, N_("_Generate Image File..."), NULL, N_("Save a snapshot of the workspace into a file"), (GCallback)draw_to_image_file_cb }, + { "GenImgDir", GTK_STOCK_DND_MULTIPLE, N_("Generate _Directory of Images..."), NULL, N_("Generate _Directory of Images"), (GCallback)draw_to_image_dir_cb }, { "Print", GTK_STOCK_PRINT, N_("_Print..."), NULL, N_("Print maps"), (GCallback)print_cb }, { "Exit", GTK_STOCK_QUIT, N_("E_xit"), "W", N_("Exit the program"), (GCallback)window_close }, { "SaveExit", GTK_STOCK_QUIT, N_("Save and Exit"), NULL, N_("Save and Exit the program"), (GCallback)save_file_and_exit }, @@ -3910,49 +4492,58 @@ static GtkActionEntry entries[] = { { "GotoLL", GTK_STOCK_JUMP_TO, N_("_Go to Lat/Lon..."), NULL, N_("Go to arbitrary lat/lon coordinate"), (GCallback)draw_goto_cb }, { "GotoUTM", GTK_STOCK_JUMP_TO, N_("Go to UTM..."), NULL, N_("Go to arbitrary UTM coordinate"), (GCallback)draw_goto_cb }, { "Refresh", GTK_STOCK_REFRESH, N_("_Refresh"), "F5", N_("Refresh any maps displayed"), (GCallback)draw_refresh_cb }, - { "SetHLColor",GTK_STOCK_SELECT_COLOR, N_("Set _Highlight Color..."), NULL, NULL, (GCallback)set_highlight_color }, - { "SetBGColor",GTK_STOCK_SELECT_COLOR, N_("Set Bac_kground Color..."), NULL, NULL, (GCallback)set_bg_color }, - { "ZoomIn", GTK_STOCK_ZOOM_IN, N_("Zoom _In"), "plus", NULL, (GCallback)draw_zoom_cb }, - { "ZoomOut", GTK_STOCK_ZOOM_OUT, N_("Zoom _Out"), "minus", NULL, (GCallback)draw_zoom_cb }, - { "ZoomTo", GTK_STOCK_ZOOM_FIT, N_("Zoom _To..."), "Z", NULL, (GCallback)zoom_to_cb }, + { "SetHLColor",GTK_STOCK_SELECT_COLOR, N_("Set _Highlight Color..."), NULL, N_("Set Highlight Color"), (GCallback)set_highlight_color }, + { "SetBGColor",GTK_STOCK_SELECT_COLOR, N_("Set Bac_kground Color..."), NULL, N_("Set Background Color"), (GCallback)set_bg_color }, + { "ZoomIn", GTK_STOCK_ZOOM_IN, N_("Zoom _In"), "plus", N_("Zoom In"), (GCallback)draw_zoom_cb }, + { "ZoomOut", GTK_STOCK_ZOOM_OUT, N_("Zoom _Out"), "minus", N_("Zoom Out"), (GCallback)draw_zoom_cb }, + { "ZoomTo", GTK_STOCK_ZOOM_FIT, N_("Zoom _To..."), "Z", N_("Zoom To"), (GCallback)zoom_to_cb }, { "PanNorth", NULL, N_("Pan _North"), "Up", NULL, (GCallback)draw_pan_cb }, { "PanEast", NULL, N_("Pan _East"), "Right", NULL, (GCallback)draw_pan_cb }, { "PanSouth", NULL, N_("Pan _South"), "Down", NULL, (GCallback)draw_pan_cb }, { "PanWest", NULL, N_("Pan _West"), "Left", NULL, (GCallback)draw_pan_cb }, - { "BGJobs", GTK_STOCK_EXECUTE, N_("Background _Jobs"), NULL, NULL, (GCallback)a_background_show_window }, + { "BGJobs", GTK_STOCK_EXECUTE, N_("Background _Jobs"), NULL, N_("Background Jobs"), (GCallback)a_background_show_window }, - { "Cut", GTK_STOCK_CUT, N_("Cu_t"), NULL, NULL, (GCallback)menu_cut_layer_cb }, - { "Copy", GTK_STOCK_COPY, N_("_Copy"), NULL, NULL, (GCallback)menu_copy_layer_cb }, - { "Paste", GTK_STOCK_PASTE, N_("_Paste"), NULL, NULL, (GCallback)menu_paste_layer_cb }, - { "Delete", GTK_STOCK_DELETE, N_("_Delete"), NULL, NULL, (GCallback)menu_delete_layer_cb }, + { "Cut", GTK_STOCK_CUT, N_("Cu_t"), NULL, N_("Cut selected layer"), (GCallback)menu_cut_layer_cb }, + { "Copy", GTK_STOCK_COPY, N_("_Copy"), NULL, N_("Copy selected layer"), (GCallback)menu_copy_layer_cb }, + { "Paste", GTK_STOCK_PASTE, N_("_Paste"), NULL, N_("Paste layer into selected container layer or otherwise above selected layer"), (GCallback)menu_paste_layer_cb }, + { "Delete", GTK_STOCK_DELETE, N_("_Delete"), NULL, N_("Remove selected layer"), (GCallback)menu_delete_layer_cb }, { "DeleteAll", NULL, N_("Delete All"), NULL, NULL, (GCallback)clear_cb }, + { "CopyCentre",NULL, N_("Copy Centre _Location"), "h", NULL, (GCallback)menu_copy_centre_cb }, { "MapCacheFlush",NULL, N_("_Flush Map Cache"), NULL, NULL, (GCallback)mapcache_flush_cb }, { "SetDefaultLocation", GTK_STOCK_GO_FORWARD, N_("_Set the Default Location"), NULL, N_("Set the Default Location to the current position"),(GCallback)default_location_cb }, - { "Preferences",GTK_STOCK_PREFERENCES, N_("_Preferences"), NULL, NULL, (GCallback)preferences_cb }, + { "Preferences",GTK_STOCK_PREFERENCES, N_("_Preferences"), NULL, N_("Program Preferences"), (GCallback)preferences_cb }, { "LayerDefaults",GTK_STOCK_PROPERTIES, N_("_Layer Defaults"), NULL, NULL, NULL }, - { "Properties",GTK_STOCK_PROPERTIES, N_("_Properties"), NULL, NULL, (GCallback)menu_properties_cb }, + { "Properties",GTK_STOCK_PROPERTIES, N_("_Properties"), NULL, N_("Layer Properties"), (GCallback)menu_properties_cb }, + + { "HelpEntry", GTK_STOCK_HELP, N_("_Help"), "F1", N_("Help"), (GCallback)help_help_cb }, + { "About", GTK_STOCK_ABOUT, N_("_About"), NULL, N_("About"), (GCallback)help_about_cb }, +}; - { "HelpEntry", GTK_STOCK_HELP, N_("_Help"), "F1", NULL, (GCallback)help_help_cb }, - { "About", GTK_STOCK_ABOUT, N_("_About"), NULL, NULL, (GCallback)help_about_cb }, +static GtkActionEntry debug_entries[] = { + { "MapCacheInfo", NULL, "_Map Cache Info", NULL, NULL, (GCallback)help_cache_info_cb }, + { "BackForwardInfo", NULL, "_Back/Forward Info", NULL, NULL, (GCallback)back_forward_info_cb }, }; static GtkActionEntry entries_gpsbabel[] = { { "ExportKML", NULL, N_("_KML..."), NULL, N_("Export as KML"), (GCallback)export_to_kml }, }; +static GtkActionEntry entries_geojson[] = { + { "AcquireGeoJSON", NULL, N_("Import Geo_JSON File..."), NULL, N_("Import GeoJSON file"), (GCallback)acquire_from_geojson }, +}; + /* Radio items */ -/* FIXME use VIEWPORT_DRAWMODE values */ static GtkRadioActionEntry mode_entries[] = { - { "ModeUTM", NULL, N_("_UTM Mode"), "u", NULL, 0 }, - { "ModeExpedia", NULL, N_("_Expedia Mode"), "e", NULL, 1 }, - { "ModeMercator", NULL, N_("_Mercator Mode"), "m", NULL, 4 }, - { "ModeLatLon", NULL, N_("Lat_/Lon Mode"), "l", NULL, 5 }, + { "ModeUTM", NULL, N_("_UTM Mode"), "u", NULL, VIK_VIEWPORT_DRAWMODE_UTM }, + { "ModeExpedia", NULL, N_("_Expedia Mode"), "e", NULL, VIK_VIEWPORT_DRAWMODE_EXPEDIA }, + { "ModeMercator", NULL, N_("_Mercator Mode"), "m", NULL, VIK_VIEWPORT_DRAWMODE_MERCATOR }, + { "ModeLatLon", NULL, N_("Lat_/Lon Mode"), "l", NULL, VIK_VIEWPORT_DRAWMODE_LATLON }, }; static GtkToggleActionEntry toggle_entries[] = { - { "ShowScale", NULL, N_("Show _Scale"), "F5", N_("Show Scale"), (GCallback)set_draw_scale, TRUE }, - { "ShowCenterMark", NULL, N_("Show _Center Mark"), "F6", N_("Show Center Mark"), (GCallback)set_draw_centermark, TRUE }, - { "ShowHighlight", GTK_STOCK_UNDERLINE, N_("Show _Highlight"), "F7", N_("Show Highlight"), (GCallback)set_draw_highlight, TRUE }, + { "ShowScale", NULL, N_("Show _Scale"), "F5", N_("Show Scale"), (GCallback)toggle_draw_scale, TRUE }, + { "ShowCenterMark", NULL, N_("Show _Center Mark"), "F6", N_("Show Center Mark"), (GCallback)toggle_draw_centermark, TRUE }, + { "ShowHighlight", GTK_STOCK_UNDERLINE, N_("Show _Highlight"), "F7", N_("Show Highlight"), (GCallback)toggle_draw_highlight, TRUE }, { "FullScreen", GTK_STOCK_FULLSCREEN, N_("_Full Screen"), "F11", N_("Activate full screen mode"), (GCallback)full_screen_cb, FALSE }, { "ViewSidePanel", GTK_STOCK_INDEX, N_("Show Side _Panel"), "F9", N_("Show Side Panel"), (GCallback)view_side_panel_cb, TRUE }, { "ViewStatusBar", NULL, N_("Show Status_bar"), "F12", N_("Show Statusbar"), (GCallback)view_statusbar_cb, TRUE }, @@ -3960,6 +4551,18 @@ static GtkToggleActionEntry toggle_entries[] = { { "ViewMainMenu", NULL, N_("Show _Menu"), "F4", N_("Show Menu"), (GCallback)view_main_menu_cb, TRUE }, }; +// This must match the toggle entries order above +static gpointer toggle_entries_toolbar_cb[] = { + (GCallback)tb_set_draw_scale, + (GCallback)tb_set_draw_centermark, + (GCallback)tb_set_draw_highlight, + (GCallback)tb_full_screen_cb, + (GCallback)tb_view_side_panel_cb, + (GCallback)tb_view_statusbar_cb, + (GCallback)tb_view_toolbar_cb, + (GCallback)tb_view_main_menu_cb, +}; + #include "menu.xml.h" static void window_create_ui( VikWindow *window ) { @@ -3981,6 +4584,11 @@ static void window_create_ui( VikWindow *window ) toolbox_add_tool(window->vt, &pan_tool, TOOL_LAYER_TYPE_NONE); toolbox_add_tool(window->vt, &select_tool, TOOL_LAYER_TYPE_NONE); + toolbar_action_tool_entry_register ( window->viking_vtb, &pan_tool.radioActionEntry ); + toolbar_action_tool_entry_register ( window->viking_vtb, &zoom_tool.radioActionEntry ); + toolbar_action_tool_entry_register ( window->viking_vtb, &ruler_tool.radioActionEntry ); + toolbar_action_tool_entry_register ( window->viking_vtb, &select_tool.radioActionEntry ); + error = NULL; if (!(mid = gtk_ui_manager_add_ui_from_string (uim, menu_xml, -1, &error))) { g_error_free (error); @@ -3992,6 +4600,34 @@ static void window_create_ui( VikWindow *window ) gtk_action_group_add_actions (action_group, entries, G_N_ELEMENTS (entries), window); gtk_action_group_add_toggle_actions (action_group, toggle_entries, G_N_ELEMENTS (toggle_entries), window); gtk_action_group_add_radio_actions (action_group, mode_entries, G_N_ELEMENTS (mode_entries), 4, (GCallback)window_change_coord_mode_cb, window); + if ( vik_debug ) { + if ( gtk_ui_manager_add_ui_from_string ( uim, + "" + "" + "" + "", + -1, NULL ) ) { + gtk_action_group_add_actions (action_group, debug_entries, G_N_ELEMENTS (debug_entries), window); + } + } + + for ( i=0; i < G_N_ELEMENTS (entries); i++ ) { + if ( entries[i].callback ) + toolbar_action_entry_register ( window->viking_vtb, &entries[i] ); + } + + if ( G_N_ELEMENTS (toggle_entries) != G_N_ELEMENTS (toggle_entries_toolbar_cb) ) { + g_print ( "Broken entries definitions\n" ); + exit (1); + } + for ( i=0; i < G_N_ELEMENTS (toggle_entries); i++ ) { + if ( toggle_entries_toolbar_cb[i] ) + toolbar_action_toggle_entry_register ( window->viking_vtb, &toggle_entries[i], toggle_entries_toolbar_cb[i] ); + } + + for ( i=0; i < G_N_ELEMENTS (mode_entries); i++ ) { + toolbar_action_mode_entry_register ( window->viking_vtb, &mode_entries[i] ); + } // Use this to see if GPSBabel is available: if ( a_babel_available () ) { @@ -4002,6 +4638,14 @@ static void window_create_ui( VikWindow *window ) gtk_action_group_add_actions ( action_group, entries_gpsbabel, G_N_ELEMENTS (entries_gpsbabel), window ); } + // GeoJSON import capability + if ( g_find_program_in_path ( a_geojson_program_import() ) ) { + if ( gtk_ui_manager_add_ui_from_string ( uim, + "", + -1, &error ) ) + gtk_action_group_add_actions ( action_group, entries_geojson, G_N_ELEMENTS (entries_geojson), window ); + } + icon_factory = gtk_icon_factory_new (); gtk_icon_factory_add_default (icon_factory); @@ -4041,7 +4685,6 @@ static void window_create_ui( VikWindow *window ) if ( vik_layer_get_interface(i)->tools_count ) { gtk_ui_manager_add_ui(uim, mid, "/ui/MainMenu/Tools/", vik_layer_get_interface(i)->name, NULL, GTK_UI_MANAGER_SEPARATOR, FALSE); - gtk_ui_manager_add_ui(uim, mid, "/ui/MainToolbar/ToolItems/", vik_layer_get_interface(i)->name, NULL, GTK_UI_MANAGER_SEPARATOR, FALSE); } // Further tool copying for to apply to the UI, also apply menu UI setup @@ -4054,12 +4697,9 @@ static void window_create_ui( VikWindow *window ) vik_layer_get_interface(i)->tools[j].radioActionEntry.label, vik_layer_get_interface(i)->tools[j].radioActionEntry.name, GTK_UI_MANAGER_MENUITEM, FALSE); - gtk_ui_manager_add_ui(uim, mid, "/ui/MainToolbar/ToolItems", - vik_layer_get_interface(i)->tools[j].radioActionEntry.label, - vik_layer_get_interface(i)->tools[j].radioActionEntry.name, - GTK_UI_MANAGER_TOOLITEM, FALSE); toolbox_add_tool(window->vt, &(vik_layer_get_interface(i)->tools[j]), i); + toolbar_action_tool_entry_register ( window->viking_vtb, &(vik_layer_get_interface(i)->tools[j].radioActionEntry) ); *radio = vik_layer_get_interface(i)->tools[j].radioActionEntry; // Overwrite with actual number to use @@ -4088,7 +4728,7 @@ static void window_create_ui( VikWindow *window ) } g_object_unref (icon_factory); - gtk_action_group_add_radio_actions(action_group, tools, ntools, 0, (GCallback)menu_tool_cb, window); + gtk_action_group_add_radio_actions(action_group, tools, ntools, 0, (GCallback)menu_cb, window); g_free(tools); gtk_ui_manager_insert_action_group (uim, action_group, 0); @@ -4265,7 +4905,12 @@ gboolean vik_window_clear_highlight ( VikWindow *vw ) return need_redraw; } +/** + * May return NULL if the window no longer exists + */ GThread *vik_window_get_thread ( VikWindow *vw ) { - return vw->thread; + if ( vw ) + return vw->thread; + return NULL; }