diff --git a/src/inkscape.cpp b/src/inkscape.cpp index ae9169f4284706e9f20f6a0d9d41ea073d941a5f..8929f061943fe62966f7e18515d3cc6fead9a29b 100644 --- a/src/inkscape.cpp +++ b/src/inkscape.cpp @@ -54,7 +54,7 @@ #include "ui/themes.h" #include "ui/tools/tool-base.h" #include "ui/util.h" -#include "ui/widget/generic/spin-button.h" +#include "ui/widget/gtk-registry.h" #include "util/font-discovery.h" static bool desktop_is_active(SPDesktop const *d) @@ -164,8 +164,9 @@ Application::Application(bool use_gui) : auto scale = prefs->getDoubleLimited(UI::ThemeContext::get_font_scale_pref_path(), 100, 50, 200); themecontext->adjustGlobalFontScale(scale / 100.0); Inkscape::UI::ThemeContext::initialize_source_syntax_styles(); + // register custom widget types - Inkscape::UI::Widget::InkSpinButton::register_type(); + Inkscape::UI::Widget::register_all(); } /* set language for user interface according setting in preferences */ diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 0dcefa1157d050044e017276575342947f3e28a7..feade3e22e913ed078dd39731b3b80190ab62626 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -246,6 +246,7 @@ target_sources(inkscape_base PRIVATE widget/gradient-selector.cpp widget/gradient-vector-selector.cpp widget/gradient-with-stops.cpp + widget/gtk-registry.cpp widget/icon-combobox.cpp widget/handle-preview.cpp widget/image-properties.cpp @@ -293,6 +294,7 @@ target_sources(inkscape_base PRIVATE widget/style/marker-combo-box.cpp widget/style-subject.cpp widget/style-swatch.cpp + widget/style/paint-order.cpp widget/swatch-editor.cpp widget/swatch-selector.cpp widget/tabs-widget.cpp @@ -577,6 +579,7 @@ target_sources(inkscape_base PRIVATE widget/gradient-selector.h widget/gradient-vector-selector.h widget/gradient-with-stops.h + widget/gtk-registry.h widget/icon-combobox.h widget/handle-preview.h widget/image-properties.h @@ -625,6 +628,7 @@ target_sources(inkscape_base PRIVATE widget/style/marker-combo-box.h widget/style-subject.h widget/style-swatch.h + widget/style/paint-order.h widget/swatch-editor.h widget/swatch-selector.h widget/tabs-widget.h diff --git a/src/ui/widget/generic/README b/src/ui/widget/generic/README deleted file mode 100644 index 2a3a2336b0fa2da60043fedbfedb4b5f666f6aa9..0000000000000000000000000000000000000000 --- a/src/ui/widget/generic/README +++ /dev/null @@ -1,41 +0,0 @@ - -# Generic widgets for Gtk4 - -This directory contains code for creating custom Inkscape specific widgets using the Gtkmm / Gtk4 libraries. - -A general rule of thumb is that if you can see this widget being dropped into some other Gtk application without -having to pull out notions or connections to SVG, and Inkscape then it's a generic widget. - -# Rules for Widgets in this Directory - -## Widget MUST NOT implement - -Widgets are expected to be generic and not have specific implementation for data and structure from other parts of the project codebase: - - * The same functionality as another widget in this directory - * String parsing, such as converting from string to numbers - * File opening, such as opening a palette file - * Format decoding, such as splitting strings into lists - * Attributes, such as setting or getting SPObject attributes - * Properties, such as setting or getting SVG CSS Styles - -## Widget MUST implement - -All widgets should be usable via Gtk Builder, and use well understood mechanisms to communicate and be in a Gtkmm style: - - * Implement GtkBuilder constructors - * Use a initaliser so they can be used in ui xml files - * Add properties where needed so they can be used - * Report changes using signals with non-Gtk/Gdk values - * Have setters and getters for their data using non-Gtk/Gdk values - -## Final Glib class - -Because of how Gtk works, if you inherit from Glib or CssNameClassInit, or implement an interface like Gtk::Orientable then your class must be marked as `final` to avoid broken widget classes. - -## Mixing Widgets - - * All sub-widgets should come from this directory OR Gtkmm NOT from parent directories. - * All sub-widgets should be deconstructed by regular Gtkmm referencing (destroyed when unparented for example) - - diff --git a/src/ui/widget/generic/README.md b/src/ui/widget/generic/README.md new file mode 100644 index 0000000000000000000000000000000000000000..e3735e5a84d2777ec118e2f68ec5dfd2d5ae8c2e --- /dev/null +++ b/src/ui/widget/generic/README.md @@ -0,0 +1,124 @@ + +# Generic widgets for Gtk4 + +This directory contains code for creating custom Inkscape specific widgets using the Gtkmm / Gtk4 libraries. + +A general rule of thumb is that if you can see this widget being dropped into some other Gtk application without +having to pull out notions or connections to SVG, and Inkscape then it's a generic widget. + +# Rules for Widgets in this Directory + +## Widget MUST NOT implement + +Widgets are expected to be generic and not have specific implementation for data and structure from other parts of the project codebase: + + * The same functionality as another widget in this directory + * String parsing, such as converting from string to numbers + * File opening, such as opening a palette file + * Format decoding, such as splitting strings into lists + * Attributes, such as setting or getting SPObject attributes + * Properties, such as setting or getting SVG CSS Styles + +## Widget MUST implement + +All widgets should be usable via Gtk Builder, and use well understood mechanisms to communicate and be in a Gtkmm style: + + * Implement GtkBuilder constructors + * Use an initaliser so they can be used in ui xml files + * Add properties where needed so they can be used + * Report changes using signals with non-Gtk/Gdk values + * Have setters and getters for their data using non-Gtk/Gdk values + +## Mixing Widgets + + * All sub-widgets should come from this directory OR Gtkmm NOT from parent directories. + * All sub-widgets should be deconstructed by regular Gtkmm referencing (destroyed when unparented for example) + +## Template + +Because the creation of widgets is quite delicate, this template should help you make a new widget, while understanding why +each parent of the copypasta is necessary to interact with gtkmm and glibmm. + +### Header file + +``` +class MyNewWidget : public BuildableWidget + // BaseWidget may be any other generic widget, or any widget from the Gtk:: namespace + +public: + // Bare constructor is used in registration to initalise the GType + MyNewWidget(); + + // The Gtk builder constructor allows this widget to be created by ui xml files + MyNewWidget(GtkWidget *cobject, const Glib::RefPtr& builder = {}); + +private: + // Optional constructor method for duplicated constructor logic + void construct(); +}; +``` + +We use `BuildableWidget` to implement registration code that is specific to each custom widget. + +Note 1: If your widget implements an interface, like `Gtk::Orientable`, you will need to add a `using` alias +to disambiguate `BaseObjectType` definition, as it appears in two places in a hierarchy. + +Example: a custom widget that derives from `Gtk::Widget` will need to add `using BaseObjectType = GtkWidget;` line. + +Note 2: Interfaces (like `Gtk::Orientable`) or helper classes (like `CssNameClassInit`) need to be specified *before* `BuildableWidget` to be initialized properly. + +Note 3: To change the name of `MyNewWidget` as seen by CSS, we can use +`CssNameClassInit` to provide a new one. For example `CssNameClassInit("my-new-widget")`. + +### Code file + +``` +// First the bare constructor, it must be EXACTLY the same as the builder constructor. +MyNewWidget::MyNewWidget() +// This allows the new widget to be correctly registered and for gobject properties of the parent +// to be accessible to this class too. + , Glib::ObjectBase("MyNewWidget") +// The parent constructor must omit the cobject entirely because the chain of construction generates +// a new cobject only if there is no argument, and not if that argument is nullptr. +// : ParentWidget() // This isn't required, just noted here for explicit symmetry + // More construction here +{ + construct(); // optional +} + +// This constructor means we already have a gobject, and the builder is passing it +// to us so we can bind it to our C++ code correctly. +MyNewWidget::MyNewWidget(GtkWidget *cobject, const Glib::RefPtr& builder) + , Glib::ObjectBase("MyNewWidget") +// As above the cobject must be passed into the base widget. builder can be omitted +// if the base is a Gtk widget and not a custom widget. + : BaseWidget(cobject, builder) + // The same construction here, you may want to use a define to reduce duplication +{ + construct(); // optional +} + +``` + +Note the call to the `Glib::ObjectBase` constructor. It is a virtual base, and as such it needs to be +initialized by the most derived class (here: `MyNewWidget`). +This call is what creates a unique `Glib` `GType` for `MyNewWidget`. + +Reference: [Derived widgets](https://gnome.pages.gitlab.gnome.org/gtkmm-documentation/sec-builder-using-derived-widgets.html) + +### Registration in gtk-registry.cpp + +``` + +#include "generic/my-new-widget.h" + +void register_all() +{ + // This makes sure the ctype is ready for the Gtk Builder and adds the required + // names to the lookup. Our widget will be available as gtkmm__CustomObject_MyNewWidget + MyNewWidget::register_type(); +} + +``` + + diff --git a/src/ui/widget/generic/reorderable-stack.cpp b/src/ui/widget/generic/reorderable-stack.cpp index 587a9ce0cbffb89883aa44cc497d7c332c521869..a3d5877b3a1d2a93ea9b3ca61f0ffcc70595859c 100644 --- a/src/ui/widget/generic/reorderable-stack.cpp +++ b/src/ui/widget/generic/reorderable-stack.cpp @@ -10,9 +10,7 @@ namespace Inkscape::UI::Widget { -ReorderableStack::ReorderableStack(Gtk::Orientation orientation) - : Glib::ObjectBase("ReorderableStack") - , TabStrip(orientation) +void ReorderableStack::construct() { set_name("ReorderableStack"); set_hexpand(); @@ -30,6 +28,18 @@ ReorderableStack::ReorderableStack(Gtk::Orientation orientation) set_new_tab_popup(nullptr); } +ReorderableStack::ReorderableStack() + : Glib::ObjectBase("ReorderableStack") +{ + construct(); +} +ReorderableStack::ReorderableStack(GtkWidget* cobject, const Glib::RefPtr& builder) + : Glib::ObjectBase("ReorderableStack") + , BuildableWidget(cobject, builder) +{ + construct(); +} + /** * Add an option to the stack, this should be done on construction. */ diff --git a/src/ui/widget/generic/reorderable-stack.h b/src/ui/widget/generic/reorderable-stack.h index e85d5c28878e02e1f058043dbe9668df406012fb..6ea335e1643014f5e37adfe2ef6ad484aab10ef9 100644 --- a/src/ui/widget/generic/reorderable-stack.h +++ b/src/ui/widget/generic/reorderable-stack.h @@ -12,16 +12,15 @@ #include #include -#include - #include "tab-strip.h" namespace Inkscape::UI::Widget { -class ReorderableStack : public TabStrip +class ReorderableStack : public BuildableWidget { public: - ReorderableStack(Gtk::Orientation orientation = Gtk::Orientation::HORIZONTAL); + ReorderableStack(); + explicit ReorderableStack(GtkWidget* cobject, const Glib::RefPtr& builder = {}); void add_option(std::string const &label, std::string const &icon, std::string const &tooltip, int value); @@ -32,6 +31,8 @@ public: sigc::signal& signal_values_changed() { return _signal_values_changed; } private: + void construct(); + sigc::signal _signal_values_changed; std::vector> _rows; diff --git a/src/ui/widget/generic/spin-button.cpp b/src/ui/widget/generic/spin-button.cpp index e5a1d88c957a61ab91f0d4178695a8ef56dfc726..73b2436895eaeeaf7f92028a6ca4f1fe4316e5cf 100644 --- a/src/ui/widget/generic/spin-button.cpp +++ b/src/ui/widget/generic/spin-button.cpp @@ -285,20 +285,12 @@ InkSpinButton::InkSpinButton(): InkSpinButton::InkSpinButton(BaseObjectType* cobject, const Glib::RefPtr& builder): CALL_CONSTRUCTORS, - Gtk::Widget(cobject), + BuildableWidget(cobject, builder), INIT_PROPERTIES { construct(); } -InkSpinButton::InkSpinButton(BaseObjectType* cobject): - CALL_CONSTRUCTORS, - Gtk::Widget(cobject), - INIT_PROPERTIES { - - construct(); -} - #undef INIT_PROPERTIES #undef CALL_CONSTRUCTORS @@ -1015,8 +1007,6 @@ void InkSpinButton::set_transformers(std::function input, std::f update(false); // apply transformer } -GType InkSpinButton::gtype = 0; - // a fade-out mask for overflowing numbers void InkSpinButton::FadeOut::snapshot_vfunc(const Glib::RefPtr& snapshot) { auto rect = Gdk::Graphene::Rect(0, 0, get_width(), get_height()); diff --git a/src/ui/widget/generic/spin-button.h b/src/ui/widget/generic/spin-button.h index cb2f3331a05e223e6969714a5367b244053903be..aa33905118500da3abf6934e3123b4a0d57d9071 100644 --- a/src/ui/widget/generic/spin-button.h +++ b/src/ui/widget/generic/spin-button.h @@ -13,6 +13,7 @@ #include #include "css-name-class-init.h" +#include "ui/widget/gtk-registry.h" namespace Gtk { class EventControllerKey; @@ -27,11 +28,12 @@ namespace Inkscape::UI { class DefocusTarget; } namespace Inkscape::UI::Widget { -class InkSpinButton : public CssNameClassInit, public Gtk::Widget { +class InkSpinButton : public CssNameClassInit, public BuildableWidget { public: + typedef GtkWidget BaseObjectType; + InkSpinButton(); - InkSpinButton(BaseObjectType* cobject, const Glib::RefPtr& builder); - explicit InkSpinButton(BaseObjectType* cobject); + explicit InkSpinButton(BaseObjectType* cobject, const Glib::RefPtr& builder = {}); ~InkSpinButton() override; @@ -222,31 +224,6 @@ public: Glib::PropertyProxy property_show_arrows() { return _show_arrows.get_proxy(); } Glib::PropertyProxy property_enter_exit() { return _enter_exit.get_proxy(); } Glib::PropertyProxy property_wrap_around() { return _wrap_around.get_proxy(); } - - // Construct a C++ object from a parent (=base) C class object - - static Glib::ObjectBase* wrap_new(GObject* o) { - auto obj = new InkSpinButton(GTK_WIDGET(o)); - - //TODO: check if this is needed - // // if (gtk_widget_is_toplevel(GTK_WIDGET(o))) - // return obj; - // else - return Gtk::manage(obj); - } - - // Register a "new" type in Glib and bind it to the C++ wrapper function - static void register_type() { - if (gtype) return; - - InkSpinButton dummy; - gtype = G_OBJECT_TYPE(dummy.gobj()); - - Glib::wrap_register(gtype, InkSpinButton::wrap_new); - } -private: - static GType gtype; - }; } // namespace Inkscape::UI::Widget diff --git a/src/ui/widget/generic/tab-strip.cpp b/src/ui/widget/generic/tab-strip.cpp index 21b3a44d354b78f9e669424d979772bdc9210603..1cb35d245ac89ab6392b5dd30a81b1745df672e8 100644 --- a/src/ui/widget/generic/tab-strip.cpp +++ b/src/ui/widget/generic/tab-strip.cpp @@ -542,14 +542,9 @@ static std::shared_ptr get_tab_drag(Gtk::DropTarget &droptarget) return content->lock(); } -TabStrip::TabStrip(Gtk::Orientation orientation) - : Glib::ObjectBase("TabStrip") - , Gtk::Orientable() - , Gtk::Widget() - , _overlay{Gtk::make_managed()} +void TabStrip::construct() { set_name("TabStrip"); - set_orientation(orientation); set_overflow(Gtk::Overflow::HIDDEN); containerize(*this); @@ -673,6 +668,22 @@ TabStrip::TabStrip(Gtk::Orientation orientation) _updateVisibility(); } +TabStrip::TabStrip(Gtk::Orientation orientation) + : Glib::ObjectBase("TabStrip") + , _overlay{Gtk::make_managed()} +{ + set_orientation(orientation); + construct(); +} + +TabStrip::TabStrip(GtkWidget* cobject, const Glib::RefPtr& builder) + : Glib::ObjectBase("TabStrip") + , BuildableWidget(cobject, builder) + , _overlay{Gtk::make_managed()} +{ + construct(); +} + TabStrip::~TabStrip() { // Note: This code will fail if TabStrip becomes a managed widget, in which diff --git a/src/ui/widget/generic/tab-strip.h b/src/ui/widget/generic/tab-strip.h index 91babd555ecb76dbbf6c6c983bfdf314fbe3dd58..0229e3d3fa382de9fd1cd4f2e9f32fbab5809147 100644 --- a/src/ui/widget/generic/tab-strip.h +++ b/src/ui/widget/generic/tab-strip.h @@ -16,9 +16,12 @@ #define INKSCAPE_UI_WIDGET_TAB_STRIP_H #include <2geom/point.h> +#include #include #include +#include "ui/widget/gtk-registry.h" + namespace Gtk { class Popover; } namespace Inkscape::UI::Widget { @@ -27,10 +30,13 @@ struct TabWidget; class TabWidgetDrag; /// Widget that implements strip of tabs -class TabStrip : public Gtk::Orientable, public Gtk::Widget +class TabStrip : public Gtk::Orientable, public BuildableWidget { public: + using BaseObjectType = GtkWidget; + TabStrip(Gtk::Orientation orientation = Gtk::Orientation::HORIZONTAL); + explicit TabStrip(BaseObjectType* cobject, const Glib::RefPtr& builder = {}); ~TabStrip() override; // create a new tab @@ -86,6 +92,8 @@ public: sigc::signal signal_dnd_end() { return _signal_dnd_end; } private: + void construct(); + Gtk::Widget *const _overlay; Gtk::Popover *_popover = nullptr; Gtk::MenuButton _plus_btn; diff --git a/src/ui/widget/gtk-registry.cpp b/src/ui/widget/gtk-registry.cpp new file mode 100644 index 0000000000000000000000000000000000000000..87eb81e7e1359d978800de94ae760e710e0a9e17 --- /dev/null +++ b/src/ui/widget/gtk-registry.cpp @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2025 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include "gtk-registry.h" + +#include "generic/reorderable-stack.h" +#include "generic/spin-button.h" +#include "generic/tab-strip.h" +#include "style/paint-order.h" + +namespace Inkscape::UI::Widget { + +void register_all() +{ + // Add generic and reusable widgets here + InkSpinButton::register_type(); + TabStrip::register_type(); + ReorderableStack::register_type(); + + // Specific widgets + PaintOrderWidget::register_type(); +} + +} // namespace Dialog::UI::Widget + +/* + 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/widget/gtk-registry.h b/src/ui/widget/gtk-registry.h new file mode 100644 index 0000000000000000000000000000000000000000..720522793898bb5f750a2fa241535db8f0b4937a --- /dev/null +++ b/src/ui/widget/gtk-registry.h @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * + * Copyright (C) 2025 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ +#ifndef SEEN_INKSCAPE_UI_WIDGET_GTK_REGISTRY_H +#define SEEN_INKSCAPE_UI_WIDGET_GTK_REGISTRY_H + +#include +#include + +namespace Gtk { +class Builder; +} + +namespace Inkscape::UI::Widget { + +// Add all custom widgets to the Gtk Builder registry so they can be +// Used from glade/ui xml files. +void register_all(); + +// helper class to handle Glib type registration details for custom widgets +template class BuildableWidget : public Base { + static GType gtype; + + static Glib::ObjectBase* wrap_new(GObject* o) { + auto obj = new T(GTK_WIDGET(o)); + return Gtk::manage(obj); + } + +protected: + BuildableWidget() = default; + BuildableWidget(typename Base::BaseObjectType* cobject, const Glib::RefPtr&) : Base(cobject) {} + +public: + static void register_type() { + if (gtype) return; + + auto dummy = T(); + gtype = G_OBJECT_TYPE(dummy.Gtk::Widget::gobj()); + Glib::wrap_register(gtype, wrap_new); + } + + static GType get_gtype() { + return gtype; + } +}; + +template +GType BuildableWidget::gtype = 0; + +} // namespace Dialog::UI::Widget + +#endif // SEEN_INKSCAPE_UI_WIDGET_GTK_REGISTRY_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/widget/status-bar.cpp b/src/ui/widget/status-bar.cpp index 0d0301faf6bb9760662fdf2d396375d4847b0041..139a2a07861d553a2a6b0adfb6b3d009a1698a01 100644 --- a/src/ui/widget/status-bar.cpp +++ b/src/ui/widget/status-bar.cpp @@ -28,7 +28,6 @@ namespace Inkscape::UI::Widget { StatusBar::StatusBar() : Gtk::Box(Gtk::Orientation::HORIZONTAL) { - UI::Widget::InkSpinButton::register_type(); auto builder = Inkscape::UI::create_builder("statusbar.ui"); auto &statusbar = UI::get_widget(builder, "statusbar"); diff --git a/src/ui/widget/style/paint-order.cpp b/src/ui/widget/style/paint-order.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fd5693ff717b9f60e4e9a8425ff5ff4ce1a40699 --- /dev/null +++ b/src/ui/widget/style/paint-order.cpp @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * Widget for paint order styles + *//* + * Copyright (C) 2025 Authors + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include + +#include "paint-order.h" + +#include "style-internal.h" + +namespace Inkscape::UI::Widget { + +void PaintOrderWidget::construct() +{ + set_orientation(Gtk::Orientation::VERTICAL); + add_option(_("Marker"), "paint-order-markers", _("Arrows, markers and points"), SP_CSS_PAINT_ORDER_MARKER); + add_option(_("Stroke"), "paint-order-stroke", _("The border line around the shape"), SP_CSS_PAINT_ORDER_STROKE); + add_option(_("Fill"), "paint-order-fill", _("The content of the shape"), SP_CSS_PAINT_ORDER_FILL); +} + +PaintOrderWidget::PaintOrderWidget() + : Glib::ObjectBase("PaintOrderWidget") +{ + construct(); +} + +PaintOrderWidget::PaintOrderWidget(GtkWidget* cobject, const Glib::RefPtr& builder) + : Glib::ObjectBase("PaintOrderWidget") + , BuildableWidget(cobject, builder) +{ + construct(); +} + +void PaintOrderWidget::setValue(SPIPaintOrder &po, bool has_markers) +{ + // array to vector + auto values = po.get_layers(); + // Note: what's painted first is presented at the bottom of the stack. + std::vector vec = {values[2], values[1], values[0]}; + setValues(vec); + + // Hide the markers if the style has no markers + setVisible((int)SP_CSS_PAINT_ORDER_MARKER, has_markers); +} + +SPIPaintOrder PaintOrderWidget::getValue() +{ + SPIPaintOrder po; + auto values = getValues(); + for (auto i = 0; i < 3; i++) { + // Note the reversed order to match setValue() + po.layer[i] = (SPPaintOrderLayer)values[2 - i]; + po.layer_set[i] = true; + } + po.set = true; + return po; +} + +} // namespace Inkscape::UI::Widget + +/* +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/widget/style/paint-order.h b/src/ui/widget/style/paint-order.h index 6aa551c0399e5b1a2943699b95b93c9f6b3e547f..a06374762a28831d0c2cd1ce7d41a32b2cadb5be 100644 --- a/src/ui/widget/style/paint-order.h +++ b/src/ui/widget/style/paint-order.h @@ -9,50 +9,23 @@ #ifndef SEEN_UI_WIDGET_PAINT_ORDER_H #define SEEN_UI_WIDGET_PAINT_ORDER_H -#include - #include "ui/widget/generic/reorderable-stack.h" -#include "style-internal.h" +class SPIPaintOrder; namespace Inkscape::UI::Widget { -class PaintOrderWidget : public ReorderableStack +class PaintOrderWidget : public BuildableWidget { public: - PaintOrderWidget() - : Glib::ObjectBase("PaintOrderWidget") - , ReorderableStack(Gtk::Orientation::VERTICAL) - { - add_option(_("Marker"), "paint-order-markers", _("Arrows, markers and points"), SP_CSS_PAINT_ORDER_MARKER); - add_option(_("Stroke"), "paint-order-stroke", _("The border line around the shape"), SP_CSS_PAINT_ORDER_STROKE); - add_option(_("Fill"), "paint-order-fill", _("The content of the shape"), SP_CSS_PAINT_ORDER_FILL); - } - - void setValue(SPIPaintOrder &po, bool has_markers) - { - // array to vector - auto values = po.get_layers(); - // Note: what's painted first is presented at the bottom of the stack. - std::vector vec = {values[2], values[1], values[0]}; - setValues(vec); + PaintOrderWidget(); + explicit PaintOrderWidget(GtkWidget* cobject, const Glib::RefPtr& builder = {}); - // Hide the markers if the style has no markers - setVisible((int)SP_CSS_PAINT_ORDER_MARKER, has_markers); - } + void setValue(SPIPaintOrder &po, bool has_markers); + SPIPaintOrder getValue(); - SPIPaintOrder getValue() - { - SPIPaintOrder po; - auto values = getValues(); - for (auto i = 0; i < 3; i++) { - // Note the reversed order to match setValue() - po.layer[i] = (SPPaintOrderLayer)values[2 - i]; - po.layer_set[i] = true; - } - po.set = true; - return po; - } +private: + void construct(); }; } // namespace Inkscape::UI::Widget