From 44ee47343755200386560c54047c93251a3b8384 Mon Sep 17 00:00:00 2001 From: Martin Owens Date: Tue, 7 Jan 2025 13:16:28 -0500 Subject: [PATCH] Add a way to set the polygon length from the star-toolbar For controlling polygons, we want to be able to show how big each side is as well as allow the user to control the star or polygon from it's side-length. This is a fancy way of setting a transform. --- share/ui/toolbar-star.ui | 33 +++++++++++++++++ src/object/sp-star.cpp | 25 +++++++++++++ src/object/sp-star.h | 7 ++-- src/ui/toolbar/star-toolbar.cpp | 63 ++++++++++++++++++++++++++++++++- src/ui/toolbar/star-toolbar.h | 8 +++++ 5 files changed, 130 insertions(+), 6 deletions(-) diff --git a/share/ui/toolbar-star.ui b/share/ui/toolbar-star.ui index ddaf932d71..d1704c343e 100644 --- a/share/ui/toolbar-star.ui +++ b/share/ui/toolbar-star.ui @@ -29,6 +29,11 @@ True True + + 1000000 + 0.10 + 5 + start center @@ -195,6 +200,34 @@ + + + Length of side + + + 5 + L: + + + + + True + 7 + 0.000 + _length_adj + 0.10 + 3 + + + + + + + + + diff --git a/src/object/sp-star.cpp b/src/object/sp-star.cpp index de4e195d97..59ddcbbd1a 100644 --- a/src/object/sp-star.cpp +++ b/src/object/sp-star.cpp @@ -522,6 +522,31 @@ void SPStar::update_patheffect(bool write) { SPShape::update_patheffect(write); } +/** + * Calculate the average side length of the polygon. + * + * For spoked polygons (stars) this is the radius delta; for non-spokjed + * polygons this is the regular side length directly. + * + * @returns the average length of the polygon sides. + */ +double SPStar::getSideLength() const +{ + if (!flatsided) { + // Pointy star + std::cout << "getSideLength(star: " << std::abs(r[0] - r[1]) << ")\n"; + return std::abs(r[0] - r[1]); + } + double diameter = 0.0; + auto tr = i2doc_affine(); + for (gint i = 1; i < sides; i++) { + diameter += Geom::distance(sp_star_get_xy(this, SP_STAR_POINT_KNOT1, i - 1, false) * tr, + sp_star_get_xy(this, SP_STAR_POINT_KNOT1, i, false) * tr); + } + std::cout << "getSideLength(polygon: " << (diameter / sides) << ")\n"; + return diameter / sides; +} + /** * sp_star_get_xy: Get X-Y value as item coordinate system * @star: star item diff --git a/src/object/sp-star.h b/src/object/sp-star.h index 47abebf70b..2c8fb53200 100644 --- a/src/object/sp-star.h +++ b/src/object/sp-star.h @@ -38,11 +38,6 @@ public: double rounded; double randomized; -// CPPIFY: This derivation is a bit weird. -// parent_class = reinterpret_cast(g_type_class_ref(SP_TYPE_SHAPE)); -// So shouldn't star be derived from shape instead of polygon? -// What does polygon have that shape doesn't? - void build(SPDocument *document, Inkscape::XML::Node *repr) override; Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, unsigned int flags) override; void set(SPAttr key, char const* value) override; @@ -55,6 +50,8 @@ public: void update_patheffect(bool write) override; void set_shape() override; Geom::Affine set_transform(Geom::Affine const& xform) override; + + double getSideLength() const; }; void sp_star_position_set (SPStar *star, int sides, Geom::Point center, double r1, double r2, double arg1, double arg2, bool isflat, double rounded, double randomized); diff --git a/src/ui/toolbar/star-toolbar.cpp b/src/ui/toolbar/star-toolbar.cpp index 27ef1109ea..cc348593ef 100644 --- a/src/ui/toolbar/star-toolbar.cpp +++ b/src/ui/toolbar/star-toolbar.cpp @@ -41,7 +41,9 @@ #include "ui/icon-names.h" #include "ui/tools/star-tool.h" #include "ui/util.h" +#include "ui/widget/combo-tool-item.h" #include "ui/widget/spinbutton.h" +#include "ui/widget/unit-tracker.h" using Inkscape::DocumentUndo; @@ -59,6 +61,8 @@ StarToolbar::StarToolbar(Glib::RefPtr const &builder) , _spoke_item{get_derived_widget(builder, "_spoke_item")} , _roundedness_item{get_derived_widget(builder, "_roundedness_item")} , _randomization_item{get_derived_widget(builder, "_randomization_item")} + , _tracker{std::make_unique(Util::UNIT_TYPE_LINEAR)} + , _length_item{get_derived_widget(builder, "_length_item")} { bool is_flat_sided = Preferences::get()->getBool("/tools/shapes/star/isflatsided", false); @@ -111,6 +115,7 @@ StarToolbar::StarToolbar(Glib::RefPtr const &builder) setup_derived_spin_button(_spoke_item, "proportion", 0.5, &StarToolbar::proportion_value_changed); setup_derived_spin_button(_roundedness_item, "rounded", 0.0, &StarToolbar::rounded_value_changed); setup_derived_spin_button(_randomization_item, "randomized", 0.0, &StarToolbar::randomized_value_changed); + setup_derived_spin_button(_length_item, "length", 0.0, &StarToolbar::length_value_changed); // Flatsided checkbox _flat_item_buttons.push_back(&get_widget(builder, "flat_polygon_button")); @@ -128,6 +133,10 @@ StarToolbar::StarToolbar(Glib::RefPtr const &builder) _spoke_box.set_visible(!is_flat_sided); + auto unit_menu = _tracker->create_tool_item(_("Units"), ("")); + get_widget(builder, "unit_menu_box").append(*unit_menu); + _tracker->addAdjustment(_length_item.get_adjustment()->gobj()); + _initMenuBtns(); } @@ -166,6 +175,7 @@ void StarToolbar::setDesktop(SPDesktop *desktop) { if (_desktop) { _selection_changed_conn.disconnect(); + _selection_modified_conn.disconnect(); if (_repr) { _detachRepr(); @@ -177,10 +187,16 @@ void StarToolbar::setDesktop(SPDesktop *desktop) if (_desktop) { auto sel = _desktop->getSelection(); _selection_changed_conn = sel->connectChanged(sigc::mem_fun(*this, &StarToolbar::_selectionChanged)); + _selection_modified_conn = sel->connectChanged(sigc::mem_fun(*this, &StarToolbar::_selectionModified)); _selectionChanged(sel); // Synthesize an emission to trigger the update } } +void StarToolbar::setActiveUnit(Util::Unit const *unit) +{ + _tracker->setActiveUnit(unit); +} + void StarToolbar::side_mode_changed(int mode) { bool const flat = mode == 0; @@ -356,6 +372,25 @@ void StarToolbar::randomized_value_changed() } } +void StarToolbar::length_value_changed() +{ + if (!_blocker.pending() || _tracker->isUpdating()) { + // in turn, prevent listener from responding + auto guard = _blocker.block(); + + auto adj = _length_item.get_adjustment(); + auto value = Util::Quantity::convert(adj->get_value(), _tracker->getActiveUnit(), "px"); + for (auto item : _desktop->getSelection()->items()) { + if (auto star = cast(item)) { + auto scale = Geom::Scale(value / star->getSideLength()); + auto set_tmp = ObjectSet{_desktop}; + set_tmp.add(item); + set_tmp.scaleRelative(star->center, scale); + } + } + } +} + void StarToolbar::_setDefaults() { _batchundo = true; @@ -393,20 +428,46 @@ void StarToolbar::_selectionChanged(Selection *selection) int n_selected = 0; XML::Node *repr = nullptr; + double lengths = 0; for (auto item : selection->items()) { - if (is(item)) { + if (auto star = cast(item)) { n_selected++; repr = item->getRepr(); + lengths += star->getSideLength(); } } _mode_item.set_markup(n_selected == 0 ? _("New:") : _("Change:")); + _length_item.set_sensitive(n_selected > 0); + if (n_selected == 1) { _attachRepr(repr); _repr->synthesizeEvents(*this); // Fixme: BAD } + _selectionModified(selection); +} + +void StarToolbar::_selectionModified(Selection *selection) +{ + if (!_blocker.pending()|| _tracker->isUpdating()) { + auto guard = _blocker.block(); + auto length_adj = _length_item.get_adjustment(); + + int n_selected = 0; + double lengths = 0; + for (auto item : selection->items()) { + if (auto star = cast(item)) { + n_selected++; + lengths += star->getSideLength(); + } + } + if (n_selected > 0) { + auto value = Util::Quantity::convert(lengths / n_selected, "px", _tracker->getActiveUnit()); + length_adj->set_value(value); + } + } } void StarToolbar::notifyAttributeChanged(XML::Node &, GQuark name_, Util::ptr_shared, Util::ptr_shared) diff --git a/src/ui/toolbar/star-toolbar.h b/src/ui/toolbar/star-toolbar.h index d3dbd2726d..9bad4f4659 100644 --- a/src/ui/toolbar/star-toolbar.h +++ b/src/ui/toolbar/star-toolbar.h @@ -45,6 +45,7 @@ namespace Tools { class ToolBase; } namespace Widget { class Label; class SpinButton; +class UnitTracker; } // namespace Widget } // namespace UI namespace XML { class Node; } @@ -61,6 +62,7 @@ public: ~StarToolbar() override; void setDesktop(SPDesktop *desktop) override; + void setActiveUnit(Util::Unit const *unit) override; private: StarToolbar(Glib::RefPtr const &builder); @@ -74,6 +76,9 @@ private: UI::Widget::SpinButton &_spoke_item; UI::Widget::SpinButton &_roundedness_item; UI::Widget::SpinButton &_randomization_item; + UI::Widget::SpinButton &_length_item; + + std::unique_ptr _tracker; XML::Node *_repr = nullptr; void _attachRepr(XML::Node *repr); @@ -82,6 +87,7 @@ private: bool _batchundo = false; OperationBlocker _blocker; sigc::connection _selection_changed_conn; + sigc::connection _selection_modified_conn; void setup_derived_spin_button(UI::Widget::SpinButton &btn, Glib::ustring const &name, double default_value, ValueChangedMemFun value_changed_mem_fun); @@ -90,8 +96,10 @@ private: void proportion_value_changed(); void rounded_value_changed(); void randomized_value_changed(); + void length_value_changed(); void _setDefaults(); void _selectionChanged(Selection *selection); + void _selectionModified(Selection *selection); void notifyAttributeChanged(XML::Node &node, GQuark name, Util::ptr_shared old_value, Util::ptr_shared new_value) override; }; -- GitLab