diff --git a/share/icons/Dash/symbolic/actions/object-recolor-art-symbolic.svg b/share/icons/Dash/symbolic/actions/object-recolor-art-symbolic.svg
new file mode 100644
index 0000000000000000000000000000000000000000..b078cf421c5c1beec4852445a720247bf9c2827c
--- /dev/null
+++ b/share/icons/Dash/symbolic/actions/object-recolor-art-symbolic.svg
@@ -0,0 +1,5 @@
+
+
diff --git a/share/icons/Dash/symbolic/actions/reset-colors-symbolic.svg b/share/icons/Dash/symbolic/actions/reset-colors-symbolic.svg
new file mode 100644
index 0000000000000000000000000000000000000000..7d47572893ed89f875798b4b0e353615b756fc70
--- /dev/null
+++ b/share/icons/Dash/symbolic/actions/reset-colors-symbolic.svg
@@ -0,0 +1,4 @@
+
diff --git a/share/icons/Dash/symbolic/actions/reset-symbolic.svg b/share/icons/Dash/symbolic/actions/reset-symbolic.svg
deleted file mode 100644
index 09c40a1e3021e4ad13a7d5a0086ef0a972d948e6..0000000000000000000000000000000000000000
--- a/share/icons/Dash/symbolic/actions/reset-symbolic.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
diff --git a/share/icons/hicolor/symbolic/actions/reset-colors-symbolic.svg b/share/icons/hicolor/symbolic/actions/reset-colors-symbolic.svg
new file mode 100644
index 0000000000000000000000000000000000000000..7d47572893ed89f875798b4b0e353615b756fc70
--- /dev/null
+++ b/share/icons/hicolor/symbolic/actions/reset-colors-symbolic.svg
@@ -0,0 +1,4 @@
+
diff --git a/share/icons/hicolor/symbolic/actions/reset-symbolic.svg b/share/icons/hicolor/symbolic/actions/reset-symbolic.svg
deleted file mode 100644
index 7dcef2b3f70fffc0d4e14bd1fdd4381979bf9177..0000000000000000000000000000000000000000
--- a/share/icons/hicolor/symbolic/actions/reset-symbolic.svg
+++ /dev/null
@@ -1,58 +0,0 @@
-
-
-
-
diff --git a/share/icons/multicolor/symbolic/actions/object-recolor-art-symbolic.svg b/share/icons/multicolor/symbolic/actions/object-recolor-art-symbolic.svg
new file mode 100644
index 0000000000000000000000000000000000000000..b078cf421c5c1beec4852445a720247bf9c2827c
--- /dev/null
+++ b/share/icons/multicolor/symbolic/actions/object-recolor-art-symbolic.svg
@@ -0,0 +1,5 @@
+
+
diff --git a/share/icons/multicolor/symbolic/actions/reset-colors-symbolic.svg b/share/icons/multicolor/symbolic/actions/reset-colors-symbolic.svg
new file mode 100644
index 0000000000000000000000000000000000000000..7d47572893ed89f875798b4b0e353615b756fc70
--- /dev/null
+++ b/share/icons/multicolor/symbolic/actions/reset-colors-symbolic.svg
@@ -0,0 +1,4 @@
+
diff --git a/share/icons/multicolor/symbolic/actions/reset-symbolic.svg b/share/icons/multicolor/symbolic/actions/reset-symbolic.svg
deleted file mode 100644
index 7dcef2b3f70fffc0d4e14bd1fdd4381979bf9177..0000000000000000000000000000000000000000
--- a/share/icons/multicolor/symbolic/actions/reset-symbolic.svg
+++ /dev/null
@@ -1,58 +0,0 @@
-
-
-
-
diff --git a/share/ui/recolor-art.glade b/share/ui/recolor-art.glade
new file mode 100644
index 0000000000000000000000000000000000000000..540e02da6573116884d1869630e83b2764fc7074
--- /dev/null
+++ b/share/ui/recolor-art.glade
@@ -0,0 +1,182 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/share/ui/style.css b/share/ui/style.css
index 5a9f9d2bf1d470bd221d55214edf8cb1777ab482..e76316ded3b0fcccb257362182368eb9a2954c6d 100644
--- a/share/ui/style.css
+++ b/share/ui/style.css
@@ -1572,3 +1572,28 @@ listview row.top-separator {
#DialogMultipaned:drop(active), #DialogMultipaned:drop(active):focus {
box-shadow: none;
}
+
+/*
+**********************
+* Recolor Art class *
+**********************
+*/
+
+
+#recolor-art #original,
+#recolored {
+ min-height: 6px;
+ border-radius: 4px;
+ border: 2px solid transparent;
+}
+
+#original-recolor-box button#original:hover,
+button#recolored:hover {
+ border-color: @theme_fq_color;
+}
+
+#recolor-art listview row:selected {
+ background-color: transparent;
+ border: 2px solid @theme_selected_bg_color;
+ border-radius: 4px;
+}
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt
index df176e03431ccbf30a5b47adb1941b7a8799563c..5d4f2108ceb642401946898a7384cb437703d60c 100644
--- a/src/ui/CMakeLists.txt
+++ b/src/ui/CMakeLists.txt
@@ -285,10 +285,10 @@ set(ui_SRC
widget/unit-tracker.cpp
widget/widget-vfuncs-class-init.cpp
widget/xml-treeview.cpp
+ widget/recolor-art.cpp
view/svg-view-widget.cpp
-
# -------
# Headers
builder-utils.h
@@ -597,7 +597,8 @@ set(ui_SRC
widget/unit-tracker.h
widget/widget-vfuncs-class-init.h
widget/xml-treeview.h
-
+ widget/recolor-art.h
+
view/svg-view-widget.h
)
diff --git a/src/ui/dialog/fill-and-stroke.cpp b/src/ui/dialog/fill-and-stroke.cpp
index a3736bae318004ddef8d59b2d620843806c00a30..55d9317b5fb844bfe7a0601cfc46bacd76270301 100644
--- a/src/ui/dialog/fill-and-stroke.cpp
+++ b/src/ui/dialog/fill-and-stroke.cpp
@@ -23,15 +23,17 @@
#include
#include
-#include "desktop.h"
#include "desktop-style.h"
+#include "desktop.h"
#include "preferences.h"
+#include "selection.h"
#include "ui/icon-loader.h"
#include "ui/icon-names.h"
#include "ui/pack.h"
#include "ui/widget/fill-style.h"
-#include "ui/widget/stroke-style.h"
#include "ui/widget/notebook-page.h"
+#include "ui/widget/recolor-art.h"
+#include "ui/widget/stroke-style.h"
namespace Inkscape::UI::Dialog {
@@ -40,12 +42,9 @@ FillAndStroke::FillAndStroke()
, _page_fill(Gtk::make_managed(1, 1))
, _page_stroke_paint(Gtk::make_managed(1, 1))
, _page_stroke_style(Gtk::make_managed(1, 1))
- , _composite_settings(INKSCAPE_ICON("dialog-fill-and-stroke"),
- "fillstroke",
- UI::Widget::SimpleFilterModifier::ISOLATION |
- UI::Widget::SimpleFilterModifier::BLEND |
- UI::Widget::SimpleFilterModifier::BLUR |
- UI::Widget::SimpleFilterModifier::OPACITY)
+ , _composite_settings(INKSCAPE_ICON("dialog-fill-and-stroke"), "fillstroke",
+ UI::Widget::SimpleFilterModifier::ISOLATION | UI::Widget::SimpleFilterModifier::BLEND |
+ UI::Widget::SimpleFilterModifier::BLUR | UI::Widget::SimpleFilterModifier::OPACITY)
, fillWdgt(nullptr)
, strokeWdgt(nullptr)
{
@@ -54,7 +53,8 @@ FillAndStroke::FillAndStroke()
_notebook.append_page(*_page_fill, _createPageTabLabel(_("_Fill"), INKSCAPE_ICON("object-fill")));
_notebook.append_page(*_page_stroke_paint, _createPageTabLabel(_("Stroke _paint"), INKSCAPE_ICON("object-stroke")));
- _notebook.append_page(*_page_stroke_style, _createPageTabLabel(_("Stroke st_yle"), INKSCAPE_ICON("object-stroke-style")));
+ _notebook.append_page(*_page_stroke_style,
+ _createPageTabLabel(_("Stroke st_yle"), INKSCAPE_ICON("object-stroke-style")));
_notebook.set_vexpand(true);
_switch_page_conn = _notebook.signal_switch_page().connect(sigc::mem_fun(*this, &FillAndStroke::_onSwitchPage));
@@ -80,6 +80,7 @@ FillAndStroke::~FillAndStroke()
void FillAndStroke::selectionChanged(Selection *selection)
{
+
if (!page_changed) {
changed_fill = true;
changed_stroke = true;
@@ -94,6 +95,7 @@ void FillAndStroke::selectionChanged(Selection *selection)
if (strokeStyleWdgt && npage == 2) {
strokeStyleWdgt->selectionChangedCB();
}
+
}
void FillAndStroke::selectionModified(Selection *selection, guint flags)
@@ -110,6 +112,7 @@ void FillAndStroke::selectionModified(Selection *selection, guint flags)
if (strokeStyleWdgt && npage == 2) {
strokeStyleWdgt->selectionModifiedCB(flags);
}
+
}
void FillAndStroke::desktopReplaced()
@@ -129,7 +132,7 @@ void FillAndStroke::desktopReplaced()
_subject.setDesktop(getDesktop());
}
-void FillAndStroke::_onSwitchPage(Gtk::Widget * page, guint pagenum)
+void FillAndStroke::_onSwitchPage(Gtk::Widget *page, guint pagenum)
{
npage = pagenum;
if (page->is_visible()) {
@@ -153,30 +156,26 @@ void FillAndStroke::_onSwitchPage(Gtk::Widget * page, guint pagenum)
_savePagePref(pagenum);
}
-void
-FillAndStroke::_savePagePref(guint page_num)
+void FillAndStroke::_savePagePref(guint page_num)
{
// remember the current page
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
prefs->setInt("/dialogs/fillstroke/page", page_num);
}
-void
-FillAndStroke::_layoutPageFill()
+void FillAndStroke::_layoutPageFill()
{
fillWdgt = Gtk::make_managed(FILL);
_page_fill->table().attach(*fillWdgt, 0, 0, 1, 1);
}
-void
-FillAndStroke::_layoutPageStrokePaint()
+void FillAndStroke::_layoutPageStrokePaint()
{
strokeWdgt = Gtk::make_managed(STROKE);
_page_stroke_paint->table().attach(*strokeWdgt, 0, 0, 1, 1);
}
-void
-FillAndStroke::_layoutPageStrokeStyle()
+void FillAndStroke::_layoutPageStrokeStyle()
{
strokeStyleWdgt = Gtk::make_managed();
strokeStyleWdgt->set_hexpand();
@@ -184,34 +183,30 @@ FillAndStroke::_layoutPageStrokeStyle()
_page_stroke_style->table().attach(*strokeStyleWdgt, 0, 0, 1, 1);
}
-void
-FillAndStroke::showPageFill()
+void FillAndStroke::showPageFill()
{
blink();
_notebook.set_current_page(0);
_savePagePref(0);
-
}
-void
-FillAndStroke::showPageStrokePaint()
+void FillAndStroke::showPageStrokePaint()
{
blink();
_notebook.set_current_page(1);
_savePagePref(1);
}
-void
-FillAndStroke::showPageStrokeStyle()
+void FillAndStroke::showPageStrokeStyle()
{
blink();
_notebook.set_current_page(2);
_savePagePref(2);
-
}
-Gtk::Box&
-FillAndStroke::_createPageTabLabel(const Glib::ustring& label, const char *label_image)
+
+
+Gtk::Box &FillAndStroke::_createPageTabLabel(Glib::ustring const &label, char const *label_image)
{
auto const _tab_label_box = Gtk::make_managed(Gtk::Orientation::HORIZONTAL, 4);
diff --git a/src/ui/dialog/fill-and-stroke.h b/src/ui/dialog/fill-and-stroke.h
index 0a918df2f0af4d1b9ec2a65a397ca69653e66a77..d8ac27dfe5b13627e880dfc1820a06745c67d7dc 100644
--- a/src/ui/dialog/fill-and-stroke.h
+++ b/src/ui/dialog/fill-and-stroke.h
@@ -24,6 +24,7 @@
namespace Gtk {
class Box;
+class Popover;
} // namespace Gtk
namespace Inkscape::UI {
@@ -32,6 +33,7 @@ namespace Widget {
class FillNStroke;
class NotebookPage;
class StrokeStyle;
+class RecolorArt;
} // namespace Widget
namespace Dialog {
@@ -47,6 +49,7 @@ public:
void showPageFill();
void showPageStrokePaint();
void showPageStrokeStyle();
+ void showPageRecolorArt();
protected:
Gtk::Notebook _notebook;
@@ -78,7 +81,6 @@ private:
UI::Widget::FillNStroke *fillWdgt = nullptr;
UI::Widget::FillNStroke *strokeWdgt = nullptr;
UI::Widget::StrokeStyle *strokeStyleWdgt = nullptr;
-
sigc::scoped_connection _switch_page_conn;
};
diff --git a/src/ui/widget/color-notebook.cpp b/src/ui/widget/color-notebook.cpp
index 88f8d099c77e32568b4c6ef5f8fce566fc6462f5..fef1120bd32095a32e388c8ce285bd0595480f54 100644
--- a/src/ui/widget/color-notebook.cpp
+++ b/src/ui/widget/color-notebook.cpp
@@ -128,7 +128,7 @@ void ColorNotebook::_initUI()
_book->set_margin_top(YPAD);
_book->set_margin_bottom(YPAD);
_book->set_hexpand();
- _book->set_vexpand();
+ _book->set_vexpand(false);
attach(*_book, 0, row, 2, 1);
// restore the last active page
@@ -195,7 +195,7 @@ void ColorNotebook::_initUI()
gtk_widget_set_margin_start(rgbabox, XPAD);
gtk_widget_set_margin_end(rgbabox, XPAD);
- gtk_widget_set_margin_top(rgbabox, YPAD);
+ gtk_widget_set_margin_top(rgbabox, 8);
gtk_widget_set_margin_bottom(rgbabox, YPAD);
attach(*Glib::wrap(rgbabox), 0, row, 2, 1);
diff --git a/src/ui/widget/paint-selector.cpp b/src/ui/widget/paint-selector.cpp
index 5ad356bd70b23474f5b7816466c7b594282bde39..99f6a4239a11c1333ce860c31bee7e63a3bd956b 100644
--- a/src/ui/widget/paint-selector.cpp
+++ b/src/ui/widget/paint-selector.cpp
@@ -34,6 +34,7 @@
#include
#include "desktop-style.h"
+#include "desktop.h"
#include "document.h"
#include "style.h"
#include "inkscape.h"
@@ -49,6 +50,8 @@
#include "object/sp-stop.h"
#include "path-prefix.h"
#include "pattern-manipulation.h"
+#include "selection.h"
+#include "style.h"
#include "svg/css-ostringstream.h"
#include "ui/icon-loader.h"
#include "ui/icon-names.h"
@@ -58,6 +61,7 @@
#include "ui/widget/gradient-selector.h"
#include "ui/widget/pattern-editor.h"
#include "ui/widget/swatch-selector.h"
+#include "ui/widget/recolor-art.h"
#include "widgets/widget-sizes.h"
#include "xml/repr.h"
@@ -135,7 +139,14 @@ GradientSelectorInterface *PaintSelector::getGradientFromData() const
PaintSelector::PaintSelector(FillOrStroke kind, std::shared_ptr colors)
: _selected_colors(std::move(colors))
+ , _recolorArtWdgt_1(Gtk::make_managed())
+ , _recolorArtWdgt_2(Gtk::make_managed())
+ , _recolorButtonTriger_1(Gtk::make_managed())
+ , _recolorButtonTriger_2(Gtk::make_managed())
+ , _recolorPopOver_1(Gtk::make_managed())
+ , _recolorPopOver_2(Gtk::make_managed())
{
+
set_orientation(Gtk::Orientation::VERTICAL);
_mode = static_cast(-1); // huh? do you mean 0xff? -- I think this means "not in the enum"
@@ -209,6 +220,29 @@ PaintSelector::PaintSelector(FillOrStroke kind, std::shared_ptrset_visible(kind == FILL);
+
+ _desktop = SP_ACTIVE_DESKTOP;
+ if (_desktop) {
+ auto selection = _desktop->getSelection();
+ if (selection) {
+ selection->connectChanged(sigc::mem_fun(*this, &PaintSelector::onSelectionChanged));
+ }
+ }
+
+ setupRecolorButton(_recolorButtonTriger_1,_recolorPopOver_1 , _recolorArtWdgt_1);
+ setupRecolorButton(_recolorButtonTriger_2,_recolorPopOver_2,_recolorArtWdgt_2);
+
+ _recolorButtonTriger_1->signal_clicked().connect([this]() {
+ _recolorPopOver_1->popup();
+ _recolorArtWdgt_1->performUpdate();
+ });
+
+ _recolorButtonTriger_2->signal_clicked().connect([this]() {
+ _recolorPopOver_2->popup();
+ _recolorArtWdgt_2->performUpdate();
+ });
+ _frame->append(*_recolorButtonTriger_1);
+ _recolorButtonTriger_1->hide();
}
StyleToggleButton *PaintSelector::style_button_add(gchar const *pixmap, PaintSelector::Mode mode, gchar const *tip)
@@ -294,6 +328,11 @@ void PaintSelector::set_mode_ex(Mode mode, bool switch_style) {
}
_mode = mode;
_signal_mode_changed.emit(_mode, switch_style);
+ if (_desktop = SP_ACTIVE_DESKTOP) {
+ if (auto sel = _desktop->getSelection()) {
+ onSelectionChanged(sel);
+ }
+}
_update = false;
}
}
@@ -515,12 +554,16 @@ void PaintSelector::set_mode_color()
auto const color_selector = Gtk::make_managed(_selected_colors);
color_selector->set_visible(true);
UI::pack_start(*_selector_solid_color, *color_selector, true, true);
+ UI::pack_start(*_selector_solid_color, *_recolorButtonTriger_2, false, false);
+ _recolorButtonTriger_2->hide();
+
/* Pack everything to frame */
_frame->append(*_selector_solid_color);
color_selector->set_label(_("Flat color"));
}
_selector_solid_color->set_visible(true);
+ _selector_solid_color->set_vexpand(false);
}
_label->set_markup(""); //_("Flat color"));
@@ -921,8 +964,10 @@ void PaintSelector::pattern_destroy(GtkWidget *widget, PaintSelector * /*psel*/)
g_object_unref(G_OBJECT(widget));
}
-void PaintSelector::pattern_change(GtkWidget * /*widget*/, PaintSelector *psel) { psel->_signal_changed.emit(); }
-
+void PaintSelector::pattern_change(GtkWidget * /*widget*/, PaintSelector *psel)
+{
+ psel->_signal_changed.emit();
+}
/*update pattern list*/
void PaintSelector::updatePatternList(SPPattern *pattern)
@@ -1141,6 +1186,51 @@ PaintSelector::Mode PaintSelector::getModeForStyle(SPStyle const &style, FillOrS
return mode;
}
+void PaintSelector::onSelectionChanged(Inkscape::Selection *selection)
+{
+ auto group = dynamic_cast(selection->single());
+ if(selection->size()>1 || group)
+ {
+ if (_mode == MODE_MULTIPLE || _mode == MODE_UNSET)
+ {
+ _recolorButtonTriger_1->show();
+ _recolorButtonTriger_2->hide();
+ // std::cout<<"shoed 1 hide 2\n";
+ }
+ else if (_mode == MODE_SOLID_COLOR)
+ {
+ _recolorButtonTriger_2->show();
+ _recolorButtonTriger_1->hide();
+ // std::cout<<"shoed 2 hide 1\n";
+ }
+ else
+ {
+ _recolorButtonTriger_1->hide();
+ _recolorButtonTriger_2->hide();
+ // std::cout<<"hide 1,2 selection size : "<size()<<" mode : "<<_mode<hide();
+ _recolorButtonTriger_2->hide();
+ // std::cout<<"hide 1,2\n";
+ }
+}
+
+void PaintSelector::setupRecolorButton(Gtk::Button *recolorButtonTriger, Gtk::Popover *recolorPopOver , UI::Widget::RecolorArt *recolorArtWdgt)
+{
+ recolorButtonTriger->set_label("Recolor Selection");
+ recolorButtonTriger->set_hexpand(false);
+ recolorButtonTriger->set_vexpand(false);
+ recolorButtonTriger->set_size_request(180);
+ recolorButtonTriger->set_halign(Gtk::Align::CENTER);
+ recolorButtonTriger->set_valign(Gtk::Align::START);
+ recolorPopOver->set_parent(*recolorButtonTriger);
+ recolorPopOver->set_child(*recolorArtWdgt);
+ recolorPopOver->set_position(Gtk::PositionType::LEFT);
+ recolorButtonTriger->set_margin_top(8);
+}
} // namespace Widget
} // namespace UI
diff --git a/src/ui/widget/paint-selector.h b/src/ui/widget/paint-selector.h
index f76eda68f6cfa78a5620674edaf59896fcf29e63..3b2978c6e77737b013791d574d38dcf6da84b04c 100644
--- a/src/ui/widget/paint-selector.h
+++ b/src/ui/widget/paint-selector.h
@@ -28,6 +28,7 @@
#include "object/sp-gradient-units.h"
#include "ui/widget/gradient-selector.h"
#include "ui/widget/swatch-selector.h"
+#include "selection.h"
class SPGradient;
class SPLinearGradient;
@@ -36,12 +37,15 @@ class SPRadialGradient;
class SPMeshGradient;
#endif
class SPDesktop;
+class Selection;
class SPPattern;
class SPStyle;
namespace Gtk {
class Label;
class ToggleButton;
+class Button;
+class Popover;
} // namespace Gtk
namespace Inkscape::UI::Widget {
@@ -50,6 +54,7 @@ class FillRuleRadioButton;
class GradientEditor;
class PatternEditor;
class StyleToggleButton;
+class RecolorArt;
/**
* Generic paint selector widget.
@@ -102,6 +107,16 @@ class PaintSelector : public Gtk::Box {
Gtk::Box *_selector_mesh = nullptr;
SwatchSelector *_selector_swatch = nullptr;
PatternEditor* _selector_pattern = nullptr;
+
+ UI::Widget::RecolorArt *_recolorArtWdgt_1 = nullptr;
+ UI::Widget::RecolorArt *_recolorArtWdgt_2 = nullptr;
+ Gtk::Button *_recolorButtonTriger_1 = nullptr;
+ Gtk::Button *_recolorButtonTriger_2 = nullptr;
+ Gtk::Popover* _recolorPopOver_1=nullptr;
+ Gtk::Popover* _recolorPopOver_2=nullptr;
+ SPDesktop*_desktop=nullptr;
+ void onSelectionChanged(Inkscape::Selection *selection);
+ void setupRecolorButton(Gtk::Button *recolorButtonTriger , Gtk::Popover*recolorPopOver , UI::Widget::RecolorArt *recolorArtWdgt);
Gtk::Label *_label;
GtkWidget *_patternmenu = nullptr;
diff --git a/src/ui/widget/recolor-art.cpp b/src/ui/widget/recolor-art.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..08ba482c9dd4d6a89c7738bfa440c55c7adbfbb5
--- /dev/null
+++ b/src/ui/widget/recolor-art.cpp
@@ -0,0 +1,566 @@
+#include "recolor-art.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+// #include
+#include
+#include
+
+#include "actions/actions-tools.h"
+#include "canvas.h"
+#include "color-notebook.h"
+#include "desktop-style.h"
+#include "desktop.h"
+#include "document-undo.h"
+#include "document.h"
+#include "gradient-chemistry.h"
+#include "object/sp-defs.h"
+#include "object/sp-gradient.h"
+#include "object/sp-linear-gradient.h"
+#include "object/sp-marker.h"
+#include "object/sp-mesh-gradient.h"
+#include "object/sp-object.h"
+#include "object/sp-pattern.h"
+#include "object/sp-radial-gradient.h"
+#include "object/sp-stop.h"
+#include "object/sp-text.h"
+#include "object/sp-use.h"
+#include "pattern-manipulation.h"
+#include "selection.h"
+#include "style-internal.h"
+#include "style.h"
+#include "inkscape.h"
+#include "ui/builder-utils.h"
+#include "ui/dialog/dialog-base.h"
+#include "ui/icon-names.h"
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+RecolorArt::RecolorArt()
+ : Gtk::Box()
+ , _builder(create_builder("recolor-art.glade"))
+ , _solid_colors(std::make_shared())
+{
+ set_name("RecolorArt");
+ append(get_widget(_builder, "recolor-art"));
+ _solid_colors->set(Color(0x000000ff));
+
+ layoutColorPicker();
+ _color_list = _builder->get_widget("colors-list");
+ _live_preview = _builder->get_widget("liveP");
+ _live_preview->signal_toggled().connect(sigc::mem_fun(*this, &RecolorArt::onLivePreviewToggled));
+ _live_preview->set_active(true);
+ _reset = _builder->get_widget("reset");
+ _reset->signal_clicked().connect(sigc::mem_fun(*this, &RecolorArt::onResetClicked));
+
+ _notebook = _builder->get_widget("list-wheel-box");
+ _color_wheel_page = _builder->get_widget("color-wheel-page");
+ _notebook->signal_switch_page().connect([this](Gtk::Widget *page, guint page_num) {
+ int wheel_index = _notebook->page_num(*_color_wheel_page);
+
+ if (static_cast(page_num) == wheel_index) {
+ _color_picker_wdgt->set_visible(false);
+ // std::cout << "Color Wheel tab is active.\n";
+ } else {
+ _color_picker_wdgt->set_visible(true);
+ // std::cout << "Color Wheel tab is NOT active.\n";
+ }
+ });
+
+ _list_view = _builder->get_widget("recolor-art-list");
+ _color_model = Gio::ListStore::create();
+ _selection_model = Gtk::SingleSelection::create(_color_model);
+ _color_factory = Gtk::SignalListItemFactory::create();
+
+ _color_factory->signal_setup().connect([](Glib::RefPtr const &list_item) {
+ auto box = Gtk::make_managed(Gtk::Orientation::HORIZONTAL);
+ auto original = Gtk::make_managed();
+ auto arrow = Gtk::make_managed();
+ auto recolored = Gtk::make_managed();
+
+ original->set_hexpand(true);
+
+ recolored->set_hexpand(true);
+
+ arrow->set_use_markup(true);
+ arrow->set_width_chars(6);
+ arrow->set_markup("➔");
+ arrow->set_halign(Gtk::Align::CENTER);
+ arrow->set_valign(Gtk::Align::CENTER);
+ arrow->set_margin_top(3);
+
+ box->set_name("original-recolor-box");
+ box->append(*original);
+ box->append(*arrow);
+ box->append(*recolored);
+ list_item->set_child(*box);
+ });
+
+ _color_factory->signal_bind().connect([this](Glib::RefPtr const &list_item) {
+ auto item = std::dynamic_pointer_cast(list_item->get_item());
+ if (!item)
+ return;
+
+ auto box = dynamic_cast(list_item->get_child());
+ if (!box || box->get_first_child() == nullptr || box->get_last_child() == nullptr)
+ return;
+
+ auto original = dynamic_cast(box->get_first_child());
+ auto recolored = dynamic_cast(box->get_last_child());
+
+ if (original && recolored) {
+ colorButtons(original, item->old_color);
+ colorButtons(recolored, item->new_color);
+
+ original->set_name("original");
+ recolored->set_name("recolored");
+ original->signal_clicked().connect([this, item, index = list_item->get_position()] {
+ _selection_model->set_selected(index);
+ onOriginalColorClicked(item->key);
+ });
+
+ recolored->signal_clicked().connect([this, item, index = list_item->get_position()] {
+ _selection_model->set_selected(index);
+ onOriginalColorClicked(item->key);
+ });
+ buttons[item->key] = {original, recolored};
+ }
+ });
+
+ _list_view->set_model(_selection_model);
+ _list_view->set_factory(_color_factory);
+ auto lm = _list_view->get_layout_manager();
+ if (auto grid_layout = std::dynamic_pointer_cast(lm)) {
+ grid_layout->set_row_spacing(0);
+ }
+ _list_view->set_hexpand(false);
+ _list_view->set_vexpand(false);
+
+ _selection_model->signal_selection_changed().connect([this](guint pos, guint n_items) {
+ int index = _selection_model->get_selected();
+ if (index < 0)
+ return;
+
+ auto item = _color_model->get_item(index);
+ auto color_item = std::dynamic_pointer_cast(item);
+ if (!color_item)
+ return;
+
+ onOriginalColorClicked(color_item->key);
+ });
+
+ // _apply = _builder->get_widget("apply");
+ // _apply->signal_clicked().connect(sigc::mem_fun(*this, &RecolorArt::_onApplyButtonClicked));
+}
+RecolorArt::~RecolorArt() {}
+
+void RecolorArt::setDesktop(SPDesktop *desktop)
+{
+ if (_desktop != desktop) {
+ _desktop = desktop;
+ }
+ g_message("setDesktop\n");
+}
+void RecolorArt::collectColors(std::vector items)
+{
+ _selected_colors.clear();
+ for (auto item : items) {
+ extractItemColors(item);
+ }
+}
+void RecolorArt::extractItemColors(SPObject *item)
+{
+ if (auto group = dynamic_cast(item)) {
+ for (SPObject &child : group->children) {
+ extractItemColors(&child);
+ }
+ } else if (item) {
+ extractItemStyle(item);
+ }
+}
+void RecolorArt::extractGradientStops(SPObject *item, std::string kind, bool isFill)
+{
+ SPPaintServer *paint_server = isFill ? item->style->getFillPaintServer() : item->style->getStrokePaintServer();
+ if (paint_server && dynamic_cast(paint_server)) {
+ SPGradient *gradient = dynamic_cast(paint_server);
+ SPGradient *vectorGradient = gradient->getVector();
+ if (vectorGradient) {
+ if (vectorGradient->hasPatches()) {
+ vectorGradient->ensureArray();
+ std::unique_ptr nodeArray;
+ if (auto mesh = dynamic_cast(gradient)) {
+ nodeArray = std::make_unique(mesh);
+ extractMeshStops(nodeArray->nodes, item, kind);
+ }
+
+ } else {
+ vectorGradient->ensureVector();
+ // int stopCount = vectorGradient->getStopCount();
+ // std::cout << "Stops count : " << stopCount << std::endl;
+ // std::cout << "has patches : " << vectorGradient->hasPatches() << std::endl;
+ populateStopsMap(vectorGradient->getFirstStop());
+ }
+ }
+ for (auto stop : vectorGradient->getGradientVector().stops) {
+ if (stop.color.has_value()) {
+ populateMap(stop.color.value(), item, kind);
+ }
+ }
+ }
+}
+void RecolorArt::extractMeshStops(std::vector> mesh_nodes, SPObject *item, std::string kind)
+{
+ for (auto nodes : mesh_nodes) {
+ for (auto node : nodes) {
+ populateStopsMap(node->stop);
+ if (node->color.has_value()) {
+ populateMap(node->color.value(), item, kind);
+ }
+ }
+ }
+}
+void RecolorArt::populateStopsMap(SPStop *stop)
+{
+ g_message("populateStopsMap in");
+ while (stop) {
+ std::string color = stop->getColor().toString();
+ _gradient_stops[color].push_back(stop);
+ stop = stop->getNextStop();
+ }
+}
+void RecolorArt::populateMap(Color color, SPObject *item, std::string kind)
+{
+ color.addOpacity();
+ ColorRef ref = ColorRef(item, kind);
+ ColorPair pair = ColorPair(color, color);
+ if (_selected_colors.count(color.toString())) {
+ _selected_colors[color.toString(true)].first.push_back(ref);
+ } else {
+ _selected_colors.emplace(color.toString(), std::make_pair(std::vector{ref}, pair));
+ }
+}
+void RecolorArt::extractItemStyle(SPObject *item)
+{
+ // check item style
+ if (!item || !item->style)
+ return;
+ SPStyle *style = item->style;
+ extractMarkerColors(style->marker_start.get_value(), item);
+ extractMarkerColors(style->marker_mid.get_value(), item);
+ extractMarkerColors(style->marker_end.get_value(), item);
+
+ // get flat fills
+ if (style->fill.isColor()) {
+ auto color = style->fill.getColor();
+ populateMap(color, item, "fill");
+ }
+ // get gradient stops strokes
+ else if (style->fill.isPaintserver()) {
+ auto ps = style->getFillPaintServer();
+ if (auto pattern = dynamic_cast(ps)) {
+ extractPatternColors(pattern);
+ std::cout << "pattern detected\n";
+ }
+ extractGradientStops(item, "stop", true);
+ }
+
+ if (style->stroke.isColor()) {
+ auto color = style->stroke.getColor();
+ populateMap(color, item, "stroke");
+ }
+ // get gradient stops strokes
+ else if (style->stroke.isPaintserver()) {
+ extractGradientStops(item, "stop", false);
+ }
+}
+void RecolorArt::extractPatternColors(SPPattern *pattern)
+{
+ SPPattern *root = pattern->rootPattern();
+ for (auto &child : root->children) {
+ extractItemStyle(&child);
+ }
+}
+void RecolorArt::extractMarkerColors(Glib::ustring marker, SPObject *item)
+{
+ // std::cout << "markerout : " << marker << std::endl;
+ if (marker.size() > 0 && item->document) {
+ // std::cout << "marker in : " << marker << std::endl;
+ std::string marker_id = std::string(marker.c_str() + 4, std::strlen(marker.c_str()) - 5);
+ // std::cout<<"marker id : "<document->getObjectByHref(marker_id);
+ if(!m) std::cout<<"m is null\n";
+ if (auto marker_obj = dynamic_cast(m)) {
+ for (auto &child : marker_obj->item_list()) {
+ extractItemColors(&*child);
+ }
+ }
+ } else
+ return;
+}
+void RecolorArt::generateVisualList()
+{
+ _color_model->remove_all();
+ buttons.clear();
+ for (auto &[key, value] : _selected_colors) {
+ auto old_color = value.second.value().old_color.toString();
+ auto new_color = value.second.value().new_color.toString();
+ _color_model->append(ColorItem::create(key, old_color, new_color));
+ }
+ _color_list->append(*_list_view);
+}
+void RecolorArt::layoutColorPicker(std::shared_ptr updated_color)
+{
+ if (updated_color)
+ _solid_colors = updated_color;
+ _color_picker_wdgt = Gtk::make_managed(_solid_colors);
+ _color_picker_wdgt->set_visible(true);
+ _color_picker_wdgt->set_label(_("Selected Color"));
+ _solid_colors->signal_changed.connect(sigc::mem_fun(*this, &RecolorArt::onColorPickerChanged));
+
+ auto container = _builder->get_widget("color-picker");
+ if (container) {
+ for (auto child : container->get_children())
+ container->remove(*child);
+ container->append(*_color_picker_wdgt);
+ } else {
+ g_warning("color picker not found");
+ }
+}
+void RecolorArt::colorButtons(Gtk::Button *button, std::string color)
+{
+ if (color.empty() || color.size() < 7 || color[0] != '#') {
+ g_warning("Invalid color string: %s", color.c_str());
+ return;
+ }
+
+ if (button) {
+ auto css_provider = Gtk::CssProvider::create();
+ Glib::ustring css = "button { background-color: " + Glib::ustring(color) + "; background-image: none;}";
+ css_provider->load_from_data(css);
+ auto style_context = button->get_style_context();
+ style_context->add_provider(css_provider, GTK_STYLE_PROVIDER_PRIORITY_USER);
+ } else {
+ g_message("button not found");
+ }
+}
+// void RecolorArt::colorBorderOnClick(Gtk::Button *button, bool kind)
+// {
+// auto &_last_button = kind == 1 ? _last_original_button : _last_recolored_button;
+// if (_last_button && _last_button != button) {
+// auto style_context = _last_button->get_style_context();
+// style_context->remove_class("selected-button");
+// }
+// if (button) {
+// auto style_context = button->get_style_context();
+// style_context->add_class("selected-button");
+// _last_button = button;
+// } else {
+// g_warning("button not found for border coloring");
+// }
+// }
+void RecolorArt::onOriginalColorClicked(std::string color_id)
+{
+ _current_color_id = color_id;
+ auto it = _selected_colors.find(color_id);
+ auto btns = buttons.find(color_id);
+ if (it != _selected_colors.end() && it->second.second.has_value() && btns != buttons.end()) {
+ Color color = it->second.second.value().new_color;
+ std::shared_ptr updated_color = std::make_shared();
+ updated_color->set(color);
+ layoutColorPicker(updated_color);
+ // colorBorderOnClick(btns->second.first, 1);
+ // colorBorderOnClick(btns->second.second, 0);
+ // g_message("original color selected at color %s", color_id.c_str());
+ }
+}
+void RecolorArt::onColorPickerChanged()
+{
+ auto it = buttons.find(_current_color_id);
+ if (it == buttons.end()) {
+ g_message("couldn't find the color id \" %s \" ", _current_color_id.c_str());
+ return;
+ }
+ Gtk::Button *_current_recolor_button = it->second.second;
+ std::optional new_color = _solid_colors->get();
+ if (!new_color.has_value()) {
+ g_message("there is no color");
+ return;
+ }
+ std::string _color_string = new_color.value().toString();
+ colorButtons(_current_recolor_button, _color_string);
+ auto _selected = _selected_colors.find(_current_color_id);
+ if (_selected != _selected_colors.end())
+ _selected->second.second.value().new_color = new_color.value();
+ if (_live_preview && _live_preview->property_active()) {
+ lpChecked();
+ }
+ guint index = _selection_model->get_selected();
+ auto item = _color_model->get_item(index);
+ auto color_item = std::dynamic_pointer_cast(item);
+ color_item->new_color = _color_string;
+ g_message("color picker changed");
+}
+void RecolorArt::lpChecked()
+{
+ auto _selected = _selected_colors.find(_current_color_id);
+ std::optional new_color = _solid_colors->get();
+ if (!new_color.has_value()) {
+ g_message("there is no color");
+ return;
+ }
+ std::string _color_string = new_color.value().toString();
+ if (_selected == _selected_colors.end()) {
+ g_message("no items found");
+ return;
+ }
+ _selected->second.second.value().new_color = new_color.value();
+ for (auto &item : _selected->second.first) {
+ if (item.kind == "stop")
+ continue;
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ sp_repr_css_set_property_string(css, item.kind.c_str(), _color_string);
+ sp_desktop_apply_css_recursive(item.item, css, true);
+ sp_repr_css_attr_unref(css);
+ }
+ recolorStops(_selected->first, new_color.value());
+ DocumentUndo::done(_desktop->getDocument(), _("Recolored items"), INKSCAPE_ICON("object-recolor-art"));
+}
+void RecolorArt::onResetClicked()
+{
+ for (auto [key, btns] : buttons) {
+ colorButtons(btns.second, key);
+ }
+
+ for (auto i = 0; i < _color_model->get_n_items(); i++) {
+ auto item = _color_model->get_item(i);
+ auto color_item = std::dynamic_pointer_cast(item);
+ color_item->new_color = color_item->key;
+ }
+ revertToOriginalColors();
+ _selection_model->set_selected(0);
+ onOriginalColorClicked(buttons.begin()->first);
+}
+void RecolorArt::revertToOriginalColors()
+{
+ for (auto [key, items] : _selected_colors) {
+ for (auto &item : items.first) {
+ if (item.kind == "stop")
+ continue;
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ sp_repr_css_set_property_string(css, item.kind.c_str(), key);
+ sp_desktop_apply_css_recursive(item.item, css, true);
+ sp_repr_css_attr_unref(css);
+ }
+ recolorStops(key, items.second.value().old_color);
+ }
+}
+void RecolorArt::convertToRecoloredColors()
+{
+ for (auto [key, items] : _selected_colors) {
+ if (items.second.has_value()) {
+ std::string new_color = items.second.value().new_color.toString();
+ for (auto &item : items.first) {
+ if (item.kind == "stop")
+ continue;
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ sp_repr_css_set_property_string(css, item.kind.c_str(), new_color);
+ sp_desktop_apply_css_recursive(item.item, css, true);
+ sp_repr_css_attr_unref(css);
+ }
+ recolorStops(key, items.second.value().new_color);
+ }
+ }
+}
+void RecolorArt::recolorStops(std::string old_color, Color new_color)
+{
+ auto stops_vector = _gradient_stops.find(old_color);
+ if (stops_vector != _gradient_stops.end()) {
+ for (auto stop : stops_vector->second) {
+ stop->setColor(new_color);
+ }
+ }
+}
+void RecolorArt::onLivePreviewToggled()
+{
+ _is_preview = _live_preview->property_active();
+ if (_is_preview) {
+ convertToRecoloredColors();
+ } else {
+ revertToOriginalColors();
+ }
+ g_message(_is_preview ? "is true" : "is false");
+ g_message("LP toggled");
+}
+bool RecolorArt::selectionSize()
+{
+ if (_desktop && _desktop->getSelection()->size() > 1) {
+ return true;
+ }
+ return false;
+}
+void RecolorArt::performUpdate()
+{
+ for (auto child : _color_list->get_children()) {
+ _color_list->remove(*child);
+ }
+ buttons.clear();
+ _gradient_stops.clear();
+ _last_original_button = nullptr;
+ _last_recolored_button = nullptr;
+ _desktop = SP_ACTIVE_DESKTOP;
+ // _current_color_id = "";
+ if (auto selection = _desktop->getSelection()) {
+ std::vector vec(selection->items().begin(), selection->items().end());
+ collectColors(vec);
+ if (!_selected_colors.empty()) {
+ generateVisualList();
+ auto first_button_id = buttons.begin()->first;
+ onOriginalColorClicked(first_button_id);
+ }
+ g_message("Performing Update\n");
+ } else
+ g_message("Desktop is NULL in Performupdate in recolor widegt\n");
+}
+} // namespace Widget
+} // namespace UI
+} // namespace Inkscape
+
+// void RecolorArt::_onApplyButtonClicked()
+// {
+// for (auto [key, items] : _selected_colors) {
+// std::string _color_string = items.second.value().new_color.toString();
+// for (auto &item : items.first) {
+// SPCSSAttr *css = sp_repr_css_attr_new();
+// sp_repr_css_set_property_string(css, item.kind.c_str(), _color_string);
+// sp_desktop_apply_css_recursive(item.item, css, true);
+// sp_repr_css_attr_unref(css);
+// }
+// }
+// g_message("apply clicked");
+// }
+// if (!_gradient_stops.empty()) {
+// for (auto [key, value] : _gradient_stops) {
+// std::cout << key << " : ";
+// for (auto stop : value)
+// std::cout << stop << " ";
+// std::cout << std::endl;
+// }
+// g_message("filled stops map");
+
+// } else {
+// g_message("empty stops map");
+// }
\ No newline at end of file
diff --git a/src/ui/widget/recolor-art.h b/src/ui/widget/recolor-art.h
new file mode 100644
index 0000000000000000000000000000000000000000..c04a3cb5b2f94c3a3bbd0859d813c95d1d5a6619
--- /dev/null
+++ b/src/ui/widget/recolor-art.h
@@ -0,0 +1,147 @@
+
+
+#ifndef SEEN_DIALOGS_SP_RECOLOR_ART_H
+#define SEEN_DIALOGS_SP_RECOLOR_ART_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "canvas.h"
+#include "style-internal.h"
+#include "style.h"
+#include "ui/widget/paint-selector.h"
+
+using namespace Inkscape::Colors;
+
+namespace Inkscape::Colors {
+class Color;
+class ColorSet;
+namespace Space {
+class AnySpace;
+}
+} // namespace Inkscape::Colors
+
+namespace Gtk {
+class Widget;
+class Builder;
+class ListStore;
+class Notebook;
+} // namespace Gtk
+
+class SPDesktop;
+
+namespace Inkscape {
+namespace UI {
+namespace Tools {
+class ToolBase;
+}
+
+namespace Widget {
+class ColorNotebook;
+
+struct ColorRef
+{
+ SPObject *item;
+ std::string kind;
+};
+
+struct ColorPair
+{
+ Color old_color;
+ Color new_color;
+};
+
+struct ColorItem : public Glib::Object
+{
+ Glib::ustring key;
+ Glib::ustring old_color;
+ Glib::ustring new_color;
+
+ static Glib::RefPtr create(Glib::ustring const &k, Glib::ustring const &old_c,
+ Glib::ustring const &new_c)
+ {
+ auto item = Glib::make_refptr_for_instance(new ColorItem());
+ item->key = k;
+ item->old_color = old_c;
+ item->new_color = new_c;
+ return item;
+ }
+};
+class RecolorArt : public Gtk::Box
+{
+private:
+ SPDesktop *_desktop = nullptr;
+ std::shared_ptr _solid_colors;
+ std::map, std::optional>> _selected_colors;
+ Inkscape::UI::Widget::ColorNotebook *_color_picker_wdgt = nullptr;
+ Gtk::Box *_color_list = nullptr;
+ Gtk::ListView *_list_view = nullptr;
+ Gtk::Button *_reset = nullptr;
+ Gtk::CheckButton *_live_preview = nullptr;
+ std::string _current_color_id;
+ std::map> buttons; // color_id : {original , recolored}
+ bool _is_preview = false;
+
+ Glib::RefPtr> _color_model;
+ Glib::RefPtr _color_factory;
+ Glib::RefPtr _selection_model;
+
+ Gtk::Button *_last_original_button = nullptr;
+ Gtk::Button *_last_recolored_button = nullptr;
+
+ std::map> _gradient_stops;
+
+ Gtk::Notebook *_notebook = nullptr;
+ Gtk::Box *_color_wheel_page = nullptr;
+
+ // Gtk::Button *_apply = nullptr;
+
+ Glib::RefPtr _builder;
+ void populateMap(Color color, SPObject *style, std::string kind);
+ void collectColors(std::vector items);
+ void extractGradientStops(SPObject *item, std::string kind, bool isFill);
+ void extractMeshStops(std::vector> mesh_nodes, SPObject *item, std::string kind);
+ void extractItemColors(SPObject *item);
+ void extractItemStyle(SPObject *item);
+ void extractPatternColors(SPPattern*pattern);
+ void extractMarkerColors(Glib::ustring marker ,SPObject *item);
+ void generateVisualList();
+ void layoutColorPicker(std::shared_ptr updated_color = nullptr);
+ void colorButtons(Gtk::Button *button, std::string color);
+ // void colorBorderOnClick(Gtk::Button *button, bool kind);
+
+ // signals handelrs
+ void onOriginalColorClicked(std::string color_id);
+ void onResetClicked();
+ void onColorPickerChanged();
+ void onLivePreviewToggled();
+ void lpChecked();
+ void revertToOriginalColors();
+ void convertToRecoloredColors();
+ // void _onApplyButtonClicked();
+
+ void populateStopsMap(SPStop *stop);
+ void recolorStops(std::string old_color, Color new_color);
+
+public:
+ RecolorArt();
+ ~RecolorArt();
+ void performUpdate();
+ bool isInPreviewMode() { return _is_preview; }
+ void setDesktop(SPDesktop *desktop);
+ bool selectionSize();
+};
+
+} // namespace Widget
+} // namespace UI
+} // namespace Inkscape
+
+#endif // SEEN_DIALOGS_SP_RECOLOR_ART_H