From 0e8b0c199da552a1d026b55d8bf5a66ee62cefd6 Mon Sep 17 00:00:00 2001 From: Henry Wong Date: Sun, 21 Sep 2025 19:00:32 -0700 Subject: [PATCH 1/3] Add tracking of "Object type's current style" and clean up style get/apply code Add tracking of "Object type's current style" to some tools. Use this option as the default. - Addresses https://gitlab.com/inkscape/inbox/-/issues/717 - Paths (pencil, pen, calligraphic, paintbucket), 3dbox, text, rect, arc, star, spiral Improve 3DBox "current style" tracking: - Distingush between "last used style" (apply one style to all faces) and "object type's last used style" (track six faces separately) - Take style from selected object now captures styles for all six faces - Attempts to address https://gitlab.com/inkscape/inbox/-/issues/1565 and https://gitlab.com/inkscape/inbox/-/issues/3626 - 3dbox faces now use a single usecurrent pref for all six faces: tools/shapes/3dbox/usecurrent - Make string_from_axes(axis) return static strings instead of dynamically-constructed strings Unified the code that retrieves desktop, tool-current or tool's-own styles - Everything now goes through SPDesktop::getCurrentOrToolStyle - Removed sp_desktop_get_style, sp_desktop_apply_style_tool - Always applies the Tool's own style, and overrides properties with one of the current styles if needed (Avoids a scenario where applying a current property (e.g., stroke) causes a different property (e.g., tool's own fill) to be unset) - Filtering of attributes is also unified: Always uses SPStyle::sp_css_attr_unset_blacklist/sp_css_attr_unset_uris/sp_css_attr_unset_text sp_desktop_get_*_tool: If it can get the requested property from the tool, don't require desktop->current to be set. --- src/axis-manip.cpp | 10 +- src/axis-manip.h | 14 ++- src/desktop-style.cpp | 155 +++++++------------------ src/desktop-style.h | 2 - src/desktop.cpp | 79 +++++++++++-- src/desktop.h | 5 +- src/libnrtype/font-lister.cpp | 8 +- src/object/box3d-side.cpp | 39 +++++-- src/object/box3d-side.h | 2 +- src/object/sp-flowtext.cpp | 2 +- src/object/sp-text.cpp | 2 +- src/preferences-skeleton.h | 30 ++--- src/style.cpp | 5 + src/ui/dialog/inkscape-preferences.cpp | 71 +++++++---- src/ui/dialog/inkscape-preferences.h | 2 +- src/ui/toolbar/text-toolbar.cpp | 7 +- src/ui/tools/arc-tool.cpp | 2 +- src/ui/tools/box3d-tool.cpp | 25 +--- src/ui/tools/calligraphic-tool.cpp | 2 +- src/ui/tools/connector-tool.cpp | 2 +- src/ui/tools/eraser-tool.cpp | 4 +- src/ui/tools/flood-tool.cpp | 2 +- src/ui/tools/freehand-base.cpp | 6 +- src/ui/tools/measure-tool.cpp | 2 +- src/ui/tools/rect-tool.cpp | 2 +- src/ui/tools/spiral-tool.cpp | 2 +- src/ui/tools/star-tool.cpp | 2 +- src/ui/tools/text-tool.cpp | 2 +- src/ui/widget/style-swatch.cpp | 28 +---- src/xml/repr-css.cpp | 2 +- src/xml/repr.h | 2 +- 31 files changed, 265 insertions(+), 253 deletions(-) diff --git a/src/axis-manip.cpp b/src/axis-manip.cpp index 66b5c82438..55b68c09bb 100644 --- a/src/axis-manip.cpp +++ b/src/axis-manip.cpp @@ -33,16 +33,8 @@ get_remaining_axes (Axis axis) { return std::make_pair (extract_first_axis_direction (plane), extract_second_axis_direction (plane)); } -Glib::ustring string_from_axes (Box3D::Axis axis) { - Glib::ustring result; - if (axis & Box3D::X) result += "X"; - if (axis & Box3D::Y) result += "Y"; - if (axis & Box3D::Z) result += "Z"; - return result; -} +} // namespace Box3D -} // namespace Box3D - /* Local Variables: mode:c++ diff --git a/src/axis-manip.h b/src/axis-manip.h index d473f4ed01..7645a31f5f 100644 --- a/src/axis-manip.h +++ b/src/axis-manip.h @@ -136,7 +136,7 @@ inline Box3D::Axis toAffine(Proj::Axis axis) { namespace Box3D { -/* +/* * Identify the axes X, Y, Z with the numbers 0, 1, 2. * A box's face is identified by the axis perpendicular to it. * For a rear face, add 3. @@ -240,7 +240,17 @@ inline Box3D::Axis get_perpendicular_axis_direction (Box3D::Axis dirs) { return Box3D::NONE; } -Glib::ustring string_from_axes (Box3D::Axis axis); +constexpr std::string string_from_axes(Box3D::Axis axis) +{ + std::string result; + if (axis & Box3D::X) + result += "X"; + if (axis & Box3D::Y) + result += "Y"; + if (axis & Box3D::Z) + result += "Z"; + return result; +} std::pair get_remaining_axes (Axis axis); } // namespace Box3D diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp index 184ff46728..165b2fbe69 100644 --- a/src/desktop-style.cpp +++ b/src/desktop-style.cpp @@ -15,6 +15,7 @@ #include #include +#include #include @@ -52,9 +53,6 @@ #include "ui/tools/tool-base.h" -#include -#include "xml/sp-css-attr.h" -#include "xml/attribute-record.h" static bool isTextualItem(SPObject const *obj) { @@ -188,16 +186,35 @@ sp_desktop_set_style(Inkscape::ObjectSet *set, SPDesktop *desktop, SPCSSAttr *cs sp_repr_css_merge(css_write, css); sp_css_attr_unset_uris(css_write); prefs->mergeStyle("/desktop/style", css_write); + + // Avoid string comparisons by assuming most strings are const char* literals where strings with the same content tend to have the same pointer value. + // Find the set of selected item types that need its per-object-type current style updated + std::unordered_set selected_item_types; auto itemlist = set->items(); for (auto i = itemlist.begin(); i!= itemlist.end(); ++i) { - /* last used styles for 3D box faces are stored separately */ - SPObject *obj = *i; - auto side = cast(obj); - if (side) { - prefs->mergeStyle( - Glib::ustring("/desktop/") + side->axes_string() + "/style", css_write); + SPItem *obj = *i; + if (auto *side = cast(obj)) { + selected_item_types.emplace(side->axes_string().data()); + } else { + selected_item_types.emplace(obj->typeName()); + } + } + + // Update item type's current style for all seleted item types + // Remap some item type names (for tools that can create more than one item type) + static const std::unordered_map item_type_map = { + {"circle", "arc"}, + {"polygon", "star"}, + {"text-flow", "text"} + }; + for (const char* item_type : selected_item_types) { + if (auto i = item_type_map.find(item_type) ; i != item_type_map.end()) { + item_type = i->second; } + prefs->mergeStyle( + Glib::ustring("/desktop/") + item_type + "/style", css_write); } + sp_repr_css_attr_unref(css_write); } @@ -246,68 +263,34 @@ sp_desktop_set_style(Inkscape::ObjectSet *set, SPDesktop *desktop, SPCSSAttr *cs } } -/** - * Return the desktop's current style. - */ -SPCSSAttr * -sp_desktop_get_style(SPDesktop *desktop, bool with_text) -{ - SPCSSAttr *css = sp_repr_css_attr_new(); - sp_repr_css_merge(css, desktop->current); - const auto & l = css->attributeList(); - if (l.empty()) { - sp_repr_css_attr_unref(css); - return nullptr; - } else { - if (!with_text) { - css = sp_css_attr_unset_text(css); - } - return css; - } -} - /** * Return the desktop's current color. */ std::optional sp_desktop_get_color(SPDesktop *desktop, bool is_fill) { - if (!desktop) return std::nullopt; + if (!desktop || !desktop->current) return std::nullopt; gchar const *property = sp_repr_css_property(desktop->current, is_fill ? "fill" : "stroke", "#000"); - - // if there is style and the property in it, - return Color::parse(desktop->current ? property : nullptr); + return Color::parse(property); } double sp_desktop_get_master_opacity_tool(SPDesktop *desktop, Glib::ustring const &tool, bool *has_opacity) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - SPCSSAttr *css = nullptr; gfloat value = 1.0; // default if nothing else found if (has_opacity) *has_opacity = false; - if (prefs->getBool(tool + "/usecurrent")) { - css = sp_desktop_get_style(desktop, true); - } else { - css = prefs->getStyle(tool + "/style"); - } - - if (css) { - gchar const *property = css ? sp_repr_css_property(css, "opacity", "1.000") : nullptr; - if (desktop->current && property) { // if there is style and the property in it, - if ( !sp_svg_number_read_f(property, &value) ) { - value = 1.0; // things failed. set back to the default - } else { + if (SPCSSAttr *css = desktop->getCurrentOrToolStyle(tool, true)) { + if (gchar const *property = sp_repr_css_property(css, "opacity", "1.000")) { + if ( sp_svg_number_read_f(property, &value) ) { if (has_opacity) *has_opacity = true; } } - sp_repr_css_attr_unref(css); } @@ -316,24 +299,12 @@ sp_desktop_get_master_opacity_tool(SPDesktop *desktop, Glib::ustring const &tool double sp_desktop_get_opacity_tool(SPDesktop *desktop, Glib::ustring const &tool, bool is_fill) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - SPCSSAttr *css = nullptr; gfloat value = 1.0; // default if nothing else found - if (prefs->getBool(tool + "/usecurrent")) { - css = sp_desktop_get_style(desktop, true); - } else { - css = prefs->getStyle(tool + "/style"); - } - - if (css) { - gchar const *property = css ? sp_repr_css_property(css, is_fill ? "fill-opacity": "stroke-opacity", "1.000") : nullptr; - if (desktop->current && property) { // if there is style and the property in it, - if ( !sp_svg_number_read_f(property, &value) ) { - value = 1.0; // things failed. set back to the default - } + if (SPCSSAttr *css = desktop->getCurrentOrToolStyle(tool, true)) { + if (gchar const *property = sp_repr_css_property(css, is_fill ? "fill-opacity": "stroke-opacity", "1.000")) { + sp_svg_number_read_f(property, &value); // Does not modify value if failed. } - sp_repr_css_attr_unref(css); } @@ -343,55 +314,17 @@ sp_desktop_get_opacity_tool(SPDesktop *desktop, Glib::ustring const &tool, bool std::optional sp_desktop_get_color_tool(SPDesktop *desktop, Glib::ustring const &tool, bool is_fill) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - SPCSSAttr *css = nullptr; - bool styleFromCurrent = prefs->getBool(tool + "/usecurrent"); - if (styleFromCurrent) { - css = sp_desktop_get_style(desktop, true); - } else { - css = prefs->getStyle(tool + "/style"); - Inkscape::GC::anchor(css); - } - std::optional ret; - if (css) { + + if (SPCSSAttr *css = desktop->getCurrentOrToolStyle(tool, true)) { gchar const *property = sp_repr_css_property(css, is_fill ? "fill" : "stroke", "#000"); // if there is style and the property in it, - ret = Color::parse(desktop->current ? property : nullptr); + ret = Color::parse(property); // parse handles property=nullptr. sp_repr_css_attr_unref(css); } return ret; } -/** - * Apply the desktop's current style or the tool style to repr. - */ -void -sp_desktop_apply_style_tool(SPDesktop *desktop, Inkscape::XML::Node *repr, Glib::ustring const &tool_path, bool with_text) -{ - SPCSSAttr *css_current = sp_desktop_get_style(desktop, with_text); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - - if (prefs->getBool(tool_path + "/usecurrent") && css_current) { - sp_repr_css_unset_property(css_current, "shape-inside"); - sp_repr_css_unset_property(css_current, "shape-subtract"); - sp_repr_css_unset_property(css_current, "mix-blend-mode"); - sp_repr_css_unset_property(css_current, "filter"); - sp_repr_css_unset_property(css_current, "stop-color"); - sp_repr_css_unset_property(css_current, "stop-opacity"); - sp_repr_css_set(repr, css_current, "style"); - } else { - SPCSSAttr *css = prefs->getInheritedStyle(tool_path + "/style"); - sp_repr_css_unset_property(css, "shape-inside"); - sp_repr_css_unset_property(css, "shape-subtract"); - sp_repr_css_set(repr, css, "style"); - sp_repr_css_attr_unref(css); - } - if (css_current) { - sp_repr_css_attr_unref(css_current); - } -} - /** * Returns the font size (in SVG pixels) of the text tool style (if text * tool uses its own style) or desktop style (otherwise). @@ -399,20 +332,10 @@ sp_desktop_apply_style_tool(SPDesktop *desktop, Inkscape::XML::Node *repr, Glib: double sp_desktop_get_font_size_tool(SPDesktop *desktop) { - (void)desktop; // TODO cleanup - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - Glib::ustring desktop_style = prefs->getString("/desktop/style"); - Glib::ustring style_str; - if ((prefs->getBool("/tools/text/usecurrent")) && !desktop_style.empty()) { - style_str = desktop_style; - } else { - style_str = prefs->getString("/tools/text/style"); - } - double ret = 12; - if (!style_str.empty()) { + if (SPCSSAttr *css = desktop->getCurrentOrToolStyle("/tools/text", true)) { SPStyle style(SP_ACTIVE_DOCUMENT); - style.mergeString(style_str.data()); + style.mergeCSS(css); ret = style.font_size.computed; } return ret; diff --git a/src/desktop-style.h b/src/desktop-style.h index fa1f4dff15..66f12c5e4f 100644 --- a/src/desktop-style.h +++ b/src/desktop-style.h @@ -75,13 +75,11 @@ void sp_desktop_apply_css_recursive(SPObject *o, SPCSSAttr *css, bool skip_lines void sp_desktop_set_color(SPDesktop *desktop, Color const &color, bool is_relative, bool fill); void sp_desktop_set_style(Inkscape::ObjectSet *set, SPDesktop *desktop, SPCSSAttr *css, bool change = true, bool write_current = true, bool switch_style = false); void sp_desktop_set_style(SPDesktop *desktop, SPCSSAttr *css, bool change = true, bool write_current = true, bool switch_style = false); -SPCSSAttr *sp_desktop_get_style(SPDesktop *desktop, bool with_text); double sp_desktop_get_master_opacity_tool(SPDesktop *desktop, Glib::ustring const &tool, bool* has_opacity = nullptr); double sp_desktop_get_opacity_tool(SPDesktop *desktop, Glib::ustring const &tool, bool is_fill); std::optional sp_desktop_get_color (SPDesktop *desktop, bool is_fill); std::optional sp_desktop_get_color_tool(SPDesktop *desktop, Glib::ustring const &tool, bool is_fill); double sp_desktop_get_font_size_tool (SPDesktop *desktop); -void sp_desktop_apply_style_tool(SPDesktop *desktop, Inkscape::XML::Node *repr, Glib::ustring const &tool, bool with_text); gdouble stroke_average_width (const std::vector &objects); diff --git a/src/desktop.cpp b/src/desktop.cpp index 7abd51c830..f499f3c6ff 100644 --- a/src/desktop.cpp +++ b/src/desktop.cpp @@ -38,6 +38,7 @@ #include "layer-manager.h" #include "message-context.h" #include "message-stack.h" +#include "style.h" #include "actions/actions-canvas-mode.h" #include "actions/actions-canvas-transform.h" #include "actions/actions-view-mode.h" // To update View menu @@ -65,6 +66,7 @@ #include "ui/tools/node-tool.h" #include "ui/tool/control-point-selection.h" #include "util/enums.h" +#include "xml/sp-css-attr.h" namespace Inkscape::XML { class Node; } @@ -1107,23 +1109,82 @@ SPDesktop::onWindowStateChanged(Gdk::Toplevel::State const changed, /** * Apply the desktop's current style or the tool style to the object. */ -void SPDesktop::applyCurrentOrToolStyle(SPObject *obj, Glib::ustring const &tool_path, bool with_text) +void SPDesktop::applyCurrentOrToolStyle(SPObject *obj, Glib::ustring const &tool_path, bool with_text, const Glib::ustring &use_current) const { - SPCSSAttr *css_current = sp_desktop_get_style(this, with_text); + applyCurrentOrToolStyle(obj->getRepr(), tool_path, with_text, use_current); +} +void SPDesktop::applyCurrentOrToolStyle(Inkscape::XML::Node *repr, Glib::ustring const &tool_path, bool with_text, const Glib::ustring &use_current) const +{ + if (SPCSSAttr *css = getCurrentOrToolStyle(tool_path, with_text, use_current)) { + sp_repr_css_set(repr, css, "style"); + sp_repr_css_attr_unref(css); + } +} + +SPCSSAttr * +SPDesktop::getCurrentOrToolStyle(Glib::ustring const &tool_path, bool with_text, const Glib::ustring &use_current_arg) const +{ + // use_current = "": Read tool_path/usecurrent preference to decide which style to fetch. + // Or, force one of the options with a non-empty string (used by 3dbox to specify faces): + // "0": Use tools/tool_path/style (Tool's own style) + // "1": Use desktop/style (Last used style) + // "itemtype": Use desktop/itemtype/style (Last used style of same object type) Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + SPCSSAttr *css = sp_repr_css_attr_new(); + Glib::ustring use_current_pref; + const Glib::ustring *use_current = &use_current_arg; + if (use_current_arg.empty()) { + use_current_pref = prefs->getString(tool_path + "/usecurrent"); + use_current = &use_current_pref; + } - if (prefs->getBool(tool_path + "/usecurrent") && css_current) { - obj->setCSS(css_current,"style"); - } else { - SPCSSAttr *css = prefs->getInheritedStyle(tool_path + "/style"); - obj->setCSS(css,"style"); + // Start with per-tool style, then apply current style on top if required + if (SPCSSAttr *css_tool = prefs->getInheritedStyle(tool_path + "/style")) { + sp_repr_css_merge(css, css_tool); + sp_repr_css_attr_unref(css_tool); + } + if (!use_current->empty() && *use_current != "0") { // use_current should never be empty, but treat empty as "0" + if (*use_current == "1") { + sp_repr_css_merge(css, this->current); + } + else { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + auto *css_new = prefs->getStyle(Glib::ustring("/desktop/") + *use_current + "/style"); // getStyle never returns nullptr + sp_repr_css_merge(css, css_new); + sp_repr_css_attr_unref(css_new); + } + } + if (css->attributeList().empty()) { sp_repr_css_attr_unref(css); + return nullptr; } - if (css_current) { - sp_repr_css_attr_unref(css_current); + + // Remove unwanted attributes + sp_css_attr_unset_blacklist(css); + sp_css_attr_unset_uris(css); + if (!with_text) { + sp_css_attr_unset_text(css); } + + return css; // Caller is responsible for sp_repr_css_attr_unref(css) } +Glib::ustring +SPDesktop::getCurrentOrToolStylePath(Glib::ustring const &tool_path) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (auto use_current = prefs->getString(tool_path + "/usecurrent"); !use_current.empty() && use_current != "0") { + if (use_current == "1") { + return "/desktop/style"; + } else { + return Glib::ustring("/desktop/") + use_current + "/style"; + } + } else { + return tool_path + "/style"; + } +} + + void SPDesktop::setToolboxFocusTo(char const * const label) { diff --git a/src/desktop.h b/src/desktop.h index d58ffcb60f..8f9d1e8a47 100644 --- a/src/desktop.h +++ b/src/desktop.h @@ -430,7 +430,10 @@ public: void onWindowStateChanged(Gdk::Toplevel::State changed, Gdk::Toplevel::State new_toplevel_state); - void applyCurrentOrToolStyle(SPObject *obj, Glib::ustring const &tool_path, bool with_text); + void applyCurrentOrToolStyle(SPObject *obj, Glib::ustring const &tool_path, bool with_text, const Glib::ustring &use_current = "") const; + void applyCurrentOrToolStyle(Inkscape::XML::Node *repr, Glib::ustring const &tool_path, bool with_text, const Glib::ustring &use_current = "") const; + SPCSSAttr *getCurrentOrToolStyle(Glib::ustring const &tool_path, bool with_text, const Glib::ustring &use_current = "") const; + Glib::ustring getCurrentOrToolStylePath(Glib::ustring const &tool_path); private: SPDesktopWidget *_widget = nullptr; diff --git a/src/libnrtype/font-lister.cpp b/src/libnrtype/font-lister.cpp index 071b3243fd..8b0e992f58 100644 --- a/src/libnrtype/font-lister.cpp +++ b/src/libnrtype/font-lister.cpp @@ -715,11 +715,9 @@ std::pair FontLister::selection_update() // From preferences if (fontspec.empty()) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - if (prefs->getBool("/tools/text/usecurrent")) { - query.mergeCSS(sp_desktop_get_style(SP_ACTIVE_DESKTOP, true)); - } else { - query.readFromPrefs("/tools/text"); + if (SPCSSAttr *css = SP_ACTIVE_DESKTOP->getCurrentOrToolStyle("/tools/text", true)) { + query.mergeCSS(css); + sp_repr_css_attr_unref(css); } fontspec = fontspec_from_style(&query); } diff --git a/src/object/box3d-side.cpp b/src/object/box3d-side.cpp index e293a599df..6c67a76f3c 100644 --- a/src/object/box3d-side.cpp +++ b/src/object/box3d-side.cpp @@ -121,7 +121,7 @@ Box3DSide * Box3DSide::createBox3DSide(SPBox3D *box) } /* - * Function which return the type attribute for Box3D. + * Function which return the type attribute for Box3D. * Acts as a replacement for directly accessing the XML Tree directly. */ int Box3DSide::getFaceId() @@ -201,30 +201,53 @@ void Box3DSide::set_shape() { setCurveInsync(std::move(c)); } -Glib::ustring Box3DSide::axes_string() const +constexpr std::string axis_string(Box3D::Axis dirs, bool rear) { - Glib::ustring result(Box3D::string_from_axes((Box3D::Axis) (this->dir1 ^ this->dir2))); + std::string result(Box3D::string_from_axes(dirs)); - switch ((Box3D::Axis) (this->dir1 ^ this->dir2)) { + switch (dirs) { case Box3D::XY: - result += ((this->front_or_rear == Box3D::FRONT) ? "front" : "rear"); + result += (!rear ? "front" : "rear"); break; case Box3D::XZ: - result += ((this->front_or_rear == Box3D::FRONT) ? "top" : "bottom"); + result += (!rear ? "top" : "bottom"); break; case Box3D::YZ: - result += ((this->front_or_rear == Box3D::FRONT) ? "right" : "left"); + result += (!rear ? "right" : "left"); break; default: break; } - return result; } +const Glib::ustring & Box3DSide::axes_string() const +{ + static const Glib::ustring strings[16] = { + axis_string((Box3D::Axis)0, 0).c_str(), + axis_string((Box3D::Axis)1, 0).c_str(), + axis_string((Box3D::Axis)2, 0).c_str(), + axis_string((Box3D::Axis)3, 0).c_str(), + axis_string((Box3D::Axis)4, 0).c_str(), + axis_string((Box3D::Axis)5, 0).c_str(), + axis_string((Box3D::Axis)6, 0).c_str(), + axis_string((Box3D::Axis)7, 0).c_str(), + axis_string((Box3D::Axis)0, 1).c_str(), + axis_string((Box3D::Axis)1, 1).c_str(), + axis_string((Box3D::Axis)2, 1).c_str(), + axis_string((Box3D::Axis)3, 1).c_str(), + axis_string((Box3D::Axis)4, 1).c_str(), + axis_string((Box3D::Axis)5, 1).c_str(), + axis_string((Box3D::Axis)6, 1).c_str(), + axis_string((Box3D::Axis)7, 1).c_str(), + }; + + return strings[ ((this->dir1 ^ this->dir2) | this->front_or_rear) ]; +} + static void box3d_side_compute_corner_ids(Box3DSide *side, unsigned int corners[4]) { Box3D::Axis orth = Box3D::third_axis_direction (side->dir1, side->dir2); diff --git a/src/object/box3d-side.h b/src/object/box3d-side.h index 775662e108..38da18d416 100644 --- a/src/object/box3d-side.h +++ b/src/object/box3d-side.h @@ -43,7 +43,7 @@ public: void position_set(); // FIXME: Replace this by Box3DSide::set_shape?? - Glib::ustring axes_string() const; + const Glib::ustring &axes_string() const; Persp3D *perspective() const; diff --git a/src/object/sp-flowtext.cpp b/src/object/sp-flowtext.cpp index 8b6d0d3140..548765fa84 100644 --- a/src/object/sp-flowtext.cpp +++ b/src/object/sp-flowtext.cpp @@ -646,7 +646,7 @@ SPItem *create_flowtext_with_internal_frame (SPDesktop *desktop, Geom::Point p0, root_repr->setAttributeOrRemoveIfEmpty("transform", sp_svg_transform_write(parent->i2doc_affine().inverse())); /* Set style */ - sp_desktop_apply_style_tool(desktop, root_repr, "/tools/text", true); + desktop->applyCurrentOrToolStyle(root_repr, "/tools/text", true); auto ft_item = cast(parent->appendChildRepr(root_repr)); g_assert(ft_item != nullptr); diff --git a/src/object/sp-text.cpp b/src/object/sp-text.cpp index 2a1f0594b0..89820e24d0 100644 --- a/src/object/sp-text.cpp +++ b/src/object/sp-text.cpp @@ -1302,7 +1302,7 @@ SPItem *create_text_with_rectangle (SPDesktop *desktop, Geom::Point p0, Geom::Po defs_repr->addChild(rect_repr, nullptr); // Apply desktop style (do before adding "shape-inside"). - sp_desktop_apply_style_tool(desktop, text_repr, "/tools/text", true); + desktop->applyCurrentOrToolStyle(text_repr, "/tools/text", true); SPCSSAttr *css = sp_repr_css_attr(text_repr, "style" ); sp_repr_css_set_property (css, "white-space", "pre"); // Respect new lines. diff --git a/src/preferences-skeleton.h b/src/preferences-skeleton.h index cf37930053..a0b96aa55e 100644 --- a/src/preferences-skeleton.h +++ b/src/preferences-skeleton.h @@ -77,28 +77,28 @@ static char const preferences_skeleton[] = - - - - - - - - + + + + + + + + - - - + + + - - + + @@ -119,7 +119,7 @@ static char const preferences_skeleton[] = - diff --git a/src/style.cpp b/src/style.cpp index 7dda499bd7..ef319f7834 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -1505,6 +1505,7 @@ sp_css_attr_unset_blacklist(SPCSSAttr *css) sp_repr_css_set_property(css, "visibility", nullptr); sp_repr_css_set_property(css, "isolation", nullptr); sp_repr_css_set_property(css, "mix-blend-mode", nullptr); + sp_repr_css_set_property(css, "filter", nullptr); sp_repr_css_set_property(css, "color-interpolation", nullptr); sp_repr_css_set_property(css, "color-interpolation-filters", nullptr); sp_repr_css_set_property(css, "solid-color", nullptr); @@ -1515,6 +1516,10 @@ sp_css_attr_unset_blacklist(SPCSSAttr *css) sp_repr_css_set_property(css, "shape-rendering", nullptr); sp_repr_css_set_property(css, "text-rendering", nullptr); sp_repr_css_set_property(css, "enable-background", nullptr); + sp_repr_css_set_property(css, "shape-inside", nullptr); // Don't want this in a style even if it doesn't contain a uri + sp_repr_css_set_property(css, "shape-subtract", nullptr); + sp_repr_css_set_property(css, "stop-color", nullptr); + sp_repr_css_set_property(css, "stop-opacity", nullptr); return css; } diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp index e2fa5f5df0..2282a00896 100644 --- a/src/ui/dialog/inkscape-preferences.cpp +++ b/src/ui/dialog/inkscape-preferences.cpp @@ -64,6 +64,8 @@ #include "selection-chemistry.h" #include "selection.h" #include "style.h" +#include "object/box3d.h" +#include "object/box3d-side.h" #include "ui/builder-utils.h" #include "ui/modifiers.h" #include "ui/pack.h" @@ -170,6 +172,9 @@ static int get_num_matches(Glib::ustring const &key, Gtk::Widget *widget) return matches; } +static void StyleFromItemToTool(SPItem *item, Glib::ustring const &prefs_path, StyleSwatch *swatch); +static void StyleFrom3DBox(SPBox3D *item, Glib::ustring const &prefs_path); + // Shortcuts model ============= class ModelColumns final : public Gtk::TreeModel::ColumnRecord { @@ -777,7 +782,6 @@ void InkscapePreferences::AddBaseSimplifySpinbutton(DialogPage &p, Glib::ustring false ); } - static void StyleFromSelectionToTool(Glib::ustring const &prefs_path, StyleSwatch *swatch) { SPDesktop *desktop = SP_ACTIVE_DESKTOP; @@ -801,6 +805,11 @@ static void StyleFromSelectionToTool(Glib::ustring const &prefs_path, StyleSwatc return; } + StyleFromItemToTool(item, prefs_path, swatch); +} + +static void StyleFromItemToTool(SPItem *item, Glib::ustring const &prefs_path, StyleSwatch *swatch) +{ SPCSSAttr *css = take_style_from_item (item); if (!css) return; @@ -820,6 +829,11 @@ static void StyleFromSelectionToTool(Glib::ustring const &prefs_path, StyleSwatc prefs->setStyle(prefs_path + "/style", css); sp_repr_css_attr_unref (css); + // Special case for 3DBox objects: Sample all six faces. + if (auto *box3d = cast(item)) { + StyleFrom3DBox(box3d, prefs_path); + } + // update the swatch if (swatch) { SPCSSAttr *css = prefs->getInheritedStyle(prefs_path + "/style"); @@ -828,20 +842,37 @@ static void StyleFromSelectionToTool(Glib::ustring const &prefs_path, StyleSwatc } } -void InkscapePreferences::AddNewObjectsStyle(DialogPage &p, Glib::ustring const &prefs_path, const gchar *banner) +static void StyleFrom3DBox(SPBox3D *item, Glib::ustring const &prefs_path) +{ + for (auto& child : item->children) { + if (auto *side = cast(&child)) { + StyleFromItemToTool(side, prefs_path + "/" + side->axes_string(), nullptr); + } + } +} + + +void InkscapePreferences::AddNewObjectsStyle(DialogPage &p, Glib::ustring const &prefs_path, Glib::ustring const &item_type, const gchar *banner) { if (banner) p.add_group_header(banner); else p.add_group_header( _("Style of new objects")); auto const current = Gtk::make_managed(); - current->init ( _("Last used style"), prefs_path + "/usecurrent", 1, true, nullptr); + current->init ( _("Last used style"), prefs_path + "/usecurrent", "1", true, nullptr); p.add_line( true, "", *current, "", _("Apply the style you last set on an object")); + if (item_type.size() >= 2) { + auto const current_tool = Gtk::make_managed(); + current_tool->init ( _("Object type's last used style"), prefs_path + "/usecurrent", item_type, false, current); + p.add_line( true, "", *current_tool, "", + _("Apply the style you last set on an object of the same type that this tool creates")); + } + auto const own = Gtk::make_managed(); auto const hb = Gtk::make_managed(); - own->init ( _("This tool's own style:"), prefs_path + "/usecurrent", 0, false, current); + own->init ( _("This tool's own style:"), prefs_path + "/usecurrent", "0", false, current); own->set_halign(Gtk::Align::START); own->set_valign(Gtk::Align::START); hb->append(*own); @@ -854,9 +885,7 @@ void InkscapePreferences::AddNewObjectsStyle(DialogPage &p, Glib::ustring const StyleSwatch *swatch = nullptr; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - if (prefs->getInt(prefs_path + "/usecurrent")) { - button->set_sensitive(false); - } + button->set_sensitive(own->get_active()); SPCSSAttr *css = prefs->getStyle(prefs_path + "/style"); swatch = Gtk::make_managed(css, _("This tool's style of new objects")); @@ -1018,7 +1047,7 @@ void InkscapePreferences::initPageTools() _page_node.add_line( false, _("Cut Mode:"), _t_node_cut_mode, "", _("What happens when nodes are cut."), false); //Tweak - this->AddNewObjectsStyle(_page_tweak, "/tools/tweak", _("Object paint style")); + this->AddNewObjectsStyle(_page_tweak, "/tools/tweak", "", _("Object paint style")); AddSelcueCheckbox(_page_tweak, "/tools/tweak", true); AddGradientCheckbox(_page_tweak, "/tools/tweak", false); @@ -1036,25 +1065,25 @@ void InkscapePreferences::initPageTools() this->AddGradientCheckbox(_page_shapes, "/tools/shapes", true); //Rectangle - this->AddNewObjectsStyle(_page_rectangle, "/tools/shapes/rect"); + this->AddNewObjectsStyle(_page_rectangle, "/tools/shapes/rect", "rect"); this->AddConvertGuidesCheckbox(_page_rectangle, "/tools/shapes/rect", true); //3D box - this->AddNewObjectsStyle(_page_3dbox, "/tools/shapes/3dbox"); + this->AddNewObjectsStyle(_page_3dbox, "/tools/shapes/3dbox", "3dbox"); this->AddConvertGuidesCheckbox(_page_3dbox, "/tools/shapes/3dbox", true); //Ellipse - this->AddNewObjectsStyle(_page_ellipse, "/tools/shapes/arc"); + this->AddNewObjectsStyle(_page_ellipse, "/tools/shapes/arc", "arc"); //Star - this->AddNewObjectsStyle(_page_star, "/tools/shapes/star"); + this->AddNewObjectsStyle(_page_star, "/tools/shapes/star", "star"); //Spiral - this->AddNewObjectsStyle(_page_spiral, "/tools/shapes/spiral"); + this->AddNewObjectsStyle(_page_spiral, "/tools/shapes/spiral", "spiral"); //Pencil this->AddSelcueCheckbox(_page_pencil, "/tools/freehand/pencil", true); - this->AddNewObjectsStyle(_page_pencil, "/tools/freehand/pencil"); + this->AddNewObjectsStyle(_page_pencil, "/tools/freehand/pencil", "path"); this->AddDotSizeSpinbutton(_page_pencil, "/tools/freehand/pencil", 3.0); this->AddBaseSimplifySpinbutton(_page_pencil, "/tools/freehand/pencil", 25.0); _page_pencil.add_group_header( _("Sketch mode")); @@ -1063,12 +1092,12 @@ void InkscapePreferences::initPageTools() //Pen this->AddSelcueCheckbox(_page_pen, "/tools/freehand/pen", true); - this->AddNewObjectsStyle(_page_pen, "/tools/freehand/pen"); + this->AddNewObjectsStyle(_page_pen, "/tools/freehand/pen", "path"); this->AddDotSizeSpinbutton(_page_pen, "/tools/freehand/pen", 3.0); //Calligraphy this->AddSelcueCheckbox(_page_calligraphy, "/tools/calligraphic", false); - this->AddNewObjectsStyle(_page_calligraphy, "/tools/calligraphic"); + this->AddNewObjectsStyle(_page_calligraphy, "/tools/calligraphic", "path"); _page_calligraphy.add_line( false, "", _calligrapy_keep_selected, "", _("If on, each newly created object will be selected (deselecting previous selection)")); @@ -1110,7 +1139,7 @@ void InkscapePreferences::initPageTools() _page_text.add_line(true, _("Additional font directories"), _font_fontdirs_custom, "", _("Load additional fonts from custom locations (one path per line)"), true); - this->AddNewObjectsStyle(_page_text, "/tools/text"); + this->AddNewObjectsStyle(_page_text, "/tools/text", "text"); //Spray AddSelcueCheckbox(_page_spray, "/tools/spray", true); @@ -1121,7 +1150,7 @@ void InkscapePreferences::initPageTools() //Paint Bucket this->AddSelcueCheckbox(_page_paintbucket, "/tools/paintbucket", false); - this->AddNewObjectsStyle(_page_paintbucket, "/tools/paintbucket"); + this->AddNewObjectsStyle(_page_paintbucket, "/tools/paintbucket", "path"); //Gradient this->AddSelcueCheckbox(_page_gradient, "/tools/gradient", true); @@ -1962,7 +1991,7 @@ void InkscapePreferences::initPageUI() button->set_active(visible); button->signal_clicked().connect([=](){ bool new_state = !button->get_active(); - button->set_active(new_state); + button->set_active(new_state); Inkscape::Preferences::get()->setBool(path, button->get_active()); }); auto *iapp = InkscapeApplication::instance(); @@ -2661,7 +2690,7 @@ void InkscapePreferences::initPageBehavior() _("If possible, apply transformation to objects without adding a transform= attribute")); _page_transforms.add_line( true, "", _trans_preserved, "", _("Always store transformation as a transform= attribute on objects")); - + this->AddPage(_page_transforms, _("Transforms"), iter_behavior, PREFS_PAGE_BEHAVIOR_TRANSFORMS); // Scrolling options @@ -3053,7 +3082,7 @@ void InkscapePreferences::initPageRendering() grid->attach_next_to(*label_widget, Gtk::PositionType::BOTTOM); }; - //TRANSLATORS: The following are options for fine-tuning rendering, meant to be used by developers, + //TRANSLATORS: The following are options for fine-tuning rendering, meant to be used by developers, //find more explanations at https://gitlab.com/inkscape/inbox/-/issues/6544#note_886540227 add_devmode_group_header(_("Low-level tuning options")); _canvas_tile_size.init("/options/rendering/tile_size", 1.0, 10000.0, 1.0, 0.0, 300.0, true, false); diff --git a/src/ui/dialog/inkscape-preferences.h b/src/ui/dialog/inkscape-preferences.h index 36f1189b65..39886b19fd 100644 --- a/src/ui/dialog/inkscape-preferences.h +++ b/src/ui/dialog/inkscape-preferences.h @@ -642,7 +642,7 @@ protected: static void AddFirstAndLastCheckbox(UI::Widget::DialogPage& p, Glib::ustring const &prefs_path, bool def_value); static void AddDotSizeSpinbutton(UI::Widget::DialogPage& p, Glib::ustring const &prefs_path, double def_value); static void AddBaseSimplifySpinbutton(UI::Widget::DialogPage& p, Glib::ustring const &prefs_path, double def_value); - static void AddNewObjectsStyle(UI::Widget::DialogPage& p, Glib::ustring const &prefs_path, const gchar* banner = nullptr); + static void AddNewObjectsStyle(UI::Widget::DialogPage& p, Glib::ustring const &prefs_path, Glib::ustring const &item_type = "", const gchar* banner = nullptr); void on_pagelist_selection_changed(); void show_not_found(); diff --git a/src/ui/toolbar/text-toolbar.cpp b/src/ui/toolbar/text-toolbar.cpp index aa4234b8de..35dd7cb7bd 100644 --- a/src/ui/toolbar/text-toolbar.cpp +++ b/src/ui/toolbar/text-toolbar.cpp @@ -1527,10 +1527,9 @@ void TextToolbar::_selectionChanged(Selection *selection) // don't bother to upd result_wmode == QUERY_STYLE_NOTHING) { // There are no texts in selection, read from preferences. - if (prefs->getBool("/tools/text/usecurrent")) { - query.mergeCSS(sp_desktop_get_style(desktop, true)); - } else { - query.readFromPrefs("/tools/text"); + if (SPCSSAttr *css = SP_ACTIVE_DESKTOP->getCurrentOrToolStyle("/tools/text", true)) { + query.mergeCSS(css); + sp_repr_css_attr_unref(css); } if constexpr (DEBUG_TEXT) { diff --git a/src/ui/tools/arc-tool.cpp b/src/ui/tools/arc-tool.cpp index 90367fd95d..064604a0df 100644 --- a/src/ui/tools/arc-tool.cpp +++ b/src/ui/tools/arc-tool.cpp @@ -282,7 +282,7 @@ void ArcTool::drag(Geom::Point const &pt, unsigned state) repr->setAttribute("sodipodi:type", "arc"); // Set style - sp_desktop_apply_style_tool(_desktop, repr, "/tools/shapes/arc", false); + _desktop->applyCurrentOrToolStyle(repr, "/tools/shapes/arc", false); auto layer = currentLayer(); this->arc = cast(layer->appendChildRepr(repr)); diff --git a/src/ui/tools/box3d-tool.cpp b/src/ui/tools/box3d-tool.cpp index 7fabdc4cd4..ee5fda7b0d 100644 --- a/src/ui/tools/box3d-tool.cpp +++ b/src/ui/tools/box3d-tool.cpp @@ -433,6 +433,7 @@ void Box3dTool::drag() _desktop->applyCurrentOrToolStyle(newbox3d, "/tools/shapes/3dbox", false); box3d = newbox3d; + auto use_current = Preferences::get()->getString("/tools/shapes/3dbox/usecurrent", "0"); // "0", "1", or "3dbox" // TODO: Incorporate this in box3d-side.cpp! for (int i = 0; i < 6; ++i) { @@ -446,25 +447,11 @@ void Box3dTool::drag() side->front_or_rear = front_or_rear; // Set style - auto prefs = Preferences::get(); - - Glib::ustring descr = "/desktop/"; - descr += side->axes_string(); - descr += "/style"; - - Glib::ustring cur_style = prefs->getString(descr); - - bool use_current = prefs->getBool("/tools/shapes/3dbox/usecurrent", false); - - if (use_current && !cur_style.empty()) { - // use last used style - side->setAttribute("style", cur_style); - } else { - // use default style - auto tool_path = Glib::ustring::compose("/tools/shapes/3dbox/%1", side->axes_string()); - _desktop->applyCurrentOrToolStyle(side, tool_path, false); - } - + _desktop->applyCurrentOrToolStyle(side, + Glib::ustring("/tools/shapes/3dbox/") + side->axes_string(), + true, + (use_current.size() == 1) ? use_current : side->axes_string() + ); side->updateRepr(); // calls Box3DSide::write() and updates, e.g., the axes string description } diff --git a/src/ui/tools/calligraphic-tool.cpp b/src/ui/tools/calligraphic-tool.cpp index 8a0257e14e..fec565d86b 100644 --- a/src/ui/tools/calligraphic-tool.cpp +++ b/src/ui/tools/calligraphic-tool.cpp @@ -833,7 +833,7 @@ void CalligraphicTool::set_to_accumulated(bool unionize, bool subtract) { Inkscape::XML::Node *repr = xml_doc->createElement("svg:path"); /* Set style */ - sp_desktop_apply_style_tool(_desktop, repr, "/tools/calligraphic", false); + _desktop->applyCurrentOrToolStyle(repr, "/tools/calligraphic", false); this->repr = repr; diff --git a/src/ui/tools/connector-tool.cpp b/src/ui/tools/connector-tool.cpp index b40526128d..3c1053d900 100644 --- a/src/ui/tools/connector-tool.cpp +++ b/src/ui/tools/connector-tool.cpp @@ -799,7 +799,7 @@ void ConnectorTool::_flushWhite(Geom::PathVector &c) Inkscape::XML::Node *repr = xml_doc->createElement("svg:path"); /* Set style */ - sp_desktop_apply_style_tool(_desktop, repr, "/tools/connector", false); + _desktop->applyCurrentOrToolStyle(repr, "/tools/connector", false); repr->setAttribute("d", sp_svg_write_path(c)); diff --git a/src/ui/tools/eraser-tool.cpp b/src/ui/tools/eraser-tool.cpp index 99632f96e1..3f505af7eb 100644 --- a/src/ui/tools/eraser-tool.cpp +++ b/src/ui/tools/eraser-tool.cpp @@ -599,7 +599,7 @@ bool EraserTool::_doWork() Inkscape::XML::Document *xml_doc = document->getReprDoc(); Inkscape::XML::Node *eraser_repr = xml_doc->createElement("svg:path"); - sp_desktop_apply_style_tool(_desktop, eraser_repr, "/tools/eraser", false); + _desktop->applyCurrentOrToolStyle(eraser_repr, "/tools/eraser", false); repr = eraser_repr; } if (!repr) { @@ -921,7 +921,7 @@ void EraserTool::_clipErase(SPItem *item) const } } else { Inkscape::XML::Node *rect_repr = xml_doc->createElement("svg:rect"); - sp_desktop_apply_style_tool(_desktop, rect_repr, "/tools/eraser", false); + _desktop->applyCurrentOrToolStyle(rect_repr, "/tools/eraser", false); auto rect = cast(item->parent->appendChildRepr(rect_repr)); Inkscape::GC::release(rect_repr); rect->setPosition(bbox->left(), bbox->top(), bbox->width(), bbox->height()); diff --git a/src/ui/tools/flood-tool.cpp b/src/ui/tools/flood-tool.cpp index b09df317be..de0e0c8105 100644 --- a/src/ui/tools/flood-tool.cpp +++ b/src/ui/tools/flood-tool.cpp @@ -356,7 +356,7 @@ static void do_trace(BitmapCoordsInfo const &bci, unsigned char *trace_px, SPDes Inkscape::XML::Node *pathRepr = xml_doc->createElement("svg:path"); /* Set style */ - sp_desktop_apply_style_tool (desktop, pathRepr, "/tools/paintbucket", false); + desktop->applyCurrentOrToolStyle(pathRepr, "/tools/paintbucket", false); Path path; path.LoadPathVector(result.path); diff --git a/src/ui/tools/freehand-base.cpp b/src/ui/tools/freehand-base.cpp index 1eb4cefcd1..4e32e335aa 100644 --- a/src/ui/tools/freehand-base.cpp +++ b/src/ui/tools/freehand-base.cpp @@ -191,7 +191,7 @@ static void spdc_apply_powerstroke_shape(std::vector const &points, if ((elemref = document->getObjectById("power_stroke_preview"))) { elemref->getRepr()->removeAttribute("style"); auto successor = cast(elemref); - sp_desktop_apply_style_tool(desktop, successor->getRepr(), + desktop->applyCurrentOrToolStyle(successor->getRepr(), Glib::ustring("/tools/freehand/pencil").data(), false); spdc_apply_style(successor); sp_object_ref(item); @@ -756,7 +756,7 @@ static void spdc_flush_white(FreehandBase *dc, std::shared_ptr } else { repr = xml_doc->createElement("svg:path"); // Set style - sp_desktop_apply_style_tool(desktop, repr, dc->getPrefsPath(), false); + desktop->applyCurrentOrToolStyle(repr, dc->getPrefsPath(), false); } auto str = sp_svg_write_path(*c); @@ -868,7 +868,7 @@ void spdc_create_single_dot(ToolBase *tool, Geom::Point const &pt, char const *p Inkscape::GC::release(repr); // apply the tool's current style - sp_desktop_apply_style_tool(desktop, repr, path, false); + desktop->applyCurrentOrToolStyle(repr, path, false); // find out stroke width (TODO: is there an easier way??) double stroke_width = 3.0; diff --git a/src/ui/tools/measure-tool.cpp b/src/ui/tools/measure-tool.cpp index 433656433d..f80e85ce45 100644 --- a/src/ui/tools/measure-tool.cpp +++ b/src/ui/tools/measure-tool.cpp @@ -838,7 +838,7 @@ void MeasureTool::setLabelText(Glib::ustring const &value, Geom::Point pos, doub /* Set style */ - sp_desktop_apply_style_tool(_desktop, rtext, "/tools/text", true); + _desktop->applyCurrentOrToolStyle(rtext, "/tools/text", true); if(measure_repr) { rtext->setAttributeSvgDouble("x", 2); rtext->setAttributeSvgDouble("y", 2); diff --git a/src/ui/tools/rect-tool.cpp b/src/ui/tools/rect-tool.cpp index 4cc9c7b6c9..bed0e678c5 100644 --- a/src/ui/tools/rect-tool.cpp +++ b/src/ui/tools/rect-tool.cpp @@ -304,7 +304,7 @@ void RectTool::drag(Geom::Point const pt, unsigned state) { Inkscape::XML::Node *repr = xml_doc->createElement("svg:rect"); // Set style - sp_desktop_apply_style_tool(_desktop, repr, "/tools/shapes/rect", false); + _desktop->applyCurrentOrToolStyle(repr, "/tools/shapes/rect", false); this->rect = cast(currentLayer()->appendChildRepr(repr)); Inkscape::GC::release(repr); diff --git a/src/ui/tools/spiral-tool.cpp b/src/ui/tools/spiral-tool.cpp index 81254021bf..3c071102f7 100644 --- a/src/ui/tools/spiral-tool.cpp +++ b/src/ui/tools/spiral-tool.cpp @@ -285,7 +285,7 @@ void SpiralTool::drag(Geom::Point const &p, guint state) { repr->setAttribute("sodipodi:type", "spiral"); // Set style - sp_desktop_apply_style_tool(_desktop, repr, "/tools/shapes/spiral", false); + _desktop->applyCurrentOrToolStyle(repr, "/tools/shapes/spiral", false); this->spiral = cast(currentLayer()->appendChildRepr(repr)); Inkscape::GC::release(repr); diff --git a/src/ui/tools/star-tool.cpp b/src/ui/tools/star-tool.cpp index 3a158008e8..3a519e2efc 100644 --- a/src/ui/tools/star-tool.cpp +++ b/src/ui/tools/star-tool.cpp @@ -297,7 +297,7 @@ void StarTool::drag(Geom::Point p, unsigned state) repr->setAttribute("sodipodi:type", "star"); // Set style - sp_desktop_apply_style_tool(_desktop, repr, "/tools/shapes/star", false); + _desktop->applyCurrentOrToolStyle(repr, "/tools/shapes/star", false); this->star = cast(currentLayer()->appendChildRepr(repr)); Inkscape::GC::release(repr); diff --git a/src/ui/tools/text-tool.cpp b/src/ui/tools/text-tool.cpp index 6a11af0785..4820de0f76 100644 --- a/src/ui/tools/text-tool.cpp +++ b/src/ui/tools/text-tool.cpp @@ -246,7 +246,7 @@ void TextTool::_setupText() rtext->setAttribute("xml:space", "preserve"); // we preserve spaces in the text objects we create /* Set style */ - sp_desktop_apply_style_tool(_desktop, rtext, "/tools/text", true); + _desktop->applyCurrentOrToolStyle(rtext, "/tools/text", true); rtext->setAttributeSvgDouble("x", pdoc.x()); rtext->setAttributeSvgDouble("y", pdoc.y()); diff --git a/src/ui/widget/style-swatch.cpp b/src/ui/widget/style-swatch.cpp index 145dfe88e3..b775c0e0e4 100644 --- a/src/ui/widget/style-swatch.cpp +++ b/src/ui/widget/style-swatch.cpp @@ -51,31 +51,15 @@ void style_obs_callback(StyleSwatch &_style_swatch, Preferences::Entry const &va */ void tool_obs_callback(StyleSwatch &_style_swatch, Preferences::Entry const &val) { - auto const prefs = Preferences::get(); - Glib::ustring path; - SPCSSAttr *css = nullptr; - - bool usecurrent = val.getBool(); - if (usecurrent) { - path = "/desktop/style"; - css = prefs->getStyle(path); - const auto &al = css->attributeList(); - if (al.empty()) { - // Fallback to own style if desktop style empty (does this ever happen?). - sp_repr_css_attr_unref(css); - css = nullptr; - } - } + Glib::ustring path = _style_swatch._desktop->getCurrentOrToolStylePath(_style_swatch._tool_path); + SPCSSAttr *css = _style_swatch._desktop->getCurrentOrToolStyle(_style_swatch._tool_path, true); - if (!css) { - path = _style_swatch._tool_path + "/style"; - css = prefs->getInheritedStyle(path); + if (css) { + // Set style at least once. + _style_swatch.setStyle(css); + sp_repr_css_attr_unref(css); } - // Set style at least once. - _style_swatch.setStyle(css); - sp_repr_css_attr_unref(css); - auto callback = sigc::bind<0>(&style_obs_callback, std::ref(_style_swatch)); _style_swatch._style_obs = StyleSwatch::PrefObs::create(std::move(path), std::move(callback)); } diff --git a/src/xml/repr-css.cpp b/src/xml/repr-css.cpp index 475202c7c1..8611c29e64 100644 --- a/src/xml/repr-css.cpp +++ b/src/xml/repr-css.cpp @@ -309,7 +309,7 @@ void sp_repr_css_print(SPCSSAttr *css) /** * Merges two SPCSSAttr's. Properties in src overwrite properties in dst if present in both. */ -void sp_repr_css_merge(SPCSSAttr *dst, SPCSSAttr *src) +void sp_repr_css_merge(SPCSSAttr *dst, const SPCSSAttr *src) { g_assert(dst != nullptr); g_assert(src != nullptr); diff --git a/src/xml/repr.h b/src/xml/repr.h index 7a2be17e6b..9d18584684 100644 --- a/src/xml/repr.h +++ b/src/xml/repr.h @@ -98,7 +98,7 @@ void sp_repr_css_set_property_string(SPCSSAttr *css, char const *name, std::stri void sp_repr_css_write_string(SPCSSAttr *css, Glib::ustring &str); void sp_repr_css_set(Inkscape::XML::Node *repr, SPCSSAttr *css, char const *key); -void sp_repr_css_merge(SPCSSAttr *dst, SPCSSAttr *src); +void sp_repr_css_merge(SPCSSAttr *dst, const SPCSSAttr *src); void sp_repr_css_attr_add_from_string(SPCSSAttr *css, const char *data); void sp_repr_css_change(Inkscape::XML::Node *repr, SPCSSAttr *css, char const *key); void sp_repr_css_change_recursive(Inkscape::XML::Node *repr, SPCSSAttr *css, char const *key); -- GitLab From 42a5d1e9d99eb267b4f109989d0da92b946f049d Mon Sep 17 00:00:00 2001 From: Henry Wong Date: Sat, 27 Sep 2025 19:18:41 -0700 Subject: [PATCH 2/3] When applying a style to an entire Box3D, update the per-object-type last-used-style for all of the affected faces. --- src/desktop-style.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp index 165b2fbe69..eb1ae54930 100644 --- a/src/desktop-style.cpp +++ b/src/desktop-style.cpp @@ -31,6 +31,7 @@ #include "message-stack.h" +#include "object/box3d.h" #include "object/box3d-side.h" #include "object/filters/blend.h" #include "object/filters/gaussian-blur.h" @@ -195,7 +196,15 @@ sp_desktop_set_style(Inkscape::ObjectSet *set, SPDesktop *desktop, SPCSSAttr *cs SPItem *obj = *i; if (auto *side = cast(obj)) { selected_item_types.emplace(side->axes_string().data()); - } else { + } else if (auto *box = cast(obj)) { + // Applied a style to an entire box. Update the box and all faces of the box. + for (auto *maybe_side : box->item_list()) { + if (auto *side = cast(maybe_side)) { + selected_item_types.emplace(side->axes_string().data()); + } + } + } + else { selected_item_types.emplace(obj->typeName()); } } @@ -205,14 +214,16 @@ sp_desktop_set_style(Inkscape::ObjectSet *set, SPDesktop *desktop, SPCSSAttr *cs static const std::unordered_map item_type_map = { {"circle", "arc"}, {"polygon", "star"}, - {"text-flow", "text"} + {"text-flow", "text"}, + {"group", nullptr} }; for (const char* item_type : selected_item_types) { if (auto i = item_type_map.find(item_type) ; i != item_type_map.end()) { item_type = i->second; } - prefs->mergeStyle( - Glib::ustring("/desktop/") + item_type + "/style", css_write); + if (item_type) { + prefs->mergeStyle(Glib::ustring("/desktop/") + item_type + "/style", css_write); + } } sp_repr_css_attr_unref(css_write); -- GitLab From 4612600ddd9db74f63b67d03d358f40709ad7380 Mon Sep 17 00:00:00 2001 From: Henry Wong Date: Sat, 27 Sep 2025 19:16:03 -0700 Subject: [PATCH 3/3] Default preferences: Remove /desktop/style default black fill --- src/preferences-skeleton.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/preferences-skeleton.h b/src/preferences-skeleton.h index a0b96aa55e..bf3c523d6c 100644 --- a/src/preferences-skeleton.h +++ b/src/preferences-skeleton.h @@ -408,8 +408,7 @@ static char const preferences_skeleton[] = org.inkscape.output.png.inkscape.png_compression="6" org.inkscape.output.png.inkscape.png_antialias="2" /> - +