X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Finterface.cpp;h=415593b7885ba76dbe76fb259af0cd718708bb4e;hb=11c5de79de3c200331e168a745b0505a50aeffea;hp=1ad90c58c5746f1dfde172fc477b812407357fd3;hpb=e77e2e02d8ab186389f86e48b1834d95f51cf68d;p=inkscape.git diff --git a/src/interface.cpp b/src/interface.cpp index 1ad90c58c..415593b78 100644 --- a/src/interface.cpp +++ b/src/interface.cpp @@ -1,9 +1,9 @@ #define __SP_INTERFACE_C__ -/** - * Main UI stuff - * - * Authors: +/** @file + * @brief Main UI stuff + */ +/* Authors: * Lauris Kaplinski * Frank Felfe * bulia byak @@ -20,14 +20,14 @@ #endif #include +#include + #include "inkscape-private.h" #include "extension/effect.h" #include "widgets/icon.h" -#include "prefs-utils.h" +#include "preferences.h" #include "path-prefix.h" - #include "shortcuts.h" - #include "document.h" #include "desktop-handles.h" #include "file.h" @@ -40,20 +40,16 @@ #include "widgets/desktop-widget.h" #include "sp-item-group.h" #include "sp-text.h" +#include "sp-gradient-fns.h" +#include "sp-gradient.h" #include "sp-flowtext.h" #include "sp-namedview.h" #include "ui/view/view.h" - #include "helper/action.h" #include "helper/gnome-utils.h" #include "helper/window.h" - #include "io/sys.h" -#include "io/stringstream.h" -#include "io/base64stream.h" - #include "dialogs/dialog-events.h" - #include "message-context.h" // Added for color drag-n-drop @@ -67,15 +63,13 @@ #include "style.h" #include "event-context.h" #include "gradient-drag.h" +#include "widgets/ege-paint-def.h" // Include Mac OS X menu synchronization on native OSX build #ifdef GDK_WINDOWING_QUARTZ #include "ige-mac-menu.h" #endif -using Inkscape::IO::StringOutputStream; -using Inkscape::IO::Base64OutputStream; - /* Drag and Drop */ typedef enum { URI_LIST, @@ -85,7 +79,8 @@ typedef enum { JPEG_DATA, IMAGE_DATA, APP_X_INKY_COLOR, - APP_X_COLOR + APP_X_COLOR, + APP_OSWB_COLOR, } ui_drop_target_info; static GtkTargetEntry ui_drop_target_entries [] = { @@ -97,11 +92,13 @@ static GtkTargetEntry ui_drop_target_entries [] = { #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 } }; 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); @@ -129,9 +126,10 @@ static void sp_ui_drag_leave( GtkWidget *widget, static void sp_ui_menu_item_set_sensitive(SPAction *action, unsigned int sensitive, void *data); -static void sp_ui_menu_item_set_name(SPAction *action, +static void sp_ui_menu_item_set_name(SPAction *action, Glib::ustring name, void *data); +static void sp_recent_open(GtkRecentChooser *, gpointer); SPActionEventVector menu_item_event_vector = { {NULL}, @@ -152,40 +150,42 @@ sp_create_window(SPViewWidget *vw, gboolean editable) 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; + 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)); - - gint prefs_geometry = - (2==prefs_get_int_attribute("options.savewindowgeometry", "value", 0)); + 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_get_int_attribute("desktop.geometry", "width", -1); - gint ph = prefs_get_int_attribute("desktop.geometry", "height", -1); - gint px = prefs_get_int_attribute("desktop.geometry", "x", -1); - gint py = prefs_get_int_attribute("desktop.geometry", "y", -1); - gint full = prefs_get_int_attribute("desktop.geometry", "fullscreen", 0); - gint maxed = prefs_get_int_attribute("desktop.geometry", "maximized", 0); + 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>0 && y>0) { + if (w>0 && h>0) { x = MIN(gdk_screen_width() - w, x); y = MIN(gdk_screen_height() - h, y); - } - if (w>0 && h>0) { desktop->setWindowSize(w, h); } @@ -195,11 +195,9 @@ sp_create_window(SPViewWidget *vw, gboolean editable) // Empirically it seems that active_desktop==this desktop only the first time a // desktop is created. - if (x>0 && y>0) { - SPDesktop *active_desktop = SP_ACTIVE_DESKTOP; - if (active_desktop == desktop || active_desktop==NULL) { - desktop->setWindowPosition(NR::Point(x, y)); - } + SPDesktop *active_desktop = SP_ACTIVE_DESKTOP; + if (active_desktop == desktop || active_desktop==NULL) { + desktop->setWindowPosition(Geom::Point(x, y)); } } if (maxed) { @@ -214,9 +212,6 @@ sp_create_window(SPViewWidget *vw, gboolean editable) gtk_window_set_policy(GTK_WINDOW(win->gobj()), TRUE, TRUE, TRUE); } - gtk_container_add(GTK_CONTAINER(win->gobj()), GTK_WIDGET(vw)); - gtk_widget_show(GTK_WIDGET(vw)); - if ( completeDropTargets == 0 || completeDropTargetsCount == 0 ) { std::vector types; @@ -314,13 +309,19 @@ sp_ui_new_view_preview() void sp_ui_close_view(GtkWidget */*widget*/) { - if (SP_ACTIVE_DESKTOP == NULL) { + SPDesktop *dt = SP_ACTIVE_DESKTOP; + + if (dt == NULL) { return; } - if ((SP_ACTIVE_DESKTOP)->shutdown()) { - return; + + if (dt->shutdown()) { + return; // Shutdown operation has been canceled, so do nothing } - SP_ACTIVE_DESKTOP->destroyWidget(); + + // 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(); } @@ -341,11 +342,14 @@ sp_ui_close_all(void) /* Iterate through all the windows, destroying each in the order they become active */ while (SP_ACTIVE_DESKTOP) { - if ((SP_ACTIVE_DESKTOP)->shutdown()) { - /* The user cancelled the operation, so end doing the close */ + SPDesktop *dt = SP_ACTIVE_DESKTOP; + if (dt->shutdown()) { + /* The user canceled the operation, so end doing the close */ return FALSE; } - SP_ACTIVE_DESKTOP->destroyWidget(); + // 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; @@ -361,7 +365,9 @@ sp_ui_close_all(void) static void sp_ui_menu_activate(void */*object*/, SPAction *action) { - sp_action_perform(action, NULL); + if (!temporarily_block_actions) { + sp_action_perform(action, NULL); + } } static void @@ -612,9 +618,8 @@ sp_ui_menu_append_item_from_verb(GtkMenu *menu, Inkscape::Verb *verb, Inkscape:: sp_ui_menuitem_add_icon(item, action->image); } gtk_widget_set_events(item, GDK_KEY_PRESS_MASK); - g_signal_connect( G_OBJECT(item), "activate", - G_CALLBACK(sp_ui_menu_activate), action ); - + 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 ); } @@ -633,14 +638,20 @@ 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"); - gchar const *pref_path; - if (reinterpret_cast(view)->is_fullscreen()) - pref_path = g_strconcat("fullscreen.", pref, NULL); - else - pref_path = g_strconcat("window.", pref, NULL); + Glib::ustring pref_path; + if (reinterpret_cast(view)->is_focusMode()) { + pref_path = "/focus/"; + } else if (reinterpret_cast(view)->is_fullscreen()) { + pref_path = "/fullscreen/"; + } else { + pref_path = "/window/"; + } + pref_path += pref; + pref_path += "/state"; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); gboolean checked = gtk_check_menu_item_get_active(menuitem); - prefs_set_int_attribute(pref_path, "state", checked); + prefs->setBool(pref_path, checked); reinterpret_cast(view)->layoutWidget(); } @@ -653,13 +664,16 @@ checkitem_update(GtkWidget *widget, GdkEventExpose */*event*/, gpointer user_dat gchar const *pref = (gchar const *) user_data; Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(menuitem), "view"); - gchar const *pref_path; - if ((static_cast(view))->is_fullscreen()) - pref_path = g_strconcat("fullscreen.", pref, NULL); - else - pref_path = g_strconcat("window.", pref, NULL); + Glib::ustring pref_path; + if ((static_cast(view))->is_fullscreen()) { + pref_path = "/fullscreen/"; + } else { + pref_path = "/window/"; + } + pref_path += pref; - gint ison = prefs_get_int_attribute_limited(pref_path, "state", 1, 0, 1); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + bool ison = prefs->getBool(pref_path + "/state", true); g_signal_handlers_block_by_func(G_OBJECT(menuitem), (gpointer)(GCallback)checkitem_toggled, user_data); gtk_check_menu_item_set_active(menuitem, ison); @@ -668,6 +682,44 @@ checkitem_update(GtkWidget *widget, GdkEventExpose */*event*/, gpointer user_dat return FALSE; } +/** + * \brief Callback function to update the status of the radio buttons in the View -> Display mode menu (Normal, No Filters, Outline) + */ + +static gboolean +update_view_menu(GtkWidget *widget, GdkEventExpose */*event*/, gpointer user_data) +{ + 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(); + + 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 { + 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; +} 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, @@ -733,9 +785,16 @@ sp_ui_menu_append_check_item_from_verb(GtkMenu *menu, Inkscape::UI::View::View * } static void -sp_recent_open(GtkWidget */*widget*/, gchar const *uri) +sp_recent_open(GtkRecentChooser *recent_menu, gpointer /*user_data*/) { - sp_file_open(uri, NULL); + // 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 @@ -801,35 +860,6 @@ sp_menu_append_new_templates(GtkWidget *menu, Inkscape::UI::View::View *view) } } -void -sp_menu_append_recent_documents(GtkWidget *menu, Inkscape::UI::View::View* /* view */) -{ - gchar const **recent = prefs_get_recent_files(); - if (recent) { - int i; - - for (i = 0; recent[i] != NULL; i += 2) { - gchar const *uri = recent[i]; - gchar const *name = recent[i + 1]; - - GtkWidget *item = gtk_menu_item_new_with_label(name); - gtk_widget_show(item); - g_signal_connect(G_OBJECT(item), - "activate", - G_CALLBACK(sp_recent_open), - (gpointer)uri); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); - } - - g_free(recent); - } else { - GtkWidget *item = gtk_menu_item_new_with_label(_("None")); - gtk_widget_show(item); - gtk_widget_set_sensitive(item, FALSE); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); - } -} - void sp_ui_checkboxes_menus(GtkMenu *m, Inkscape::UI::View::View *view) { @@ -837,6 +867,8 @@ sp_ui_checkboxes_menus(GtkMenu *m, Inkscape::UI::View::View *view) // checkitem_toggled, checkitem_update, 0); sp_ui_menu_append_check_item_from_verb(m, view, _("Commands Bar"), _("Show or hide the Commands bar (under the menu)"), "commands", checkitem_toggled, checkitem_update, 0); + sp_ui_menu_append_check_item_from_verb(m, view, _("Snap Controls Bar"), _("Show or hide the snapping controls"), "snaptoolbox", + checkitem_toggled, checkitem_update, 0); sp_ui_menu_append_check_item_from_verb(m, view, _("Tool Controls Bar"), _("Show or hide the Tool Controls bar"), "toppanel", checkitem_toggled, checkitem_update, 0); sp_ui_menu_append_check_item_from_verb(m, view, _("_Toolbox"), _("Show or hide the main toolbox (on the left)"), "toolbox", @@ -851,6 +883,22 @@ sp_ui_checkboxes_menus(GtkMenu *m, Inkscape::UI::View::View *view) checkitem_toggled, checkitem_update, 0); } +/** @brief 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; +}; + /** \brief This function turns XML into a menu \param menus This is the XML that defines the menu \param menu Menu to be added to @@ -862,7 +910,7 @@ sp_ui_checkboxes_menus(GtkMenu *m, Inkscape::UI::View::View *view) a couple of submenus, it is unlikely this will go more than two or three times. - In the case of an unreconginzed verb, a menu item is made to identify + 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. */ @@ -895,6 +943,10 @@ sp_ui_build_dyn_menus(Inkscape::XML::Node *menus, GtkWidget *menu, Inkscape::UI: 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(view); + g_signal_connect( G_OBJECT(item), "expose_event", (GCallback) update_view_menu, (void *) action); + } } else { sp_ui_menu_append_item_from_verb(GTK_MENU(menu), verb, view); group = NULL; @@ -925,7 +977,31 @@ sp_ui_build_dyn_menus(Inkscape::XML::Node *menus, GtkWidget *menu, Inkscape::UI: continue; } if (!strcmp(menu_pntr->name(), "recent-file-list")) { - sp_menu_append_recent_documents(menu, view); + 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_append(GTK_MENU(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")) { @@ -948,13 +1024,13 @@ sp_ui_main_menubar(Inkscape::UI::View::View *view) GtkWidget *mbar = gtk_menu_bar_new(); #ifdef GDK_WINDOWING_QUARTZ - ige_mac_menu_set_menu_bar(GTK_MENU_SHELL(mbar)); + ige_mac_menu_set_menu_bar(GTK_MENU_SHELL(mbar)); #endif sp_ui_build_dyn_menus(inkscape_get_menus(INKSCAPE), mbar, view); #ifdef GDK_WINDOWING_QUARTZ - return NULL; + return NULL; #else return mbar; #endif @@ -1062,7 +1138,7 @@ sp_ui_drag_data_received(GtkWidget *widget, int destX = 0; int destY = 0; gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY ); - NR::Point where( sp_canvas_window_to_world( desktop->canvas, NR::Point( destX, destY ) ) ); + Geom::Point where( sp_canvas_window_to_world( desktop->canvas, Geom::Point( destX, destY ) ) ); SPItem *item = desktop->item_at_point( where, true ); if ( item ) @@ -1121,7 +1197,7 @@ sp_ui_drag_data_received(GtkWidget *widget, sp_desktop_apply_css_recursive( item, css, true ); item->updateRepr(); - sp_document_done( doc , SP_VERB_NONE, + sp_document_done( doc , SP_VERB_NONE, _("Drop color")); if ( srgbProf ) { @@ -1138,15 +1214,15 @@ sp_ui_drag_data_received(GtkWidget *widget, int destX = 0; int destY = 0; gtk_widget_translate_coordinates( widget, &(desktop->canvas->widget), x, y, &destX, &destY ); - NR::Point where( sp_canvas_window_to_world( desktop->canvas, NR::Point( destX, destY ) ) ); - NR::Point const button_dt(desktop->w2d(where)); - NR::Point const button_doc(desktop->dt2doc(button_dt)); + 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 ( data->length == 8 ) { - gchar c[64] = {0}; + gchar colorspec[64] = {0}; // Careful about endian issues. guint16* dataVals = (guint16*)data->data; - sp_svg_write_color( c, 64, + sp_svg_write_color( colorspec, sizeof(colorspec), SP_RGBA32_U_COMPOSE( 0x0ff & (dataVals[0] >> 8), 0x0ff & (dataVals[1] >> 8), @@ -1159,7 +1235,7 @@ sp_ui_drag_data_received(GtkWidget *widget, bool consumed = false; if (desktop->event_context && desktop->event_context->get_drag()) { - consumed = desktop->event_context->get_drag()->dropColor(item, c, button_dt); + consumed = desktop->event_context->get_drag()->dropColor(item, colorspec, button_dt); if (consumed) { sp_document_done( doc , SP_VERB_NONE, _("Drop color on gradient")); desktop->event_context->get_drag()->updateDraggers(); @@ -1175,25 +1251,129 @@ sp_ui_drag_data_received(GtkWidget *widget, if (!consumed && item) { bool fillnotstroke = (drag_context->action != GDK_ACTION_MOVE); - if (fillnotstroke && + 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 = + ( !SP_OBJECT_STYLE(item)->stroke.isNone() ? + desktop->current_zoom() * + SP_OBJECT_STYLE (item)->stroke_width.computed * + to_2geom(sp_item_i2d_affine(item)).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(); + + sp_document_done( doc , SP_VERB_NONE, + _("Drop color")); + } + } + } + break; + + case APP_OSWB_COLOR: + { + bool worked = false; + Glib::ustring colorspec; + if ( data->format == 8 ) { + ege::PaintDef color; + worked = color.fromMIMEData("application/x-oswb-color", + reinterpret_cast(data->data), + data->length, + data->format); + 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 = sp_document_get_resource_list(doc, "gradient"); + for (const GSList *item = gradients; item; item = item->next) { + SPGradient* grad = SP_GRADIENT(item->data); + if ( color.descr == grad->id ) { + if ( grad->has_stops ) { + matches = grad; + break; + } + } + } + if (matches) { + colorspec = "url(#"; + colorspec += matches->id; + 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->item_at_point( 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) { + sp_document_done( doc , SP_VERB_NONE, _("Drop color on gradient")); + desktop->event_context->get_drag()->updateDraggers(); + } + } + + if (!consumed && item) { + bool fillnotstroke = (drag_context->action != 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); - NR::Maybe position = get_nearest_position_on_Path(livarot_path, button_doc); + boost::optional position = get_nearest_position_on_Path(livarot_path, button_doc); if (position) { - NR::Point nearest = get_point_on_Path(livarot_path, position->piece, position->t); - NR::Point delta = nearest - button_doc; + 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 = ( !SP_OBJECT_STYLE(item)->stroke.isNone() ? desktop->current_zoom() * SP_OBJECT_STYLE (item)->stroke_width.computed * - NR::expansion(from_2geom(sp_item_i2d_affine(item))) * 0.5 + to_2geom(sp_item_i2d_affine(item)).descrim() * 0.5 : 0.0) - + prefs_get_int_attribute_limited("options.dragtolerance", "value", 0, 0, 100); + + prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); - if (NR::L2 (delta) < stroke_tolerance) { + if (Geom::L2 (delta) < stroke_tolerance) { fillnotstroke = false; } } @@ -1201,12 +1381,12 @@ sp_ui_drag_data_received(GtkWidget *widget, } SPCSSAttr *css = sp_repr_css_attr_new(); - sp_repr_css_set_property( css, fillnotstroke ? "fill":"stroke", c ); + sp_repr_css_set_property( css, fillnotstroke ? "fill":"stroke", colorspec.c_str() ); sp_desktop_apply_css_recursive( item, css, true ); item->updateRepr(); - sp_document_done( doc , SP_VERB_NONE, + sp_document_done( doc , SP_VERB_NONE, _("Drop color")); } } @@ -1246,22 +1426,19 @@ sp_ui_drag_data_received(GtkWidget *widget, Inkscape::Selection *selection = sp_desktop_selection(desktop); selection->set(SP_ITEM(new_obj)); - // To move the imported object, we must temporarily set the "transform pattern with - // object" option. + + // move to mouse pointer { - int const saved_pref = prefs_get_int_attribute("options.transform", "pattern", 1); - prefs_set_int_attribute("options.transform", "pattern", 1); sp_document_ensure_up_to_date(sp_desktop_document(desktop)); - NR::Maybe sel_bbox = selection->bounds(); + Geom::OptRect sel_bbox = selection->bounds(); if (sel_bbox) { - NR::Point m( desktop->point() - sel_bbox->midpoint() ); - sp_selection_move_relative(selection, m); + Geom::Point m( desktop->point() - sel_bbox->midpoint() ); + sp_selection_move_relative(selection, m, false); } - prefs_set_int_attribute("options.transform", "pattern", saved_pref); } Inkscape::GC::release(newgroup); - sp_document_done(doc, SP_VERB_NONE, + sp_document_done(doc, SP_VERB_NONE, _("Drop SVG")); break; } @@ -1275,27 +1452,23 @@ sp_ui_drag_data_received(GtkWidget *widget, case PNG_DATA: case JPEG_DATA: case IMAGE_DATA: { - char tmp[1024]; - - StringOutputStream outs; - Base64OutputStream b64out(outs); - b64out.setColumnWidth(0); - Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc); - Inkscape::XML::Node *newImage = xml_doc->createElement("svg:image"); + gchar *atom_name = gdk_atom_name(data->type); - for ( int i = 0; i < data->length; i++ ) { - b64out.put( data->data[i] ); - } - b64out.close(); + // this formula taken from Glib docs + guint needed_size = data->length * 4 / 3 + data->length * 4 / (3 * 72) + 7; + needed_size += 5 + 8 + strlen(atom_name); // 5 bytes for data:, 8 for ;base64, + gchar *buffer = (gchar *) g_malloc(needed_size), *buf_work = buffer; + buf_work += g_sprintf(buffer, "data:%s;base64,", atom_name); - Glib::ustring str = outs.getString(); + gint state = 0, save = 0; + g_base64_encode_step(data->data, data->length, TRUE, buf_work, &state, &save); + g_base64_encode_close(TRUE, buf_work, &state, &save); - snprintf( tmp, sizeof(tmp), "data:%s;base64,", gdk_atom_name(data->type) ); - str.insert( 0, tmp ); - newImage->setAttribute("xlink:href", str.c_str()); + newImage->setAttribute("xlink:href", buffer); + g_free(buffer); GError *error = NULL; GdkPixbufLoader *loader = gdk_pixbuf_loader_new_with_mime_type( gdk_atom_name(data->type), &error ); @@ -1304,6 +1477,7 @@ sp_ui_drag_data_received(GtkWidget *widget, if ( gdk_pixbuf_loader_write( loader, data->data, data->length, &error) ) { GdkPixbuf *pbuf = gdk_pixbuf_loader_get_pixbuf(loader); if ( pbuf ) { + char tmp[1024]; int width = gdk_pixbuf_get_width(pbuf); int height = gdk_pixbuf_get_height(pbuf); snprintf( tmp, sizeof(tmp), "%d", width ); @@ -1314,12 +1488,13 @@ sp_ui_drag_data_received(GtkWidget *widget, } } } + g_free(atom_name); // Add it to the current layer desktop->currentLayer()->appendChildRepr(newImage); Inkscape::GC::release(newImage); - sp_document_done( doc , SP_VERB_NONE, + sp_document_done( doc , SP_VERB_NONE, _("Drop bitmap image")); break; } @@ -1456,7 +1631,7 @@ sp_ui_menu_item_set_name(SPAction */*action*/, Glib::ustring name, void *data) gtk_label_set_markup_with_mnemonic(GTK_LABEL (child), name.c_str()); } else if (GTK_IS_HBOX(child)) { gtk_label_set_markup_with_mnemonic( - GTK_LABEL (gtk_container_get_children(GTK_CONTAINER (child))->data), + 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...