From 1dd7f0f174b7a3dac809567e780bba97a44b9d65 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Date: Fri, 11 Dec 2020 21:41:08 +0100 Subject: [PATCH] Improved version --- src/live_effects/effect-enum.h | 6 +- src/live_effects/effect.cpp | 251 ++++++++++++++++--- src/live_effects/effect.h | 69 +++-- src/live_effects/lpe-bool.cpp | 1 + src/live_effects/lpe-copy_rotate.cpp | 85 ++++++- src/live_effects/lpe-copy_rotate.h | 2 + src/live_effects/lpe-mirror_symmetry.cpp | 52 +++- src/live_effects/lpe-mirror_symmetry.h | 2 + src/live_effects/lpe-slice.cpp | 126 +++++++++- src/live_effects/lpe-slice.h | 6 + src/live_effects/lpe-test-doEffect-stack.cpp | 2 +- src/object/sp-item-group.cpp | 1 + src/object/sp-lpe-item.cpp | 215 +++++++++++++++- src/object/sp-lpe-item.h | 21 ++ src/object/sp-shape.cpp | 3 + src/selection-chemistry.cpp | 54 ++++ src/seltrans.cpp | 24 +- src/ui/dialog/livepatheffect-editor.cpp | 2 +- src/ui/toolbar/pencil-toolbar.cpp | 4 +- 19 files changed, 829 insertions(+), 97 deletions(-) diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h index 166e4d3fa9..678d43decb 100644 --- a/src/live_effects/effect-enum.h +++ b/src/live_effects/effect-enum.h @@ -16,7 +16,8 @@ namespace Inkscape { namespace LivePathEffect { //Please fill in the same order than in effect.cpp:98 -enum EffectType { +enum EffectType +{ BEND_PATH = 0, GEARS, PATTERN_ALONG_PATH, @@ -65,6 +66,8 @@ enum EffectType { PARALLEL, PERP_BISECTOR, TANGENT_TO_CURVE, + SLICE, + // PUT NEW LPE BEFORE EXPERIMENTAL IN THE SAME ORDER AS IN effect.cpp DOEFFECTSTACK_TEST, DYNASTROKE, LATTICE, @@ -72,7 +75,6 @@ enum EffectType { RECURSIVE_SKELETON, TEXT_LABEL, EMBRODERY_STITCH, - SLICE, INVALID_LPE // This must be last (I made it such that it is not needed anymore I think..., Don't trust on it being // last. - johan) }; diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 4863a62a19..11784b86a4 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -13,6 +13,12 @@ //#define LPE_ENABLE_TEST_EFFECTS //uncomment for toy effects // include effects: +#include +#include +#include +#include + +#include "display/curve.h" #include "live_effects/lpe-angle_bisector.h" #include "live_effects/lpe-attach-path.h" #include "live_effects/lpe-bendpath.h" @@ -69,28 +75,18 @@ #include "live_effects/lpe-text_label.h" #include "live_effects/lpe-transform_2pts.h" #include "live_effects/lpe-vonkoch.h" - #include "live_effects/lpeobject.h" - -#include "xml/node-event-vector.h" -#include "xml/sp-css-attr.h" - -#include "display/curve.h" #include "message-stack.h" +#include "object/sp-defs.h" +#include "object/sp-root.h" +#include "object/sp-shape.h" #include "path-chemistry.h" #include "ui/icon-loader.h" #include "ui/tools-switch.h" #include "ui/tools/node-tool.h" #include "ui/tools/pen-tool.h" - -#include "object/sp-defs.h" -#include "object/sp-root.h" -#include "object/sp-shape.h" - -#include -#include -#include -#include +#include "xml/node-event-vector.h" +#include "xml/sp-css-attr.h" namespace Inkscape { @@ -676,7 +672,7 @@ const EnumEffectData LPETypeData[] = { true ,//on_group false ,//on_image false ,//on_text - true ,//experimental + true ,//experimental }, { CIRCLE_WITH_RADIUS, @@ -690,7 +686,7 @@ const EnumEffectData LPETypeData[] = { true ,//on_group false ,//on_image false ,//on_text - true ,//experimental + true ,//experimental }, { CIRCLE_3PTS, @@ -704,7 +700,7 @@ const EnumEffectData LPETypeData[] = { true ,//on_group false ,//on_image false ,//on_text - true ,//experimental + true ,//experimental }, { EXTRUDE, @@ -718,7 +714,7 @@ const EnumEffectData LPETypeData[] = { true ,//on_group false ,//on_image false ,//on_text - true ,//experimental + true ,//experimental }, { LINE_SEGMENT, @@ -732,7 +728,7 @@ const EnumEffectData LPETypeData[] = { true ,//on_group false ,//on_image false ,//on_text - true ,//experimental + true ,//experimental }, { PARALLEL, @@ -746,7 +742,7 @@ const EnumEffectData LPETypeData[] = { true ,//on_group false ,//on_image false ,//on_text - true ,//experimental + true ,//experimental }, { PERP_BISECTOR, @@ -760,7 +756,7 @@ const EnumEffectData LPETypeData[] = { true ,//on_group false ,//on_image false ,//on_text - true ,//experimental + true ,//experimental }, { TANGENT_TO_CURVE, @@ -774,7 +770,7 @@ const EnumEffectData LPETypeData[] = { true ,//on_group false ,//on_image false ,//on_text - true ,//experimental + true ,//experimental }, /* 1.1 */ { @@ -786,7 +782,7 @@ const EnumEffectData LPETypeData[] = { N_("Slices the item into parts. It can also be applied multiple times.") ,//description true ,//on_path true ,//on_shape - true ,//on_group + true ,//on_group false ,//on_image false ,//on_text false ,//experimental @@ -804,7 +800,7 @@ const EnumEffectData LPETypeData[] = { true ,//on_group false ,//on_image false ,//on_text - true ,//experimental + true ,//experimental }, { DYNASTROKE, @@ -818,7 +814,7 @@ const EnumEffectData LPETypeData[] = { true ,//on_group false ,//on_image false ,//on_text - true ,//experimental + true ,//experimental }, { LATTICE, @@ -832,7 +828,7 @@ const EnumEffectData LPETypeData[] = { true ,//on_group false ,//on_image false ,//on_text - true ,//experimental + true ,//experimental }, { PATH_LENGTH, @@ -846,7 +842,7 @@ const EnumEffectData LPETypeData[] = { true ,//on_group false ,//on_image false ,//on_text - true ,//experimental + true ,//experimental }, { RECURSIVE_SKELETON, @@ -860,7 +856,7 @@ const EnumEffectData LPETypeData[] = { true ,//on_group false ,//on_image false ,//on_text - true ,//experimental + true ,//experimental }, { TEXT_LABEL, @@ -874,7 +870,7 @@ const EnumEffectData LPETypeData[] = { true ,//on_group false ,//on_image false ,//on_text - true ,//experimental + true ,//experimental }, { EMBRODERY_STITCH, @@ -1129,18 +1125,19 @@ Effect::Effect(LivePathEffectObject *lpeobject) lpeobj(lpeobject), concatenate_before_pwd2(false), sp_lpe_item(nullptr), - current_zoom(1), + current_zoom(0), refresh_widgets(false), current_shape(nullptr), provides_own_flash_paths(true), // is automatically set to false if providesOwnFlashPaths() is not overridden defaultsopen(false), is_ready(false), - is_applied(false) + is_oncut(false), + is_applied(false), + prevlpeobjid("") { registerParameter( dynamic_cast(&is_visible) ); registerParameter( dynamic_cast(&lpeversion) ); is_visible.widget_is_visible = false; - current_zoom = 0.0; } Effect::~Effect() = default; @@ -1186,7 +1183,7 @@ void Effect::transform_multiply(Geom::Affine const &postmul, bool /*set*/) {} * FIXME Probably only makes sense if this effect is referenced by exactly one * item (`this->lpeobj->hrefList` contains exactly one element)? */ -void Effect::transform_multiply(Geom::Affine const &postmul, SPLPEItem *lpeitem) +void Effect::transform_multiply_impl(Geom::Affine const &postmul, SPLPEItem *lpeitem) { assert("pre: effect is referenced by lpeitem" && std::any_of(lpeobj->hrefList.begin(), lpeobj->hrefList.end(), @@ -1240,9 +1237,11 @@ void Effect::processObjects(LPEAction lpe_action) { SPDocument *document = getSPDoc(); - if (!document) { + sp_lpe_item = dynamic_cast(*getLPEObj()->hrefList.begin()); + if (!document || !sp_lpe_item) { return; } + sp_lpe_item_enable_path_effects(sp_lpe_item, false); for (auto id : items) { if (id.empty()) { return; @@ -1296,6 +1295,7 @@ Effect::processObjects(LPEAction lpe_action) if (lpe_action == LPE_ERASE || lpe_action == LPE_TO_OBJECTS) { items.clear(); } + sp_lpe_item_enable_path_effects(sp_lpe_item, true); } /** @@ -1306,6 +1306,80 @@ Effect::doBeforeEffect (SPLPEItem const*/*lpeitem*/) { //Do nothing for simple effects } + +/** + * Is performed each time lpe is load into document. + */ +void +Effect::doOnLoad (SPLPEItem const*/*lpeitem*/) +{ + //Do nothing for simple effects +} + +/** + * Is performed each time lpe item ic copy. + */ +void +Effect::doOnCopy (SPLPEItem const*/*lpeitem*/) +{ + //Do nothing for simple effects +} + +/** + * Is performed each time lpe item is cut. + */ +void +Effect::doOnCut (SPLPEItem const*/*lpeitem*/) +{ + //Do nothing for simple effects +} + +/** + * Is performed each time lpe item is pasted. + */ +void +Effect::doOnPaste (SPLPEItem const*/*lpeitem*/) +{ + //Do nothing for simple effects +} + +/** + * Is performed each time lpe item is dupled. + */ +void +Effect::doOnDuple (SPLPEItem const*/*lpeitem*/) +{ + //Do nothing for simple effects +} + +/** + * Is performed previously lpe item is dupled. + */ +void +Effect::doOnPreDuple (SPLPEItem const*/*lpeitem*/) +{ + //Do nothing for simple effects +} + + +/** + * Is performed each time lpe item is stamped. + */ +void +Effect::doOnStamp (SPLPEItem const*/*lpeitem*/) +{ + //Do nothing for simple effects +} + +/** + * Is performed previously lpe item is stamped. + */ +void +Effect::doOnPreStamp (SPLPEItem const*/*lpeitem*/) +{ + //Do nothing for simple effects +} + /** * Is performed at the end of the LPE only one time per "lpeitem" * in paths/shapes is called in middle of the effect so we add the @@ -1319,6 +1393,19 @@ void Effect::doAfterEffect (SPLPEItem const* /*lpeitem*/, SPCurve *curve) { is_load = false; } +/** + * Is performed at the end of all lpe`s stack + */ +void Effect::doAfterAllEffects (SPLPEItem const* /*lpeitem*/) +{ +} + +/** + * Is performed at lpe`s fork + */ +void Effect::doOnFork (SPLPEItem const* /*lpeitem*/) +{ +} void Effect::doOnException(SPLPEItem const * /*lpeitem*/) { @@ -1340,6 +1427,20 @@ void Effect::doAfterEffect_impl(SPLPEItem const *lpeitem, SPCurve *curve) is_load = false; is_applied = false; } + +void Effect::doOnFork_impl(SPLPEItem const *lpeitem, Glib::ustring lpeobjectid) +{ + is_load = true; + is_applied = false; + prevlpeobjid = lpeobjectid; + doOnFork(lpeitem); +} + +void Effect::doAfterAllEffects_impl(SPLPEItem const* lpeitem) +{ + doAfterAllEffects(lpeitem); +} + void Effect::doOnApply_impl(SPLPEItem const* lpeitem) { sp_lpe_item = const_cast(lpeitem); @@ -1350,7 +1451,7 @@ void Effect::doOnApply_impl(SPLPEItem const* lpeitem) // of only update this value per each LPE when changes. // and use the Inkscape release version that has this new LPE change // LPE without lpeversion are created in a inkscape lower than 1.0 - lpeversion.param_setValue("1", true); + lpeversion.param_setValue("1", true); doOnApply(lpeitem); setReady(); has_exception = false; @@ -1363,6 +1464,72 @@ void Effect::doBeforeEffect_impl(SPLPEItem const* lpeitem) update_helperpath(); } +void Effect::doEffect_impl(SPCurve * curve) +{ + doEffect(curve); +} + +void Effect::doOnLoad_impl (SPLPEItem const*lpeitem) +{ + doOnLoad(lpeitem); +} + +void Effect::doOnCut_impl (SPLPEItem const*lpeitem) +{ + is_oncut = true; + doOnCut(lpeitem); +} + +void Effect::doOnPaste_impl (SPLPEItem const*lpeitem) +{ + doOnPaste(lpeitem); +} + +void Effect::doOnCopy_impl (SPLPEItem const*lpeitem) +{ + if (is_oncut) { + is_oncut = false; + } else { + doOnCopy(lpeitem); + } +} + +void Effect::doOnDuple_impl (SPLPEItem const*lpeitem) +{ + doOnDuple(lpeitem); +} + +void Effect::doOnPreDuple_impl (SPLPEItem const*lpeitem) +{ + doOnPreDuple(lpeitem); +} + +void Effect::doOnStamp_impl (SPLPEItem const*lpeitem) +{ + doOnStamp(lpeitem); +} + +void Effect::doOnPreStamp_impl (SPLPEItem const*lpeitem) +{ + doOnPreStamp(lpeitem); +} + +void Effect::doOnRemove_impl (SPLPEItem const*lpeitem) +{ + doOnRemove(lpeitem); +} + +void Effect::doOnVisibilityToggled_impl (SPLPEItem const*lpeitem) +{ + doOnVisibilityToggled(lpeitem); +} + + +void Effect::doOnException_impl (SPLPEItem const*lpeitem) +{ + doOnException(lpeitem); +} + void Effect::writeParamsToSVG() { std::vector::iterator p; @@ -1549,6 +1716,18 @@ Effect::update_helperpath() { } } +/** + * Get selection + */ +Inkscape::Selection *Effect::getSelection() +{ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if (desktop) { + return desktop->getSelection(); + } + return nullptr; +} + /** * This *creates* a new widget, management of deletion should be done by the caller */ diff --git a/src/live_effects/effect.h b/src/live_effects/effect.h index 2b68661347..401f98f118 100644 --- a/src/live_effects/effect.h +++ b/src/live_effects/effect.h @@ -8,15 +8,16 @@ * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ -#include "effect-enum.h" -#include "parameter/bool.h" -#include "parameter/hidden.h" -#include "ui/widget/registry.h" #include <2geom/forward.h> #include #include #include +#include "effect-enum.h" +#include "parameter/bool.h" +#include "parameter/hidden.h" +#include "selection.h" +#include "ui/widget/registry.h" #define LPE_CONVERSION_TOLERANCE 0.01 // FIXME: find good solution for this. @@ -68,25 +69,12 @@ public: //basically, to get this method called before the derived classes, a bit //of indirection is needed. We first call these methods, then the below. - void doAfterEffect_impl(SPLPEItem const *lpeitem, SPCurve *curve); - void doOnApply_impl(SPLPEItem const* lpeitem); - void doBeforeEffect_impl(SPLPEItem const* lpeitem); + void setCurrentZoom(double cZ); void setSelectedNodePoints(std::vector sNP); bool isNodePointSelected(Geom::Point const &nodePoint) const; bool isOnClipboard(); - virtual void doOnApply (SPLPEItem const* lpeitem); - virtual void doBeforeEffect (SPLPEItem const* lpeitem); -private: - virtual void transform_multiply(Geom::Affine const &postmul, bool set); - -public: - void transform_multiply(Geom::Affine const &postmul, SPLPEItem *); - virtual void doAfterEffect (SPLPEItem const* lpeitem, SPCurve *curve); - virtual void doOnException(SPLPEItem const *lpeitem); - virtual void doOnRemove (SPLPEItem const* lpeitem); - virtual void doOnVisibilityToggled(SPLPEItem const* lpeitem); void writeParamsToSVG(); virtual void acceptParamPath (SPPath const* param_path); @@ -104,7 +92,6 @@ public: inline bool isReady() const { return is_ready; } inline void setReady(bool ready = true) { is_ready = ready; } - virtual void doEffect (SPCurve * curve); virtual Gtk::Widget * newWidget(); virtual Gtk::Widget * defaultParamSet(); @@ -122,6 +109,7 @@ public: void addHandles(KnotHolder *knotholder, SPItem *item); std::vector getCanvasIndicators(SPLPEItem const* lpeitem); void update_helperpath(); + Inkscape::Selection *getSelection(); bool has_exception; inline bool providesOwnFlashPaths() const { @@ -142,6 +130,26 @@ public: inline bool isVisible() const { return is_visible; } void editNextParamOncanvas(SPItem * item, SPDesktop * desktop); + + void doOnApply_impl(SPLPEItem const* lpeitem); + void doBeforeEffect_impl(SPLPEItem const* lpeitem); + void doOnFork_impl(SPLPEItem const* lpeitem, Glib::ustring lpeobjectid); + void doEffect_impl(SPCurve * curve); + void doAfterEffect_impl(SPLPEItem const *lpeitem, SPCurve *curve); + void doAfterAllEffects_impl(SPLPEItem const* lpeitem); + void transform_multiply_impl(Geom::Affine const &postmul, SPLPEItem *); + void doOnLoad_impl (SPLPEItem const* lpeitem); + void doOnCopy_impl (SPLPEItem const* lpeitem); + void doOnCut_impl (SPLPEItem const* lpeitem); + void doOnPaste_impl (SPLPEItem const* lpeitem); + void doOnDuple_impl (SPLPEItem const* lpeitem); + void doOnPreDuple_impl (SPLPEItem const* lpeitem); + void doOnStamp_impl (SPLPEItem const* lpeitem); + void doOnPreStamp_impl (SPLPEItem const* lpeitem); + void doOnException_impl (SPLPEItem const* lpeitem); + void doOnRemove_impl (SPLPEItem const* lpeitem); + void doOnVisibilityToggled_impl (SPLPEItem const* lpeitem); + bool apply_to_clippath_and_mask; bool keep_paths; // set this to false allow retain extra generated objects, see measure line LPE bool is_load; @@ -153,6 +161,7 @@ public: SPLPEItem *sp_lpe_item; // these get stored in doBeforeEffect_impl, and derived classes may do as they please with // them. SPShape *current_shape; // these get stored in performPathEffects. + std::vector items; protected: Effect(LivePathEffectObject *lpeobject); @@ -184,11 +193,11 @@ public: Inkscape::UI::Widget::Registry wr; LivePathEffectObject *lpeobj; + Glib::ustring prevlpeobjid; //we store prev LPE id on forked LPE we need to check stuill exist before reuse // this boolean defaults to false, it concatenates the input path to one pwd2, // instead of normally 'splitting' the path into continuous pwd2 paths and calling doEffect_pwd2 for each. bool concatenate_before_pwd2; - std::vector items; double current_zoom; std::vector selectedNodesPoints; @@ -199,8 +208,26 @@ private: void unsetDefaultParam(Glib::ustring pref_path, Glib::ustring tooltip, Parameter *param, Gtk::Image *info, Gtk::Button *set, Gtk::Button *unset); bool provides_own_flash_paths; // if true, the standard flash path is suppressed - + virtual void doOnApply (SPLPEItem const* lpeitem); + virtual void doBeforeEffect (SPLPEItem const* lpeitem); + virtual void doOnFork (SPLPEItem const* lpeitem); + virtual void doEffect (SPCurve * curve); + virtual void doAfterEffect (SPLPEItem const* lpeitem, SPCurve *curve); + virtual void doAfterAllEffects (SPLPEItem const* sp_lpe_item); + virtual void transform_multiply(Geom::Affine const &postmul, bool set); + virtual void doOnLoad (SPLPEItem const* lpeitem); + virtual void doOnCopy (SPLPEItem const* lpeitem); + virtual void doOnCut (SPLPEItem const* lpeitem); + virtual void doOnDuple (SPLPEItem const* lpeitem); + virtual void doOnPreDuple (SPLPEItem const* lpeitem); + virtual void doOnPaste (SPLPEItem const* lpeitem); + virtual void doOnStamp (SPLPEItem const* lpeitem); + virtual void doOnPreStamp (SPLPEItem const* lpeitem); + virtual void doOnException (SPLPEItem const *lpeitem); + virtual void doOnRemove (SPLPEItem const* lpeitem); + virtual void doOnVisibilityToggled (SPLPEItem const* lpeitem); bool is_ready; + bool is_oncut; bool defaultsopen; }; diff --git a/src/live_effects/lpe-bool.cpp b/src/live_effects/lpe-bool.cpp index 09b0ccf02d..84c17d5a74 100644 --- a/src/live_effects/lpe-bool.cpp +++ b/src/live_effects/lpe-bool.cpp @@ -100,6 +100,7 @@ LPEBool::LPEBool(LivePathEffectObject *lpeobject) LPEBool::~LPEBool() { doOnRemove(nullptr); } + bool cmp_cut_position(const Path::cut_position &a, const Path::cut_position &b) { return a.piece == b.piece ? a.t < b.t : a.piece < b.piece; diff --git a/src/live_effects/lpe-copy_rotate.cpp b/src/live_effects/lpe-copy_rotate.cpp index 2c9f088c00..4086a06d39 100644 --- a/src/live_effects/lpe-copy_rotate.cpp +++ b/src/live_effects/lpe-copy_rotate.cpp @@ -129,6 +129,8 @@ LPECopyRotate::doAfterEffect (SPLPEItem const* lpeitem, SPCurve *curve) id += std::to_string(counter); id += "-"; id += this->lpeobj->getId(); + id += "_"; + id += this->sp_lpe_item->getId(); if (id.empty()) { return; } @@ -146,11 +148,18 @@ LPECopyRotate::doAfterEffect (SPLPEItem const* lpeitem, SPCurve *curve) guint counter = 0; Glib::ustring id = "rotated-0-"; id += this->lpeobj->getId(); + id += "_"; + id += this->sp_lpe_item->getId(); while((elemref = document->getObjectById(id.c_str()))) { id = Glib::ustring("rotated-"); id += std::to_string(counter); id += "-"; id += this->lpeobj->getId(); + id += "_"; + id += this->sp_lpe_item->getId(); + if (id.empty()) { + return; + } if (SP_ITEM(elemref)->isHidden()) { items.push_back(id); } @@ -181,11 +190,42 @@ LPECopyRotate::doAfterEffect (SPLPEItem const* lpeitem, SPCurve *curve) } reset = false; } else { + SPDocument *document = getSPDoc(); + if (!document) { + return; + } + regenerateItems(); processObjects(LPE_ERASE); items.clear(); } } +void +LPECopyRotate::upgradeLegacy() { + lpeversion.param_setValue("1.1", true); // to avoid multiple applyes + SPDocument *document = getSPDoc(); + if (!document) { + return; + } + items.clear(); + SPObject *elemref = nullptr; + guint counter = 0; + Glib::ustring id = "rotated-0-"; + id += this->lpeobj->getId(); + while((elemref = document->getObjectById(id.c_str()))) { + id = Glib::ustring("rotated-"); + id += std::to_string(counter); + id += "-"; + id += this->lpeobj->getId(); + Glib::ustring new_elemref_id = id; + new_elemref_id += "_"; + new_elemref_id += this->sp_lpe_item->getId(); + items.push_back(new_elemref_id); + elemref->setAttribute("id",new_elemref_id.c_str()); + counter++; + } +} + void LPECopyRotate::cloneStyle(SPObject *orig, SPObject *dest) { dest->getRepr()->setAttribute("style", orig->getRepr()->attribute("style")); @@ -297,11 +337,12 @@ LPECopyRotate::toItem(Geom::Affine transform, size_t i, bool reset) if (!document) { return; } - Inkscape::XML::Document *xml_doc = document->getReprDoc(); Glib::ustring elemref_id = Glib::ustring("rotated-"); elemref_id += std::to_string(i); elemref_id += "-"; elemref_id += this->lpeobj->getId(); + elemref_id += "_"; + elemref_id += this->sp_lpe_item->getId(); items.push_back(elemref_id); SPObject *elemref = document->getObjectById(elemref_id.c_str()); Inkscape::XML::Node *phantom = nullptr; @@ -312,10 +353,12 @@ LPECopyRotate::toItem(Geom::Affine transform, size_t i, bool reset) phantom->setAttribute("id", elemref_id); reset = true; elemref = container->appendChildRepr(phantom); + elemref->parent->reorder(elemref, sp_lpe_item); Inkscape::GC::release(phantom); } cloneD(SP_OBJECT(sp_lpe_item), elemref, transform, reset); elemref->getRepr()->setAttributeOrRemoveIfEmpty("transform", sp_svg_transform_write(transform)); + Inkscape::XML::Document *xml_doc = document->getReprDoc(); SP_ITEM(elemref)->setHidden(false); if (elemref->parent != container) { Inkscape::XML::Node *copy = phantom->duplicate(xml_doc); @@ -376,6 +419,7 @@ Gtk::Widget * LPECopyRotate::newWidget() void LPECopyRotate::doOnApply(SPLPEItem const* lpeitem) { + using namespace Geom; original_bbox(lpeitem, false, true); @@ -385,11 +429,15 @@ LPECopyRotate::doOnApply(SPLPEItem const* lpeitem) origin.param_update_default(A); dist_angle_handle = L2(B - A); dir = unit_vector(B - A); + lpeversion.param_setValue("1.1", true); } void LPECopyRotate::doBeforeEffect (SPLPEItem const* lpeitem) { + if (is_load && lpeversion.param_getSVGValue() < "1.1") { + upgradeLegacy(); + } using namespace Geom; original_bbox(lpeitem, false, true); if (copies_to_360 && num_copies > 2) { @@ -657,15 +705,50 @@ LPECopyRotate::resetDefaults(SPItem const* item) original_bbox(SP_LPE_ITEM(item), false, true); } +void +LPECopyRotate::regenerateItems() { + SPDocument *document = getSPDoc(); + items.clear(); + sp_lpe_item = dynamic_cast(*getLPEObj()->hrefList.begin()); + if (!document || !sp_lpe_item) { + return; + } + SPObject *elemref = nullptr; + guint counter = 0; + Glib::ustring id = "rotated-0-"; + id += getLPEObj()->getId(); + if (sp_lpe_item->getId()) { + id += "_"; + id += sp_lpe_item->getId(); + } + while((elemref = document->getObjectById(id.c_str()))) { + id = Glib::ustring("rotated-"); + id += std::to_string(counter); + id += "-"; + id += this->lpeobj->getId(); + if (sp_lpe_item->getId()) { + id += "_"; + id += this->sp_lpe_item->getId(); + } + if (id.empty()) { + return; + } + items.push_back(id); + counter++; + } +} + void LPECopyRotate::doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/) { + regenerateItems(); processObjects(LPE_VISIBILITY); } void LPECopyRotate::doOnRemove (SPLPEItem const* lpeitem) { + regenerateItems(); //set "keep paths" hook on sp-lpe-item.cpp if (keep_paths) { processObjects(LPE_TO_OBJECTS); diff --git a/src/live_effects/lpe-copy_rotate.h b/src/live_effects/lpe-copy_rotate.h index b97beefc06..45db264777 100644 --- a/src/live_effects/lpe-copy_rotate.h +++ b/src/live_effects/lpe-copy_rotate.h @@ -54,6 +54,8 @@ public: void toItem(Geom::Affine transform, size_t i, bool reset); void cloneD(SPObject *orig, SPObject *dest, Geom::Affine transform, bool reset); Inkscape::XML::Node * createPathBase(SPObject *elemref); + void upgradeLegacy(); + void regenerateItems(); void resetStyles(); //virtual void setFusion(Geom::PathVector &path_in, Geom::Path divider, double sizeDivider); protected: diff --git a/src/live_effects/lpe-mirror_symmetry.cpp b/src/live_effects/lpe-mirror_symmetry.cpp index e571ab8826..193b00b489 100644 --- a/src/live_effects/lpe-mirror_symmetry.cpp +++ b/src/live_effects/lpe-mirror_symmetry.cpp @@ -103,10 +103,26 @@ LPEMirrorSymmetry::doAfterEffect (SPLPEItem const* lpeitem, SPCurve *curve) m *= sp_lpe_item->transform; toMirror(m); } else { + regenerateItems(); processObjects(LPE_ERASE); items.clear(); } } +void +LPEMirrorSymmetry::regenerateItems() { + items.clear(); + sp_lpe_item = dynamic_cast(*getLPEObj()->hrefList.begin()); + if (sp_lpe_item) { + Glib::ustring elemref_id = Glib::ustring("mirror-"); + elemref_id += getLPEObj()->getId(); + if (sp_lpe_item->getId()) { + elemref_id += "_"; + elemref_id += sp_lpe_item->getId(); + } + items.push_back(elemref_id); + } +} + Gtk::Widget * LPEMirrorSymmetry::newWidget() @@ -176,6 +192,9 @@ LPEMirrorSymmetry::centerHoriz(){ void LPEMirrorSymmetry::doBeforeEffect (SPLPEItem const* lpeitem) { + if (is_load && lpeversion.param_getSVGValue() < "1.1") { + upgradeLegacy(); + } using namespace Geom; original_bbox(lpeitem, false, true); Point point_a(boundingbox_X.max(), boundingbox_Y.min()); @@ -358,26 +377,45 @@ LPEMirrorSymmetry::createPathBase(SPObject *elemref) { } void -LPEMirrorSymmetry::toMirror(Geom::Affine transform) -{ +LPEMirrorSymmetry::upgradeLegacy() { + lpeversion.param_setValue("1.1", true); // to avoid multiple applyes SPDocument *document = getSPDoc(); if (!document) { return; } - Inkscape::XML::Document *xml_doc = document->getReprDoc(); Glib::ustring elemref_id = Glib::ustring("mirror-"); elemref_id += this->lpeobj->getId(); + Glib::ustring new_elemref_id = Glib::ustring("mirror-"); + new_elemref_id += this->lpeobj->getId(); + new_elemref_id += "_"; + new_elemref_id += this->sp_lpe_item->getId(); items.clear(); - items.push_back(elemref_id); + items.push_back(new_elemref_id); SPObject *elemref = document->getObjectById(elemref_id.c_str()); + if (elemref) { + elemref->setAttribute("id",new_elemref_id.c_str()); + } +} + +void +LPEMirrorSymmetry::toMirror(Geom::Affine transform) +{ + SPDocument *document = getSPDoc(); + if (!document) { + return; + } + Inkscape::XML::Document *xml_doc = document->getReprDoc(); + regenerateItems(); + SPObject *elemref = document->getObjectById(items[0].c_str()); Inkscape::XML::Node *phantom = nullptr; if (elemref) { phantom = elemref->getRepr(); } else { phantom = createPathBase(sp_lpe_item); - phantom->setAttribute("id", elemref_id); + phantom->setAttribute("id", items[0]); reset = true; elemref = container->appendChildRepr(phantom); + elemref->parent->reorder(elemref, sp_lpe_item); Inkscape::GC::release(phantom); } cloneD(SP_OBJECT(sp_lpe_item), elemref); @@ -385,7 +423,7 @@ LPEMirrorSymmetry::toMirror(Geom::Affine transform) elemref->getRepr()->setAttributeOrRemoveIfEmpty("transform", sp_svg_transform_write(transform)); if (elemref->parent != container) { Inkscape::XML::Node *copy = phantom->duplicate(xml_doc); - copy->setAttribute("id", elemref_id); + copy->setAttribute("id", items[0]); container->appendChildRepr(copy); Inkscape::GC::release(copy); elemref->deleteObject(); @@ -405,6 +443,7 @@ LPEMirrorSymmetry::resetStyles(){ void LPEMirrorSymmetry::doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/) { + regenerateItems(); processObjects(LPE_VISIBILITY); } @@ -412,6 +451,7 @@ void LPEMirrorSymmetry::doOnRemove (SPLPEItem const* /*lpeitem*/) { //set "keep paths" hook on sp-lpe-item.cpp + regenerateItems(); if (keep_paths) { processObjects(LPE_TO_OBJECTS); items.clear(); diff --git a/src/live_effects/lpe-mirror_symmetry.h b/src/live_effects/lpe-mirror_symmetry.h index 9a87ab34a4..c70f7651f0 100644 --- a/src/live_effects/lpe-mirror_symmetry.h +++ b/src/live_effects/lpe-mirror_symmetry.h @@ -53,6 +53,8 @@ public: void toMirror(Geom::Affine transform); void cloneD(SPObject *orig, SPObject *dest); Inkscape::XML::Node * createPathBase(SPObject *elemref); + void upgradeLegacy(); + void regenerateItems(); void resetStyles(); void centerVert(); void centerHoriz(); diff --git a/src/live_effects/lpe-slice.cpp b/src/live_effects/lpe-slice.cpp index 4a2e4d06d5..4e88119895 100644 --- a/src/live_effects/lpe-slice.cpp +++ b/src/live_effects/lpe-slice.cpp @@ -317,7 +317,9 @@ LPESlice::cloneD(SPObject *orig, SPObject *dest, bool is_original) return; } SPItem *originalitem = dynamic_cast(orig); - if ( SP_IS_GROUP(orig) && SP_IS_GROUP(dest) && SP_GROUP(orig)->getItemCount() == SP_GROUP(dest)->getItemCount() ) { + SPGroup *grouporig = dynamic_cast(orig); + SPGroup *groupdest = dynamic_cast(dest); + if ( grouporig && groupdest && grouporig->getItemCount() == groupdest->getItemCount() ) { if (reset) { cloneStyle(orig, dest); } @@ -523,24 +525,121 @@ LPESlice::splititem(SPItem* item, SPCurve * curve, std::pair auto cpro = SPCurve::copy(shape->curve()); if (cpro) { if (!path && is_original) { - //shape->setCurveInsync(std::move(cpro)); shape->bbox_vis_cache_is_valid = false; shape->bbox_geom_cache_is_valid = false; - cpro->set_pathvector(path_out); - shape->setCurveInsync(std::move(cpro)); } + cpro->set_pathvector(path_out); + shape->setCurveInsync(std::move(cpro)); auto str = sp_svg_write_path(path_out); if (!is_original && shape->hasPathEffectRecursive()) { - shape->getRepr()->setAttribute("inkscape:original-d", str); + shape->setAttribute("inkscape:original-d", str); sp_lpe_item_update_patheffect(shape, false, false); } else { - shape->getRepr()->setAttribute("d", str); + shape->setAttribute("d", str); } } } } } +void +LPESlice::cleanSelection() +{ + auto *selection = getSelection(); + if (selection) { + for (auto item:items) { + SPObject *elemref = getSPDoc()->getObjectById(item); + if (elemref) { + selection->remove(elemref); + } + } + } +} + +void +LPESlice::doOnPreDuple (SPLPEItem const* lpeitem) +{ + cleanSelection(); +} + +void +LPESlice::doOnDuple (SPLPEItem const* lpeitem) +{ + forkData(lpeitem_action::duplelpe); +} + +void +LPESlice::doOnPreStamp (SPLPEItem const* lpeitem) +{ + cleanSelection(); +} + +void +LPESlice::doOnStamp (SPLPEItem const* lpeitem) +{ + forkData(lpeitem_action::stamplpe); +} +void +LPESlice::forkData(lpeitem_action action) +{ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + Inkscape::Selection *selection = nullptr; + if (desktop) { + selection = desktop->selection; + } + LivePathEffectObject *prevlpeobj = dynamic_cast(getSPDoc()->getObjectById(prevlpeobjid.c_str())); + if (prevlpeobj) { + LPESlice *slice = dynamic_cast(prevlpeobj->get_lpe()); + if (slice) { + size_t counter = 0; + std::vector newitemstmp; + newitemstmp.assign(items.begin(), items.end()); + for (auto item: slice->items) { + SPItem *elemref = dynamic_cast(getSPDoc()->getObjectById(item)); + if (elemref && newitemstmp.size() > counter) { + SPItem *newone = dynamic_cast(getSPDoc()->getObjectById(newitemstmp[counter])); + if (newone) { + newone->setAttribute("style", elemref->getAttribute("style")); + newone->setAttribute("mask", elemref->getAttribute("mask")); + newone->setAttribute("clip", elemref->getAttribute("clip")); + Glib::ustring classes = newone->getId(); + classes += "-slice UnoptimicedTransforms"; + newone->setAttribute("class", classes); + if (action == lpeitem_action::duplelpe) { + newone->setAttribute("transform", elemref->getAttribute("transform")); + } + SPLPEItem *lpeitem = dynamic_cast(newone); + if (action == lpeitem_action::stamplpe) { + newone->transform = elemref->transform; + } + if (lpeitem && elemref->getAttribute("inkscape:path-effect")) { + lpeitem->setAttribute("inkscape:path-effect", elemref->getAttribute("inkscape:path-effect")); + lpeitem->forkPathEffectsIfNecessary(1); + sp_lpe_item_update_patheffect(lpeitem, true, true); + switch(action) { + case lpeitem_action::duplelpe: + sp_lpe_item_onduple(lpeitem); + break; + case lpeitem_action::stamplpe: + sp_lpe_item_onstamp(lpeitem); + break; + default: + break; + } + } + if (selection && action == lpeitem_action::duplelpe) { + selection->add(newone); + } + } + } + counter++; + } + newitemstmp.clear(); + } + sp_lpe_item_update_patheffect(sp_lpe_item, true, true); + } +} + void LPESlice::doBeforeEffect (SPLPEItem const* lpeitem) { @@ -685,13 +784,22 @@ LPESlice::doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/) } void -LPESlice::doOnRemove (SPLPEItem const* /*lpeitem*/) +LPESlice::doOnRemove (SPLPEItem const* lpeitem) { //set "keep paths" hook on sp-lpe-item.cpp items.clear(); - Glib::ustring theclass = sp_lpe_item->getId(); + Glib::ustring theclass = lpeitem->getId(); theclass += "-slice"; for (auto item : getSPDoc()->getObjectsByClass(theclass)) { + theclass += " UnoptimicedTransforms"; + if (item->getAttribute("class")) { + Glib::ustring classupd = item->getAttribute("class"); + size_t pos = classupd.find(theclass); + if (pos != Glib::ustring::npos) { + classupd.replace(pos,theclass.size(),""); + item->setAttribute("class", classupd); + } + } items.emplace_back(item->getId()); } if (keep_paths) { @@ -699,7 +807,7 @@ LPESlice::doOnRemove (SPLPEItem const* /*lpeitem*/) items.clear(); return; } - if (sp_lpe_item->countLPEOfType(SLICE) == 1) { + if (lpeitem->countLPEOfType(SLICE) == 1) { processObjects(LPE_ERASE); } else { for (auto item: items) { diff --git a/src/live_effects/lpe-slice.h b/src/live_effects/lpe-slice.h index afbad52c75..3e327a6a30 100644 --- a/src/live_effects/lpe-slice.h +++ b/src/live_effects/lpe-slice.h @@ -46,6 +46,10 @@ public: void doBeforeEffect (SPLPEItem const* lpeitem) override; void doAfterEffect (SPLPEItem const* lpeitem, SPCurve *curve) override; Geom::PathVector doEffect_path (Geom::PathVector const & path_in) override; + void doOnDuple (SPLPEItem const* lpeitem) override; + void doOnPreDuple (SPLPEItem const* lpeitem) override; + void doOnStamp (SPLPEItem const* lpeitem) override; + void doOnPreStamp (SPLPEItem const* lpeitem) override; void doOnRemove (SPLPEItem const* /*lpeitem*/) override; void doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/) override; Gtk::Widget * newWidget() override; @@ -56,6 +60,8 @@ public: void cloneD(SPObject *orig, SPObject *dest, bool is_original); Inkscape::XML::Node *createPathBase(SPObject *elemref); Geom::PathVector cutter(Geom::PathVector const & path_in); + void forkData(lpeitem_action action); + void cleanSelection(); void resetStyles(); void centerVert(); void centerHoriz(); diff --git a/src/live_effects/lpe-test-doEffect-stack.cpp b/src/live_effects/lpe-test-doEffect-stack.cpp index 30b93881c8..4a22cfb2be 100644 --- a/src/live_effects/lpe-test-doEffect-stack.cpp +++ b/src/live_effects/lpe-test-doEffect-stack.cpp @@ -36,7 +36,7 @@ void LPEdoEffectStackTest::doEffect (SPCurve * curve) { if (step >= 1) { - Effect::doEffect(curve); + Effect::doEffect_impl(curve); } else { // return here return; diff --git a/src/object/sp-item-group.cpp b/src/object/sp-item-group.cpp index 9232466374..840984565a 100644 --- a/src/object/sp-item-group.cpp +++ b/src/object/sp-item-group.cpp @@ -849,6 +849,7 @@ void SPGroup::update_patheffect(bool write) { } } } + this->finishPatheffectStack(); } } diff --git a/src/object/sp-lpe-item.cpp b/src/object/sp-lpe-item.cpp index 38d1c68ac7..8fd9a32b97 100755 --- a/src/object/sp-lpe-item.cpp +++ b/src/object/sp-lpe-item.cpp @@ -225,6 +225,28 @@ bool SPLPEItem::performPathEffect(SPCurve *curve, SPShape *current, bool is_clip return true; } +void +SPLPEItem::finishPatheffectStack() { + if (this->hasPathEffect() && this->pathEffectsEnabled()) { + PathEffectList path_effect_list(*this->path_effect_list); + for (auto &lperef : path_effect_list) { + LivePathEffectObject *lpeobj = lperef->lpeobject; + if (!lpeobj) { + /** \todo Investigate the cause of this. + * For example, this happens when copy pasting an object with LPE applied. Probably because the object is pasted while the effect is not yet pasted to defs, and cannot be found. + */ + g_warning("SPLPEItem::performPathEffect - NULL lpeobj in list!"); + return; + } + + Inkscape::LivePathEffect::Effect *lpe = lpeobj->get_lpe(); + if (lpe) { + lpe->doAfterAllEffects_impl(this); + } + } + } +} + /** * returns true when LPE was successful. */ @@ -250,17 +272,13 @@ bool SPLPEItem::performOnePathEffect(SPCurve *curve, SPShape *current, Inkscape: } // To Calculate BBox on shapes and nested LPE current->setCurveInsync(curve); - if (lpe->lpeversion.param_getSVGValue() != "0") { // we are on 1 or up - current->bbox_vis_cache_is_valid = false; - current->bbox_geom_cache_is_valid = false; - } // Groups have their doBeforeEffect called elsewhere if (!SP_IS_GROUP(this) && !is_clip_or_mask) { lpe->doBeforeEffect_impl(this); } try { - lpe->doEffect(curve); + lpe->doEffect_impl(curve); lpe->has_exception = false; } @@ -270,7 +288,7 @@ bool SPLPEItem::performOnePathEffect(SPCurve *curve, SPShape *current, Inkscape: SP_ACTIVE_DESKTOP->messageStack()->flash( Inkscape::WARNING_MESSAGE, _("An exception occurred during execution of the Path Effect.") ); } - lpe->doOnException(this); + lpe->doOnException_impl(this); return false; } @@ -283,6 +301,10 @@ bool SPLPEItem::performOnePathEffect(SPCurve *curve, SPShape *current, Inkscape: } lpe->doAfterEffect_impl(this, curve); } + if (lpe->lpeversion.param_getSVGValue() != "0") { // we are on 1 or up + current->bbox_vis_cache_is_valid = false; + current->bbox_geom_cache_is_valid = false; + } } } return true; @@ -338,7 +360,8 @@ bool SPLPEItem::optimizeTransforms() } } g_free(classes); - return true; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + return true;//!prefs->getBool("/options/preservetransform/value", false); } /** @@ -358,7 +381,7 @@ void SPLPEItem::notifyTransform(Geom::Affine const &postmul) if (lpeobj) { Inkscape::LivePathEffect::Effect *lpe = lpeobj->get_lpe(); if (lpe && !lpe->is_load) { - lpe->transform_multiply(postmul, this); + lpe->transform_multiply_impl(postmul, this); } } } @@ -369,6 +392,160 @@ void SPLPEItem::update_patheffect(bool /*write*/) { //throw; } +/** + * Calls lpe items actions from enum lpeitem_action + */ +void +sp_lpe_item_action (SPLPEItem *lpeitem, lpeitem_action action) +{ +#ifdef SHAPE_VERBOSE + g_message("sp_lpe_item_onload: %p\n", lpeitem); +#endif + g_return_if_fail (lpeitem != nullptr); + g_return_if_fail (SP_IS_OBJECT (lpeitem)); + g_return_if_fail (SP_IS_LPE_ITEM (lpeitem)); + SPGroup * group = dynamic_cast(lpeitem); + if (group) { + std::vector item_list = sp_item_group_item_list(group); + for (auto iter : item_list) { + SPLPEItem* subitem = dynamic_cast(iter); + if (subitem) { + sp_lpe_item_action(subitem, action); + } + } + } + PathEffectList path_effect_list(*lpeitem->path_effect_list); + for (auto &lperef : path_effect_list) { + if (!lperef) { + continue; + } + LivePathEffectObject *lpeobj = lperef->lpeobject; + if (lpeobj) { + Inkscape::LivePathEffect::Effect * lpe = lpeobj->get_lpe(); + if (lpe) { + switch(action) { + case lpeitem_action::loadlpe: + lpe->doOnLoad_impl(lpeitem); + break; + case lpeitem_action::copylpe: + lpe->doOnCopy_impl(lpeitem); + break; + case lpeitem_action::cutlpe: + lpe->doOnCut_impl(lpeitem); + break; + case lpeitem_action::pastelpe: + lpe->doOnPaste_impl(lpeitem); + break; + case lpeitem_action::duplelpe: + lpe->doOnDuple_impl(lpeitem); + break; + case lpeitem_action::preduplelpe: + lpe->doOnPreDuple_impl(lpeitem); + break; + case lpeitem_action::stamplpe: + lpe->doOnStamp_impl(lpeitem); + break; + case lpeitem_action::prestamplpe: + lpe->doOnPreStamp_impl(lpeitem); + break; + default: + break; + } + } + } + } +} + + +/** + * Calls on load LPE from existing documents + * This can be used by LPE thar need some kind of process on loading outside the whole stack + */ +void +sp_lpe_item_onload (SPLPEItem *lpeitem) { +#ifdef SHAPE_VERBOSE + g_message("sp_lpe_item_onload: %p\n", lpeitem); +#endif + sp_lpe_item_action(lpeitem, lpeitem_action::loadlpe); +} + +/** + * Calls on copy lpeitem + */ +void +sp_lpe_item_oncopy (SPLPEItem *lpeitem) { +#ifdef SHAPE_VERBOSE + g_message("sp_lpe_item_oncopy: %p\n", lpeitem); +#endif + sp_lpe_item_action(lpeitem, lpeitem_action::copylpe); +} + +/** + * Calls on cut lpeitem + */ +void +sp_lpe_item_oncut (SPLPEItem *lpeitem) { +#ifdef SHAPE_VERBOSE + g_message("sp_lpe_item_oncut: %p\n", lpeitem); +#endif + sp_lpe_item_action(lpeitem, lpeitem_action::cutlpe); +} + +/** + * Calls on paste lpeitem + */ +void +sp_lpe_item_onpaste (SPLPEItem *lpeitem) { +#ifdef SHAPE_VERBOSE + g_message("sp_lpe_item_onpaste: %p\n", lpeitem); +#endif + sp_lpe_item_action(lpeitem, lpeitem_action::pastelpe); +} + +/** + * Calls on previously to duple lpeitem + */ +void +sp_lpe_item_onpreduple (SPLPEItem *lpeitem) { +#ifdef SHAPE_VERBOSE + g_message("sp_lpe_item_onpreduple: %p\n", lpeitem); +#endif + sp_lpe_item_action(lpeitem, lpeitem_action::preduplelpe); +} + +/** + * Calls on duple lpeitem + */ +void +sp_lpe_item_onduple (SPLPEItem *lpeitem) { +#ifdef SHAPE_VERBOSE + g_message("sp_lpe_item_onduple: %p\n", lpeitem); +#endif + sp_lpe_item_action(lpeitem, lpeitem_action::duplelpe); +} + +/** + * Calls on before stamp lpeitem + */ +void +sp_lpe_item_onprestamp (SPLPEItem *lpeitem) { +#ifdef SHAPE_VERBOSE + g_message("sp_lpe_item_onprestamp: %p\n", lpeitem); +#endif + sp_lpe_item_action(lpeitem, lpeitem_action::prestamplpe); +} + +/** + * Calls on stamp lpeitem + */ +void +sp_lpe_item_onstamp (SPLPEItem *lpeitem) { +#ifdef SHAPE_VERBOSE + g_message("sp_lpe_item_onstamp: %p\n", lpeitem); +#endif + sp_lpe_item_action(lpeitem, lpeitem_action::stamplpe); +} + /** * Calls any registered handlers for the update_patheffect action */ @@ -414,6 +591,8 @@ lpeobject_ref_modified(SPObject */*href*/, guint flags, SPLPEItem *lpeitem) #endif if (flags != 29 && flags != 253) { sp_lpe_item_update_patheffect (lpeitem, true, true); + } else if (flags == 29) { + sp_lpe_item_onload (lpeitem); } } @@ -439,8 +618,8 @@ sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem) sp_lpe_item_create_original_path_recursive(mask_data); } } - if (SP_IS_GROUP(lpeitem)) { - std::vector item_list = sp_item_group_item_list(SP_GROUP(lpeitem)); + if (SPGroup * group = dynamic_cast(lpeitem)) { + std::vector item_list = sp_item_group_item_list(group); for (auto subitem : item_list) { if (SP_IS_LPE_ITEM(subitem)) { sp_lpe_item_create_original_path_recursive(SP_LPE_ITEM(subitem)); @@ -687,7 +866,7 @@ void SPLPEItem::removeCurrentPathEffect(bool keep_paths) } if (Inkscape::LivePathEffect::Effect* effect_ = this->getCurrentLPE()) { effect_->keep_paths = keep_paths; - effect_->doOnRemove(this); + effect_->doOnRemove_impl(this); this->path_effect_list->remove(lperef); //current lpe ref is always our 'own' pointer from the path_effect_list this->setAttributeOrRemoveIfEmpty("inkscape:path-effect", patheffectlist_svg_string(*this->path_effect_list)); if (!keep_paths) { @@ -720,7 +899,7 @@ void SPLPEItem::removeAllPathEffects(bool keep_paths) Inkscape::LivePathEffect::Effect * lpe = lpeobj->get_lpe(); if (lpe) { lpe->keep_paths = keep_paths; - lpe->doOnRemove(this); + lpe->doOnRemove_impl(this); } } } @@ -1358,7 +1537,11 @@ bool SPLPEItem::forkPathEffectsIfNecessary(unsigned int nr_of_allowed_users, boo LivePathEffectObject *forked_lpeobj = lpeobj->fork_private_if_necessary(nr_of_allowed_users); if (forked_lpeobj && forked_lpeobj != lpeobj) { forked = true; - forked_lpeobj->get_lpe()->is_load = true; + Glib::ustring prevlpeid = ""; + if (lpeobj->getId()) { + prevlpeid = lpeobj->getId(); + } + forked_lpeobj->get_lpe()->doOnFork_impl(this, prevlpeid); old_lpeobjs.push_back(lpeobj); new_lpeobjs.push_back(forked_lpeobj); } @@ -1387,6 +1570,12 @@ void sp_lpe_item_enable_path_effects(SPLPEItem *lpeitem, bool enable) // Are the path effects enabled on this item ? bool SPLPEItem::pathEffectsEnabled() const { + // we supress on cliboard LPE calculations + Inkscape::XML::Node *root = this->document->getReprRoot(); + Inkscape::XML::Node *clipnode = sp_repr_lookup_name(root, "inkscape:clipboard", 1); + if (clipnode) { + return false; + } return path_effects_enabled > 0; } diff --git a/src/object/sp-lpe-item.h b/src/object/sp-lpe-item.h index 95bee2dcf4..f194163adb 100644 --- a/src/object/sp-lpe-item.h +++ b/src/object/sp-lpe-item.h @@ -39,6 +39,18 @@ namespace Inkscape{ typedef std::list PathEffectList; +enum lpeitem_action { + loadlpe, + cutlpe, + copylpe, + pastelpe, + preduplelpe, + duplelpe, + prestamplpe, + stamplpe +}; + + class SPLPEItem : public SPItem { public: SPLPEItem(); @@ -91,6 +103,7 @@ public: void downCurrentPathEffect(); void upCurrentPathEffect(); + void finishPatheffectStack(); Inkscape::LivePathEffect::LPEObjectReference* getCurrentLPEReference(); Inkscape::LivePathEffect::Effect* getCurrentLPE(); Inkscape::LivePathEffect::LPEObjectReference* getPrevLPEReference(Inkscape::LivePathEffect::LPEObjectReference* lperef); @@ -110,6 +123,14 @@ public: void editNextParamOncanvas(SPDesktop *dt); }; +void sp_lpe_item_onload (SPLPEItem *lpeitem); +void sp_lpe_item_oncopy (SPLPEItem *lpeitem); +void sp_lpe_item_oncut (SPLPEItem *lpeitem); +void sp_lpe_item_onpaste (SPLPEItem *lpeitem); +void sp_lpe_item_onduple (SPLPEItem *lpeitem); +void sp_lpe_item_onpreduple (SPLPEItem *lpeitem); +void sp_lpe_item_onstamp (SPLPEItem *lpeitem); +void sp_lpe_item_onprestamp (SPLPEItem *lpeitem); void sp_lpe_item_update_patheffect (SPLPEItem *lpeitem, bool wholetree, bool write); // careful, class already has method with *very* similar name! void sp_lpe_item_enable_path_effects(SPLPEItem *lpeitem, bool enable); diff --git a/src/object/sp-shape.cpp b/src/object/sp-shape.cpp index 1d5df5ea37..be7e3afac7 100644 --- a/src/object/sp-shape.cpp +++ b/src/object/sp-shape.cpp @@ -838,6 +838,9 @@ void SPShape::update_patheffect(bool write) repr->removeAttribute("d"); } } + if (hasPathEffectRecursive() && pathEffectsEnabled()) { + finishPatheffectStack(); + } this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } } diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index ac76c43dbc..ce42bd282a 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -445,6 +445,13 @@ static void add_ids_recursive(std::vector &ids, SPObject *obj) void ObjectSet::duplicate(bool suppressDone, bool duplicateLayer) { + auto list= items(); + for (auto itemlist=list.begin();itemlist!=list.end();++itemlist) { + SPLPEItem *lpeitem = dynamic_cast(*itemlist); + if (lpeitem) { + sp_lpe_item_onpreduple(lpeitem); + } + } if(duplicateLayer && !desktop() ){ //TODO: understand why layer management is tied to desktop and not to document. return; @@ -611,6 +618,13 @@ void ObjectSet::duplicate(bool suppressDone, bool duplicateLayer) desktop()->layer_manager->renameLayer( new_layer, name, TRUE ); g_free(name); } + list= items(); + for (auto itemlist=list.begin();itemlist!=list.end();++itemlist) { + SPLPEItem *lpeitem = dynamic_cast(*itemlist); + if (lpeitem) { + sp_lpe_item_onduple(lpeitem); + } + } } void sp_edit_clear_all(Inkscape::Selection *selection) @@ -1252,6 +1266,13 @@ sp_redo(SPDesktop *desktop, SPDocument *) void ObjectSet::cut() { + auto list= items(); + for (auto itemlist=list.begin();itemlist!=list.end();++itemlist) { + SPLPEItem *lpeitem = dynamic_cast(*itemlist); + if (lpeitem) { + sp_lpe_item_oncut(lpeitem); + } + } copy(); deleteItems(); } @@ -1310,8 +1331,34 @@ take_style_from_item(SPObject *object) void ObjectSet::copy() { + // We want to fire oncopy on LPE items, mainly to alter selection + // after it instead copy to clipboard we duplicate the resulting selection + // to allow get forked LPE items as we want on the clipboard ready to paste into new docs + // If do not this way we need to work in the volatile clipboard with no garantee of final sucess + // So the steps are: + // PASTE: + // 1:we store the selection + // 2:we make a call to LPE items to allow applied make necesary tweaks to current selection + // 3:we duplicate the resulting selection firing LPE methods in duplicate to + // fork adecuate the lpe items + // 4: we copy to clipboard a good result, all forked and updated + // 5: we remove the selection duplicated + // 6: finaly we reselect original selection + std::vector items_copy(items().begin(), items().end()); + for (auto &item:items_copy) { + SPLPEItem *lpeitem = dynamic_cast(item); + if (lpeitem) { + sp_lpe_item_oncopy(lpeitem); + } + } + duplicate(); Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get(); cm->copy(this); + deleteItems(); + //we resurrect selecton in case LPE change it + for (auto &item:items_copy) { + add(item); + } } void sp_selection_paste(SPDesktop *desktop, bool in_place) @@ -1320,6 +1367,13 @@ void sp_selection_paste(SPDesktop *desktop, bool in_place) if (cm->paste(desktop, in_place)) { DocumentUndo::done(desktop->getDocument(), SP_VERB_EDIT_PASTE, _("Paste")); } + auto list= desktop->selection->items(); + for (auto itemlist=list.begin();itemlist!=list.end();++itemlist) { + SPLPEItem *lpeitem = dynamic_cast(*itemlist); + if (lpeitem) { + sp_lpe_item_onpaste(lpeitem); + } + } } void ObjectSet::pasteStyle() diff --git a/src/seltrans.cpp b/src/seltrans.cpp index 2163a273db..360da78b73 100644 --- a/src/seltrans.cpp +++ b/src/seltrans.cpp @@ -498,7 +498,7 @@ void Inkscape::SelTrans::ungrab() void Inkscape::SelTrans::stamp() { Inkscape::Selection *selection = _desktop->getSelection(); - + bool fixup = !_grabbed; if ( fixup && !_stamp_cache.empty() ) { // TODO - give a proper fix. Simple temporary work-around for the grab() issue @@ -511,10 +511,20 @@ void Inkscape::SelTrans::stamp() if (!_stamp_cache.empty()) { l = _stamp_cache; } else { + std::vector items_copy(selection->items().begin(), selection->items().end()); + for (auto &item:items_copy) { + SPLPEItem *lpeitem = dynamic_cast(item); + if (lpeitem) { + sp_lpe_item_onprestamp(lpeitem); + } + } /* Build cache */ l.insert(l.end(), selection->items().begin(), selection->items().end()); sort(l.begin(), l.end(), sp_object_compare_position_bool); _stamp_cache = l; + for (auto &item:items_copy) { + selection->add(item); + } } for(auto original_item : l) { @@ -540,16 +550,20 @@ void Inkscape::SelTrans::stamp() new_affine = &original_item->transform; } + + Inkscape::GC::release(copy_repr); + SPLPEItem * lpeitem = dynamic_cast(copy_item); + if(lpeitem && lpeitem->hasPathEffectRecursive()) { + lpeitem->forkPathEffectsIfNecessary(1); + sp_lpe_item_update_patheffect(lpeitem, true, true); + } copy_item->doWriteTransform(*new_affine); if ( copy_item->isCenterSet() && _center ) { copy_item->setCenter(*_center * _current_relative_affine); } - Inkscape::GC::release(copy_repr); - SPLPEItem * lpeitem = dynamic_cast(copy_item); if(lpeitem && lpeitem->hasPathEffectRecursive()) { - lpeitem->forkPathEffectsIfNecessary(1); - sp_lpe_item_update_patheffect(lpeitem, true, true); + sp_lpe_item_onstamp(lpeitem); } } DocumentUndo::done(_desktop->getDocument(), SP_VERB_CONTEXT_SELECT, diff --git a/src/ui/dialog/livepatheffect-editor.cpp b/src/ui/dialog/livepatheffect-editor.cpp index 8a22570693..9170f105f6 100644 --- a/src/ui/dialog/livepatheffect-editor.cpp +++ b/src/ui/dialog/livepatheffect-editor.cpp @@ -617,7 +617,7 @@ void LivePathEffectEditor::on_visibility_toggled( Glib::ustring const& str ) SPItem *item = sel->singleItem(); SPLPEItem *lpeitem = dynamic_cast(item); if ( lpeitem ) { - lpeobjref->lpeobject->get_lpe()->doOnVisibilityToggled(lpeitem); + lpeobjref->lpeobject->get_lpe()->doOnVisibilityToggled_impl(lpeitem); } } DocumentUndo::done( current_desktop->getDocument(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, diff --git a/src/ui/toolbar/pencil-toolbar.cpp b/src/ui/toolbar/pencil-toolbar.cpp index 06ad319df1..7ec51fc19e 100644 --- a/src/ui/toolbar/pencil-toolbar.cpp +++ b/src/ui/toolbar/pencil-toolbar.cpp @@ -566,7 +566,7 @@ PencilToolbar::simplify_flatten() SPShape * shape = dynamic_cast(lpeitem); if(shape){ auto c = SPCurve::copy(shape->curveForEdit()); - lpe->doEffect(c.get()); + lpe->doEffect_impl(c.get()); lpeitem->setCurrentPathEffect(*i); if (lpelist.size() > 1){ lpeitem->removeCurrentPathEffect(true); @@ -610,7 +610,7 @@ PencilToolbar::flatten_spiro_bspline() SPShape * shape = dynamic_cast(lpeitem); if(shape){ auto c = SPCurve::copy(shape->curveForEdit()); - lpe->doEffect(c.get()); + lpe->doEffect_impl(c.get()); lpeitem->setCurrentPathEffect(*i); if (lpelist.size() > 1){ lpeitem->removeCurrentPathEffect(true); -- GitLab