From efd39893a4f5e629a9df2d0674222aea1be14199 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sun, 5 Oct 2014 12:38:15 -0400 Subject: Move obvious ui component to ui/ (bzr r13341.1.247) --- src/Makefile_insert | 1 - src/desktop.cpp | 2 +- src/extension/system.cpp | 2 +- src/file.cpp | 2 +- src/helper/pixbuf-ops.cpp | 2 +- src/helper/png-write.cpp | 2 +- src/interface.cpp | 2230 -------------------------------- src/interface.h | 277 ---- src/main.cpp | 2 +- src/ui/Makefile_insert | 2 + src/ui/dialog/clonetiler.cpp | 2 +- src/ui/dialog/dialog.cpp | 2 +- src/ui/dialog/dock-behavior.cpp | 2 +- src/ui/dialog/export.cpp | 2 +- src/ui/dialog/extension-editor.cpp | 2 +- src/ui/dialog/filedialogimpl-gtkmm.cpp | 2 +- src/ui/dialog/find.cpp | 2 +- src/ui/dialog/floating-behavior.cpp | 2 +- src/ui/dialog/ocaldialogs.cpp | 2 +- src/ui/dialog/spellcheck.cpp | 2 +- src/ui/dialog/template-load-tab.cpp | 2 +- src/ui/dialog/text-edit.cpp | 2 +- src/ui/dialog/xml-tree.cpp | 2 +- src/ui/interface.cpp | 2230 ++++++++++++++++++++++++++++++++ src/ui/interface.h | 277 ++++ src/ui/tools/tool-base.cpp | 2 +- src/verbs.cpp | 2 +- src/widgets/button.cpp | 2 +- src/widgets/desktop-widget.cpp | 2 +- src/widgets/toolbox.cpp | 2 +- 30 files changed, 2533 insertions(+), 2532 deletions(-) delete mode 100644 src/interface.cpp delete mode 100644 src/interface.h create mode 100644 src/ui/interface.cpp create mode 100644 src/ui/interface.h (limited to 'src') diff --git a/src/Makefile_insert b/src/Makefile_insert index 86ae970d1..47ea28ebc 100644 --- a/src/Makefile_insert +++ b/src/Makefile_insert @@ -72,7 +72,6 @@ ink_common_sources += \ ink-comboboxentry-action.cpp \ ink-comboboxentry-action.h \ inkscape.cpp inkscape.h inkscape-private.h \ - interface.cpp interface.h \ isinf.h \ knot.cpp knot.h \ knot-enums.h \ diff --git a/src/desktop.cpp b/src/desktop.cpp index f14a314b9..b72e9c776 100644 --- a/src/desktop.cpp +++ b/src/desktop.cpp @@ -55,7 +55,7 @@ #include "document-undo.h" #include "event-log.h" #include "helper/action-context.h" -#include "interface.h" +#include "ui/interface.h" #include "inkscape-private.h" #include "layer-fns.h" #include "layer-manager.h" diff --git a/src/extension/system.cpp b/src/extension/system.cpp index c244d9c16..d02d801dc 100644 --- a/src/extension/system.cpp +++ b/src/extension/system.cpp @@ -20,7 +20,7 @@ # include #endif -#include +#include "ui/interface.h" #include #include diff --git a/src/file.cpp b/src/file.cpp index 7181f4f98..307944001 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -46,7 +46,7 @@ #include "id-clash.h" #include "inkscape.h" #include "inkscape.h" -#include "interface.h" +#include "ui/interface.h" #include "io/sys.h" #include "message.h" #include "message-stack.h" diff --git a/src/helper/pixbuf-ops.cpp b/src/helper/pixbuf-ops.cpp index d44b2207b..acb2be4da 100644 --- a/src/helper/pixbuf-ops.cpp +++ b/src/helper/pixbuf-ops.cpp @@ -19,7 +19,7 @@ #include #include <2geom/transforms.h> -#include "interface.h" +#include "ui/interface.h" #include "helper/png-write.h" #include "display/cairo-utils.h" #include "display/drawing.h" diff --git a/src/helper/png-write.cpp b/src/helper/png-write.cpp index a7ebe7423..32e50b537 100644 --- a/src/helper/png-write.cpp +++ b/src/helper/png-write.cpp @@ -18,7 +18,7 @@ #endif #include -#include "interface.h" +#include "ui/interface.h" #include <2geom/rect.h> #include <2geom/transforms.h> #include diff --git a/src/interface.cpp b/src/interface.cpp deleted file mode 100644 index 591887c3d..000000000 --- a/src/interface.cpp +++ /dev/null @@ -1,2230 +0,0 @@ -/** - * @file - * Main UI stuff. - */ -/* Authors: - * Lauris Kaplinski - * Frank Felfe - * bulia byak - * Jon A. Cruz - * Abhishek Sharma - * Kris De Gussem - * - * Copyright (C) 2012 Kris De Gussem - * Copyright (C) 2010 authors - * Copyright (C) 1999-2005 authors - * Copyright (C) 2004 David Turner - * Copyright (C) 2001-2002 Ximian, Inc. - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "ui/dialog/dialog-manager.h" -#include -#include "file.h" -#include -#include - -#include "inkscape-private.h" -#include "extension/db.h" -#include "extension/effect.h" -#include "extension/input.h" -#include "widgets/icon.h" -#include "preferences.h" -#include "path-prefix.h" -#include "shortcuts.h" -#include "document.h" -#include "desktop-handles.h" -#include "interface.h" -#include "desktop.h" -#include "selection.h" -#include "selection-chemistry.h" -#include "svg-view-widget.h" -#include "widgets/desktop-widget.h" -#include "sp-item-group.h" -#include "sp-text.h" -#include "sp-gradient.h" -#include "sp-flowtext.h" -#include "sp-namedview.h" -#include "sp-root.h" -#include "ui/view/view.h" -#include "helper/action.h" -#include "helper/action-context.h" -#include "helper/gnome-utils.h" -#include "helper/window.h" -#include "io/sys.h" -#include "ui/dialog-events.h" -#include "message-context.h" -#include "ui/uxmanager.h" -#include "ui/clipboard.h" - -#include "display/sp-canvas.h" -#include "color.h" -#include "svg/svg-color.h" -#include "desktop-style.h" -#include "style.h" -#include "ui/tools/tool-base.h" -#include "gradient-drag.h" -#include "widgets/ege-paint-def.h" -#include "document-undo.h" -#include "sp-anchor.h" -#include "sp-clippath.h" -#include "sp-image.h" -#include "sp-item.h" -#include "sp-mask.h" -#include "message-stack.h" -#include "ui/dialog/layer-properties.h" - -#include - -#include - -using Inkscape::DocumentUndo; - -/* Drag and Drop */ -typedef enum { - URI_LIST, - SVG_XML_DATA, - SVG_DATA, - PNG_DATA, - JPEG_DATA, - IMAGE_DATA, - APP_X_INKY_COLOR, - APP_X_COLOR, - APP_OSWB_COLOR, - APP_X_INK_PASTE -} ui_drop_target_info; - -static GtkTargetEntry ui_drop_target_entries [] = { - {(gchar *)"text/uri-list", 0, URI_LIST }, - {(gchar *)"image/svg+xml", 0, SVG_XML_DATA }, - {(gchar *)"image/svg", 0, SVG_DATA }, - {(gchar *)"image/png", 0, PNG_DATA }, - {(gchar *)"image/jpeg", 0, JPEG_DATA }, -#if ENABLE_MAGIC_COLORS - {(gchar *)"application/x-inkscape-color", 0, APP_X_INKY_COLOR}, -#endif // ENABLE_MAGIC_COLORS - {(gchar *)"application/x-oswb-color", 0, APP_OSWB_COLOR }, - {(gchar *)"application/x-color", 0, APP_X_COLOR }, - {(gchar *)"application/x-inkscape-paste", 0, APP_X_INK_PASTE } -}; - -static GtkTargetEntry *completeDropTargets = 0; -static int completeDropTargetsCount = 0; -static bool temporarily_block_actions = false; - -#define ENTRIES_SIZE(n) sizeof(n)/sizeof(n[0]) -static guint nui_drop_target_entries = ENTRIES_SIZE(ui_drop_target_entries); -static void sp_ui_import_files(gchar *buffer); -static void sp_ui_import_one_file(char const *filename); -static void sp_ui_import_one_file_with_check(gpointer filename, gpointer unused); -static void sp_ui_drag_data_received(GtkWidget *widget, - GdkDragContext *drag_context, - gint x, gint y, - GtkSelectionData *data, - guint info, - guint event_time, - gpointer user_data); -static void sp_ui_drag_motion( GtkWidget *widget, - GdkDragContext *drag_context, - gint x, gint y, - GtkSelectionData *data, - guint info, - guint event_time, - gpointer user_data ); -static void sp_ui_drag_leave( GtkWidget *widget, - GdkDragContext *drag_context, - guint event_time, - gpointer user_data ); -static void sp_ui_menu_item_set_name(GtkWidget *data, - Glib::ustring const &name); -static void sp_recent_open(GtkRecentChooser *, gpointer); - -static void injectRenamedIcons(); - -static const int MIN_ONSCREEN_DISTANCE = 50; - -void -sp_create_window(SPViewWidget *vw, bool editable) -{ - g_return_if_fail(vw != NULL); - g_return_if_fail(SP_IS_VIEW_WIDGET(vw)); - - Gtk::Window *win = Inkscape::UI::window_new("", TRUE); - - gtk_container_add(GTK_CONTAINER(win->gobj()), GTK_WIDGET(vw)); - gtk_widget_show(GTK_WIDGET(vw)); - - if (editable) { - g_object_set_data(G_OBJECT(vw), "window", win); - - SPDesktopWidget *desktop_widget = reinterpret_cast(vw); - SPDesktop* desktop = desktop_widget->desktop; - - desktop_widget->window = win; - - win->set_data("desktop", desktop); - win->set_data("desktopwidget", desktop_widget); - - win->signal_delete_event().connect(sigc::mem_fun(*(SPDesktop*)vw->view, &SPDesktop::onDeleteUI)); - win->signal_window_state_event().connect(sigc::mem_fun(*desktop, &SPDesktop::onWindowStateEvent)); - win->signal_focus_in_event().connect(sigc::mem_fun(*desktop_widget, &SPDesktopWidget::onFocusInEvent)); - - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - gint prefs_geometry = - (2==prefs->getInt("/options/savewindowgeometry/value", 0)); - if (prefs_geometry) { - gint pw = prefs->getInt("/desktop/geometry/width", -1); - gint ph = prefs->getInt("/desktop/geometry/height", -1); - gint px = prefs->getInt("/desktop/geometry/x", -1); - gint py = prefs->getInt("/desktop/geometry/y", -1); - gint full = prefs->getBool("/desktop/geometry/fullscreen"); - gint maxed = prefs->getBool("/desktop/geometry/maximized"); - if (pw>0 && ph>0) { - gint w = MIN(gdk_screen_width(), pw); - gint h = MIN(gdk_screen_height(), ph); - gint x = MIN(gdk_screen_width() - MIN_ONSCREEN_DISTANCE, px); - gint y = MIN(gdk_screen_height() - MIN_ONSCREEN_DISTANCE, py); - if (w>0 && h>0) { - x = MIN(gdk_screen_width() - w, x); - y = MIN(gdk_screen_height() - h, y); - desktop->setWindowSize(w, h); - } - - // Only restore xy for the first window so subsequent windows don't overlap exactly - // with first. (Maybe rule should be only restore xy if it's different from xy of - // other desktops?) - - // Empirically it seems that active_desktop==this desktop only the first time a - // desktop is created. - SPDesktop *active_desktop = SP_ACTIVE_DESKTOP; - if (active_desktop == desktop || active_desktop==NULL) { - desktop->setWindowPosition(Geom::Point(x, y)); - } - } - if (maxed) { - win->maximize(); - } - if (full) { - win->fullscreen(); - } - } - - } - - if ( completeDropTargets == 0 || completeDropTargetsCount == 0 ) - { - std::vector types; - - GSList *list = gdk_pixbuf_get_formats(); - while ( list ) { - int i = 0; - GdkPixbufFormat *one = (GdkPixbufFormat*)list->data; - gchar** typesXX = gdk_pixbuf_format_get_mime_types(one); - for ( i = 0; typesXX[i]; i++ ) { - types.push_back(g_strdup(typesXX[i])); - } - g_strfreev(typesXX); - - list = g_slist_next(list); - } - completeDropTargetsCount = nui_drop_target_entries + types.size(); - completeDropTargets = new GtkTargetEntry[completeDropTargetsCount]; - for ( int i = 0; i < (int)nui_drop_target_entries; i++ ) { - completeDropTargets[i] = ui_drop_target_entries[i]; - } - int pos = nui_drop_target_entries; - - for (std::vector::iterator it = types.begin() ; it != types.end() ; it++) { - completeDropTargets[pos].target = *it; - completeDropTargets[pos].flags = 0; - completeDropTargets[pos].info = IMAGE_DATA; - pos++; - } - } - - gtk_drag_dest_set((GtkWidget*)win->gobj(), - GTK_DEST_DEFAULT_ALL, - completeDropTargets, - completeDropTargetsCount, - GdkDragAction(GDK_ACTION_COPY | GDK_ACTION_MOVE)); - - - g_signal_connect(G_OBJECT(win->gobj()), - "drag_data_received", - G_CALLBACK(sp_ui_drag_data_received), - NULL); - g_signal_connect(G_OBJECT(win->gobj()), - "drag_motion", - G_CALLBACK(sp_ui_drag_motion), - NULL); - g_signal_connect(G_OBJECT(win->gobj()), - "drag_leave", - G_CALLBACK(sp_ui_drag_leave), - NULL); - win->show(); - - // needed because the first ACTIVATE_DESKTOP was sent when there was no window yet - if ( SP_IS_DESKTOP_WIDGET(vw) ) { - inkscape_reactivate_desktop(SP_DESKTOP_WIDGET(vw)->desktop); - } -} - -void -sp_ui_new_view() -{ - SPDocument *document; - SPViewWidget *dtw; - - document = SP_ACTIVE_DOCUMENT; - if (!document) return; - - dtw = sp_desktop_widget_new(sp_document_namedview(document, NULL)); - g_return_if_fail(dtw != NULL); - - sp_create_window(dtw, TRUE); - sp_namedview_window_from_document(static_cast(dtw->view)); - sp_namedview_update_layers_from_document(static_cast(dtw->view)); -} - -void sp_ui_new_view_preview() -{ - SPDocument *document = SP_ACTIVE_DOCUMENT; - if ( document ) { - SPViewWidget *dtw = reinterpret_cast(sp_svg_view_widget_new(document)); - g_return_if_fail(dtw != NULL); - SP_SVG_VIEW_WIDGET(dtw)->setResize(true, 400.0, 400.0); - - sp_create_window(dtw, FALSE); - } -} - -void -sp_ui_close_view(GtkWidget */*widget*/) -{ - SPDesktop *dt = SP_ACTIVE_DESKTOP; - - if (dt == NULL) { - return; - } - - if (dt->shutdown()) { - return; // Shutdown operation has been canceled, so do nothing - } - - // If closing the last document, open a new document so Inkscape doesn't quit. - std::list desktops; - inkscape_get_all_desktops(desktops); - if (desktops.size() == 1) { - Glib::ustring templateUri = sp_file_default_template_uri(); - SPDocument *doc = SPDocument::createNewDoc( templateUri.c_str() , TRUE, true ); - // Set viewBox if it doesn't exist - if (!doc->getRoot()->viewBox_set) { - doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value(doc->getDefaultUnit()), doc->getHeight().value(doc->getDefaultUnit()))); - } - dt->change_document(doc); - sp_namedview_window_from_document(dt); - sp_namedview_update_layers_from_document(dt); - return; - } - - // Shutdown can proceed; use the stored reference to the desktop here instead of the current SP_ACTIVE_DESKTOP, - // because the user might have changed the focus in the meantime (see bug #381357 on Launchpad) - dt->destroyWidget(); -} - - -unsigned int -sp_ui_close_all(void) -{ - /* Iterate through all the windows, destroying each in the order they - become active */ - while (SP_ACTIVE_DESKTOP) { - SPDesktop *dt = SP_ACTIVE_DESKTOP; - if (dt->shutdown()) { - /* The user canceled the operation, so end doing the close */ - return FALSE; - } - // Shutdown can proceed; use the stored reference to the desktop here instead of the current SP_ACTIVE_DESKTOP, - // because the user might have changed the focus in the meantime (see bug #381357 on Launchpad) - dt->destroyWidget(); - } - - return TRUE; -} - -/* - * Some day when the right-click menus are ready to start working - * smarter with the verbs, we'll need to change this NULL being - * sent to sp_action_perform to something useful, or set some kind - * of global "right-clicked position" variable for actions to - * investigate when they're called. - */ -static void -sp_ui_menu_activate(void */*object*/, SPAction *action) -{ - if (!temporarily_block_actions) { - sp_action_perform(action, NULL); - } -} - -static void -sp_ui_menu_select_action(void */*object*/, SPAction *action) -{ - sp_action_get_view(action)->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, action->tip); -} - -static void -sp_ui_menu_deselect_action(void */*object*/, SPAction *action) -{ - sp_action_get_view(action)->tipsMessageContext()->clear(); -} - -static void -sp_ui_menu_select(gpointer object, gpointer tip) -{ - Inkscape::UI::View::View *view = static_cast (g_object_get_data(G_OBJECT(object), "view")); - view->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, (gchar *)tip); -} - -static void -sp_ui_menu_deselect(gpointer object) -{ - Inkscape::UI::View::View *view = static_cast (g_object_get_data(G_OBJECT(object), "view")); - view->tipsMessageContext()->clear(); -} - -/** - * Creates and attaches a scaled icon to the given menu item. - */ -static void -sp_ui_menuitem_add_icon( GtkWidget *item, gchar *icon_name ) -{ - static bool iconsInjected = false; - if ( !iconsInjected ) { - iconsInjected = true; - injectRenamedIcons(); - } - GtkWidget *icon; - - icon = sp_icon_new( Inkscape::ICON_SIZE_MENU, icon_name ); - gtk_widget_show(icon); - gtk_image_menu_item_set_image((GtkImageMenuItem *) item, icon); -} // end of sp_ui_menu_add_icon - -void -sp_ui_dialog_title_string(Inkscape::Verb *verb, gchar *c) -{ - SPAction *action; - unsigned int shortcut; - gchar *s; - gchar *atitle; - - action = verb->get_action(Inkscape::ActionContext()); - if (!action) - return; - - atitle = sp_action_get_title(action); - - s = g_stpcpy(c, atitle); - - g_free(atitle); - - shortcut = sp_shortcut_get_primary(verb); - if (shortcut!=GDK_KEY_VoidSymbol) { - gchar* key = sp_shortcut_get_label(shortcut); - s = g_stpcpy(s, " ("); - s = g_stpcpy(s, key); - s = g_stpcpy(s, ")"); - g_free(key); - } -} - - -/** - * Appends a custom menu UI from a verb. - * - * @see ContextMenu::AppendItemFromVerb for a c++ified alternative. Consider dropping sp_ui_menu_append_item_from_verb when c++ifying interface.cpp. - */ -static GtkWidget *sp_ui_menu_append_item_from_verb(GtkMenu *menu, Inkscape::Verb *verb, Inkscape::UI::View::View *view, bool radio = false, GSList *group = NULL) -{ - SPAction *action; - GtkWidget *item; - - if (verb->get_code() == SP_VERB_NONE) { - - item = gtk_separator_menu_item_new(); - - } else { - - action = verb->get_action(Inkscape::ActionContext(view)); - if (!action) return NULL; - - if (radio) { - item = gtk_radio_menu_item_new_with_mnemonic(group, action->name); - } else { - item = gtk_image_menu_item_new_with_mnemonic(action->name); - } - - gtk_label_set_markup_with_mnemonic( GTK_LABEL(gtk_bin_get_child(GTK_BIN (item))), action->name); - - GtkAccelGroup *accel_group = sp_shortcut_get_accel_group(); - gtk_menu_set_accel_group(menu, accel_group); - - sp_shortcut_add_accelerator(item, sp_shortcut_get_primary(verb)); - - action->signal_set_sensitive.connect( - sigc::bind<0>( - sigc::ptr_fun(>k_widget_set_sensitive), - item)); - action->signal_set_name.connect( - sigc::bind<0>( - sigc::ptr_fun(&sp_ui_menu_item_set_name), - item)); - - if (!action->sensitive) { - gtk_widget_set_sensitive(item, FALSE); - } - - if (action->image) { - sp_ui_menuitem_add_icon(item, action->image); - } - gtk_widget_set_events(item, GDK_KEY_PRESS_MASK); - g_object_set_data(G_OBJECT(item), "view", (gpointer) view); - g_signal_connect( G_OBJECT(item), "activate", G_CALLBACK(sp_ui_menu_activate), action ); - g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select_action), action ); - g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect_action), action ); - } - - gtk_widget_show(item); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); - - return item; - -} // end of sp_ui_menu_append_item_from_verb - - -Glib::ustring getLayoutPrefPath( Inkscape::UI::View::View *view ) -{ - Glib::ustring prefPath; - - if (reinterpret_cast(view)->is_focusMode()) { - prefPath = "/focus/"; - } else if (reinterpret_cast(view)->is_fullscreen()) { - prefPath = "/fullscreen/"; - } else { - prefPath = "/window/"; - } - - return prefPath; -} - -static void -checkitem_toggled(GtkCheckMenuItem *menuitem, gpointer user_data) -{ - gchar const *pref = (gchar const *) user_data; - Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view"); - SPAction *action = (SPAction *) g_object_get_data(G_OBJECT(menuitem), "action"); - - if (action) { - - sp_ui_menu_activate(menuitem, action); - - } else if (pref) { - // All check menu items should have actions now, but just in case - Glib::ustring pref_path = getLayoutPrefPath( view ); - pref_path += pref; - pref_path += "/state"; - - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - gboolean checked = gtk_check_menu_item_get_active(menuitem); - prefs->setBool(pref_path, checked); - - reinterpret_cast(view)->layoutWidget(); - } -} - -static bool getViewStateFromPref(Inkscape::UI::View::View *view, gchar const *pref) -{ - Glib::ustring pref_path = getLayoutPrefPath( view ); - pref_path += pref; - pref_path += "/state"; - - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - return prefs->getBool(pref_path, true); -} - -#if GTK_CHECK_VERSION(3,0,0) -static gboolean checkitem_update(GtkWidget *widget, cairo_t * /*cr*/, gpointer user_data) -#else -static gboolean checkitem_update(GtkWidget *widget, GdkEventExpose * /*event*/, gpointer user_data) -#endif -{ - GtkCheckMenuItem *menuitem=GTK_CHECK_MENU_ITEM(widget); - - gchar const *pref = (gchar const *) user_data; - Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view"); - SPAction *action = (SPAction *) g_object_get_data(G_OBJECT(menuitem), "action"); - SPDesktop *dt = static_cast(view); - - bool ison = false; - if (action) { - - if (!strcmp(action->id, "ToggleGrid")) { - ison = dt->gridsEnabled(); - } - else if (!strcmp(action->id, "ToggleGuides")) { - ison = dt->namedview->getGuides(); - } - else if (!strcmp(action->id, "ViewCmsToggle")) { - ison = dt->colorProfAdjustEnabled(); - } - else { - ison = getViewStateFromPref(view, pref); - } - } else if (pref) { - // The Show/Hide menu items without actions - ison = getViewStateFromPref(view, pref); - } - - g_signal_handlers_block_by_func(G_OBJECT(menuitem), (gpointer)(GCallback)checkitem_toggled, user_data); - gtk_check_menu_item_set_active(menuitem, ison); - g_signal_handlers_unblock_by_func(G_OBJECT(menuitem), (gpointer)(GCallback)checkitem_toggled, user_data); - - return FALSE; -} - - -static void taskToggled(GtkCheckMenuItem *menuitem, gpointer userData) -{ - if ( gtk_check_menu_item_get_active(menuitem) ) { - gint taskNum = GPOINTER_TO_INT(userData); - taskNum = (taskNum < 0) ? 0 : (taskNum > 2) ? 2 : taskNum; - - Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view"); - - // note: this will change once more options are in the task set support: - Inkscape::UI::UXManager::getInstance()->setTask( dynamic_cast(view), taskNum ); - } -} - - -/** - * Callback function to update the status of the radio buttons in the View -> Display mode menu (Normal, No Filters, Outline) and Color display mode. - */ -#if GTK_CHECK_VERSION(3,0,0) -static gboolean update_view_menu(GtkWidget *widget, cairo_t * /*cr*/, gpointer user_data) -#else -static gboolean update_view_menu(GtkWidget *widget, GdkEventExpose * /*event*/, gpointer user_data) -#endif -{ - SPAction *action = (SPAction *) user_data; - g_assert(action->id != NULL); - - Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(widget), "view"); - SPDesktop *dt = static_cast(view); - Inkscape::RenderMode mode = dt->getMode(); - Inkscape::ColorMode colormode = dt->getColorMode(); - - bool new_state = false; - if (!strcmp(action->id, "ViewModeNormal")) { - new_state = mode == Inkscape::RENDERMODE_NORMAL; - } else if (!strcmp(action->id, "ViewModeNoFilters")) { - new_state = mode == Inkscape::RENDERMODE_NO_FILTERS; - } else if (!strcmp(action->id, "ViewModeOutline")) { - new_state = mode == Inkscape::RENDERMODE_OUTLINE; - } else if (!strcmp(action->id, "ViewColorModeNormal")) { - new_state = colormode == Inkscape::COLORMODE_NORMAL; - } else if (!strcmp(action->id, "ViewColorModeGrayscale")) { - new_state = colormode == Inkscape::COLORMODE_GRAYSCALE; - } else if (!strcmp(action->id, "ViewColorModePrintColorsPreview")) { - new_state = colormode == Inkscape::COLORMODE_PRINT_COLORS_PREVIEW; - } else { - g_warning("update_view_menu does not handle this verb"); - } - - if (new_state) { //only one of the radio buttons has to be activated; the others will automatically be deactivated - if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget))) { - // When the GtkMenuItem version of the "activate" signal has been emitted by a GtkRadioMenuItem, there is a second - // emission as the most recently active item is toggled to inactive. This is dealt with before the original signal is handled. - // This emission however should not invoke any actions, hence we block it here: - temporarily_block_actions = true; - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (widget), TRUE); - temporarily_block_actions = false; - } - } - - return FALSE; -} - -static void -sp_ui_menu_append_check_item_from_verb(GtkMenu *menu, Inkscape::UI::View::View *view, gchar const *label, gchar const *tip, gchar const *pref, - void (*callback_toggle)(GtkCheckMenuItem *, gpointer user_data), -#if GTK_CHECK_VERSION(3,0,0) - gboolean (*callback_update)(GtkWidget *widget, cairo_t *cr, gpointer user_data), -#else - gboolean (*callback_update)(GtkWidget *widget, GdkEventExpose *event, gpointer user_data), -#endif - Inkscape::Verb *verb) -{ - unsigned int shortcut = (verb) ? sp_shortcut_get_primary(verb) : 0; - SPAction *action = (verb) ? verb->get_action(Inkscape::ActionContext(view)) : 0; - GtkWidget *item = gtk_check_menu_item_new_with_mnemonic(action ? action->name : label); - -#if 0 - if (!action->sensitive) { - gtk_widget_set_sensitive(item, FALSE); - } -#endif - - sp_shortcut_add_accelerator(item, shortcut); - - gtk_widget_show(item); - - gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); - - g_object_set_data(G_OBJECT(item), "view", (gpointer) view); - g_object_set_data(G_OBJECT(item), "action", (gpointer) action); - - g_signal_connect( G_OBJECT(item), "toggled", (GCallback) callback_toggle, (void *) pref); - -#if GTK_CHECK_VERSION(3,0,0) - g_signal_connect( G_OBJECT(item), "draw", (GCallback) callback_update, (void *) pref); -#else - g_signal_connect( G_OBJECT(item), "expose_event", (GCallback) callback_update, (void *) pref); -#endif - - (*callback_update)(item, NULL, (void *)pref); - - g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select), (gpointer) (action ? action->tip : tip)); - g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect), NULL); - -} - -static void -sp_recent_open(GtkRecentChooser *recent_menu, gpointer /*user_data*/) -{ - // dealing with the bizarre filename convention in Inkscape for now - gchar *uri = gtk_recent_chooser_get_current_uri(GTK_RECENT_CHOOSER(recent_menu)); - gchar *local_fn = g_filename_from_uri(uri, NULL, NULL); - gchar *utf8_fn = g_filename_to_utf8(local_fn, -1, NULL, NULL, NULL); - sp_file_open(utf8_fn, NULL); - g_free(utf8_fn); - g_free(local_fn); - g_free(uri); -} - -static void -sp_ui_checkboxes_menus(GtkMenu *m, Inkscape::UI::View::View *view) -{ - //sp_ui_menu_append_check_item_from_verb(m, view, _("_Menu"), _("Show or hide the menu bar"), "menu", - // checkitem_toggled, checkitem_update, 0); - sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "commands", - checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_COMMANDS_TOOLBAR)); - sp_ui_menu_append_check_item_from_verb(m, view,NULL, NULL, "snaptoolbox", - checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_SNAP_TOOLBAR)); - sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "toppanel", - checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_TOOL_TOOLBAR)); - sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "toolbox", - checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_TOOLBOX)); - sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "rulers", - checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_RULERS)); - sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "scrollbars", - checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_SCROLLBARS)); - sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "panels", - checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_PALETTE)); - sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "statusbar", - checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_STATUSBAR)); -} - - -static void addTaskMenuItems(GtkMenu *menu, Inkscape::UI::View::View *view) -{ - gchar const* data[] = { - C_("Interface setup", "Default"), _("Default interface setup"), - C_("Interface setup", "Custom"), _("Setup for custom task"), - C_("Interface setup", "Wide"), _("Setup for widescreen work"), - 0, 0 - }; - - GSList *group = 0; - int count = 0; - gint active = Inkscape::UI::UXManager::getInstance()->getDefaultTask( dynamic_cast(view) ); - for (gchar const **strs = data; strs[0]; strs += 2, count++) - { - GtkWidget *item = gtk_radio_menu_item_new_with_label( group, strs[0] ); - group = gtk_radio_menu_item_get_group( GTK_RADIO_MENU_ITEM(item) ); - if ( count == active ) - { - gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM(item), TRUE ); - } - - g_object_set_data( G_OBJECT(item), "view", view ); - g_signal_connect( G_OBJECT(item), "toggled", reinterpret_cast(taskToggled), GINT_TO_POINTER(count) ); - g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select), const_cast(strs[1]) ); - g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect), 0 ); - - gtk_widget_show( item ); - gtk_menu_shell_append( GTK_MENU_SHELL(menu), item ); - } -} - - -/** - * Observer that updates the recent list's max document count. - */ -class MaxRecentObserver : public Inkscape::Preferences::Observer { -public: - MaxRecentObserver(GtkWidget *recent_menu) : - Observer("/options/maxrecentdocuments/value"), - _rm(recent_menu) - {} - virtual void notify(Inkscape::Preferences::Entry const &e) { - gtk_recent_chooser_set_limit(GTK_RECENT_CHOOSER(_rm), e.getInt()); - // hack: the recent menu doesn't repopulate after changing the limit, so we force it - g_signal_emit_by_name((gpointer) gtk_recent_manager_get_default(), "changed"); - } -private: - GtkWidget *_rm; -}; - -/** - * This function turns XML into a menu. - * - * This function is realitively simple as it just goes through the XML - * and parses the individual elements. In the case of a submenu, it - * just calls itself recursively. Because it is only reasonable to have - * a couple of submenus, it is unlikely this will go more than two or - * three times. - * - * In the case of an unrecognized verb, a menu item is made to identify - * the verb that is missing, and display that. The menu item is also made - * insensitive. - * - * @param menus This is the XML that defines the menu - * @param menu Menu to be added to - * @param view The View that this menu is being built for - */ -static void sp_ui_build_dyn_menus(Inkscape::XML::Node *menus, GtkWidget *menu, Inkscape::UI::View::View *view) -{ - if (menus == NULL) return; - if (menu == NULL) return; - GSList *group = NULL; - - for (Inkscape::XML::Node *menu_pntr = menus; - menu_pntr != NULL; - menu_pntr = menu_pntr->next()) { - if (!strcmp(menu_pntr->name(), "submenu")) { - GtkWidget *mitem = gtk_menu_item_new_with_mnemonic(_(menu_pntr->attribute("name"))); - GtkWidget *submenu = gtk_menu_new(); - sp_ui_build_dyn_menus(menu_pntr->firstChild(), submenu, view); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), GTK_WIDGET(submenu)); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem); - continue; - } - if (!strcmp(menu_pntr->name(), "verb")) { - gchar const *verb_name = menu_pntr->attribute("verb-id"); - Inkscape::Verb *verb = Inkscape::Verb::getbyid(verb_name); - - if (verb != NULL) { - if (menu_pntr->attribute("radio") != NULL) { - GtkWidget *item = sp_ui_menu_append_item_from_verb (GTK_MENU(menu), verb, view, true, group); - group = gtk_radio_menu_item_get_group( GTK_RADIO_MENU_ITEM(item)); - if (menu_pntr->attribute("default") != NULL) { - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); - } - if (verb->get_code() != SP_VERB_NONE) { - SPAction *action = verb->get_action(Inkscape::ActionContext(view)); -#if GTK_CHECK_VERSION(3,0,0) - g_signal_connect( G_OBJECT(item), "draw", (GCallback) update_view_menu, (void *) action); -#else - g_signal_connect( G_OBJECT(item), "expose_event", (GCallback) update_view_menu, (void *) action); -#endif - } - } else if (menu_pntr->attribute("check") != NULL) { - SPAction *action = NULL; - if (verb->get_code() != SP_VERB_NONE) { - action = verb->get_action(Inkscape::ActionContext(view)); - } - sp_ui_menu_append_check_item_from_verb(GTK_MENU(menu), view, action->name, action->tip, NULL, - checkitem_toggled, checkitem_update, verb); - - } else { - sp_ui_menu_append_item_from_verb(GTK_MENU(menu), verb, view); - group = NULL; - } - } else { - gchar string[120]; - g_snprintf(string, 120, _("Verb \"%s\" Unknown"), verb_name); - string[119] = '\0'; /* may not be terminated */ - GtkWidget *item = gtk_menu_item_new_with_label(string); - gtk_widget_set_sensitive(item, false); - gtk_widget_show(item); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); - } - continue; - } - if (!strcmp(menu_pntr->name(), "separator") - // This was spelt wrong in the original version - // and so this is for backward compatibility. It can - // probably be dropped after the 0.44 release. - || !strcmp(menu_pntr->name(), "seperator")) { - GtkWidget *item = gtk_separator_menu_item_new(); - gtk_widget_show(item); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); - continue; - } - - if (!strcmp(menu_pntr->name(), "recent-file-list")) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - - // create recent files menu - int max_recent = prefs->getInt("/options/maxrecentdocuments/value"); - GtkWidget *recent_menu = gtk_recent_chooser_menu_new_for_manager(gtk_recent_manager_get_default()); - gtk_recent_chooser_set_limit(GTK_RECENT_CHOOSER(recent_menu), max_recent); - // sort most recently used documents first to preserve previous behavior - gtk_recent_chooser_set_sort_type(GTK_RECENT_CHOOSER(recent_menu), GTK_RECENT_SORT_MRU); - g_signal_connect(G_OBJECT(recent_menu), "item-activated", G_CALLBACK(sp_recent_open), (gpointer) NULL); - - // add filter to only open files added by Inkscape - GtkRecentFilter *inkscape_only_filter = gtk_recent_filter_new(); - gtk_recent_filter_add_application(inkscape_only_filter, g_get_prgname()); - gtk_recent_chooser_add_filter(GTK_RECENT_CHOOSER(recent_menu), inkscape_only_filter); - - gtk_recent_chooser_set_show_tips (GTK_RECENT_CHOOSER(recent_menu), TRUE); - gtk_recent_chooser_set_show_not_found (GTK_RECENT_CHOOSER(recent_menu), FALSE); - - GtkWidget *recent_item = gtk_menu_item_new_with_mnemonic(_("Open _Recent")); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(recent_item), recent_menu); - - gtk_menu_shell_append(GTK_MENU_SHELL(menu), GTK_WIDGET(recent_item)); - // this will just sit and update the list's item count - static MaxRecentObserver *mro = new MaxRecentObserver(recent_menu); - prefs->addObserver(*mro); - continue; - } - if (!strcmp(menu_pntr->name(), "objects-checkboxes")) { - sp_ui_checkboxes_menus(GTK_MENU(menu), view); - continue; - } - if (!strcmp(menu_pntr->name(), "task-checkboxes")) { - addTaskMenuItems(GTK_MENU(menu), view); - continue; - } - } -} - -GtkWidget *sp_ui_main_menubar(Inkscape::UI::View::View *view) -{ - GtkWidget *mbar = gtk_menu_bar_new(); - sp_ui_build_dyn_menus(inkscape_get_menus(INKSCAPE), mbar, view); - return mbar; -} - - -/* Drag and Drop */ -void -sp_ui_drag_data_received(GtkWidget *widget, - GdkDragContext *drag_context, - gint x, gint y, - GtkSelectionData *data, - guint info, - guint /*event_time*/, - gpointer /*user_data*/) -{ - SPDocument *doc = SP_ACTIVE_DOCUMENT; - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - - switch (info) { -#if ENABLE_MAGIC_COLORS - case APP_X_INKY_COLOR: - { - int destX = 0; - int destY = 0; - gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY ); - Geom::Point where( sp_canvas_window_to_world( desktop->canvas, Geom::Point( destX, destY ) ) ); - - SPItem *item = desktop->getItemAtPoint( where, true ); - if ( item ) - { - bool fillnotstroke = (drag_context->action != GDK_ACTION_MOVE); - - if ( data->length >= 8 ) { - cmsHPROFILE srgbProf = cmsCreate_sRGBProfile(); - - gchar c[64] = {0}; - // Careful about endian issues. - guint16* dataVals = (guint16*)data->data; - sp_svg_write_color( c, sizeof(c), - SP_RGBA32_U_COMPOSE( - 0x0ff & (dataVals[0] >> 8), - 0x0ff & (dataVals[1] >> 8), - 0x0ff & (dataVals[2] >> 8), - 0xff // can't have transparency in the color itself - //0x0ff & (data->data[3] >> 8), - )); - SPCSSAttr *css = sp_repr_css_attr_new(); - bool updatePerformed = false; - - if ( data->length > 14 ) { - int flags = dataVals[4]; - - // piggie-backed palette entry info - int index = dataVals[5]; - Glib::ustring palName; - for ( int i = 0; i < dataVals[6]; i++ ) { - palName += (gunichar)dataVals[7+i]; - } - - // Now hook in a magic tag of some sort. - if ( !palName.empty() && (flags & 1) ) { - gchar* str = g_strdup_printf("%d|", index); - palName.insert( 0, str ); - g_free(str); - str = 0; - - item->setAttribute( - fillnotstroke ? "inkscape:x-fill-tag":"inkscape:x-stroke-tag", - palName.c_str(), - false ); - item->updateRepr(); - - sp_repr_css_set_property( css, fillnotstroke ? "fill":"stroke", c ); - updatePerformed = true; - } - } - - if ( !updatePerformed ) { - sp_repr_css_set_property( css, fillnotstroke ? "fill":"stroke", c ); - } - - sp_desktop_apply_css_recursive( item, css, true ); - item->updateRepr(); - - SPDocumentUndo::done( doc , SP_VERB_NONE, - _("Drop color")); - - if ( srgbProf ) { - cmsCloseProfile( srgbProf ); - } - } - } - } - break; -#endif // ENABLE_MAGIC_COLORS - - case APP_X_COLOR: - { - int destX = 0; - int destY = 0; - gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY ); - Geom::Point where( sp_canvas_window_to_world( desktop->canvas, Geom::Point( destX, destY ) ) ); - Geom::Point const button_dt(desktop->w2d(where)); - Geom::Point const button_doc(desktop->dt2doc(button_dt)); - - if ( gtk_selection_data_get_length (data) == 8 ) { - gchar colorspec[64] = {0}; - // Careful about endian issues. - guint16* dataVals = (guint16*)gtk_selection_data_get_data (data); - sp_svg_write_color( colorspec, sizeof(colorspec), - SP_RGBA32_U_COMPOSE( - 0x0ff & (dataVals[0] >> 8), - 0x0ff & (dataVals[1] >> 8), - 0x0ff & (dataVals[2] >> 8), - 0xff // can't have transparency in the color itself - //0x0ff & (data->data[3] >> 8), - )); - - SPItem *item = desktop->getItemAtPoint( where, true ); - - bool consumed = false; - if (desktop->event_context && desktop->event_context->get_drag()) { - consumed = desktop->event_context->get_drag()->dropColor(item, colorspec, button_dt); - if (consumed) { - DocumentUndo::done( doc , SP_VERB_NONE, _("Drop color on gradient") ); - desktop->event_context->get_drag()->updateDraggers(); - } - } - - //if (!consumed && tools_active(desktop, TOOLS_TEXT)) { - // consumed = sp_text_context_drop_color(c, button_doc); - // if (consumed) { - // SPDocumentUndo::done( doc , SP_VERB_NONE, _("Drop color on gradient stop")); - // } - //} - - if (!consumed && item) { - bool fillnotstroke = (gdk_drag_context_get_actions (drag_context) != GDK_ACTION_MOVE); - if (fillnotstroke && - (SP_IS_SHAPE(item) || SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item))) { - Path *livarot_path = Path_for_item(item, true, true); - livarot_path->ConvertWithBackData(0.04); - - boost::optional position = get_nearest_position_on_Path(livarot_path, button_doc); - if (position) { - Geom::Point nearest = get_point_on_Path(livarot_path, position->piece, position->t); - Geom::Point delta = nearest - button_doc; - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - delta = desktop->d2w(delta); - double stroke_tolerance = - ( !item->style->stroke.isNone() ? - desktop->current_zoom() * - item->style->stroke_width.computed * - item->i2dt_affine().descrim() * 0.5 - : 0.0) - + prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); - - if (Geom::L2 (delta) < stroke_tolerance) { - fillnotstroke = false; - } - } - delete livarot_path; - } - - SPCSSAttr *css = sp_repr_css_attr_new(); - sp_repr_css_set_property( css, fillnotstroke ? "fill":"stroke", colorspec ); - - sp_desktop_apply_css_recursive( item, css, true ); - item->updateRepr(); - - DocumentUndo::done( doc , SP_VERB_NONE, - _("Drop color") ); - } - } - } - break; - - case APP_OSWB_COLOR: - { - bool worked = false; - Glib::ustring colorspec; - if ( gtk_selection_data_get_format (data) == 8 ) { - ege::PaintDef color; - worked = color.fromMIMEData("application/x-oswb-color", - reinterpret_cast(gtk_selection_data_get_data (data)), - gtk_selection_data_get_length (data), - gtk_selection_data_get_format (data)); - if ( worked ) { - if ( color.getType() == ege::PaintDef::CLEAR ) { - colorspec = ""; // TODO check if this is sufficient - } else if ( color.getType() == ege::PaintDef::NONE ) { - colorspec = "none"; - } else { - unsigned int r = color.getR(); - unsigned int g = color.getG(); - unsigned int b = color.getB(); - - SPGradient* matches = 0; - const GSList *gradients = doc->getResourceList("gradient"); - for (const GSList *item = gradients; item; item = item->next) { - SPGradient* grad = SP_GRADIENT(item->data); - if ( color.descr == grad->getId() ) { - if ( grad->hasStops() ) { - matches = grad; - break; - } - } - } - if (matches) { - colorspec = "url(#"; - colorspec += matches->getId(); - colorspec += ")"; - } else { - gchar* tmp = g_strdup_printf("#%02x%02x%02x", r, g, b); - colorspec = tmp; - g_free(tmp); - } - } - } - } - if ( worked ) { - int destX = 0; - int destY = 0; - gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY ); - Geom::Point where( sp_canvas_window_to_world( desktop->canvas, Geom::Point( destX, destY ) ) ); - Geom::Point const button_dt(desktop->w2d(where)); - Geom::Point const button_doc(desktop->dt2doc(button_dt)); - - SPItem *item = desktop->getItemAtPoint( where, true ); - - bool consumed = false; - if (desktop->event_context && desktop->event_context->get_drag()) { - consumed = desktop->event_context->get_drag()->dropColor(item, colorspec.c_str(), button_dt); - if (consumed) { - DocumentUndo::done( doc , SP_VERB_NONE, _("Drop color on gradient") ); - desktop->event_context->get_drag()->updateDraggers(); - } - } - - if (!consumed && item) { - bool fillnotstroke = (gdk_drag_context_get_actions (drag_context) != GDK_ACTION_MOVE); - if (fillnotstroke && - (SP_IS_SHAPE(item) || SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item))) { - Path *livarot_path = Path_for_item(item, true, true); - livarot_path->ConvertWithBackData(0.04); - - boost::optional position = get_nearest_position_on_Path(livarot_path, button_doc); - if (position) { - Geom::Point nearest = get_point_on_Path(livarot_path, position->piece, position->t); - Geom::Point delta = nearest - button_doc; - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - delta = desktop->d2w(delta); - double stroke_tolerance = - ( !item->style->stroke.isNone() ? - desktop->current_zoom() * - item->style->stroke_width.computed * - item->i2dt_affine().descrim() * 0.5 - : 0.0) - + prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); - - if (Geom::L2 (delta) < stroke_tolerance) { - fillnotstroke = false; - } - } - delete livarot_path; - } - - SPCSSAttr *css = sp_repr_css_attr_new(); - sp_repr_css_set_property( css, fillnotstroke ? "fill":"stroke", colorspec.c_str() ); - - sp_desktop_apply_css_recursive( item, css, true ); - item->updateRepr(); - - DocumentUndo::done( doc , SP_VERB_NONE, - _("Drop color") ); - } - } - } - break; - - case SVG_DATA: - case SVG_XML_DATA: { - gchar *svgdata = (gchar *)gtk_selection_data_get_data (data); - - Inkscape::XML::Document *rnewdoc = sp_repr_read_mem(svgdata, gtk_selection_data_get_length (data), SP_SVG_NS_URI); - - if (rnewdoc == NULL) { - sp_ui_error_dialog(_("Could not parse SVG data")); - return; - } - - Inkscape::XML::Node *repr = rnewdoc->root(); - gchar const *style = repr->attribute("style"); - - Inkscape::XML::Node *newgroup = rnewdoc->createElement("svg:g"); - newgroup->setAttribute("style", style); - - Inkscape::XML::Document * xml_doc = doc->getReprDoc(); - for (Inkscape::XML::Node *child = repr->firstChild(); child != NULL; child = child->next()) { - Inkscape::XML::Node *newchild = child->duplicate(xml_doc); - newgroup->appendChild(newchild); - } - - Inkscape::GC::release(rnewdoc); - - // Add it to the current layer - - // Greg's edits to add intelligent positioning of svg drops - SPObject *new_obj = NULL; - new_obj = desktop->currentLayer()->appendChildRepr(newgroup); - - Inkscape::Selection *selection = sp_desktop_selection(desktop); - selection->set(SP_ITEM(new_obj)); - - // move to mouse pointer - { - sp_desktop_document(desktop)->ensureUpToDate(); - Geom::OptRect sel_bbox = selection->visualBounds(); - if (sel_bbox) { - Geom::Point m( desktop->point() - sel_bbox->midpoint() ); - sp_selection_move_relative(selection, m, false); - } - } - - Inkscape::GC::release(newgroup); - DocumentUndo::done( doc, SP_VERB_NONE, - _("Drop SVG") ); - break; - } - - case URI_LIST: { - gchar *uri = (gchar *)gtk_selection_data_get_data (data); - sp_ui_import_files(uri); - break; - } - - case APP_X_INK_PASTE: { - Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get(); - cm->paste(desktop); - DocumentUndo::done( doc, SP_VERB_NONE, _("Drop Symbol") ); - break; - } - - case PNG_DATA: - case JPEG_DATA: - case IMAGE_DATA: { - const char *mime = (info == JPEG_DATA ? "image/jpeg" : "image/png"); - - Inkscape::Extension::DB::InputList o; - Inkscape::Extension::db.get_input_list(o); - Inkscape::Extension::DB::InputList::const_iterator i = o.begin(); - while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) { - ++i; - } - Inkscape::Extension::Extension *ext = *i; - bool save = (strcmp(ext->get_param_optiongroup("link"), "embed") == 0); - ext->set_param_optiongroup("link", "embed"); - ext->set_gui(false); - - gchar *filename = g_build_filename( g_get_tmp_dir(), "inkscape-dnd-import", NULL ); - g_file_set_contents(filename, - reinterpret_cast(gtk_selection_data_get_data (data)), - gtk_selection_data_get_length (data), - NULL); - file_import(doc, filename, ext); - g_free(filename); - - ext->set_param_optiongroup("link", save ? "embed" : "link"); - ext->set_gui(true); - DocumentUndo::done( doc , SP_VERB_NONE, - _("Drop bitmap image") ); - break; - } - } -} - -#include "ui/tools/gradient-tool.h" - -void sp_ui_drag_motion( GtkWidget */*widget*/, - GdkDragContext */*drag_context*/, - gint /*x*/, gint /*y*/, - GtkSelectionData */*data*/, - guint /*info*/, - guint /*event_time*/, - gpointer /*user_data*/) -{ -// SPDocument *doc = SP_ACTIVE_DOCUMENT; -// SPDesktop *desktop = SP_ACTIVE_DESKTOP; - - -// g_message("drag-n-drop motion (%4d, %4d) at %d", x, y, event_time); -} - -static void sp_ui_drag_leave( GtkWidget */*widget*/, - GdkDragContext */*drag_context*/, - guint /*event_time*/, - gpointer /*user_data*/ ) -{ -// g_message("drag-n-drop leave at %d", event_time); -} - -static void -sp_ui_import_files(gchar *buffer) -{ - GList *list = gnome_uri_list_extract_filenames(buffer); - if (!list) - return; - g_list_foreach(list, sp_ui_import_one_file_with_check, NULL); - g_list_foreach(list, (GFunc) g_free, NULL); - g_list_free(list); -} - -static void -sp_ui_import_one_file_with_check(gpointer filename, gpointer /*unused*/) -{ - if (filename) { - if (strlen((char const *)filename) > 2) - sp_ui_import_one_file((char const *)filename); - } -} - -static void -sp_ui_import_one_file(char const *filename) -{ - SPDocument *doc = SP_ACTIVE_DOCUMENT; - if (!doc) return; - - if (filename == NULL) return; - - // Pass off to common implementation - // TODO might need to get the proper type of Inkscape::Extension::Extension - file_import( doc, filename, NULL ); -} - -void -sp_ui_error_dialog(gchar const *message) -{ - GtkWidget *dlg; - gchar *safeMsg = Inkscape::IO::sanitizeString(message); - - dlg = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, - GTK_BUTTONS_CLOSE, "%s", safeMsg); - sp_transientize(dlg); - gtk_window_set_resizable(GTK_WINDOW(dlg), FALSE); - gtk_dialog_run(GTK_DIALOG(dlg)); - gtk_widget_destroy(dlg); - g_free(safeMsg); -} - -bool -sp_ui_overwrite_file(gchar const *filename) -{ - bool return_value = FALSE; - - if (Inkscape::IO::file_test(filename, G_FILE_TEST_EXISTS)) { - Gtk::Window *window = SP_ACTIVE_DESKTOP->getToplevel(); - gchar* baseName = g_path_get_basename( filename ); - gchar* dirName = g_path_get_dirname( filename ); - GtkWidget* dialog = gtk_message_dialog_new_with_markup( window->gobj(), - (GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), - GTK_MESSAGE_QUESTION, - GTK_BUTTONS_NONE, - _( "A file named \"%s\" already exists. Do you want to replace it?\n\n" - "The file already exists in \"%s\". Replacing it will overwrite its contents." ), - baseName, - dirName - ); - gtk_dialog_add_buttons( GTK_DIALOG(dialog), - _("_Cancel"), GTK_RESPONSE_NO, - _("Replace"), GTK_RESPONSE_YES, - NULL ); - gtk_dialog_set_default_response( GTK_DIALOG(dialog), GTK_RESPONSE_YES ); - - if ( gtk_dialog_run( GTK_DIALOG(dialog) ) == GTK_RESPONSE_YES ) { - return_value = TRUE; - } else { - return_value = FALSE; - } - gtk_widget_destroy(dialog); - g_free( baseName ); - g_free( dirName ); - } else { - return_value = TRUE; - } - - return return_value; -} - -static void -sp_ui_menu_item_set_name(GtkWidget *data, Glib::ustring const &name) -{ - if (data || GTK_IS_BIN (data)) { - void *child = gtk_bin_get_child (GTK_BIN (data)); - //child is either - //- a GtkBox, whose first child is a label displaying name if the menu - //item has an accel key - //- a GtkLabel if the menu has no accel key - if (child != NULL){ - if (GTK_IS_LABEL(child)) { - gtk_label_set_markup_with_mnemonic(GTK_LABEL (child), name.c_str()); - } else if (GTK_IS_BOX(child)) { - gtk_label_set_markup_with_mnemonic( - GTK_LABEL (gtk_container_get_children(GTK_CONTAINER (child))->data), - name.c_str()); - }//else sp_ui_menu_append_item_from_verb has been modified and can set - //a menu item in yet another way... - } - } -} - -void injectRenamedIcons() -{ - Glib::RefPtr iconTheme = Gtk::IconTheme::get_default(); - - std::vector< std::pair > renamed; - renamed.push_back(std::make_pair("gtk-file", "document-x-generic")); - renamed.push_back(std::make_pair("gtk-directory", "folder")); - - for ( std::vector< std::pair >::iterator it = renamed.begin(); it < renamed.end(); ++it ) { - bool hasIcon = iconTheme->has_icon(it->first); - bool hasSecondIcon = iconTheme->has_icon(it->second); - - if ( !hasIcon && hasSecondIcon ) { - Glib::ArrayHandle sizes = iconTheme->get_icon_sizes(it->second); - for ( Glib::ArrayHandle::iterator it2 = sizes.begin(); it2 < sizes.end(); ++it2 ) { - Glib::RefPtr pb = iconTheme->load_icon( it->second, *it2 ); - if ( pb ) { - // install a private copy of the pixbuf to avoid pinning a theme - Glib::RefPtr pbCopy = pb->copy(); - Gtk::IconTheme::add_builtin_icon( it->first, *it2, pbCopy ); - } - } - } - } -} - - -ContextMenu::ContextMenu(SPDesktop *desktop, SPItem *item) : - _item(item), - MIGroup(), - MIParent(_("Go to parent")) -{ -// g_message("ContextMenu"); - _object = static_cast(item); - _desktop = desktop; - - AppendItemFromVerb(Inkscape::Verb::get(SP_VERB_EDIT_UNDO)); - AppendItemFromVerb(Inkscape::Verb::get(SP_VERB_EDIT_REDO)); - AddSeparator(); - AppendItemFromVerb(Inkscape::Verb::get(SP_VERB_EDIT_CUT)); - AppendItemFromVerb(Inkscape::Verb::get(SP_VERB_EDIT_COPY)); - AppendItemFromVerb(Inkscape::Verb::get(SP_VERB_EDIT_PASTE)); - AddSeparator(); - AppendItemFromVerb(Inkscape::Verb::get(SP_VERB_EDIT_DUPLICATE)); - AppendItemFromVerb(Inkscape::Verb::get(SP_VERB_EDIT_DELETE)); - - positionOfLastDialog = 10; // 9 in front + 1 for the separator in the next if; used to position the dialog menu entries below each other - - /* Item menu */ - if (item!=NULL) { - AddSeparator(); - MakeObjectMenu(); - } - - /* layer menu */ - SPGroup *group=NULL; - if (item) { - if (SP_IS_GROUP(item)) { - group = SP_GROUP(item); - } else if ( item != _desktop->currentRoot() && SP_IS_GROUP(item->parent) ) { - group = SP_GROUP(item->parent); - } - } - - if (( group && group != _desktop->currentLayer() ) || - ( _desktop->currentLayer() != _desktop->currentRoot() && _desktop->currentLayer()->parent != _desktop->currentRoot() ) ) { - AddSeparator(); - } - - if ( group && group != _desktop->currentLayer() ) { - /* TRANSLATORS: #%1 is the id of the group e.g. , not a number. */ - MIGroup.set_label (Glib::ustring::compose(_("Enter group #%1"), group->getId())); - MIGroup.set_data("group", group); - MIGroup.signal_activate().connect(sigc::bind(sigc::mem_fun(*this, &ContextMenu::EnterGroup),&MIGroup)); - MIGroup.show(); - append(MIGroup); - } - - if ( _desktop->currentLayer() != _desktop->currentRoot() ) { - if ( _desktop->currentLayer()->parent != _desktop->currentRoot() ) { - MIParent.signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::LeaveGroup)); - MIParent.show(); - append(MIParent); - } - } -} - -ContextMenu::~ContextMenu(void) -{ -} - -Gtk::SeparatorMenuItem* ContextMenu::AddSeparator(void) -{ - Gtk::SeparatorMenuItem* sep = Gtk::manage(new Gtk::SeparatorMenuItem()); - sep->show(); - append(*sep); - return sep; -} - -void ContextMenu::EnterGroup(Gtk::MenuItem* mi) -{ - _desktop->setCurrentLayer(reinterpret_cast(mi->get_data("group"))); - _desktop->selection->clear(); -} - -void ContextMenu::LeaveGroup(void) -{ - _desktop->setCurrentLayer(_desktop->currentLayer()->parent); -} - -void ContextMenu::AppendItemFromVerb(Inkscape::Verb *verb)//, SPDesktop *view)//, bool radio, GSList *group) -{ - SPAction *action; - SPDesktop *view = _desktop; - - if (verb->get_code() == SP_VERB_NONE) { - Gtk::MenuItem *item = AddSeparator(); - item->show(); - append(*item); - } else { - action = verb->get_action(Inkscape::ActionContext(view)); - if (!action) { - return; - } - - Gtk::ImageMenuItem *item = Gtk::manage(new Gtk::ImageMenuItem(action->name, true)); - - sp_shortcut_add_accelerator(GTK_WIDGET(item->gobj()), sp_shortcut_get_primary(verb)); - - action->signal_set_sensitive.connect(sigc::mem_fun(*this, &ContextMenu::set_sensitive)); - action->signal_set_name.connect(sigc::mem_fun(*item, &ContextMenu::set_name)); - - if (!action->sensitive) { - item->set_sensitive(FALSE); - } - - if (action->image) { - sp_ui_menuitem_add_icon((GtkWidget*)item->gobj(), action->image); - } - item->set_events(Gdk::KEY_PRESS_MASK); - item->signal_activate().connect(sigc::bind(sigc::ptr_fun(sp_ui_menu_activate),item,action)); - item->signal_select().connect(sigc::bind(sigc::ptr_fun(sp_ui_menu_select_action),item,action)); - item->signal_deselect().connect(sigc::bind(sigc::ptr_fun(sp_ui_menu_deselect_action),item,action)); - item->show(); - append(*item); - } -} - -void ContextMenu::MakeObjectMenu(void) -{ -// GObjectClass *klass = G_OBJECT_GET_CLASS(_object); //to deduce the object's type from its class -// -// if (G_TYPE_CHECK_CLASS_TYPE(klass, SP_TYPE_ITEM)) -// { -// MakeItemMenu (); -// } -// if (G_TYPE_CHECK_CLASS_TYPE(klass, SP_TYPE_GROUP)) -// { -// MakeGroupMenu(); -// } -// if (G_TYPE_CHECK_CLASS_TYPE(klass, SP_TYPE_ANCHOR)) -// { -// MakeAnchorMenu(); -// } -// if (G_TYPE_CHECK_CLASS_TYPE(klass, SP_TYPE_IMAGE)) -// { -// MakeImageMenu(); -// } -// if (G_TYPE_CHECK_CLASS_TYPE(klass, SP_TYPE_SHAPE)) -// { -// MakeShapeMenu(); -// } -// if (G_TYPE_CHECK_CLASS_TYPE(klass, SP_TYPE_TEXT)) -// { -// MakeTextMenu(); -// } - - if (SP_IS_ITEM(_object)) { - MakeItemMenu(); - } - - if (SP_IS_GROUP(_object)) { - MakeGroupMenu(); - } - - if (SP_IS_ANCHOR(_object)) { - MakeAnchorMenu(); - } - - if (SP_IS_IMAGE(_object)) { - MakeImageMenu(); - } - - if (SP_IS_SHAPE(_object)) { - MakeShapeMenu(); - } - - if (SP_IS_TEXT(_object)) { - MakeTextMenu(); - } -} - -void ContextMenu::MakeItemMenu (void) -{ - Gtk::MenuItem* mi; - - /* Item dialog */ - mi = Gtk::manage(new Gtk::MenuItem(_("_Object Properties..."),1)); - mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ItemProperties)); - mi->show(); - append(*mi);//insert(*mi,positionOfLastDialog++); - - AddSeparator(); - - /* Select item */ - if (Inkscape::Verb::getbyid( "org.inkscape.followlink" )) { - mi = Gtk::manage(new Gtk::MenuItem(_("_Select This"), 1)); - if (_desktop->selection->includes(_item)) { - mi->set_sensitive(FALSE); - } else { - mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ItemSelectThis)); - } - mi->show(); - append(*mi); - } - - - mi = Gtk::manage(new Gtk::MenuItem(_("Select Same"))); - mi->show(); - Gtk::Menu *select_same_submenu = Gtk::manage(new Gtk::Menu()); - if (_desktop->selection->isEmpty()) { - mi->set_sensitive(FALSE); - } - mi->set_submenu(*select_same_submenu); - append(*mi); - - /* Select same fill and stroke */ - mi = Gtk::manage(new Gtk::MenuItem(_("Fill and Stroke"), 1)); - mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::SelectSameFillStroke)); - mi->set_sensitive(!SP_IS_ANCHOR(_item)); - mi->show(); - select_same_submenu->append(*mi); - - /* Select same fill color */ - mi = Gtk::manage(new Gtk::MenuItem(_("Fill Color"), 1)); - mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::SelectSameFillColor)); - mi->set_sensitive(!SP_IS_ANCHOR(_item)); - mi->show(); - select_same_submenu->append(*mi); - - /* Select same stroke color */ - mi = Gtk::manage(new Gtk::MenuItem(_("Stroke Color"), 1)); - mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::SelectSameStrokeColor)); - mi->set_sensitive(!SP_IS_ANCHOR(_item)); - mi->show(); - select_same_submenu->append(*mi); - - /* Select same stroke style */ - mi = Gtk::manage(new Gtk::MenuItem(_("Stroke Style"), 1)); - mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::SelectSameStrokeStyle)); - mi->set_sensitive(!SP_IS_ANCHOR(_item)); - mi->show(); - select_same_submenu->append(*mi); - - /* Select same stroke style */ - mi = Gtk::manage(new Gtk::MenuItem(_("Object type"), 1)); - mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::SelectSameObjectType)); - mi->set_sensitive(!SP_IS_ANCHOR(_item)); - mi->show(); - select_same_submenu->append(*mi); - - /* Move to layer */ - mi = Gtk::manage(new Gtk::MenuItem(_("_Move to layer ..."), 1)); - if (_desktop->selection->isEmpty()) { - mi->set_sensitive(FALSE); - } else { - mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ItemMoveTo)); - } - mi->show(); - append(*mi); - - /* Create link */ - mi = Gtk::manage(new Gtk::MenuItem(_("Create _Link"), 1)); - mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ItemCreateLink)); - mi->set_sensitive(!SP_IS_ANCHOR(_item)); - mi->show(); - append(*mi); - - bool ClipRefOK=false; - bool MaskRefOK=false; - if (_item){ - if (_item->clip_ref){ - if (_item->clip_ref->getObject()){ - ClipRefOK=true; - } - } - } - if (_item){ - if (_item->mask_ref){ - if (_item->mask_ref->getObject()){ - MaskRefOK=true; - } - } - } - /* Set mask */ - mi = Gtk::manage(new Gtk::MenuItem(_("Set Mask"), 1)); - mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::SetMask)); - if (ClipRefOK || MaskRefOK) { - mi->set_sensitive(FALSE); - } else { - mi->set_sensitive(TRUE); - } - mi->show(); - append(*mi); - - /* Release mask */ - mi = Gtk::manage(new Gtk::MenuItem(_("Release Mask"), 1)); - mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ReleaseMask)); - if (MaskRefOK) { - mi->set_sensitive(TRUE); - } else { - mi->set_sensitive(FALSE); - } - mi->show(); - append(*mi); - - /*SSet Clip Group */ - mi = Gtk::manage(new Gtk::MenuItem(_("Create Clip G_roup"),1)); - mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::CreateGroupClip)); - mi->set_sensitive(TRUE); - mi->show(); - append(*mi); - - /* Set Clip */ - mi = Gtk::manage(new Gtk::MenuItem(_("Set Cl_ip"), 1)); - mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::SetClip)); - if (ClipRefOK || MaskRefOK) { - mi->set_sensitive(FALSE); - } else { - mi->set_sensitive(TRUE); - } - mi->show(); - append(*mi); - - /* Release Clip */ - mi = Gtk::manage(new Gtk::MenuItem(_("Release C_lip"), 1)); - mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ReleaseClip)); - if (ClipRefOK) { - mi->set_sensitive(TRUE); - } else { - mi->set_sensitive(FALSE); - } - mi->show(); - append(*mi); - - /* Group */ - mi = Gtk::manage(new Gtk::MenuItem(_("_Group"), 1)); - mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ActivateGroup)); - if (_desktop->selection->isEmpty() || _desktop->selection->single()) { - mi->set_sensitive(FALSE); - } else { - mi->set_sensitive(TRUE); - } - mi->show(); - append(*mi); -} - -void ContextMenu::SelectSameFillStroke(void) -{ - sp_select_same_fill_stroke_style(_desktop, true, true, true); -} - -void ContextMenu::SelectSameFillColor(void) -{ - sp_select_same_fill_stroke_style(_desktop, true, false, false); -} - -void ContextMenu::SelectSameStrokeColor(void) -{ - sp_select_same_fill_stroke_style(_desktop, false, true, false); -} - -void ContextMenu::SelectSameStrokeStyle(void) -{ - sp_select_same_stroke_style(_desktop); -} - -void ContextMenu::SelectSameObjectType(void) -{ - sp_select_same_object_type(_desktop); -} - -void ContextMenu::ItemProperties(void) -{ - _desktop->selection->set(_item); - _desktop->_dlg_mgr->showDialog("ObjectProperties"); -} - -void ContextMenu::ItemSelectThis(void) -{ - _desktop->selection->set(_item); -} - -void ContextMenu::ItemMoveTo(void) -{ - Inkscape::UI::Dialogs::LayerPropertiesDialog::showMove(_desktop, _desktop->currentLayer()); -} - - - -void ContextMenu::ItemCreateLink(void) -{ - Inkscape::XML::Document *xml_doc = _desktop->doc()->getReprDoc(); - Inkscape::XML::Node *repr = xml_doc->createElement("svg:a"); - _item->parent->getRepr()->addChild(repr, _item->getRepr()); - SPObject *object = _item->document->getObjectByRepr(repr); - g_return_if_fail(SP_IS_ANCHOR(object)); - - const char *id = _item->getRepr()->attribute("id"); - Inkscape::XML::Node *child = _item->getRepr()->duplicate(xml_doc); - _item->deleteObject(false); - repr->addChild(child, NULL); - child->setAttribute("id", id); - - Inkscape::GC::release(repr); - Inkscape::GC::release(child); - - DocumentUndo::done(object->document, SP_VERB_NONE, _("Create link")); - - _desktop->selection->set(SP_ITEM(object)); - _desktop->_dlg_mgr->showDialog("ObjectAttributes"); -} - -void ContextMenu::SetMask(void) -{ - sp_selection_set_mask(_desktop, false, false); -} - -void ContextMenu::ReleaseMask(void) -{ - sp_selection_unset_mask(_desktop, false); -} - -void ContextMenu::CreateGroupClip(void) -{ - sp_selection_set_clipgroup(_desktop); -} - -void ContextMenu::SetClip(void) -{ - sp_selection_set_mask(_desktop, true, false); -} - - -void ContextMenu::ReleaseClip(void) -{ - sp_selection_unset_mask(_desktop, true); -} - -void ContextMenu::MakeGroupMenu(void) -{ - /* Ungroup */ - Gtk::MenuItem* mi = Gtk::manage(new Gtk::MenuItem(_("_Ungroup"), 1)); - mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ActivateUngroup)); - mi->show(); - append(*mi); -} - -void ContextMenu::ActivateGroup(void) -{ - sp_selection_group(_desktop->selection, _desktop); -} - -void ContextMenu::ActivateUngroup(void) -{ - GSList *children = NULL; - - sp_item_group_ungroup(static_cast(_item), &children); - _desktop->selection->setList(children); - g_slist_free(children); -} - -void ContextMenu::MakeAnchorMenu(void) -{ - Gtk::MenuItem* mi; - - /* Link dialog */ - mi = Gtk::manage(new Gtk::MenuItem(_("Link _Properties..."), 1)); - mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::AnchorLinkProperties)); - mi->show(); - insert(*mi,positionOfLastDialog++); - - /* Select item */ - mi = Gtk::manage(new Gtk::MenuItem(_("_Follow Link"), 1)); - mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::AnchorLinkFollow)); - mi->show(); - append(*mi); - - /* Reset transformations */ - mi = Gtk::manage(new Gtk::MenuItem(_("_Remove Link"), 1)); - mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::AnchorLinkRemove)); - mi->show(); - append(*mi); -} - -void ContextMenu::AnchorLinkProperties(void) -{ - _desktop->_dlg_mgr->showDialog("ObjectAttributes"); -} - -void ContextMenu::AnchorLinkFollow(void) -{ - - if (_desktop->selection->isEmpty()) { - _desktop->selection->set(_item); - } - // Opening the selected links with a python extension - Inkscape::Verb *verb = Inkscape::Verb::getbyid( "org.inkscape.followlink" ); - if (verb) { - SPAction *action = verb->get_action(Inkscape::ActionContext(_desktop)); - if (action) { - sp_action_perform(action, NULL); - } - } -} - -void ContextMenu::AnchorLinkRemove(void) -{ - GSList *children = NULL; - sp_item_group_ungroup(static_cast(_item), &children, false); - DocumentUndo::done(_desktop->doc(), SP_VERB_NONE, _("Remove link")); - g_slist_free(children); -} - -void ContextMenu::MakeImageMenu (void) -{ - Gtk::MenuItem* mi; - Inkscape::XML::Node *ir = _object->getRepr(); - const gchar *href = ir->attribute("xlink:href"); - - /* Image properties */ - mi = Gtk::manage(new Gtk::MenuItem(_("Image _Properties..."), 1)); - mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ImageProperties)); - mi->show(); - insert(*mi,positionOfLastDialog++); - - /* Edit externally */ - mi = Gtk::manage(new Gtk::MenuItem(_("Edit Externally..."), 1)); - mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ImageEdit)); - mi->show(); - insert(*mi,positionOfLastDialog++); - if ( (!href) || ((strncmp(href, "data:", 5) == 0)) ) { - mi->set_sensitive( FALSE ); - } - - /* Trace Bitmap */ - mi = Gtk::manage(new Gtk::MenuItem(_("_Trace Bitmap..."), 1)); - mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ImageTraceBitmap)); - mi->show(); - insert(*mi,positionOfLastDialog++); - if (_desktop->selection->isEmpty()) { - mi->set_sensitive(FALSE); - } - - /* Trace Pixel Art */ - mi = Gtk::manage(new Gtk::MenuItem(_("Trace Pixel Art"), 1)); - mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ImageTracePixelArt)); - mi->show(); - insert(*mi,positionOfLastDialog++); - if (_desktop->selection->isEmpty()) { - mi->set_sensitive(FALSE); - } - - /* Embed image */ - if (Inkscape::Verb::getbyid( "org.ekips.filter.embedselectedimages" )) { - mi = Gtk::manage(new Gtk::MenuItem(C_("Context menu", "Embed Image"))); - mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ImageEmbed)); - mi->show(); - insert(*mi,positionOfLastDialog++); - if ( (!href) || ((strncmp(href, "data:", 5) == 0)) ) { - mi->set_sensitive( FALSE ); - } - } - - /* Extract image */ - if (Inkscape::Verb::getbyid( "org.ekips.filter.extractimage" )) { - mi = Gtk::manage(new Gtk::MenuItem(C_("Context menu", "Extract Image..."))); - mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ImageExtract)); - mi->show(); - insert(*mi,positionOfLastDialog++); - if ( (!href) || ((strncmp(href, "data:", 5) != 0)) ) { - mi->set_sensitive( FALSE ); - } - } -} - -void ContextMenu::ImageProperties(void) -{ - _desktop->_dlg_mgr->showDialog("ObjectAttributes"); -} - -Glib::ustring ContextMenu::getImageEditorName() { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - Glib::ustring value; - Glib::ustring choices = prefs->getString("/options/bitmapeditor/value"); - if (!choices.empty()) { - value = choices; - } - else { - value = "gimp"; - } - return value; -} - -void ContextMenu::ImageEdit(void) -{ - if (_desktop->selection->isEmpty()) { - _desktop->selection->set(_item); - } - - GSList const *selected = _desktop->selection->itemList(); - - GError* errThing = 0; - Glib::ustring cmdline = getImageEditorName(); - Glib::ustring name; - Glib::ustring fullname; - -#ifdef WIN32 - // g_spawn_command_line_sync parsing is done according to Unix shell rules, - // not Windows command interpreter rules. Thus we need to enclose the - // executable path with single quotes. - int index = cmdline.find(".exe"); - if ( index < 0 ) index = cmdline.find(".bat"); - if ( index < 0 ) index = cmdline.find(".com"); - if ( index >= 0 ) { - Glib::ustring editorBin = cmdline.substr(0, index + 4).c_str(); - Glib::ustring args = cmdline.substr(index + 4, cmdline.length()).c_str(); - editorBin.insert(0, "'"); - editorBin.append("'"); - cmdline = editorBin; - cmdline.append(args); - } else { - // Enclose the whole command line if no executable path can be extracted. - cmdline.insert(0, "'"); - cmdline.append("'"); - } -#endif - - for (GSList const *iter = selected; iter != NULL; iter = iter->next) { - Inkscape::XML::Node *ir = SP_ITEM(iter->data)->getRepr(); - const gchar *href = ir->attribute("xlink:href"); - - if (strncmp (href,"file:",5) == 0) { - // URI to filename conversion - name = g_filename_from_uri(href, NULL, NULL); - } else { - name.append(href); - } - - if (Glib::path_is_absolute(name)) { - fullname = name; - } else if (SP_ACTIVE_DOCUMENT->getBase()) { - fullname = Glib::build_filename(SP_ACTIVE_DOCUMENT->getBase(), name); - } else { - fullname = Glib::build_filename(Glib::get_current_dir(), name); - } - - cmdline.append(" '"); - cmdline.append(fullname.c_str()); - cmdline.append("'"); - } - - //g_warning("##Command line: %s\n", cmdline.c_str()); - - g_spawn_command_line_async(cmdline.c_str(), &errThing); - - if ( errThing ) { - g_warning("Problem launching editor (%d). %s", errThing->code, errThing->message); - (_desktop->messageStack())->flash(Inkscape::ERROR_MESSAGE, errThing->message); - g_error_free(errThing); - errThing = 0; - } -} - -void ContextMenu::ImageTraceBitmap(void) -{ - inkscape_dialogs_unhide(); - _desktop->_dlg_mgr->showDialog("Trace"); -} - -void ContextMenu::ImageTracePixelArt(void) -{ - inkscape_dialogs_unhide(); - _desktop->_dlg_mgr->showDialog("PixelArt"); -} - -void ContextMenu::ImageEmbed(void) -{ - if (_desktop->selection->isEmpty()) { - _desktop->selection->set(_item); - } - - Inkscape::Verb *verb = Inkscape::Verb::getbyid( "org.ekips.filter.embedselectedimages" ); - if (verb) { - SPAction *action = verb->get_action(Inkscape::ActionContext(_desktop)); - if (action) { - sp_action_perform(action, NULL); - } - } -} - -void ContextMenu::ImageExtract(void) -{ - if (_desktop->selection->isEmpty()) { - _desktop->selection->set(_item); - } - - Inkscape::Verb *verb = Inkscape::Verb::getbyid( "org.ekips.filter.extractimage" ); - if (verb) { - SPAction *action = verb->get_action(Inkscape::ActionContext(_desktop)); - if (action) { - sp_action_perform(action, NULL); - } - } -} - -void ContextMenu::MakeShapeMenu (void) -{ - Gtk::MenuItem* mi; - - /* Item dialog */ - mi = Gtk::manage(new Gtk::MenuItem(_("_Fill and Stroke..."), 1)); - mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::FillSettings)); - mi->show(); - insert(*mi,positionOfLastDialog++); -} - -void ContextMenu::FillSettings(void) -{ - if (_desktop->selection->isEmpty()) { - _desktop->selection->set(_item); - } - - _desktop->_dlg_mgr->showDialog("FillAndStroke"); -} - -void ContextMenu::MakeTextMenu (void) -{ - Gtk::MenuItem* mi; - - /* Fill and Stroke dialog */ - mi = Gtk::manage(new Gtk::MenuItem(_("_Fill and Stroke..."), 1)); - mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::FillSettings)); - mi->show(); - insert(*mi,positionOfLastDialog++); - - /* Edit Text dialog */ - mi = Gtk::manage(new Gtk::MenuItem(_("_Text and Font..."), 1)); - mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::TextSettings)); - mi->show(); - insert(*mi,positionOfLastDialog++); - - /* Spellcheck dialog */ - mi = Gtk::manage(new Gtk::MenuItem(_("Check Spellin_g..."), 1)); - mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::SpellcheckSettings)); - mi->show(); - insert(*mi,positionOfLastDialog++); -} - -void ContextMenu::TextSettings (void) -{ - if (_desktop->selection->isEmpty()) { - _desktop->selection->set(_item); - } - - _desktop->_dlg_mgr->showDialog("TextFont"); -} - -void ContextMenu::SpellcheckSettings (void) -{ - if (_desktop->selection->isEmpty()) { - _desktop->selection->set(_item); - } - - _desktop->_dlg_mgr->showDialog("SpellCheck"); -} - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/interface.h b/src/interface.h deleted file mode 100644 index 6fb74046f..000000000 --- a/src/interface.h +++ /dev/null @@ -1,277 +0,0 @@ -#ifndef SEEN_SP_INTERFACE_H -#define SEEN_SP_INTERFACE_H - -/* - * Main UI stuff - * - * Authors: - * Lauris Kaplinski - * Frank Felfe - * Abhishek Sharma - * Kris De Gussem - * - * Copyright (C) 2012 Kris De Gussem - * Copyright (C) 1999-2002 authors - * Copyright (C) 2001-2002 Ximian, Inc. - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -//#ifdef HAVE_CONFIG_H -//# include -//#endif - -#include - -class SPItem; -class SPObject; -class SPDesktop; -class SPViewWidget; - -namespace Gtk { -class SeparatorMenuItem; -} - -namespace Inkscape { - -class Verb; - -namespace UI { -namespace View { -class View; -} // namespace View -} // namespace UI -} // namespace Inkscape - -/** - * Create a new document window. - */ -void sp_create_window (SPViewWidget *vw, bool editable); - -/** - * \param widget unused - */ -void sp_ui_close_view (GtkWidget *widget); - -void sp_ui_new_view (void); - -/** - * @todo TODO: not yet working. To be re-enabled (by adding to menu) once it works. - */ -void sp_ui_new_view_preview (void); - -/** - * This function is called to exit the program, and iterates through all - * open document view windows, attempting to close each in turn. If the - * view has unsaved information, the user will be prompted to save, - * discard, or cancel. - * - * Returns FALSE if the user cancels the close_all operation, TRUE - * otherwise. - */ -unsigned int sp_ui_close_all (void); - -/** - * Build the main tool bar. - * - * Currently the main tool bar is built as a dynamic XML menu using - * \c sp_ui_build_dyn_menus. This function builds the bar, and then - * pass it to get items attached to it. - * - * @param view View to build the bar for - */ -GtkWidget *sp_ui_main_menubar (Inkscape::UI::View::View *view); - -void sp_menu_append_recent_documents (GtkWidget *menu); -void sp_ui_dialog_title_string (Inkscape::Verb * verb, char* c); - -Glib::ustring getLayoutPrefPath( Inkscape::UI::View::View *view ); - -/** - * - */ -void sp_ui_error_dialog (char const* message); -bool sp_ui_overwrite_file (char const* filename); - - -/** - * Implements the Inkscape context menu. - * - * For the context menu implementation, the ContextMenu class stores the object - * that was selected in a private data member. This should be farely safe to do - * and a pointer to the SPItem as well as SPObject class are kept. - * All callbacks of the context menu entries are implemented as private - * functions. - * - * @todo add callbacks to destroy the context menu when it is closed (=key or mouse button pressed out of the scope of the context menu) - */ -class ContextMenu : public Gtk::Menu -{ - public: - /** - * The ContextMenu constructor contains all code to create and show the - * menu entries (aka child widgets). - * - * @param desktop pointer to the desktop the user is currently working on. - * @param item SPItem pointer to the object selected at the time the ContextMenu is created. - */ - ContextMenu(SPDesktop *desktop, SPItem *item); - ~ContextMenu(void); - - private: - SPItem *_item; // pointer to the object selected at the time the ContextMenu is created - SPObject *_object; // pointer to the object selected at the time the ContextMenu is created - SPDesktop *_desktop; //pointer to the desktop the user was currently working on at the time the ContextMenu is created - - int positionOfLastDialog; - - Gtk::MenuItem MIGroup; //menu entry to enter a group - Gtk::MenuItem MIParent; //menu entry to leave a group - - /** - * auxiliary function that adds a separator line in the context menu - */ - Gtk::SeparatorMenuItem* AddSeparator(void); - - /** - * c++ified version of sp_ui_menu_append_item. - * - * @see sp_ui_menu_append_item_from_verb and synchronize/drop that function when c++ifying other code in interface.cpp - */ - void AppendItemFromVerb(Inkscape::Verb *verb); - - /** - * main function which is responsible for creating the context sensitive menu items, - * calls subfunctions below to create the menu entry widgets. - */ - void MakeObjectMenu (void); - /** - * creates menu entries for an SP_TYPE_ITEM object - */ - void MakeItemMenu (void); - /** - * creates menu entries for a grouped object - */ - void MakeGroupMenu (void); - /** - * creates menu entries for an anchor object - */ - void MakeAnchorMenu (void); - /** - * creates menu entries for a bitmap image object - */ - void MakeImageMenu (void); - /** - * creates menu entries for a shape object - */ - void MakeShapeMenu (void); - /** - * creates menu entries for a text object - */ - void MakeTextMenu (void); - - void EnterGroup(Gtk::MenuItem* mi); - void LeaveGroup(void); - ////////////////////////////////////////// - //callbacks for the context menu entries of an SP_TYPE_ITEM object - void ItemProperties(void); - void ItemSelectThis(void); - void ItemMoveTo(void); - void SelectSameFillStroke(void); - void SelectSameFillColor(void); - void SelectSameStrokeColor(void); - void SelectSameStrokeStyle(void); - void SelectSameObjectType(void); - void ItemCreateLink(void); - void CreateGroupClip(void); - void SetMask(void); - void ReleaseMask(void); - void SetClip(void); - void ReleaseClip(void); - ////////////////////////////////////////// - - - /** - * callback, is executed on clicking the anchor "Group" and "Ungroup" menu entry - */ - void ActivateUngroup(void); - void ActivateGroup(void); - - void AnchorLinkProperties(void); - /** - * placeholder for callback to be executed on clicking the anchor "Follow link" context menu entry - * @todo add code to follow link externally - */ - void AnchorLinkFollow(void); - - /** - * callback, is executed on clicking the anchor "Link remove" menu entry - */ - void AnchorLinkRemove(void); - - - /** - * callback, opens the image properties dialog and is executed on clicking the context menu entry with similar name - */ - void ImageProperties(void); - - /** - * callback, is executed on clicking the image "Edit Externally" menu entry - */ - void ImageEdit(void); - - /** - * auxiliary function that loads the external image editor name from the settings. - */ - Glib::ustring getImageEditorName(); - - /** - * callback, is executed on clicking the "Embed Image" menu entry - */ - void ImageEmbed(void); - - /** - * callback, is executed on clicking the "Trace Bitmap" menu entry - */ - void ImageTraceBitmap(void); - - /** - * callback, is executed on clicking the "Trace Pixel Art" menu entry - */ - void ImageTracePixelArt(void); - - /** - * callback, is executed on clicking the "Extract Image" menu entry - */ - void ImageExtract(void); - - - /** - * callback, is executed on clicking the "Fill and Stroke" menu entry - */ - void FillSettings(void); - - - /** - * callback, is executed on clicking the "Text and Font" menu entry - */ - void TextSettings(void); - - /** - * callback, is executed on clicking the "Check spelling" menu entry - */ - void SpellcheckSettings(void); -}; - -#endif // SEEN_SP_INTERFACE_H - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/main.cpp b/src/main.cpp index 517ba0506..caec66b05 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -64,7 +64,7 @@ #include "layer-model.h" #include "selection.h" #include "sp-object.h" -#include "interface.h" +#include "ui/interface.h" #include "print.h" #include "color.h" #include "sp-item.h" diff --git a/src/ui/Makefile_insert b/src/ui/Makefile_insert index 94064d0cf..4c6b49ed6 100644 --- a/src/ui/Makefile_insert +++ b/src/ui/Makefile_insert @@ -9,6 +9,8 @@ ink_common_sources += \ ui/dialog-events.cpp \ ui/dialog-events.h \ ui/icon-names.h \ + ui/interface.cpp \ + ui/interface.h \ ui/previewable.h \ ui/previewfillable.h \ ui/previewholder.cpp \ diff --git a/src/ui/dialog/clonetiler.cpp b/src/ui/dialog/clonetiler.cpp index d9e2c03ba..1d6d0403e 100644 --- a/src/ui/dialog/clonetiler.cpp +++ b/src/ui/dialog/clonetiler.cpp @@ -38,7 +38,7 @@ #include "util/units.h" #include "helper/window.h" #include "inkscape.h" -#include "interface.h" +#include "ui/interface.h" #include "macros.h" #include "message-stack.h" #include "preferences.h" diff --git a/src/ui/dialog/dialog.cpp b/src/ui/dialog/dialog.cpp index 4f0d9fbe1..213965a18 100644 --- a/src/ui/dialog/dialog.cpp +++ b/src/ui/dialog/dialog.cpp @@ -28,7 +28,7 @@ #include "desktop-handles.h" #include "shortcuts.h" #include "preferences.h" -#include "interface.h" +#include "ui/interface.h" #include "verbs.h" #include "ui/tool/event-utils.h" diff --git a/src/ui/dialog/dock-behavior.cpp b/src/ui/dialog/dock-behavior.cpp index f65b298c9..50a6db208 100644 --- a/src/ui/dialog/dock-behavior.cpp +++ b/src/ui/dialog/dock-behavior.cpp @@ -18,7 +18,7 @@ #include "dock-behavior.h" #include "inkscape.h" #include "desktop.h" -#include "interface.h" +#include "ui/interface.h" #include "widgets/icon.h" #include "ui/widget/dock.h" #include "verbs.h" diff --git a/src/ui/dialog/export.cpp b/src/ui/dialog/export.cpp index cd8fdbd92..a4d8801f7 100644 --- a/src/ui/dialog/export.cpp +++ b/src/ui/dialog/export.cpp @@ -65,7 +65,7 @@ #include "ui/dialog-events.h" #include "preferences.h" #include "verbs.h" -#include "interface.h" +#include "ui/interface.h" #include "sp-root.h" #include "extension/output.h" diff --git a/src/ui/dialog/extension-editor.cpp b/src/ui/dialog/extension-editor.cpp index cd5491c24..9bdddc0e0 100644 --- a/src/ui/dialog/extension-editor.cpp +++ b/src/ui/dialog/extension-editor.cpp @@ -25,7 +25,7 @@ #include "verbs.h" #include "preferences.h" -#include "interface.h" +#include "ui/interface.h" #include "extension/extension.h" #include "extension/db.h" diff --git a/src/ui/dialog/filedialogimpl-gtkmm.cpp b/src/ui/dialog/filedialogimpl-gtkmm.cpp index 5778b44db..511237f4d 100644 --- a/src/ui/dialog/filedialogimpl-gtkmm.cpp +++ b/src/ui/dialog/filedialogimpl-gtkmm.cpp @@ -23,7 +23,7 @@ #include "filedialogimpl-gtkmm.h" #include "ui/dialog-events.h" -#include "interface.h" +#include "ui/interface.h" #include "io/sys.h" #include "path-prefix.h" #include "preferences.h" diff --git a/src/ui/dialog/find.cpp b/src/ui/dialog/find.cpp index 9b814bb9f..1a4823e4a 100644 --- a/src/ui/dialog/find.cpp +++ b/src/ui/dialog/find.cpp @@ -33,7 +33,7 @@ #include "ui/dialog-events.h" #include "verbs.h" -#include "interface.h" +#include "ui/interface.h" #include "preferences.h" #include "sp-text.h" #include "sp-flowtext.h" diff --git a/src/ui/dialog/floating-behavior.cpp b/src/ui/dialog/floating-behavior.cpp index f286588b2..11db14801 100644 --- a/src/ui/dialog/floating-behavior.cpp +++ b/src/ui/dialog/floating-behavior.cpp @@ -29,7 +29,7 @@ #include "inkscape.h" #include "desktop.h" #include "ui/dialog-events.h" -#include "interface.h" +#include "ui/interface.h" #include "preferences.h" #include "verbs.h" diff --git a/src/ui/dialog/ocaldialogs.cpp b/src/ui/dialog/ocaldialogs.cpp index 607087f6d..c4dd9df98 100644 --- a/src/ui/dialog/ocaldialogs.cpp +++ b/src/ui/dialog/ocaldialogs.cpp @@ -25,7 +25,7 @@ #include "path-prefix.h" #include "filedialogimpl-gtkmm.h" -#include "interface.h" +#include "ui/interface.h" #include "gc-core.h" #include "ui/dialog-events.h" #include "io/sys.h" diff --git a/src/ui/dialog/spellcheck.cpp b/src/ui/dialog/spellcheck.cpp index a887a7355..b8436ebf1 100644 --- a/src/ui/dialog/spellcheck.cpp +++ b/src/ui/dialog/spellcheck.cpp @@ -25,7 +25,7 @@ #include "desktop-handles.h" #include "tools-switch.h" #include "ui/tools/text-tool.h" -#include "interface.h" +#include "ui/interface.h" #include "preferences.h" #include "sp-text.h" #include "sp-flowtext.h" diff --git a/src/ui/dialog/template-load-tab.cpp b/src/ui/dialog/template-load-tab.cpp index d75f81456..13cb01eef 100644 --- a/src/ui/dialog/template-load-tab.cpp +++ b/src/ui/dialog/template-load-tab.cpp @@ -24,7 +24,7 @@ #include "extension/db.h" #include "extension/effect.h" #include "inkscape.h" -#include "interface.h" +#include "ui/interface.h" #include "file.h" #include "path-prefix.h" #include "preferences.h" diff --git a/src/ui/dialog/text-edit.cpp b/src/ui/dialog/text-edit.cpp index 9996fc0f9..0f4a6f7f1 100644 --- a/src/ui/dialog/text-edit.cpp +++ b/src/ui/dialog/text-edit.cpp @@ -51,7 +51,7 @@ extern "C" { #include "ui/icon-names.h" #include "preferences.h" #include "verbs.h" -#include "interface.h" +#include "ui/interface.h" #include "svg/css-ostringstream.h" #include "widgets/icon.h" #include "widgets/font-selector.h" diff --git a/src/ui/dialog/xml-tree.cpp b/src/ui/dialog/xml-tree.cpp index 9a8c188b2..7ab6c78ba 100644 --- a/src/ui/dialog/xml-tree.cpp +++ b/src/ui/dialog/xml-tree.cpp @@ -30,7 +30,7 @@ #include "ui/tools/tool-base.h" #include "helper/window.h" #include "inkscape.h" -#include "interface.h" +#include "ui/interface.h" #include "macros.h" #include "message-context.h" #include "message-stack.h" diff --git a/src/ui/interface.cpp b/src/ui/interface.cpp new file mode 100644 index 000000000..7830a8de1 --- /dev/null +++ b/src/ui/interface.cpp @@ -0,0 +1,2230 @@ +/** + * @file + * Main UI stuff. + */ +/* Authors: + * Lauris Kaplinski + * Frank Felfe + * bulia byak + * Jon A. Cruz + * Abhishek Sharma + * Kris De Gussem + * + * Copyright (C) 2012 Kris De Gussem + * Copyright (C) 2010 authors + * Copyright (C) 1999-2005 authors + * Copyright (C) 2004 David Turner + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "ui/dialog/dialog-manager.h" +#include +#include "file.h" +#include +#include + +#include "inkscape-private.h" +#include "extension/db.h" +#include "extension/effect.h" +#include "extension/input.h" +#include "widgets/icon.h" +#include "preferences.h" +#include "path-prefix.h" +#include "shortcuts.h" +#include "document.h" +#include "desktop-handles.h" +#include "ui/interface.h" +#include "desktop.h" +#include "selection.h" +#include "selection-chemistry.h" +#include "svg-view-widget.h" +#include "widgets/desktop-widget.h" +#include "sp-item-group.h" +#include "sp-text.h" +#include "sp-gradient.h" +#include "sp-flowtext.h" +#include "sp-namedview.h" +#include "sp-root.h" +#include "ui/view/view.h" +#include "helper/action.h" +#include "helper/action-context.h" +#include "helper/gnome-utils.h" +#include "helper/window.h" +#include "io/sys.h" +#include "ui/dialog-events.h" +#include "message-context.h" +#include "ui/uxmanager.h" +#include "ui/clipboard.h" + +#include "display/sp-canvas.h" +#include "color.h" +#include "svg/svg-color.h" +#include "desktop-style.h" +#include "style.h" +#include "ui/tools/tool-base.h" +#include "gradient-drag.h" +#include "widgets/ege-paint-def.h" +#include "document-undo.h" +#include "sp-anchor.h" +#include "sp-clippath.h" +#include "sp-image.h" +#include "sp-item.h" +#include "sp-mask.h" +#include "message-stack.h" +#include "ui/dialog/layer-properties.h" + +#include + +#include + +using Inkscape::DocumentUndo; + +/* Drag and Drop */ +typedef enum { + URI_LIST, + SVG_XML_DATA, + SVG_DATA, + PNG_DATA, + JPEG_DATA, + IMAGE_DATA, + APP_X_INKY_COLOR, + APP_X_COLOR, + APP_OSWB_COLOR, + APP_X_INK_PASTE +} ui_drop_target_info; + +static GtkTargetEntry ui_drop_target_entries [] = { + {(gchar *)"text/uri-list", 0, URI_LIST }, + {(gchar *)"image/svg+xml", 0, SVG_XML_DATA }, + {(gchar *)"image/svg", 0, SVG_DATA }, + {(gchar *)"image/png", 0, PNG_DATA }, + {(gchar *)"image/jpeg", 0, JPEG_DATA }, +#if ENABLE_MAGIC_COLORS + {(gchar *)"application/x-inkscape-color", 0, APP_X_INKY_COLOR}, +#endif // ENABLE_MAGIC_COLORS + {(gchar *)"application/x-oswb-color", 0, APP_OSWB_COLOR }, + {(gchar *)"application/x-color", 0, APP_X_COLOR }, + {(gchar *)"application/x-inkscape-paste", 0, APP_X_INK_PASTE } +}; + +static GtkTargetEntry *completeDropTargets = 0; +static int completeDropTargetsCount = 0; +static bool temporarily_block_actions = false; + +#define ENTRIES_SIZE(n) sizeof(n)/sizeof(n[0]) +static guint nui_drop_target_entries = ENTRIES_SIZE(ui_drop_target_entries); +static void sp_ui_import_files(gchar *buffer); +static void sp_ui_import_one_file(char const *filename); +static void sp_ui_import_one_file_with_check(gpointer filename, gpointer unused); +static void sp_ui_drag_data_received(GtkWidget *widget, + GdkDragContext *drag_context, + gint x, gint y, + GtkSelectionData *data, + guint info, + guint event_time, + gpointer user_data); +static void sp_ui_drag_motion( GtkWidget *widget, + GdkDragContext *drag_context, + gint x, gint y, + GtkSelectionData *data, + guint info, + guint event_time, + gpointer user_data ); +static void sp_ui_drag_leave( GtkWidget *widget, + GdkDragContext *drag_context, + guint event_time, + gpointer user_data ); +static void sp_ui_menu_item_set_name(GtkWidget *data, + Glib::ustring const &name); +static void sp_recent_open(GtkRecentChooser *, gpointer); + +static void injectRenamedIcons(); + +static const int MIN_ONSCREEN_DISTANCE = 50; + +void +sp_create_window(SPViewWidget *vw, bool editable) +{ + g_return_if_fail(vw != NULL); + g_return_if_fail(SP_IS_VIEW_WIDGET(vw)); + + Gtk::Window *win = Inkscape::UI::window_new("", TRUE); + + gtk_container_add(GTK_CONTAINER(win->gobj()), GTK_WIDGET(vw)); + gtk_widget_show(GTK_WIDGET(vw)); + + if (editable) { + g_object_set_data(G_OBJECT(vw), "window", win); + + SPDesktopWidget *desktop_widget = reinterpret_cast(vw); + SPDesktop* desktop = desktop_widget->desktop; + + desktop_widget->window = win; + + win->set_data("desktop", desktop); + win->set_data("desktopwidget", desktop_widget); + + win->signal_delete_event().connect(sigc::mem_fun(*(SPDesktop*)vw->view, &SPDesktop::onDeleteUI)); + win->signal_window_state_event().connect(sigc::mem_fun(*desktop, &SPDesktop::onWindowStateEvent)); + win->signal_focus_in_event().connect(sigc::mem_fun(*desktop_widget, &SPDesktopWidget::onFocusInEvent)); + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + gint prefs_geometry = + (2==prefs->getInt("/options/savewindowgeometry/value", 0)); + if (prefs_geometry) { + gint pw = prefs->getInt("/desktop/geometry/width", -1); + gint ph = prefs->getInt("/desktop/geometry/height", -1); + gint px = prefs->getInt("/desktop/geometry/x", -1); + gint py = prefs->getInt("/desktop/geometry/y", -1); + gint full = prefs->getBool("/desktop/geometry/fullscreen"); + gint maxed = prefs->getBool("/desktop/geometry/maximized"); + if (pw>0 && ph>0) { + gint w = MIN(gdk_screen_width(), pw); + gint h = MIN(gdk_screen_height(), ph); + gint x = MIN(gdk_screen_width() - MIN_ONSCREEN_DISTANCE, px); + gint y = MIN(gdk_screen_height() - MIN_ONSCREEN_DISTANCE, py); + if (w>0 && h>0) { + x = MIN(gdk_screen_width() - w, x); + y = MIN(gdk_screen_height() - h, y); + desktop->setWindowSize(w, h); + } + + // Only restore xy for the first window so subsequent windows don't overlap exactly + // with first. (Maybe rule should be only restore xy if it's different from xy of + // other desktops?) + + // Empirically it seems that active_desktop==this desktop only the first time a + // desktop is created. + SPDesktop *active_desktop = SP_ACTIVE_DESKTOP; + if (active_desktop == desktop || active_desktop==NULL) { + desktop->setWindowPosition(Geom::Point(x, y)); + } + } + if (maxed) { + win->maximize(); + } + if (full) { + win->fullscreen(); + } + } + + } + + if ( completeDropTargets == 0 || completeDropTargetsCount == 0 ) + { + std::vector types; + + GSList *list = gdk_pixbuf_get_formats(); + while ( list ) { + int i = 0; + GdkPixbufFormat *one = (GdkPixbufFormat*)list->data; + gchar** typesXX = gdk_pixbuf_format_get_mime_types(one); + for ( i = 0; typesXX[i]; i++ ) { + types.push_back(g_strdup(typesXX[i])); + } + g_strfreev(typesXX); + + list = g_slist_next(list); + } + completeDropTargetsCount = nui_drop_target_entries + types.size(); + completeDropTargets = new GtkTargetEntry[completeDropTargetsCount]; + for ( int i = 0; i < (int)nui_drop_target_entries; i++ ) { + completeDropTargets[i] = ui_drop_target_entries[i]; + } + int pos = nui_drop_target_entries; + + for (std::vector::iterator it = types.begin() ; it != types.end() ; it++) { + completeDropTargets[pos].target = *it; + completeDropTargets[pos].flags = 0; + completeDropTargets[pos].info = IMAGE_DATA; + pos++; + } + } + + gtk_drag_dest_set((GtkWidget*)win->gobj(), + GTK_DEST_DEFAULT_ALL, + completeDropTargets, + completeDropTargetsCount, + GdkDragAction(GDK_ACTION_COPY | GDK_ACTION_MOVE)); + + + g_signal_connect(G_OBJECT(win->gobj()), + "drag_data_received", + G_CALLBACK(sp_ui_drag_data_received), + NULL); + g_signal_connect(G_OBJECT(win->gobj()), + "drag_motion", + G_CALLBACK(sp_ui_drag_motion), + NULL); + g_signal_connect(G_OBJECT(win->gobj()), + "drag_leave", + G_CALLBACK(sp_ui_drag_leave), + NULL); + win->show(); + + // needed because the first ACTIVATE_DESKTOP was sent when there was no window yet + if ( SP_IS_DESKTOP_WIDGET(vw) ) { + inkscape_reactivate_desktop(SP_DESKTOP_WIDGET(vw)->desktop); + } +} + +void +sp_ui_new_view() +{ + SPDocument *document; + SPViewWidget *dtw; + + document = SP_ACTIVE_DOCUMENT; + if (!document) return; + + dtw = sp_desktop_widget_new(sp_document_namedview(document, NULL)); + g_return_if_fail(dtw != NULL); + + sp_create_window(dtw, TRUE); + sp_namedview_window_from_document(static_cast(dtw->view)); + sp_namedview_update_layers_from_document(static_cast(dtw->view)); +} + +void sp_ui_new_view_preview() +{ + SPDocument *document = SP_ACTIVE_DOCUMENT; + if ( document ) { + SPViewWidget *dtw = reinterpret_cast(sp_svg_view_widget_new(document)); + g_return_if_fail(dtw != NULL); + SP_SVG_VIEW_WIDGET(dtw)->setResize(true, 400.0, 400.0); + + sp_create_window(dtw, FALSE); + } +} + +void +sp_ui_close_view(GtkWidget */*widget*/) +{ + SPDesktop *dt = SP_ACTIVE_DESKTOP; + + if (dt == NULL) { + return; + } + + if (dt->shutdown()) { + return; // Shutdown operation has been canceled, so do nothing + } + + // If closing the last document, open a new document so Inkscape doesn't quit. + std::list desktops; + inkscape_get_all_desktops(desktops); + if (desktops.size() == 1) { + Glib::ustring templateUri = sp_file_default_template_uri(); + SPDocument *doc = SPDocument::createNewDoc( templateUri.c_str() , TRUE, true ); + // Set viewBox if it doesn't exist + if (!doc->getRoot()->viewBox_set) { + doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value(doc->getDefaultUnit()), doc->getHeight().value(doc->getDefaultUnit()))); + } + dt->change_document(doc); + sp_namedview_window_from_document(dt); + sp_namedview_update_layers_from_document(dt); + return; + } + + // Shutdown can proceed; use the stored reference to the desktop here instead of the current SP_ACTIVE_DESKTOP, + // because the user might have changed the focus in the meantime (see bug #381357 on Launchpad) + dt->destroyWidget(); +} + + +unsigned int +sp_ui_close_all(void) +{ + /* Iterate through all the windows, destroying each in the order they + become active */ + while (SP_ACTIVE_DESKTOP) { + SPDesktop *dt = SP_ACTIVE_DESKTOP; + if (dt->shutdown()) { + /* The user canceled the operation, so end doing the close */ + return FALSE; + } + // Shutdown can proceed; use the stored reference to the desktop here instead of the current SP_ACTIVE_DESKTOP, + // because the user might have changed the focus in the meantime (see bug #381357 on Launchpad) + dt->destroyWidget(); + } + + return TRUE; +} + +/* + * Some day when the right-click menus are ready to start working + * smarter with the verbs, we'll need to change this NULL being + * sent to sp_action_perform to something useful, or set some kind + * of global "right-clicked position" variable for actions to + * investigate when they're called. + */ +static void +sp_ui_menu_activate(void */*object*/, SPAction *action) +{ + if (!temporarily_block_actions) { + sp_action_perform(action, NULL); + } +} + +static void +sp_ui_menu_select_action(void */*object*/, SPAction *action) +{ + sp_action_get_view(action)->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, action->tip); +} + +static void +sp_ui_menu_deselect_action(void */*object*/, SPAction *action) +{ + sp_action_get_view(action)->tipsMessageContext()->clear(); +} + +static void +sp_ui_menu_select(gpointer object, gpointer tip) +{ + Inkscape::UI::View::View *view = static_cast (g_object_get_data(G_OBJECT(object), "view")); + view->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, (gchar *)tip); +} + +static void +sp_ui_menu_deselect(gpointer object) +{ + Inkscape::UI::View::View *view = static_cast (g_object_get_data(G_OBJECT(object), "view")); + view->tipsMessageContext()->clear(); +} + +/** + * Creates and attaches a scaled icon to the given menu item. + */ +static void +sp_ui_menuitem_add_icon( GtkWidget *item, gchar *icon_name ) +{ + static bool iconsInjected = false; + if ( !iconsInjected ) { + iconsInjected = true; + injectRenamedIcons(); + } + GtkWidget *icon; + + icon = sp_icon_new( Inkscape::ICON_SIZE_MENU, icon_name ); + gtk_widget_show(icon); + gtk_image_menu_item_set_image((GtkImageMenuItem *) item, icon); +} // end of sp_ui_menu_add_icon + +void +sp_ui_dialog_title_string(Inkscape::Verb *verb, gchar *c) +{ + SPAction *action; + unsigned int shortcut; + gchar *s; + gchar *atitle; + + action = verb->get_action(Inkscape::ActionContext()); + if (!action) + return; + + atitle = sp_action_get_title(action); + + s = g_stpcpy(c, atitle); + + g_free(atitle); + + shortcut = sp_shortcut_get_primary(verb); + if (shortcut!=GDK_KEY_VoidSymbol) { + gchar* key = sp_shortcut_get_label(shortcut); + s = g_stpcpy(s, " ("); + s = g_stpcpy(s, key); + s = g_stpcpy(s, ")"); + g_free(key); + } +} + + +/** + * Appends a custom menu UI from a verb. + * + * @see ContextMenu::AppendItemFromVerb for a c++ified alternative. Consider dropping sp_ui_menu_append_item_from_verb when c++ifying interface.cpp. + */ +static GtkWidget *sp_ui_menu_append_item_from_verb(GtkMenu *menu, Inkscape::Verb *verb, Inkscape::UI::View::View *view, bool radio = false, GSList *group = NULL) +{ + SPAction *action; + GtkWidget *item; + + if (verb->get_code() == SP_VERB_NONE) { + + item = gtk_separator_menu_item_new(); + + } else { + + action = verb->get_action(Inkscape::ActionContext(view)); + if (!action) return NULL; + + if (radio) { + item = gtk_radio_menu_item_new_with_mnemonic(group, action->name); + } else { + item = gtk_image_menu_item_new_with_mnemonic(action->name); + } + + gtk_label_set_markup_with_mnemonic( GTK_LABEL(gtk_bin_get_child(GTK_BIN (item))), action->name); + + GtkAccelGroup *accel_group = sp_shortcut_get_accel_group(); + gtk_menu_set_accel_group(menu, accel_group); + + sp_shortcut_add_accelerator(item, sp_shortcut_get_primary(verb)); + + action->signal_set_sensitive.connect( + sigc::bind<0>( + sigc::ptr_fun(>k_widget_set_sensitive), + item)); + action->signal_set_name.connect( + sigc::bind<0>( + sigc::ptr_fun(&sp_ui_menu_item_set_name), + item)); + + if (!action->sensitive) { + gtk_widget_set_sensitive(item, FALSE); + } + + if (action->image) { + sp_ui_menuitem_add_icon(item, action->image); + } + gtk_widget_set_events(item, GDK_KEY_PRESS_MASK); + g_object_set_data(G_OBJECT(item), "view", (gpointer) view); + g_signal_connect( G_OBJECT(item), "activate", G_CALLBACK(sp_ui_menu_activate), action ); + g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select_action), action ); + g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect_action), action ); + } + + gtk_widget_show(item); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); + + return item; + +} // end of sp_ui_menu_append_item_from_verb + + +Glib::ustring getLayoutPrefPath( Inkscape::UI::View::View *view ) +{ + Glib::ustring prefPath; + + if (reinterpret_cast(view)->is_focusMode()) { + prefPath = "/focus/"; + } else if (reinterpret_cast(view)->is_fullscreen()) { + prefPath = "/fullscreen/"; + } else { + prefPath = "/window/"; + } + + return prefPath; +} + +static void +checkitem_toggled(GtkCheckMenuItem *menuitem, gpointer user_data) +{ + gchar const *pref = (gchar const *) user_data; + Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view"); + SPAction *action = (SPAction *) g_object_get_data(G_OBJECT(menuitem), "action"); + + if (action) { + + sp_ui_menu_activate(menuitem, action); + + } else if (pref) { + // All check menu items should have actions now, but just in case + Glib::ustring pref_path = getLayoutPrefPath( view ); + pref_path += pref; + pref_path += "/state"; + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + gboolean checked = gtk_check_menu_item_get_active(menuitem); + prefs->setBool(pref_path, checked); + + reinterpret_cast(view)->layoutWidget(); + } +} + +static bool getViewStateFromPref(Inkscape::UI::View::View *view, gchar const *pref) +{ + Glib::ustring pref_path = getLayoutPrefPath( view ); + pref_path += pref; + pref_path += "/state"; + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + return prefs->getBool(pref_path, true); +} + +#if GTK_CHECK_VERSION(3,0,0) +static gboolean checkitem_update(GtkWidget *widget, cairo_t * /*cr*/, gpointer user_data) +#else +static gboolean checkitem_update(GtkWidget *widget, GdkEventExpose * /*event*/, gpointer user_data) +#endif +{ + GtkCheckMenuItem *menuitem=GTK_CHECK_MENU_ITEM(widget); + + gchar const *pref = (gchar const *) user_data; + Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view"); + SPAction *action = (SPAction *) g_object_get_data(G_OBJECT(menuitem), "action"); + SPDesktop *dt = static_cast(view); + + bool ison = false; + if (action) { + + if (!strcmp(action->id, "ToggleGrid")) { + ison = dt->gridsEnabled(); + } + else if (!strcmp(action->id, "ToggleGuides")) { + ison = dt->namedview->getGuides(); + } + else if (!strcmp(action->id, "ViewCmsToggle")) { + ison = dt->colorProfAdjustEnabled(); + } + else { + ison = getViewStateFromPref(view, pref); + } + } else if (pref) { + // The Show/Hide menu items without actions + ison = getViewStateFromPref(view, pref); + } + + g_signal_handlers_block_by_func(G_OBJECT(menuitem), (gpointer)(GCallback)checkitem_toggled, user_data); + gtk_check_menu_item_set_active(menuitem, ison); + g_signal_handlers_unblock_by_func(G_OBJECT(menuitem), (gpointer)(GCallback)checkitem_toggled, user_data); + + return FALSE; +} + + +static void taskToggled(GtkCheckMenuItem *menuitem, gpointer userData) +{ + if ( gtk_check_menu_item_get_active(menuitem) ) { + gint taskNum = GPOINTER_TO_INT(userData); + taskNum = (taskNum < 0) ? 0 : (taskNum > 2) ? 2 : taskNum; + + Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view"); + + // note: this will change once more options are in the task set support: + Inkscape::UI::UXManager::getInstance()->setTask( dynamic_cast(view), taskNum ); + } +} + + +/** + * Callback function to update the status of the radio buttons in the View -> Display mode menu (Normal, No Filters, Outline) and Color display mode. + */ +#if GTK_CHECK_VERSION(3,0,0) +static gboolean update_view_menu(GtkWidget *widget, cairo_t * /*cr*/, gpointer user_data) +#else +static gboolean update_view_menu(GtkWidget *widget, GdkEventExpose * /*event*/, gpointer user_data) +#endif +{ + SPAction *action = (SPAction *) user_data; + g_assert(action->id != NULL); + + Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(widget), "view"); + SPDesktop *dt = static_cast(view); + Inkscape::RenderMode mode = dt->getMode(); + Inkscape::ColorMode colormode = dt->getColorMode(); + + bool new_state = false; + if (!strcmp(action->id, "ViewModeNormal")) { + new_state = mode == Inkscape::RENDERMODE_NORMAL; + } else if (!strcmp(action->id, "ViewModeNoFilters")) { + new_state = mode == Inkscape::RENDERMODE_NO_FILTERS; + } else if (!strcmp(action->id, "ViewModeOutline")) { + new_state = mode == Inkscape::RENDERMODE_OUTLINE; + } else if (!strcmp(action->id, "ViewColorModeNormal")) { + new_state = colormode == Inkscape::COLORMODE_NORMAL; + } else if (!strcmp(action->id, "ViewColorModeGrayscale")) { + new_state = colormode == Inkscape::COLORMODE_GRAYSCALE; + } else if (!strcmp(action->id, "ViewColorModePrintColorsPreview")) { + new_state = colormode == Inkscape::COLORMODE_PRINT_COLORS_PREVIEW; + } else { + g_warning("update_view_menu does not handle this verb"); + } + + if (new_state) { //only one of the radio buttons has to be activated; the others will automatically be deactivated + if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget))) { + // When the GtkMenuItem version of the "activate" signal has been emitted by a GtkRadioMenuItem, there is a second + // emission as the most recently active item is toggled to inactive. This is dealt with before the original signal is handled. + // This emission however should not invoke any actions, hence we block it here: + temporarily_block_actions = true; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (widget), TRUE); + temporarily_block_actions = false; + } + } + + return FALSE; +} + +static void +sp_ui_menu_append_check_item_from_verb(GtkMenu *menu, Inkscape::UI::View::View *view, gchar const *label, gchar const *tip, gchar const *pref, + void (*callback_toggle)(GtkCheckMenuItem *, gpointer user_data), +#if GTK_CHECK_VERSION(3,0,0) + gboolean (*callback_update)(GtkWidget *widget, cairo_t *cr, gpointer user_data), +#else + gboolean (*callback_update)(GtkWidget *widget, GdkEventExpose *event, gpointer user_data), +#endif + Inkscape::Verb *verb) +{ + unsigned int shortcut = (verb) ? sp_shortcut_get_primary(verb) : 0; + SPAction *action = (verb) ? verb->get_action(Inkscape::ActionContext(view)) : 0; + GtkWidget *item = gtk_check_menu_item_new_with_mnemonic(action ? action->name : label); + +#if 0 + if (!action->sensitive) { + gtk_widget_set_sensitive(item, FALSE); + } +#endif + + sp_shortcut_add_accelerator(item, shortcut); + + gtk_widget_show(item); + + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); + + g_object_set_data(G_OBJECT(item), "view", (gpointer) view); + g_object_set_data(G_OBJECT(item), "action", (gpointer) action); + + g_signal_connect( G_OBJECT(item), "toggled", (GCallback) callback_toggle, (void *) pref); + +#if GTK_CHECK_VERSION(3,0,0) + g_signal_connect( G_OBJECT(item), "draw", (GCallback) callback_update, (void *) pref); +#else + g_signal_connect( G_OBJECT(item), "expose_event", (GCallback) callback_update, (void *) pref); +#endif + + (*callback_update)(item, NULL, (void *)pref); + + g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select), (gpointer) (action ? action->tip : tip)); + g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect), NULL); + +} + +static void +sp_recent_open(GtkRecentChooser *recent_menu, gpointer /*user_data*/) +{ + // dealing with the bizarre filename convention in Inkscape for now + gchar *uri = gtk_recent_chooser_get_current_uri(GTK_RECENT_CHOOSER(recent_menu)); + gchar *local_fn = g_filename_from_uri(uri, NULL, NULL); + gchar *utf8_fn = g_filename_to_utf8(local_fn, -1, NULL, NULL, NULL); + sp_file_open(utf8_fn, NULL); + g_free(utf8_fn); + g_free(local_fn); + g_free(uri); +} + +static void +sp_ui_checkboxes_menus(GtkMenu *m, Inkscape::UI::View::View *view) +{ + //sp_ui_menu_append_check_item_from_verb(m, view, _("_Menu"), _("Show or hide the menu bar"), "menu", + // checkitem_toggled, checkitem_update, 0); + sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "commands", + checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_COMMANDS_TOOLBAR)); + sp_ui_menu_append_check_item_from_verb(m, view,NULL, NULL, "snaptoolbox", + checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_SNAP_TOOLBAR)); + sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "toppanel", + checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_TOOL_TOOLBAR)); + sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "toolbox", + checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_TOOLBOX)); + sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "rulers", + checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_RULERS)); + sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "scrollbars", + checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_SCROLLBARS)); + sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "panels", + checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_PALETTE)); + sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "statusbar", + checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_STATUSBAR)); +} + + +static void addTaskMenuItems(GtkMenu *menu, Inkscape::UI::View::View *view) +{ + gchar const* data[] = { + C_("Interface setup", "Default"), _("Default interface setup"), + C_("Interface setup", "Custom"), _("Setup for custom task"), + C_("Interface setup", "Wide"), _("Setup for widescreen work"), + 0, 0 + }; + + GSList *group = 0; + int count = 0; + gint active = Inkscape::UI::UXManager::getInstance()->getDefaultTask( dynamic_cast(view) ); + for (gchar const **strs = data; strs[0]; strs += 2, count++) + { + GtkWidget *item = gtk_radio_menu_item_new_with_label( group, strs[0] ); + group = gtk_radio_menu_item_get_group( GTK_RADIO_MENU_ITEM(item) ); + if ( count == active ) + { + gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM(item), TRUE ); + } + + g_object_set_data( G_OBJECT(item), "view", view ); + g_signal_connect( G_OBJECT(item), "toggled", reinterpret_cast(taskToggled), GINT_TO_POINTER(count) ); + g_signal_connect( G_OBJECT(item), "select", G_CALLBACK(sp_ui_menu_select), const_cast(strs[1]) ); + g_signal_connect( G_OBJECT(item), "deselect", G_CALLBACK(sp_ui_menu_deselect), 0 ); + + gtk_widget_show( item ); + gtk_menu_shell_append( GTK_MENU_SHELL(menu), item ); + } +} + + +/** + * Observer that updates the recent list's max document count. + */ +class MaxRecentObserver : public Inkscape::Preferences::Observer { +public: + MaxRecentObserver(GtkWidget *recent_menu) : + Observer("/options/maxrecentdocuments/value"), + _rm(recent_menu) + {} + virtual void notify(Inkscape::Preferences::Entry const &e) { + gtk_recent_chooser_set_limit(GTK_RECENT_CHOOSER(_rm), e.getInt()); + // hack: the recent menu doesn't repopulate after changing the limit, so we force it + g_signal_emit_by_name((gpointer) gtk_recent_manager_get_default(), "changed"); + } +private: + GtkWidget *_rm; +}; + +/** + * This function turns XML into a menu. + * + * This function is realitively simple as it just goes through the XML + * and parses the individual elements. In the case of a submenu, it + * just calls itself recursively. Because it is only reasonable to have + * a couple of submenus, it is unlikely this will go more than two or + * three times. + * + * In the case of an unrecognized verb, a menu item is made to identify + * the verb that is missing, and display that. The menu item is also made + * insensitive. + * + * @param menus This is the XML that defines the menu + * @param menu Menu to be added to + * @param view The View that this menu is being built for + */ +static void sp_ui_build_dyn_menus(Inkscape::XML::Node *menus, GtkWidget *menu, Inkscape::UI::View::View *view) +{ + if (menus == NULL) return; + if (menu == NULL) return; + GSList *group = NULL; + + for (Inkscape::XML::Node *menu_pntr = menus; + menu_pntr != NULL; + menu_pntr = menu_pntr->next()) { + if (!strcmp(menu_pntr->name(), "submenu")) { + GtkWidget *mitem = gtk_menu_item_new_with_mnemonic(_(menu_pntr->attribute("name"))); + GtkWidget *submenu = gtk_menu_new(); + sp_ui_build_dyn_menus(menu_pntr->firstChild(), submenu, view); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), GTK_WIDGET(submenu)); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem); + continue; + } + if (!strcmp(menu_pntr->name(), "verb")) { + gchar const *verb_name = menu_pntr->attribute("verb-id"); + Inkscape::Verb *verb = Inkscape::Verb::getbyid(verb_name); + + if (verb != NULL) { + if (menu_pntr->attribute("radio") != NULL) { + GtkWidget *item = sp_ui_menu_append_item_from_verb (GTK_MENU(menu), verb, view, true, group); + group = gtk_radio_menu_item_get_group( GTK_RADIO_MENU_ITEM(item)); + if (menu_pntr->attribute("default") != NULL) { + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); + } + if (verb->get_code() != SP_VERB_NONE) { + SPAction *action = verb->get_action(Inkscape::ActionContext(view)); +#if GTK_CHECK_VERSION(3,0,0) + g_signal_connect( G_OBJECT(item), "draw", (GCallback) update_view_menu, (void *) action); +#else + g_signal_connect( G_OBJECT(item), "expose_event", (GCallback) update_view_menu, (void *) action); +#endif + } + } else if (menu_pntr->attribute("check") != NULL) { + SPAction *action = NULL; + if (verb->get_code() != SP_VERB_NONE) { + action = verb->get_action(Inkscape::ActionContext(view)); + } + sp_ui_menu_append_check_item_from_verb(GTK_MENU(menu), view, action->name, action->tip, NULL, + checkitem_toggled, checkitem_update, verb); + + } else { + sp_ui_menu_append_item_from_verb(GTK_MENU(menu), verb, view); + group = NULL; + } + } else { + gchar string[120]; + g_snprintf(string, 120, _("Verb \"%s\" Unknown"), verb_name); + string[119] = '\0'; /* may not be terminated */ + GtkWidget *item = gtk_menu_item_new_with_label(string); + gtk_widget_set_sensitive(item, false); + gtk_widget_show(item); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); + } + continue; + } + if (!strcmp(menu_pntr->name(), "separator") + // This was spelt wrong in the original version + // and so this is for backward compatibility. It can + // probably be dropped after the 0.44 release. + || !strcmp(menu_pntr->name(), "seperator")) { + GtkWidget *item = gtk_separator_menu_item_new(); + gtk_widget_show(item); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); + continue; + } + + if (!strcmp(menu_pntr->name(), "recent-file-list")) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + // create recent files menu + int max_recent = prefs->getInt("/options/maxrecentdocuments/value"); + GtkWidget *recent_menu = gtk_recent_chooser_menu_new_for_manager(gtk_recent_manager_get_default()); + gtk_recent_chooser_set_limit(GTK_RECENT_CHOOSER(recent_menu), max_recent); + // sort most recently used documents first to preserve previous behavior + gtk_recent_chooser_set_sort_type(GTK_RECENT_CHOOSER(recent_menu), GTK_RECENT_SORT_MRU); + g_signal_connect(G_OBJECT(recent_menu), "item-activated", G_CALLBACK(sp_recent_open), (gpointer) NULL); + + // add filter to only open files added by Inkscape + GtkRecentFilter *inkscape_only_filter = gtk_recent_filter_new(); + gtk_recent_filter_add_application(inkscape_only_filter, g_get_prgname()); + gtk_recent_chooser_add_filter(GTK_RECENT_CHOOSER(recent_menu), inkscape_only_filter); + + gtk_recent_chooser_set_show_tips (GTK_RECENT_CHOOSER(recent_menu), TRUE); + gtk_recent_chooser_set_show_not_found (GTK_RECENT_CHOOSER(recent_menu), FALSE); + + GtkWidget *recent_item = gtk_menu_item_new_with_mnemonic(_("Open _Recent")); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(recent_item), recent_menu); + + gtk_menu_shell_append(GTK_MENU_SHELL(menu), GTK_WIDGET(recent_item)); + // this will just sit and update the list's item count + static MaxRecentObserver *mro = new MaxRecentObserver(recent_menu); + prefs->addObserver(*mro); + continue; + } + if (!strcmp(menu_pntr->name(), "objects-checkboxes")) { + sp_ui_checkboxes_menus(GTK_MENU(menu), view); + continue; + } + if (!strcmp(menu_pntr->name(), "task-checkboxes")) { + addTaskMenuItems(GTK_MENU(menu), view); + continue; + } + } +} + +GtkWidget *sp_ui_main_menubar(Inkscape::UI::View::View *view) +{ + GtkWidget *mbar = gtk_menu_bar_new(); + sp_ui_build_dyn_menus(inkscape_get_menus(INKSCAPE), mbar, view); + return mbar; +} + + +/* Drag and Drop */ +void +sp_ui_drag_data_received(GtkWidget *widget, + GdkDragContext *drag_context, + gint x, gint y, + GtkSelectionData *data, + guint info, + guint /*event_time*/, + gpointer /*user_data*/) +{ + SPDocument *doc = SP_ACTIVE_DOCUMENT; + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + + switch (info) { +#if ENABLE_MAGIC_COLORS + case APP_X_INKY_COLOR: + { + int destX = 0; + int destY = 0; + gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY ); + Geom::Point where( sp_canvas_window_to_world( desktop->canvas, Geom::Point( destX, destY ) ) ); + + SPItem *item = desktop->getItemAtPoint( where, true ); + if ( item ) + { + bool fillnotstroke = (drag_context->action != GDK_ACTION_MOVE); + + if ( data->length >= 8 ) { + cmsHPROFILE srgbProf = cmsCreate_sRGBProfile(); + + gchar c[64] = {0}; + // Careful about endian issues. + guint16* dataVals = (guint16*)data->data; + sp_svg_write_color( c, sizeof(c), + SP_RGBA32_U_COMPOSE( + 0x0ff & (dataVals[0] >> 8), + 0x0ff & (dataVals[1] >> 8), + 0x0ff & (dataVals[2] >> 8), + 0xff // can't have transparency in the color itself + //0x0ff & (data->data[3] >> 8), + )); + SPCSSAttr *css = sp_repr_css_attr_new(); + bool updatePerformed = false; + + if ( data->length > 14 ) { + int flags = dataVals[4]; + + // piggie-backed palette entry info + int index = dataVals[5]; + Glib::ustring palName; + for ( int i = 0; i < dataVals[6]; i++ ) { + palName += (gunichar)dataVals[7+i]; + } + + // Now hook in a magic tag of some sort. + if ( !palName.empty() && (flags & 1) ) { + gchar* str = g_strdup_printf("%d|", index); + palName.insert( 0, str ); + g_free(str); + str = 0; + + item->setAttribute( + fillnotstroke ? "inkscape:x-fill-tag":"inkscape:x-stroke-tag", + palName.c_str(), + false ); + item->updateRepr(); + + sp_repr_css_set_property( css, fillnotstroke ? "fill":"stroke", c ); + updatePerformed = true; + } + } + + if ( !updatePerformed ) { + sp_repr_css_set_property( css, fillnotstroke ? "fill":"stroke", c ); + } + + sp_desktop_apply_css_recursive( item, css, true ); + item->updateRepr(); + + SPDocumentUndo::done( doc , SP_VERB_NONE, + _("Drop color")); + + if ( srgbProf ) { + cmsCloseProfile( srgbProf ); + } + } + } + } + break; +#endif // ENABLE_MAGIC_COLORS + + case APP_X_COLOR: + { + int destX = 0; + int destY = 0; + gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY ); + Geom::Point where( sp_canvas_window_to_world( desktop->canvas, Geom::Point( destX, destY ) ) ); + Geom::Point const button_dt(desktop->w2d(where)); + Geom::Point const button_doc(desktop->dt2doc(button_dt)); + + if ( gtk_selection_data_get_length (data) == 8 ) { + gchar colorspec[64] = {0}; + // Careful about endian issues. + guint16* dataVals = (guint16*)gtk_selection_data_get_data (data); + sp_svg_write_color( colorspec, sizeof(colorspec), + SP_RGBA32_U_COMPOSE( + 0x0ff & (dataVals[0] >> 8), + 0x0ff & (dataVals[1] >> 8), + 0x0ff & (dataVals[2] >> 8), + 0xff // can't have transparency in the color itself + //0x0ff & (data->data[3] >> 8), + )); + + SPItem *item = desktop->getItemAtPoint( where, true ); + + bool consumed = false; + if (desktop->event_context && desktop->event_context->get_drag()) { + consumed = desktop->event_context->get_drag()->dropColor(item, colorspec, button_dt); + if (consumed) { + DocumentUndo::done( doc , SP_VERB_NONE, _("Drop color on gradient") ); + desktop->event_context->get_drag()->updateDraggers(); + } + } + + //if (!consumed && tools_active(desktop, TOOLS_TEXT)) { + // consumed = sp_text_context_drop_color(c, button_doc); + // if (consumed) { + // SPDocumentUndo::done( doc , SP_VERB_NONE, _("Drop color on gradient stop")); + // } + //} + + if (!consumed && item) { + bool fillnotstroke = (gdk_drag_context_get_actions (drag_context) != GDK_ACTION_MOVE); + if (fillnotstroke && + (SP_IS_SHAPE(item) || SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item))) { + Path *livarot_path = Path_for_item(item, true, true); + livarot_path->ConvertWithBackData(0.04); + + boost::optional position = get_nearest_position_on_Path(livarot_path, button_doc); + if (position) { + Geom::Point nearest = get_point_on_Path(livarot_path, position->piece, position->t); + Geom::Point delta = nearest - button_doc; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + delta = desktop->d2w(delta); + double stroke_tolerance = + ( !item->style->stroke.isNone() ? + desktop->current_zoom() * + item->style->stroke_width.computed * + item->i2dt_affine().descrim() * 0.5 + : 0.0) + + prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); + + if (Geom::L2 (delta) < stroke_tolerance) { + fillnotstroke = false; + } + } + delete livarot_path; + } + + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_set_property( css, fillnotstroke ? "fill":"stroke", colorspec ); + + sp_desktop_apply_css_recursive( item, css, true ); + item->updateRepr(); + + DocumentUndo::done( doc , SP_VERB_NONE, + _("Drop color") ); + } + } + } + break; + + case APP_OSWB_COLOR: + { + bool worked = false; + Glib::ustring colorspec; + if ( gtk_selection_data_get_format (data) == 8 ) { + ege::PaintDef color; + worked = color.fromMIMEData("application/x-oswb-color", + reinterpret_cast(gtk_selection_data_get_data (data)), + gtk_selection_data_get_length (data), + gtk_selection_data_get_format (data)); + if ( worked ) { + if ( color.getType() == ege::PaintDef::CLEAR ) { + colorspec = ""; // TODO check if this is sufficient + } else if ( color.getType() == ege::PaintDef::NONE ) { + colorspec = "none"; + } else { + unsigned int r = color.getR(); + unsigned int g = color.getG(); + unsigned int b = color.getB(); + + SPGradient* matches = 0; + const GSList *gradients = doc->getResourceList("gradient"); + for (const GSList *item = gradients; item; item = item->next) { + SPGradient* grad = SP_GRADIENT(item->data); + if ( color.descr == grad->getId() ) { + if ( grad->hasStops() ) { + matches = grad; + break; + } + } + } + if (matches) { + colorspec = "url(#"; + colorspec += matches->getId(); + colorspec += ")"; + } else { + gchar* tmp = g_strdup_printf("#%02x%02x%02x", r, g, b); + colorspec = tmp; + g_free(tmp); + } + } + } + } + if ( worked ) { + int destX = 0; + int destY = 0; + gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY ); + Geom::Point where( sp_canvas_window_to_world( desktop->canvas, Geom::Point( destX, destY ) ) ); + Geom::Point const button_dt(desktop->w2d(where)); + Geom::Point const button_doc(desktop->dt2doc(button_dt)); + + SPItem *item = desktop->getItemAtPoint( where, true ); + + bool consumed = false; + if (desktop->event_context && desktop->event_context->get_drag()) { + consumed = desktop->event_context->get_drag()->dropColor(item, colorspec.c_str(), button_dt); + if (consumed) { + DocumentUndo::done( doc , SP_VERB_NONE, _("Drop color on gradient") ); + desktop->event_context->get_drag()->updateDraggers(); + } + } + + if (!consumed && item) { + bool fillnotstroke = (gdk_drag_context_get_actions (drag_context) != GDK_ACTION_MOVE); + if (fillnotstroke && + (SP_IS_SHAPE(item) || SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item))) { + Path *livarot_path = Path_for_item(item, true, true); + livarot_path->ConvertWithBackData(0.04); + + boost::optional position = get_nearest_position_on_Path(livarot_path, button_doc); + if (position) { + Geom::Point nearest = get_point_on_Path(livarot_path, position->piece, position->t); + Geom::Point delta = nearest - button_doc; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + delta = desktop->d2w(delta); + double stroke_tolerance = + ( !item->style->stroke.isNone() ? + desktop->current_zoom() * + item->style->stroke_width.computed * + item->i2dt_affine().descrim() * 0.5 + : 0.0) + + prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); + + if (Geom::L2 (delta) < stroke_tolerance) { + fillnotstroke = false; + } + } + delete livarot_path; + } + + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_set_property( css, fillnotstroke ? "fill":"stroke", colorspec.c_str() ); + + sp_desktop_apply_css_recursive( item, css, true ); + item->updateRepr(); + + DocumentUndo::done( doc , SP_VERB_NONE, + _("Drop color") ); + } + } + } + break; + + case SVG_DATA: + case SVG_XML_DATA: { + gchar *svgdata = (gchar *)gtk_selection_data_get_data (data); + + Inkscape::XML::Document *rnewdoc = sp_repr_read_mem(svgdata, gtk_selection_data_get_length (data), SP_SVG_NS_URI); + + if (rnewdoc == NULL) { + sp_ui_error_dialog(_("Could not parse SVG data")); + return; + } + + Inkscape::XML::Node *repr = rnewdoc->root(); + gchar const *style = repr->attribute("style"); + + Inkscape::XML::Node *newgroup = rnewdoc->createElement("svg:g"); + newgroup->setAttribute("style", style); + + Inkscape::XML::Document * xml_doc = doc->getReprDoc(); + for (Inkscape::XML::Node *child = repr->firstChild(); child != NULL; child = child->next()) { + Inkscape::XML::Node *newchild = child->duplicate(xml_doc); + newgroup->appendChild(newchild); + } + + Inkscape::GC::release(rnewdoc); + + // Add it to the current layer + + // Greg's edits to add intelligent positioning of svg drops + SPObject *new_obj = NULL; + new_obj = desktop->currentLayer()->appendChildRepr(newgroup); + + Inkscape::Selection *selection = sp_desktop_selection(desktop); + selection->set(SP_ITEM(new_obj)); + + // move to mouse pointer + { + sp_desktop_document(desktop)->ensureUpToDate(); + Geom::OptRect sel_bbox = selection->visualBounds(); + if (sel_bbox) { + Geom::Point m( desktop->point() - sel_bbox->midpoint() ); + sp_selection_move_relative(selection, m, false); + } + } + + Inkscape::GC::release(newgroup); + DocumentUndo::done( doc, SP_VERB_NONE, + _("Drop SVG") ); + break; + } + + case URI_LIST: { + gchar *uri = (gchar *)gtk_selection_data_get_data (data); + sp_ui_import_files(uri); + break; + } + + case APP_X_INK_PASTE: { + Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get(); + cm->paste(desktop); + DocumentUndo::done( doc, SP_VERB_NONE, _("Drop Symbol") ); + break; + } + + case PNG_DATA: + case JPEG_DATA: + case IMAGE_DATA: { + const char *mime = (info == JPEG_DATA ? "image/jpeg" : "image/png"); + + Inkscape::Extension::DB::InputList o; + Inkscape::Extension::db.get_input_list(o); + Inkscape::Extension::DB::InputList::const_iterator i = o.begin(); + while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) { + ++i; + } + Inkscape::Extension::Extension *ext = *i; + bool save = (strcmp(ext->get_param_optiongroup("link"), "embed") == 0); + ext->set_param_optiongroup("link", "embed"); + ext->set_gui(false); + + gchar *filename = g_build_filename( g_get_tmp_dir(), "inkscape-dnd-import", NULL ); + g_file_set_contents(filename, + reinterpret_cast(gtk_selection_data_get_data (data)), + gtk_selection_data_get_length (data), + NULL); + file_import(doc, filename, ext); + g_free(filename); + + ext->set_param_optiongroup("link", save ? "embed" : "link"); + ext->set_gui(true); + DocumentUndo::done( doc , SP_VERB_NONE, + _("Drop bitmap image") ); + break; + } + } +} + +#include "ui/tools/gradient-tool.h" + +void sp_ui_drag_motion( GtkWidget */*widget*/, + GdkDragContext */*drag_context*/, + gint /*x*/, gint /*y*/, + GtkSelectionData */*data*/, + guint /*info*/, + guint /*event_time*/, + gpointer /*user_data*/) +{ +// SPDocument *doc = SP_ACTIVE_DOCUMENT; +// SPDesktop *desktop = SP_ACTIVE_DESKTOP; + + +// g_message("drag-n-drop motion (%4d, %4d) at %d", x, y, event_time); +} + +static void sp_ui_drag_leave( GtkWidget */*widget*/, + GdkDragContext */*drag_context*/, + guint /*event_time*/, + gpointer /*user_data*/ ) +{ +// g_message("drag-n-drop leave at %d", event_time); +} + +static void +sp_ui_import_files(gchar *buffer) +{ + GList *list = gnome_uri_list_extract_filenames(buffer); + if (!list) + return; + g_list_foreach(list, sp_ui_import_one_file_with_check, NULL); + g_list_foreach(list, (GFunc) g_free, NULL); + g_list_free(list); +} + +static void +sp_ui_import_one_file_with_check(gpointer filename, gpointer /*unused*/) +{ + if (filename) { + if (strlen((char const *)filename) > 2) + sp_ui_import_one_file((char const *)filename); + } +} + +static void +sp_ui_import_one_file(char const *filename) +{ + SPDocument *doc = SP_ACTIVE_DOCUMENT; + if (!doc) return; + + if (filename == NULL) return; + + // Pass off to common implementation + // TODO might need to get the proper type of Inkscape::Extension::Extension + file_import( doc, filename, NULL ); +} + +void +sp_ui_error_dialog(gchar const *message) +{ + GtkWidget *dlg; + gchar *safeMsg = Inkscape::IO::sanitizeString(message); + + dlg = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, "%s", safeMsg); + sp_transientize(dlg); + gtk_window_set_resizable(GTK_WINDOW(dlg), FALSE); + gtk_dialog_run(GTK_DIALOG(dlg)); + gtk_widget_destroy(dlg); + g_free(safeMsg); +} + +bool +sp_ui_overwrite_file(gchar const *filename) +{ + bool return_value = FALSE; + + if (Inkscape::IO::file_test(filename, G_FILE_TEST_EXISTS)) { + Gtk::Window *window = SP_ACTIVE_DESKTOP->getToplevel(); + gchar* baseName = g_path_get_basename( filename ); + gchar* dirName = g_path_get_dirname( filename ); + GtkWidget* dialog = gtk_message_dialog_new_with_markup( window->gobj(), + (GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_NONE, + _( "A file named \"%s\" already exists. Do you want to replace it?\n\n" + "The file already exists in \"%s\". Replacing it will overwrite its contents." ), + baseName, + dirName + ); + gtk_dialog_add_buttons( GTK_DIALOG(dialog), + _("_Cancel"), GTK_RESPONSE_NO, + _("Replace"), GTK_RESPONSE_YES, + NULL ); + gtk_dialog_set_default_response( GTK_DIALOG(dialog), GTK_RESPONSE_YES ); + + if ( gtk_dialog_run( GTK_DIALOG(dialog) ) == GTK_RESPONSE_YES ) { + return_value = TRUE; + } else { + return_value = FALSE; + } + gtk_widget_destroy(dialog); + g_free( baseName ); + g_free( dirName ); + } else { + return_value = TRUE; + } + + return return_value; +} + +static void +sp_ui_menu_item_set_name(GtkWidget *data, Glib::ustring const &name) +{ + if (data || GTK_IS_BIN (data)) { + void *child = gtk_bin_get_child (GTK_BIN (data)); + //child is either + //- a GtkBox, whose first child is a label displaying name if the menu + //item has an accel key + //- a GtkLabel if the menu has no accel key + if (child != NULL){ + if (GTK_IS_LABEL(child)) { + gtk_label_set_markup_with_mnemonic(GTK_LABEL (child), name.c_str()); + } else if (GTK_IS_BOX(child)) { + gtk_label_set_markup_with_mnemonic( + GTK_LABEL (gtk_container_get_children(GTK_CONTAINER (child))->data), + name.c_str()); + }//else sp_ui_menu_append_item_from_verb has been modified and can set + //a menu item in yet another way... + } + } +} + +void injectRenamedIcons() +{ + Glib::RefPtr iconTheme = Gtk::IconTheme::get_default(); + + std::vector< std::pair > renamed; + renamed.push_back(std::make_pair("gtk-file", "document-x-generic")); + renamed.push_back(std::make_pair("gtk-directory", "folder")); + + for ( std::vector< std::pair >::iterator it = renamed.begin(); it < renamed.end(); ++it ) { + bool hasIcon = iconTheme->has_icon(it->first); + bool hasSecondIcon = iconTheme->has_icon(it->second); + + if ( !hasIcon && hasSecondIcon ) { + Glib::ArrayHandle sizes = iconTheme->get_icon_sizes(it->second); + for ( Glib::ArrayHandle::iterator it2 = sizes.begin(); it2 < sizes.end(); ++it2 ) { + Glib::RefPtr pb = iconTheme->load_icon( it->second, *it2 ); + if ( pb ) { + // install a private copy of the pixbuf to avoid pinning a theme + Glib::RefPtr pbCopy = pb->copy(); + Gtk::IconTheme::add_builtin_icon( it->first, *it2, pbCopy ); + } + } + } + } +} + + +ContextMenu::ContextMenu(SPDesktop *desktop, SPItem *item) : + _item(item), + MIGroup(), + MIParent(_("Go to parent")) +{ +// g_message("ContextMenu"); + _object = static_cast(item); + _desktop = desktop; + + AppendItemFromVerb(Inkscape::Verb::get(SP_VERB_EDIT_UNDO)); + AppendItemFromVerb(Inkscape::Verb::get(SP_VERB_EDIT_REDO)); + AddSeparator(); + AppendItemFromVerb(Inkscape::Verb::get(SP_VERB_EDIT_CUT)); + AppendItemFromVerb(Inkscape::Verb::get(SP_VERB_EDIT_COPY)); + AppendItemFromVerb(Inkscape::Verb::get(SP_VERB_EDIT_PASTE)); + AddSeparator(); + AppendItemFromVerb(Inkscape::Verb::get(SP_VERB_EDIT_DUPLICATE)); + AppendItemFromVerb(Inkscape::Verb::get(SP_VERB_EDIT_DELETE)); + + positionOfLastDialog = 10; // 9 in front + 1 for the separator in the next if; used to position the dialog menu entries below each other + + /* Item menu */ + if (item!=NULL) { + AddSeparator(); + MakeObjectMenu(); + } + + /* layer menu */ + SPGroup *group=NULL; + if (item) { + if (SP_IS_GROUP(item)) { + group = SP_GROUP(item); + } else if ( item != _desktop->currentRoot() && SP_IS_GROUP(item->parent) ) { + group = SP_GROUP(item->parent); + } + } + + if (( group && group != _desktop->currentLayer() ) || + ( _desktop->currentLayer() != _desktop->currentRoot() && _desktop->currentLayer()->parent != _desktop->currentRoot() ) ) { + AddSeparator(); + } + + if ( group && group != _desktop->currentLayer() ) { + /* TRANSLATORS: #%1 is the id of the group e.g. , not a number. */ + MIGroup.set_label (Glib::ustring::compose(_("Enter group #%1"), group->getId())); + MIGroup.set_data("group", group); + MIGroup.signal_activate().connect(sigc::bind(sigc::mem_fun(*this, &ContextMenu::EnterGroup),&MIGroup)); + MIGroup.show(); + append(MIGroup); + } + + if ( _desktop->currentLayer() != _desktop->currentRoot() ) { + if ( _desktop->currentLayer()->parent != _desktop->currentRoot() ) { + MIParent.signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::LeaveGroup)); + MIParent.show(); + append(MIParent); + } + } +} + +ContextMenu::~ContextMenu(void) +{ +} + +Gtk::SeparatorMenuItem* ContextMenu::AddSeparator(void) +{ + Gtk::SeparatorMenuItem* sep = Gtk::manage(new Gtk::SeparatorMenuItem()); + sep->show(); + append(*sep); + return sep; +} + +void ContextMenu::EnterGroup(Gtk::MenuItem* mi) +{ + _desktop->setCurrentLayer(reinterpret_cast(mi->get_data("group"))); + _desktop->selection->clear(); +} + +void ContextMenu::LeaveGroup(void) +{ + _desktop->setCurrentLayer(_desktop->currentLayer()->parent); +} + +void ContextMenu::AppendItemFromVerb(Inkscape::Verb *verb)//, SPDesktop *view)//, bool radio, GSList *group) +{ + SPAction *action; + SPDesktop *view = _desktop; + + if (verb->get_code() == SP_VERB_NONE) { + Gtk::MenuItem *item = AddSeparator(); + item->show(); + append(*item); + } else { + action = verb->get_action(Inkscape::ActionContext(view)); + if (!action) { + return; + } + + Gtk::ImageMenuItem *item = Gtk::manage(new Gtk::ImageMenuItem(action->name, true)); + + sp_shortcut_add_accelerator(GTK_WIDGET(item->gobj()), sp_shortcut_get_primary(verb)); + + action->signal_set_sensitive.connect(sigc::mem_fun(*this, &ContextMenu::set_sensitive)); + action->signal_set_name.connect(sigc::mem_fun(*item, &ContextMenu::set_name)); + + if (!action->sensitive) { + item->set_sensitive(FALSE); + } + + if (action->image) { + sp_ui_menuitem_add_icon((GtkWidget*)item->gobj(), action->image); + } + item->set_events(Gdk::KEY_PRESS_MASK); + item->signal_activate().connect(sigc::bind(sigc::ptr_fun(sp_ui_menu_activate),item,action)); + item->signal_select().connect(sigc::bind(sigc::ptr_fun(sp_ui_menu_select_action),item,action)); + item->signal_deselect().connect(sigc::bind(sigc::ptr_fun(sp_ui_menu_deselect_action),item,action)); + item->show(); + append(*item); + } +} + +void ContextMenu::MakeObjectMenu(void) +{ +// GObjectClass *klass = G_OBJECT_GET_CLASS(_object); //to deduce the object's type from its class +// +// if (G_TYPE_CHECK_CLASS_TYPE(klass, SP_TYPE_ITEM)) +// { +// MakeItemMenu (); +// } +// if (G_TYPE_CHECK_CLASS_TYPE(klass, SP_TYPE_GROUP)) +// { +// MakeGroupMenu(); +// } +// if (G_TYPE_CHECK_CLASS_TYPE(klass, SP_TYPE_ANCHOR)) +// { +// MakeAnchorMenu(); +// } +// if (G_TYPE_CHECK_CLASS_TYPE(klass, SP_TYPE_IMAGE)) +// { +// MakeImageMenu(); +// } +// if (G_TYPE_CHECK_CLASS_TYPE(klass, SP_TYPE_SHAPE)) +// { +// MakeShapeMenu(); +// } +// if (G_TYPE_CHECK_CLASS_TYPE(klass, SP_TYPE_TEXT)) +// { +// MakeTextMenu(); +// } + + if (SP_IS_ITEM(_object)) { + MakeItemMenu(); + } + + if (SP_IS_GROUP(_object)) { + MakeGroupMenu(); + } + + if (SP_IS_ANCHOR(_object)) { + MakeAnchorMenu(); + } + + if (SP_IS_IMAGE(_object)) { + MakeImageMenu(); + } + + if (SP_IS_SHAPE(_object)) { + MakeShapeMenu(); + } + + if (SP_IS_TEXT(_object)) { + MakeTextMenu(); + } +} + +void ContextMenu::MakeItemMenu (void) +{ + Gtk::MenuItem* mi; + + /* Item dialog */ + mi = Gtk::manage(new Gtk::MenuItem(_("_Object Properties..."),1)); + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ItemProperties)); + mi->show(); + append(*mi);//insert(*mi,positionOfLastDialog++); + + AddSeparator(); + + /* Select item */ + if (Inkscape::Verb::getbyid( "org.inkscape.followlink" )) { + mi = Gtk::manage(new Gtk::MenuItem(_("_Select This"), 1)); + if (_desktop->selection->includes(_item)) { + mi->set_sensitive(FALSE); + } else { + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ItemSelectThis)); + } + mi->show(); + append(*mi); + } + + + mi = Gtk::manage(new Gtk::MenuItem(_("Select Same"))); + mi->show(); + Gtk::Menu *select_same_submenu = Gtk::manage(new Gtk::Menu()); + if (_desktop->selection->isEmpty()) { + mi->set_sensitive(FALSE); + } + mi->set_submenu(*select_same_submenu); + append(*mi); + + /* Select same fill and stroke */ + mi = Gtk::manage(new Gtk::MenuItem(_("Fill and Stroke"), 1)); + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::SelectSameFillStroke)); + mi->set_sensitive(!SP_IS_ANCHOR(_item)); + mi->show(); + select_same_submenu->append(*mi); + + /* Select same fill color */ + mi = Gtk::manage(new Gtk::MenuItem(_("Fill Color"), 1)); + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::SelectSameFillColor)); + mi->set_sensitive(!SP_IS_ANCHOR(_item)); + mi->show(); + select_same_submenu->append(*mi); + + /* Select same stroke color */ + mi = Gtk::manage(new Gtk::MenuItem(_("Stroke Color"), 1)); + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::SelectSameStrokeColor)); + mi->set_sensitive(!SP_IS_ANCHOR(_item)); + mi->show(); + select_same_submenu->append(*mi); + + /* Select same stroke style */ + mi = Gtk::manage(new Gtk::MenuItem(_("Stroke Style"), 1)); + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::SelectSameStrokeStyle)); + mi->set_sensitive(!SP_IS_ANCHOR(_item)); + mi->show(); + select_same_submenu->append(*mi); + + /* Select same stroke style */ + mi = Gtk::manage(new Gtk::MenuItem(_("Object type"), 1)); + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::SelectSameObjectType)); + mi->set_sensitive(!SP_IS_ANCHOR(_item)); + mi->show(); + select_same_submenu->append(*mi); + + /* Move to layer */ + mi = Gtk::manage(new Gtk::MenuItem(_("_Move to layer ..."), 1)); + if (_desktop->selection->isEmpty()) { + mi->set_sensitive(FALSE); + } else { + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ItemMoveTo)); + } + mi->show(); + append(*mi); + + /* Create link */ + mi = Gtk::manage(new Gtk::MenuItem(_("Create _Link"), 1)); + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ItemCreateLink)); + mi->set_sensitive(!SP_IS_ANCHOR(_item)); + mi->show(); + append(*mi); + + bool ClipRefOK=false; + bool MaskRefOK=false; + if (_item){ + if (_item->clip_ref){ + if (_item->clip_ref->getObject()){ + ClipRefOK=true; + } + } + } + if (_item){ + if (_item->mask_ref){ + if (_item->mask_ref->getObject()){ + MaskRefOK=true; + } + } + } + /* Set mask */ + mi = Gtk::manage(new Gtk::MenuItem(_("Set Mask"), 1)); + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::SetMask)); + if (ClipRefOK || MaskRefOK) { + mi->set_sensitive(FALSE); + } else { + mi->set_sensitive(TRUE); + } + mi->show(); + append(*mi); + + /* Release mask */ + mi = Gtk::manage(new Gtk::MenuItem(_("Release Mask"), 1)); + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ReleaseMask)); + if (MaskRefOK) { + mi->set_sensitive(TRUE); + } else { + mi->set_sensitive(FALSE); + } + mi->show(); + append(*mi); + + /*SSet Clip Group */ + mi = Gtk::manage(new Gtk::MenuItem(_("Create Clip G_roup"),1)); + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::CreateGroupClip)); + mi->set_sensitive(TRUE); + mi->show(); + append(*mi); + + /* Set Clip */ + mi = Gtk::manage(new Gtk::MenuItem(_("Set Cl_ip"), 1)); + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::SetClip)); + if (ClipRefOK || MaskRefOK) { + mi->set_sensitive(FALSE); + } else { + mi->set_sensitive(TRUE); + } + mi->show(); + append(*mi); + + /* Release Clip */ + mi = Gtk::manage(new Gtk::MenuItem(_("Release C_lip"), 1)); + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ReleaseClip)); + if (ClipRefOK) { + mi->set_sensitive(TRUE); + } else { + mi->set_sensitive(FALSE); + } + mi->show(); + append(*mi); + + /* Group */ + mi = Gtk::manage(new Gtk::MenuItem(_("_Group"), 1)); + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ActivateGroup)); + if (_desktop->selection->isEmpty() || _desktop->selection->single()) { + mi->set_sensitive(FALSE); + } else { + mi->set_sensitive(TRUE); + } + mi->show(); + append(*mi); +} + +void ContextMenu::SelectSameFillStroke(void) +{ + sp_select_same_fill_stroke_style(_desktop, true, true, true); +} + +void ContextMenu::SelectSameFillColor(void) +{ + sp_select_same_fill_stroke_style(_desktop, true, false, false); +} + +void ContextMenu::SelectSameStrokeColor(void) +{ + sp_select_same_fill_stroke_style(_desktop, false, true, false); +} + +void ContextMenu::SelectSameStrokeStyle(void) +{ + sp_select_same_stroke_style(_desktop); +} + +void ContextMenu::SelectSameObjectType(void) +{ + sp_select_same_object_type(_desktop); +} + +void ContextMenu::ItemProperties(void) +{ + _desktop->selection->set(_item); + _desktop->_dlg_mgr->showDialog("ObjectProperties"); +} + +void ContextMenu::ItemSelectThis(void) +{ + _desktop->selection->set(_item); +} + +void ContextMenu::ItemMoveTo(void) +{ + Inkscape::UI::Dialogs::LayerPropertiesDialog::showMove(_desktop, _desktop->currentLayer()); +} + + + +void ContextMenu::ItemCreateLink(void) +{ + Inkscape::XML::Document *xml_doc = _desktop->doc()->getReprDoc(); + Inkscape::XML::Node *repr = xml_doc->createElement("svg:a"); + _item->parent->getRepr()->addChild(repr, _item->getRepr()); + SPObject *object = _item->document->getObjectByRepr(repr); + g_return_if_fail(SP_IS_ANCHOR(object)); + + const char *id = _item->getRepr()->attribute("id"); + Inkscape::XML::Node *child = _item->getRepr()->duplicate(xml_doc); + _item->deleteObject(false); + repr->addChild(child, NULL); + child->setAttribute("id", id); + + Inkscape::GC::release(repr); + Inkscape::GC::release(child); + + DocumentUndo::done(object->document, SP_VERB_NONE, _("Create link")); + + _desktop->selection->set(SP_ITEM(object)); + _desktop->_dlg_mgr->showDialog("ObjectAttributes"); +} + +void ContextMenu::SetMask(void) +{ + sp_selection_set_mask(_desktop, false, false); +} + +void ContextMenu::ReleaseMask(void) +{ + sp_selection_unset_mask(_desktop, false); +} + +void ContextMenu::CreateGroupClip(void) +{ + sp_selection_set_clipgroup(_desktop); +} + +void ContextMenu::SetClip(void) +{ + sp_selection_set_mask(_desktop, true, false); +} + + +void ContextMenu::ReleaseClip(void) +{ + sp_selection_unset_mask(_desktop, true); +} + +void ContextMenu::MakeGroupMenu(void) +{ + /* Ungroup */ + Gtk::MenuItem* mi = Gtk::manage(new Gtk::MenuItem(_("_Ungroup"), 1)); + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ActivateUngroup)); + mi->show(); + append(*mi); +} + +void ContextMenu::ActivateGroup(void) +{ + sp_selection_group(_desktop->selection, _desktop); +} + +void ContextMenu::ActivateUngroup(void) +{ + GSList *children = NULL; + + sp_item_group_ungroup(static_cast(_item), &children); + _desktop->selection->setList(children); + g_slist_free(children); +} + +void ContextMenu::MakeAnchorMenu(void) +{ + Gtk::MenuItem* mi; + + /* Link dialog */ + mi = Gtk::manage(new Gtk::MenuItem(_("Link _Properties..."), 1)); + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::AnchorLinkProperties)); + mi->show(); + insert(*mi,positionOfLastDialog++); + + /* Select item */ + mi = Gtk::manage(new Gtk::MenuItem(_("_Follow Link"), 1)); + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::AnchorLinkFollow)); + mi->show(); + append(*mi); + + /* Reset transformations */ + mi = Gtk::manage(new Gtk::MenuItem(_("_Remove Link"), 1)); + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::AnchorLinkRemove)); + mi->show(); + append(*mi); +} + +void ContextMenu::AnchorLinkProperties(void) +{ + _desktop->_dlg_mgr->showDialog("ObjectAttributes"); +} + +void ContextMenu::AnchorLinkFollow(void) +{ + + if (_desktop->selection->isEmpty()) { + _desktop->selection->set(_item); + } + // Opening the selected links with a python extension + Inkscape::Verb *verb = Inkscape::Verb::getbyid( "org.inkscape.followlink" ); + if (verb) { + SPAction *action = verb->get_action(Inkscape::ActionContext(_desktop)); + if (action) { + sp_action_perform(action, NULL); + } + } +} + +void ContextMenu::AnchorLinkRemove(void) +{ + GSList *children = NULL; + sp_item_group_ungroup(static_cast(_item), &children, false); + DocumentUndo::done(_desktop->doc(), SP_VERB_NONE, _("Remove link")); + g_slist_free(children); +} + +void ContextMenu::MakeImageMenu (void) +{ + Gtk::MenuItem* mi; + Inkscape::XML::Node *ir = _object->getRepr(); + const gchar *href = ir->attribute("xlink:href"); + + /* Image properties */ + mi = Gtk::manage(new Gtk::MenuItem(_("Image _Properties..."), 1)); + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ImageProperties)); + mi->show(); + insert(*mi,positionOfLastDialog++); + + /* Edit externally */ + mi = Gtk::manage(new Gtk::MenuItem(_("Edit Externally..."), 1)); + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ImageEdit)); + mi->show(); + insert(*mi,positionOfLastDialog++); + if ( (!href) || ((strncmp(href, "data:", 5) == 0)) ) { + mi->set_sensitive( FALSE ); + } + + /* Trace Bitmap */ + mi = Gtk::manage(new Gtk::MenuItem(_("_Trace Bitmap..."), 1)); + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ImageTraceBitmap)); + mi->show(); + insert(*mi,positionOfLastDialog++); + if (_desktop->selection->isEmpty()) { + mi->set_sensitive(FALSE); + } + + /* Trace Pixel Art */ + mi = Gtk::manage(new Gtk::MenuItem(_("Trace Pixel Art"), 1)); + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ImageTracePixelArt)); + mi->show(); + insert(*mi,positionOfLastDialog++); + if (_desktop->selection->isEmpty()) { + mi->set_sensitive(FALSE); + } + + /* Embed image */ + if (Inkscape::Verb::getbyid( "org.ekips.filter.embedselectedimages" )) { + mi = Gtk::manage(new Gtk::MenuItem(C_("Context menu", "Embed Image"))); + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ImageEmbed)); + mi->show(); + insert(*mi,positionOfLastDialog++); + if ( (!href) || ((strncmp(href, "data:", 5) == 0)) ) { + mi->set_sensitive( FALSE ); + } + } + + /* Extract image */ + if (Inkscape::Verb::getbyid( "org.ekips.filter.extractimage" )) { + mi = Gtk::manage(new Gtk::MenuItem(C_("Context menu", "Extract Image..."))); + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ImageExtract)); + mi->show(); + insert(*mi,positionOfLastDialog++); + if ( (!href) || ((strncmp(href, "data:", 5) != 0)) ) { + mi->set_sensitive( FALSE ); + } + } +} + +void ContextMenu::ImageProperties(void) +{ + _desktop->_dlg_mgr->showDialog("ObjectAttributes"); +} + +Glib::ustring ContextMenu::getImageEditorName() { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + Glib::ustring value; + Glib::ustring choices = prefs->getString("/options/bitmapeditor/value"); + if (!choices.empty()) { + value = choices; + } + else { + value = "gimp"; + } + return value; +} + +void ContextMenu::ImageEdit(void) +{ + if (_desktop->selection->isEmpty()) { + _desktop->selection->set(_item); + } + + GSList const *selected = _desktop->selection->itemList(); + + GError* errThing = 0; + Glib::ustring cmdline = getImageEditorName(); + Glib::ustring name; + Glib::ustring fullname; + +#ifdef WIN32 + // g_spawn_command_line_sync parsing is done according to Unix shell rules, + // not Windows command interpreter rules. Thus we need to enclose the + // executable path with single quotes. + int index = cmdline.find(".exe"); + if ( index < 0 ) index = cmdline.find(".bat"); + if ( index < 0 ) index = cmdline.find(".com"); + if ( index >= 0 ) { + Glib::ustring editorBin = cmdline.substr(0, index + 4).c_str(); + Glib::ustring args = cmdline.substr(index + 4, cmdline.length()).c_str(); + editorBin.insert(0, "'"); + editorBin.append("'"); + cmdline = editorBin; + cmdline.append(args); + } else { + // Enclose the whole command line if no executable path can be extracted. + cmdline.insert(0, "'"); + cmdline.append("'"); + } +#endif + + for (GSList const *iter = selected; iter != NULL; iter = iter->next) { + Inkscape::XML::Node *ir = SP_ITEM(iter->data)->getRepr(); + const gchar *href = ir->attribute("xlink:href"); + + if (strncmp (href,"file:",5) == 0) { + // URI to filename conversion + name = g_filename_from_uri(href, NULL, NULL); + } else { + name.append(href); + } + + if (Glib::path_is_absolute(name)) { + fullname = name; + } else if (SP_ACTIVE_DOCUMENT->getBase()) { + fullname = Glib::build_filename(SP_ACTIVE_DOCUMENT->getBase(), name); + } else { + fullname = Glib::build_filename(Glib::get_current_dir(), name); + } + + cmdline.append(" '"); + cmdline.append(fullname.c_str()); + cmdline.append("'"); + } + + //g_warning("##Command line: %s\n", cmdline.c_str()); + + g_spawn_command_line_async(cmdline.c_str(), &errThing); + + if ( errThing ) { + g_warning("Problem launching editor (%d). %s", errThing->code, errThing->message); + (_desktop->messageStack())->flash(Inkscape::ERROR_MESSAGE, errThing->message); + g_error_free(errThing); + errThing = 0; + } +} + +void ContextMenu::ImageTraceBitmap(void) +{ + inkscape_dialogs_unhide(); + _desktop->_dlg_mgr->showDialog("Trace"); +} + +void ContextMenu::ImageTracePixelArt(void) +{ + inkscape_dialogs_unhide(); + _desktop->_dlg_mgr->showDialog("PixelArt"); +} + +void ContextMenu::ImageEmbed(void) +{ + if (_desktop->selection->isEmpty()) { + _desktop->selection->set(_item); + } + + Inkscape::Verb *verb = Inkscape::Verb::getbyid( "org.ekips.filter.embedselectedimages" ); + if (verb) { + SPAction *action = verb->get_action(Inkscape::ActionContext(_desktop)); + if (action) { + sp_action_perform(action, NULL); + } + } +} + +void ContextMenu::ImageExtract(void) +{ + if (_desktop->selection->isEmpty()) { + _desktop->selection->set(_item); + } + + Inkscape::Verb *verb = Inkscape::Verb::getbyid( "org.ekips.filter.extractimage" ); + if (verb) { + SPAction *action = verb->get_action(Inkscape::ActionContext(_desktop)); + if (action) { + sp_action_perform(action, NULL); + } + } +} + +void ContextMenu::MakeShapeMenu (void) +{ + Gtk::MenuItem* mi; + + /* Item dialog */ + mi = Gtk::manage(new Gtk::MenuItem(_("_Fill and Stroke..."), 1)); + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::FillSettings)); + mi->show(); + insert(*mi,positionOfLastDialog++); +} + +void ContextMenu::FillSettings(void) +{ + if (_desktop->selection->isEmpty()) { + _desktop->selection->set(_item); + } + + _desktop->_dlg_mgr->showDialog("FillAndStroke"); +} + +void ContextMenu::MakeTextMenu (void) +{ + Gtk::MenuItem* mi; + + /* Fill and Stroke dialog */ + mi = Gtk::manage(new Gtk::MenuItem(_("_Fill and Stroke..."), 1)); + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::FillSettings)); + mi->show(); + insert(*mi,positionOfLastDialog++); + + /* Edit Text dialog */ + mi = Gtk::manage(new Gtk::MenuItem(_("_Text and Font..."), 1)); + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::TextSettings)); + mi->show(); + insert(*mi,positionOfLastDialog++); + + /* Spellcheck dialog */ + mi = Gtk::manage(new Gtk::MenuItem(_("Check Spellin_g..."), 1)); + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::SpellcheckSettings)); + mi->show(); + insert(*mi,positionOfLastDialog++); +} + +void ContextMenu::TextSettings (void) +{ + if (_desktop->selection->isEmpty()) { + _desktop->selection->set(_item); + } + + _desktop->_dlg_mgr->showDialog("TextFont"); +} + +void ContextMenu::SpellcheckSettings (void) +{ + if (_desktop->selection->isEmpty()) { + _desktop->selection->set(_item); + } + + _desktop->_dlg_mgr->showDialog("SpellCheck"); +} + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/interface.h b/src/ui/interface.h new file mode 100644 index 000000000..6fb74046f --- /dev/null +++ b/src/ui/interface.h @@ -0,0 +1,277 @@ +#ifndef SEEN_SP_INTERFACE_H +#define SEEN_SP_INTERFACE_H + +/* + * Main UI stuff + * + * Authors: + * Lauris Kaplinski + * Frank Felfe + * Abhishek Sharma + * Kris De Gussem + * + * Copyright (C) 2012 Kris De Gussem + * Copyright (C) 1999-2002 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +//#ifdef HAVE_CONFIG_H +//# include +//#endif + +#include + +class SPItem; +class SPObject; +class SPDesktop; +class SPViewWidget; + +namespace Gtk { +class SeparatorMenuItem; +} + +namespace Inkscape { + +class Verb; + +namespace UI { +namespace View { +class View; +} // namespace View +} // namespace UI +} // namespace Inkscape + +/** + * Create a new document window. + */ +void sp_create_window (SPViewWidget *vw, bool editable); + +/** + * \param widget unused + */ +void sp_ui_close_view (GtkWidget *widget); + +void sp_ui_new_view (void); + +/** + * @todo TODO: not yet working. To be re-enabled (by adding to menu) once it works. + */ +void sp_ui_new_view_preview (void); + +/** + * This function is called to exit the program, and iterates through all + * open document view windows, attempting to close each in turn. If the + * view has unsaved information, the user will be prompted to save, + * discard, or cancel. + * + * Returns FALSE if the user cancels the close_all operation, TRUE + * otherwise. + */ +unsigned int sp_ui_close_all (void); + +/** + * Build the main tool bar. + * + * Currently the main tool bar is built as a dynamic XML menu using + * \c sp_ui_build_dyn_menus. This function builds the bar, and then + * pass it to get items attached to it. + * + * @param view View to build the bar for + */ +GtkWidget *sp_ui_main_menubar (Inkscape::UI::View::View *view); + +void sp_menu_append_recent_documents (GtkWidget *menu); +void sp_ui_dialog_title_string (Inkscape::Verb * verb, char* c); + +Glib::ustring getLayoutPrefPath( Inkscape::UI::View::View *view ); + +/** + * + */ +void sp_ui_error_dialog (char const* message); +bool sp_ui_overwrite_file (char const* filename); + + +/** + * Implements the Inkscape context menu. + * + * For the context menu implementation, the ContextMenu class stores the object + * that was selected in a private data member. This should be farely safe to do + * and a pointer to the SPItem as well as SPObject class are kept. + * All callbacks of the context menu entries are implemented as private + * functions. + * + * @todo add callbacks to destroy the context menu when it is closed (=key or mouse button pressed out of the scope of the context menu) + */ +class ContextMenu : public Gtk::Menu +{ + public: + /** + * The ContextMenu constructor contains all code to create and show the + * menu entries (aka child widgets). + * + * @param desktop pointer to the desktop the user is currently working on. + * @param item SPItem pointer to the object selected at the time the ContextMenu is created. + */ + ContextMenu(SPDesktop *desktop, SPItem *item); + ~ContextMenu(void); + + private: + SPItem *_item; // pointer to the object selected at the time the ContextMenu is created + SPObject *_object; // pointer to the object selected at the time the ContextMenu is created + SPDesktop *_desktop; //pointer to the desktop the user was currently working on at the time the ContextMenu is created + + int positionOfLastDialog; + + Gtk::MenuItem MIGroup; //menu entry to enter a group + Gtk::MenuItem MIParent; //menu entry to leave a group + + /** + * auxiliary function that adds a separator line in the context menu + */ + Gtk::SeparatorMenuItem* AddSeparator(void); + + /** + * c++ified version of sp_ui_menu_append_item. + * + * @see sp_ui_menu_append_item_from_verb and synchronize/drop that function when c++ifying other code in interface.cpp + */ + void AppendItemFromVerb(Inkscape::Verb *verb); + + /** + * main function which is responsible for creating the context sensitive menu items, + * calls subfunctions below to create the menu entry widgets. + */ + void MakeObjectMenu (void); + /** + * creates menu entries for an SP_TYPE_ITEM object + */ + void MakeItemMenu (void); + /** + * creates menu entries for a grouped object + */ + void MakeGroupMenu (void); + /** + * creates menu entries for an anchor object + */ + void MakeAnchorMenu (void); + /** + * creates menu entries for a bitmap image object + */ + void MakeImageMenu (void); + /** + * creates menu entries for a shape object + */ + void MakeShapeMenu (void); + /** + * creates menu entries for a text object + */ + void MakeTextMenu (void); + + void EnterGroup(Gtk::MenuItem* mi); + void LeaveGroup(void); + ////////////////////////////////////////// + //callbacks for the context menu entries of an SP_TYPE_ITEM object + void ItemProperties(void); + void ItemSelectThis(void); + void ItemMoveTo(void); + void SelectSameFillStroke(void); + void SelectSameFillColor(void); + void SelectSameStrokeColor(void); + void SelectSameStrokeStyle(void); + void SelectSameObjectType(void); + void ItemCreateLink(void); + void CreateGroupClip(void); + void SetMask(void); + void ReleaseMask(void); + void SetClip(void); + void ReleaseClip(void); + ////////////////////////////////////////// + + + /** + * callback, is executed on clicking the anchor "Group" and "Ungroup" menu entry + */ + void ActivateUngroup(void); + void ActivateGroup(void); + + void AnchorLinkProperties(void); + /** + * placeholder for callback to be executed on clicking the anchor "Follow link" context menu entry + * @todo add code to follow link externally + */ + void AnchorLinkFollow(void); + + /** + * callback, is executed on clicking the anchor "Link remove" menu entry + */ + void AnchorLinkRemove(void); + + + /** + * callback, opens the image properties dialog and is executed on clicking the context menu entry with similar name + */ + void ImageProperties(void); + + /** + * callback, is executed on clicking the image "Edit Externally" menu entry + */ + void ImageEdit(void); + + /** + * auxiliary function that loads the external image editor name from the settings. + */ + Glib::ustring getImageEditorName(); + + /** + * callback, is executed on clicking the "Embed Image" menu entry + */ + void ImageEmbed(void); + + /** + * callback, is executed on clicking the "Trace Bitmap" menu entry + */ + void ImageTraceBitmap(void); + + /** + * callback, is executed on clicking the "Trace Pixel Art" menu entry + */ + void ImageTracePixelArt(void); + + /** + * callback, is executed on clicking the "Extract Image" menu entry + */ + void ImageExtract(void); + + + /** + * callback, is executed on clicking the "Fill and Stroke" menu entry + */ + void FillSettings(void); + + + /** + * callback, is executed on clicking the "Text and Font" menu entry + */ + void TextSettings(void); + + /** + * callback, is executed on clicking the "Check spelling" menu entry + */ + void SpellcheckSettings(void); +}; + +#endif // SEEN_SP_INTERFACE_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/tools/tool-base.cpp b/src/ui/tools/tool-base.cpp index c28b86416..150e899ce 100644 --- a/src/ui/tools/tool-base.cpp +++ b/src/ui/tools/tool-base.cpp @@ -44,7 +44,7 @@ #include "desktop-style.h" #include "sp-namedview.h" #include "selection.h" -#include "interface.h" +#include "ui/interface.h" #include "macros.h" #include "tools-switch.h" #include "preferences.h" diff --git a/src/verbs.cpp b/src/verbs.cpp index f0a49a81a..ea4c336d7 100644 --- a/src/verbs.cpp +++ b/src/verbs.cpp @@ -53,7 +53,7 @@ #include "helper/action-context.h" #include "help.h" #include "inkscape-private.h" -#include "interface.h" +#include "ui/interface.h" #include "layer-fns.h" #include "layer-manager.h" #include "message-stack.h" diff --git a/src/widgets/button.cpp b/src/widgets/button.cpp index cda97654e..1776e28c4 100644 --- a/src/widgets/button.cpp +++ b/src/widgets/button.cpp @@ -16,7 +16,7 @@ #include "button.h" #include "helper/action-context.h" -#include "interface.h" +#include "ui/interface.h" #include "shortcuts.h" #include "helper/action.h" diff --git a/src/widgets/desktop-widget.cpp b/src/widgets/desktop-widget.cpp index fec46b188..388d22e29 100644 --- a/src/widgets/desktop-widget.cpp +++ b/src/widgets/desktop-widget.cpp @@ -46,7 +46,7 @@ #include "util/units.h" #include "ui/widget/unit-tracker.h" #include "inkscape-private.h" -#include "interface.h" +#include "ui/interface.h" #include "macros.h" #include "preferences.h" #include "sp-image.h" diff --git a/src/widgets/toolbox.cpp b/src/widgets/toolbox.cpp index 939546f78..ba70c081e 100644 --- a/src/widgets/toolbox.cpp +++ b/src/widgets/toolbox.cpp @@ -53,7 +53,7 @@ #include "../ink-action.h" #include "../ink-comboboxentry-action.h" #include "../inkscape.h" -#include "../interface.h" +#include "ui/interface.h" #include "../shortcuts.h" #include "../sp-namedview.h" #include "../tools-switch.h" -- cgit v1.2.3