diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:24:48 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:24:48 +0000 |
commit | cca66b9ec4e494c1d919bff0f71a820d8afab1fa (patch) | |
tree | 146f39ded1c938019e1ed42d30923c2ac9e86789 /src/ui/shape-editor.cpp | |
parent | Initial commit. (diff) | |
download | inkscape-upstream/1.2.2.tar.xz inkscape-upstream/1.2.2.zip |
Adding upstream version 1.2.2.upstream/1.2.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/ui/shape-editor.cpp')
-rw-r--r-- | src/ui/shape-editor.cpp | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/src/ui/shape-editor.cpp b/src/ui/shape-editor.cpp new file mode 100644 index 0000000..6290014 --- /dev/null +++ b/src/ui/shape-editor.cpp @@ -0,0 +1,223 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * Inkscape::ShapeEditor + * This is a container class which contains a knotholder for shapes. + * It is attached to a single item. + *//* + * Authors: see git history + * bulia byak <buliabyak@users.sf.net> + * Krzysztof KosiĆski <tweenk.pl@gmail.com> + * + * Copyright (C) 2018 Authors + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include "shape-editor.h" + +#include "desktop.h" +#include "document.h" +#include "live_effects/effect.h" +#include "object/sp-lpe-item.h" +#include "ui/knot/knot-holder.h" +#include "xml/node-event-vector.h" + +namespace Inkscape { +namespace UI { + +KnotHolder *createKnotHolder(SPItem *item, SPDesktop *desktop, double edit_rotation, int edit_marker_mode); +KnotHolder *createLPEKnotHolder(SPItem *item, SPDesktop *desktop); + +bool ShapeEditor::_blockSetItem = false; + +ShapeEditor::ShapeEditor(SPDesktop *dt, Geom::Affine edit_transform, double edit_rotation, int edit_marker_mode) : + desktop(dt), + knotholder(nullptr), + lpeknotholder(nullptr), + knotholder_listener_attached_for(nullptr), + lpeknotholder_listener_attached_for(nullptr), + _edit_transform(edit_transform), + _edit_rotation(edit_rotation), + _edit_marker_mode(edit_marker_mode) +{ +} + +ShapeEditor::~ShapeEditor() { + unset_item(); +} + +void ShapeEditor::unset_item(bool keep_knotholder) { + if (this->knotholder) { + Inkscape::XML::Node *old_repr = this->knotholder->repr; + if (old_repr && old_repr == knotholder_listener_attached_for) { + sp_repr_remove_listener_by_data(old_repr, this); + Inkscape::GC::release(old_repr); + knotholder_listener_attached_for = nullptr; + } + + if (!keep_knotholder) { + delete this->knotholder; + this->knotholder = nullptr; + } + } + if (this->lpeknotholder) { + Inkscape::XML::Node *old_repr = this->lpeknotholder->repr; + bool remove = false; + if (old_repr && old_repr == lpeknotholder_listener_attached_for) { + sp_repr_remove_listener_by_data(old_repr, this); + Inkscape::GC::release(old_repr); + remove = true; + } + + if (!keep_knotholder) { + delete this->lpeknotholder; + this->lpeknotholder = nullptr; + } + if (remove) { + lpeknotholder_listener_attached_for = nullptr; + } + } +} + +bool ShapeEditor::has_knotholder() { + return this->knotholder != nullptr || this->lpeknotholder != nullptr; +} + +void ShapeEditor::update_knotholder() { + if (this->knotholder) + this->knotholder->update_knots(); + if (this->lpeknotholder) + this->lpeknotholder->update_knots(); +} + +bool ShapeEditor::has_local_change() { + return (this->knotholder && this->knotholder->local_change != 0) || (this->lpeknotholder && this->lpeknotholder->local_change != 0); +} + +void ShapeEditor::decrement_local_change() { + if (this->knotholder) { + this->knotholder->local_change = FALSE; + } + if (this->lpeknotholder) { + this->lpeknotholder->local_change = FALSE; + } +} + +void ShapeEditor::event_attr_changed(Inkscape::XML::Node * node, gchar const *name, gchar const *, gchar const *, bool, void *data) +{ + g_assert(data); + ShapeEditor *sh = static_cast<ShapeEditor *>(data); + bool changed_kh = false; + + if (sh->has_knotholder()) + { + changed_kh = !sh->has_local_change(); + sh->decrement_local_change(); + if (changed_kh) { + sh->reset_item(); + } + } +} + +static Inkscape::XML::NodeEventVector shapeeditor_repr_events = { + nullptr, /* child_added */ + nullptr, /* child_removed */ + ShapeEditor::event_attr_changed, + nullptr, /* content_changed */ + nullptr /* order_changed */ +}; + + +void ShapeEditor::set_item(SPItem *item) { + if (_blockSetItem) { + return; + } + // this happens (and should only happen) when for an LPEItem having both knotholder and + // nodepath the knotholder is adapted; in this case we don't want to delete the knotholder + // since this freezes the handles + unset_item(true); + + if (item) { + Inkscape::XML::Node *repr; + if (!this->knotholder) { + // only recreate knotholder if none is present + this->knotholder = createKnotHolder(item, desktop, _edit_rotation, _edit_marker_mode); + } + SPLPEItem *lpe = dynamic_cast<SPLPEItem *>(item); + if (!(lpe && + lpe->getCurrentLPE() && + lpe->getCurrentLPE()->isVisible() && + lpe->getCurrentLPE()->providesKnotholder())) + { + delete this->lpeknotholder; + this->lpeknotholder = nullptr; + } + if (!this->lpeknotholder) { + // only recreate knotholder if none is present + this->lpeknotholder = createLPEKnotHolder(item, desktop); + } + if (this->knotholder) { + this->knotholder->setEditTransform(_edit_transform); + this->knotholder->update_knots(); + // setting new listener + repr = this->knotholder->repr; + if (repr != knotholder_listener_attached_for) { + Inkscape::GC::anchor(repr); + sp_repr_add_listener(repr, &shapeeditor_repr_events, this); + knotholder_listener_attached_for = repr; + } + } + if (this->lpeknotholder) { + this->lpeknotholder->setEditTransform(_edit_transform); + this->lpeknotholder->update_knots(); + // setting new listener + repr = this->lpeknotholder->repr; + if (repr != lpeknotholder_listener_attached_for) { + Inkscape::GC::anchor(repr); + sp_repr_add_listener(repr, &shapeeditor_repr_events, this); + lpeknotholder_listener_attached_for = repr; + } + } + } +} + + +/** FIXME: This thing is only called when the item needs to be updated in response to repr change. + Why not make a reload function in KnotHolder? */ +void ShapeEditor::reset_item() +{ + if (knotholder) { + SPObject *obj = desktop->getDocument()->getObjectByRepr(knotholder_listener_attached_for); /// note that it is not certain that this is an SPItem; it could be a LivePathEffectObject. + set_item(SP_ITEM(obj)); + } else if (lpeknotholder) { + SPObject *obj = desktop->getDocument()->getObjectByRepr(lpeknotholder_listener_attached_for); /// note that it is not certain that this is an SPItem; it could be a LivePathEffectObject. + set_item(SP_ITEM(obj)); + } +} + +/** + * Returns true if this ShapeEditor has a knot above which the mouse currently hovers. + */ +bool ShapeEditor::knot_mouseover() const { + if (this->knotholder) { + return knotholder->knot_mouseover(); + } + if (this->lpeknotholder) { + return lpeknotholder->knot_mouseover(); + } + + return false; +} + +} // namespace UI +} // namespace Inkscape + +/* + 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 : |