diff --git a/src/file.cpp b/src/file.cpp index 2953f8b1030a1890849f9ed68957a597fa197370..23f28531dea45c2a67a974b219d476b430bd37fb 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -961,12 +961,12 @@ void sp_import_document(SPDesktop *desktop, SPDocument *clipdoc, bool in_place) target_parent->addChild(obj_copy, node_after); node_after = obj_copy; Inkscape::GC::release(obj_copy); - + SPObject *copy = target_document->getObjectByRepr(obj_copy); pasted_objects.push_back(obj_copy); // if we are pasting a clone to an already existing object, its // transform is relative to the document, not to its original (see ui/clipboard.cpp) - SPUse *use = dynamic_cast(obj_copy); + SPUse *use = dynamic_cast(copy); if (use) { SPItem *original = use->get_original(); if (original) { @@ -976,33 +976,11 @@ void sp_import_document(SPDesktop *desktop, SPDocument *clipdoc, bool in_place) } } - std::vector pasted_objects_not; - if(clipboard) //???? Removed dead code can cause any bug, need to reimplement undead - for (Inkscape::XML::Node *obj = clipboard->firstChild() ; obj ; obj = obj->next()) { - if(target_document->getObjectById(obj->attribute("id"))) continue; - Inkscape::XML::Node *obj_copy = obj->duplicate(target_document->getReprDoc()); - SPObject * pasted = desktop->currentLayer()->appendChildRepr(obj_copy); - Inkscape::GC::release(obj_copy); - SPLPEItem * pasted_lpe_item = dynamic_cast(pasted); - if (pasted_lpe_item){ - pasted_lpe_item->forkPathEffectsIfNecessary(1); - } - pasted_objects_not.push_back(obj_copy); - } - Inkscape::Selection *selection = desktop->getSelection(); - selection->setReprList(pasted_objects_not); - Geom::Affine doc2parent = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse(); - selection->applyAffine(desktop->dt2doc() * doc2parent * desktop->doc2dt(), true, false, false); - selection->deleteItems(); - // Change the selection to the freshly pasted objects + SPItem * item = dynamic_cast(desktop->currentLayer()); + Geom::Affine doc2parent = item->i2doc_affine().inverse(); + Inkscape::Selection *selection = desktop->getSelection(); selection->setReprList(pasted_objects); - for (auto item : selection->items()) { - SPLPEItem *pasted_lpe_item = dynamic_cast(item); - if (pasted_lpe_item) { - pasted_lpe_item->forkPathEffectsIfNecessary(1); - } - } // Apply inverse of parent transform selection->applyAffine(desktop->dt2doc() * doc2parent * desktop->doc2dt(), true, false, false); diff --git a/src/filter-chemistry.cpp b/src/filter-chemistry.cpp index 5da05717c4a130ae3a58c34da602428c38c3b73c..2b34025b96e77b362f5106055f7ff655cb9ba867 100644 --- a/src/filter-chemistry.cpp +++ b/src/filter-chemistry.cpp @@ -400,19 +400,6 @@ void remove_filter (SPObject *item, bool recursive) sp_repr_css_attr_unref(css); } -// 1.1 COPYPASTECLONESTAMPLPEBUG -void remove_hidder_filter (SPObject *item) -{ - SPFilter *filt = item->style->getFilter(); - if (filt && filt->getId()) { - Glib::ustring filter = filt->getId(); - if (!filter.rfind("selectable_hidder_filter", 0)) { - remove_filter(item, false); - } - } -} -// END COPYPASTECLONESTAMPLPEBUG - /** * Removes the first feGaussianBlur from the filter attached to given item. * Should this leave us with an empty filter, remove that filter. diff --git a/src/filter-chemistry.h b/src/filter-chemistry.h index 9d20aa9f5c5cf303a573b46b0f6f5484179b6f3b..7e70c0ddcf7f45142e8f1ad2056414fa258cf9c0 100644 --- a/src/filter-chemistry.h +++ b/src/filter-chemistry.h @@ -30,7 +30,6 @@ SPFilter *new_filter_gaussian_blur (SPDocument *document, double stdDeviation, d SPFilter *new_filter_simple_from_item (SPDocument *document, SPItem *item, const char *mode, double stdDeviation); SPFilter *modify_filter_gaussian_blur_from_item (SPDocument *document, SPItem *item, double stdDeviation); void remove_filter (SPObject *item, bool recursive); -void remove_hidder_filter (SPObject *item); void remove_filter_gaussian_blur (SPObject *item); void remove_filter_legacy_blend(SPObject *item); SPBlendMode filter_get_legacy_blend(SPObject *item); diff --git a/src/helper/geom.cpp b/src/helper/geom.cpp index 5e8e763f5dc415d71769d08e7d024f3ee66c43d5..eb687c78910a2a9e94c1ff8234c83922bc0d90ca 100644 --- a/src/helper/geom.cpp +++ b/src/helper/geom.cpp @@ -191,6 +191,34 @@ bounds_exact_transformed(Geom::PathVector const & pv, Geom::Affine const & t) return bbox; } +bool +geom_path_compare(Geom::PathVector apv, Geom::PathVector bpv, double precission) +{ + size_t totala = apv.curveCount(); + size_t totalb = bpv.curveCount(); + if (totala != totalb) { + return false; + } + std::vector pos; + for (size_t i = 0; i < apv.curveCount(); i++) { + Geom::Point pointa = apv.pointAt(float(i)+0.2); + Geom::Point pointb = bpv.pointAt(float(i)+0.2); + Geom::Point pointc = apv.pointAt(float(i)+0.4); + Geom::Point pointd = bpv.pointAt(float(i)+0.4); + Geom::Point pointe = apv.pointAt(float(i)); + Geom::Point pointf = bpv.pointAt(float(i)); + if (!Geom::are_near(pointa[Geom::X], pointb[Geom::X], precission) || + !Geom::are_near(pointa[Geom::Y], pointb[Geom::Y], precission) || + !Geom::are_near(pointc[Geom::X], pointd[Geom::X], precission) || + !Geom::are_near(pointc[Geom::Y], pointd[Geom::Y], precission) || + !Geom::are_near(pointe[Geom::X], pointf[Geom::X], precission) || + !Geom::are_near(pointe[Geom::Y], pointf[Geom::Y], precission)) + { + return false; + } + } + return true; +} static void diff --git a/src/helper/geom.h b/src/helper/geom.h index 58f323efee45eb133d8512d2c2b530dac77e04ec..46b47c9eae25f92e0d7f36ab3d5209bd4b27e334 100644 --- a/src/helper/geom.h +++ b/src/helper/geom.h @@ -31,6 +31,7 @@ size_t count_path_nodes(Geom::Path const &path); Geom::PathVector pathv_to_linear_and_cubic_beziers( Geom::PathVector const &pathv ); Geom::PathVector pathv_to_linear( Geom::PathVector const &pathv, double maxdisp ); Geom::PathVector pathv_to_cubicbezier( Geom::PathVector const &pathv); +bool geom_path_compare(Geom::PathVector apv, Geom::PathVector bpv, double precission = 0.001); void recursive_bezier4(const double x1, const double y1, const double x2, const double y2, const double x3, const double y3, const double x4, const double y4, std::vector &pointlist, diff --git a/src/id-clash.cpp b/src/id-clash.cpp index ea1b9030a9ead3092531670eda7256674a95abe2..65508f5e20abc554213e150707006c0a9e54c1e2 100644 --- a/src/id-clash.cpp +++ b/src/id-clash.cpp @@ -24,6 +24,10 @@ #include "id-clash.h" #include "live_effects/lpeobject.h" +#include "live_effects/effect.h" +#include "live_effects/parameter/originalitem.h" +#include "live_effects/parameter/originalitemarrayhidden.h" +#include "live_effects/parameter/parameter.h" #include "object/sp-gradient.h" #include "object/sp-object.h" #include "object/sp-paint-server.h" @@ -49,6 +53,7 @@ const char *href_like_attributes[] = { "inkscape:connection-start", "inkscape:connection-start-point", "inkscape:href", + "inkscape:href-list", "inkscape:path-effect", "inkscape:perspectiveID", "inkscape:tiled-clone-of", @@ -107,9 +112,24 @@ static void fix_ref(IdReference const &idref, SPObject *to_obj, const char *old_id) { switch (idref.type) { case REF_HREF: { - gchar *new_uri = g_strdup_printf("#%s", to_obj->getId()); - idref.elem->setAttribute(idref.attr, new_uri); - g_free(new_uri); + if (idref.elem->getAttribute(idref.attr)) { + gchar *new_uri = g_strdup_printf("#%s", to_obj->getId()); + Glib::ustring value = idref.elem->getAttribute(idref.attr); + // look to values stores as separated id references like inkscape::path-effect or LPE satellites param + size_t pos = value.find(";"); + if (pos != Glib::ustring::npos) { + Glib::ustring old = "#"; + old += old_id; + size_t posid = value.find(old_id); + if (posid != Glib::ustring::npos) { + value = value.replace(posid - 1, old.size(), new_uri); + idref.elem->setAttribute(idref.attr, value.c_str()); + } + } else { + idref.elem->setAttribute(idref.attr, new_uri); + } + g_free(new_uri); + } break; } case REF_STYLE: { @@ -156,7 +176,7 @@ fix_ref(IdReference const &idref, SPObject *to_obj, const char *old_id) { * (e.g., ID selectors in CSS stylesheets, and references in scripts). */ static void -find_references(SPObject *elem, refmap_type &refmap) +find_references(SPObject *elem, refmap_type &refmap, bool from_clipboard) { if (elem->cloned) return; Inkscape::XML::Node *repr_elem = elem->getRepr(); @@ -179,16 +199,59 @@ find_references(SPObject *elem, refmap_type &refmap) } } - return; // nothing more to do for inkscape:clipboard elements + if (!from_clipboard) { + return; // nothing more to do for inkscape:clipboard elements + } + } + if (!std::strcmp(repr_elem->name(), "inkscape:path-effect")) { + LivePathEffectObject *lpeobj = dynamic_cast(elem); + if (lpeobj) { + Inkscape::LivePathEffect::Effect *effect = lpeobj->get_lpe(); + if (effect) { + std::vector::iterator p; + for (p = effect->param_vector.begin(); p != effect->param_vector.end(); ++p) { + Inkscape::LivePathEffect::Parameter *param = *p; + if (dynamic_cast(param) || + dynamic_cast(param)) + { + const gchar *val = repr_elem->attribute(param->param_key.c_str()); + if (val) { + gchar ** strarray = g_strsplit(val, ";", 0); + if (strarray) { + unsigned int i = 0; + while (strarray[i]) { + if (strarray[i][0] == '#') { + std::string id(strarray[i]+1); + IdReference idref = { REF_HREF, elem, param->param_key.c_str()}; + refmap[id].push_back(idref); + } + i++; + } + g_strfreev (strarray); + } + } + } + } + } + } } - /* check for xlink:href="#..." and similar */ for (auto attr : href_like_attributes) { const gchar *val = repr_elem->attribute(attr); - if (val && val[0] == '#') { - std::string id(val+1); - IdReference idref = { REF_HREF, elem, attr }; - refmap[id].push_back(idref); + if (val) { + gchar ** strarray = g_strsplit(val, ";", 0); + if (strarray) { + unsigned int i = 0; + while (strarray[i]) { + if (strarray[i][0] == '#') { + std::string id(strarray[i]+1); + IdReference idref = { REF_HREF, elem, attr }; + refmap[id].push_back(idref); + } + i++; + } + g_strfreev (strarray); + } } } @@ -261,7 +324,7 @@ find_references(SPObject *elem, refmap_type &refmap) // recurse for (auto& child: elem->children) { - find_references(&child, refmap); + find_references(&child, refmap, from_clipboard); } } @@ -272,7 +335,7 @@ find_references(SPObject *elem, refmap_type &refmap) static void change_clashing_ids(SPDocument *imported_doc, SPDocument *current_doc, SPObject *elem, refmap_type const &refmap, - id_changelist_type *id_changes) + id_changelist_type *id_changes, bool from_clipboard) { const gchar *id = elem->getId(); bool fix_clashing_ids = true; @@ -299,7 +362,7 @@ change_clashing_ids(SPDocument *imported_doc, SPDocument *current_doc, SPObject *cd_obj = current_doc->getObjectById(id); LivePathEffectObject *cd_lpeobj = dynamic_cast(cd_obj); if (cd_lpeobj && lpeobj->is_similar(cd_lpeobj)) { - fix_clashing_ids = false; + fix_clashing_ids = from_clipboard; } } @@ -325,7 +388,7 @@ change_clashing_ids(SPDocument *imported_doc, SPDocument *current_doc, // recurse for (auto& child: elem->children) { - change_clashing_ids(imported_doc, current_doc, &child, refmap, id_changes); + change_clashing_ids(imported_doc, current_doc, &child, refmap, id_changes, from_clipboard); } } @@ -355,15 +418,15 @@ fix_up_refs(refmap_type const &refmap, const id_changelist_type &id_changes) * those IDs are updated accordingly. */ void -prevent_id_clashes(SPDocument *imported_doc, SPDocument *current_doc) +prevent_id_clashes(SPDocument *imported_doc, SPDocument *current_doc, bool from_clipboard) { refmap_type refmap; id_changelist_type id_changes; SPObject *imported_root = imported_doc->getRoot(); - find_references(imported_root, refmap); + find_references(imported_root, refmap, from_clipboard); change_clashing_ids(imported_doc, current_doc, imported_root, refmap, - &id_changes); + &id_changes, from_clipboard); fix_up_refs(refmap, id_changes); } @@ -377,7 +440,7 @@ change_def_references(SPObject *from_obj, SPObject *to_obj) SPDocument *current_doc = from_obj->document; std::string old_id(from_obj->getId()); - find_references(current_doc->getRoot(), refmap); + find_references(current_doc->getRoot(), refmap, false); refmap_type::const_iterator pos = refmap.find(old_id); if (pos != refmap.end()) { @@ -460,7 +523,7 @@ void rename_id(SPObject *elem, Glib::ustring const &new_name) SPDocument *current_doc = elem->document; refmap_type refmap; - find_references(current_doc->getRoot(), refmap); + find_references(current_doc->getRoot(), refmap, false); std::string old_id(elem->getId()); if (current_doc->getObjectById(id)) { diff --git a/src/id-clash.h b/src/id-clash.h index 9a5617d69c98239d72acb680415dabcc91ebb43b..85e748c76ad11e6d25abd393bc6bdbdd54555676 100644 --- a/src/id-clash.h +++ b/src/id-clash.h @@ -12,7 +12,7 @@ #include "document.h" -void prevent_id_clashes(SPDocument *imported_doc, SPDocument *current_doc); +void prevent_id_clashes(SPDocument *imported_doc, SPDocument *current_doc, bool from_clipboard = false); void rename_id(SPObject *elem, Glib::ustring const &newname); void change_def_references(SPObject *replace_obj, SPObject *with_obj); Glib::ustring generate_unique_id(SPDocument* document, const Glib::ustring& base_name); diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt index 939e7ee4439f70835c37c1f8f834aa0084147351..8fa51340bb08f12392d12e590768f2c50e801598 100644 --- a/src/live_effects/CMakeLists.txt +++ b/src/live_effects/CMakeLists.txt @@ -74,6 +74,7 @@ set(live_effects_SRC parameter/item.cpp parameter/message.cpp parameter/originalitemarray.cpp + parameter/originalitemarrayhidden.cpp parameter/originalitem.cpp parameter/originalpath.cpp parameter/originalpatharray.cpp @@ -169,7 +170,8 @@ set(live_effects_SRC parameter/enum.h parameter/item.h parameter/message.h - parameter/originalitemarray.cpp + parameter/originalitemarray.h + parameter/originalitemarrayhidden.h parameter/item-reference.h parameter/originalitem.h parameter/originalpath.h diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index e02eecab693a95b44d882c29b965625e3de6f7a5..cc5b84bf22f61c7bc633b55d72a940fee8b34299 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -1068,6 +1068,7 @@ Effect::Effect(LivePathEffectObject *lpeobject) oncanvasedit_it(0), is_visible(_("Is visible?"), _("If unchecked, the effect remains applied to the object but is temporarily disabled on canvas"), "is_visible", &wr, this, true), lpeversion(_("Version"), _("LPE version"), "lpeversion", &wr, this, "0", true), + lpesatellites(_("lpesatellites"), _("Items satellites"), "lpesatellites", &wr, this), show_orig_path(false), keep_paths(false), is_load(true), @@ -1083,8 +1084,9 @@ Effect::Effect(LivePathEffectObject *lpeobject) is_ready(false), is_applied(false) { - registerParameter( dynamic_cast(&is_visible) ); - registerParameter( dynamic_cast(&lpeversion) ); + registerParameter(&is_visible); + registerParameter(&lpeversion); + registerParameter(&lpesatellites); is_visible.widget_is_visible = false; } @@ -1194,6 +1196,140 @@ Effect::isNodePointSelected(Geom::Point const &nodePoint) const return false; } +void +Effect::_processObjects(LPEAction lpe_action) +{ + SPDocument *document = getSPDoc(); + if (!document) { + return; + } + SPLPEItem *sp_lpe_item = dynamic_cast(*getLPEObj()->hrefList.begin()); + if (!document || !sp_lpe_item) { + return; + } + sp_lpe_item_enable_path_effects(sp_lpe_item, false); + // we check the items are not deleted + lpesatellites.param_readSVGValue(lpesatellites.param_getSVGValue().c_str()); + // end + //std::cout << lpesatellites._vector.size() << std::endl; + for (auto &iter : lpesatellites._vector) { + SPObject *elemref; + if (iter && iter->isAttached() && (elemref = iter->getObject())) { + SPItem *item = dynamic_cast(elemref); + if (item) { + Inkscape::XML::Node * elemnode = elemref->getRepr(); + SPCSSAttr *css; + Glib::ustring css_str; + switch (lpe_action){ + case LPE_TO_OBJECTS: + if (item->isHidden()) { + item->deleteObject(true); + } else { + elemnode->removeAttribute("sodipodi:insensitive"); + SPDefs *defs = dynamic_cast(elemref->parent); + if (!defs) { + item->moveTo(sp_lpe_item, false); + } + } + break; + + case LPE_ERASE: + item->deleteObject(true); + break; + + case LPE_ERASE_UNREF: + if (item->hrefList.size() == 1) { + item->deleteObject(true); + } + break; + + case LPE_VISIBILITY: + css = sp_repr_css_attr_new(); + sp_repr_css_attr_add_from_string(css, elemref->getRepr()->attribute("style")); + if (!isVisible()/* && std::strcmp(elemref->getId(),sp_lpe_item->getId()) != 0*/) { + css->setAttribute("display", "none"); + } else { + css->removeAttribute("display"); + } + sp_repr_css_write_string(css,css_str); + elemnode->setAttributeOrRemoveIfEmpty("style", css_str); + sp_lpe_item_update_patheffect(sp_lpe_item, false, false); + break; + default: + break; + } + } + } else { + sp_lpe_item_enable_path_effects(sp_lpe_item, true); + return; + } + } + if (lpe_action == LPE_ERASE || lpe_action == LPE_ERASE_UNREF || lpe_action == LPE_TO_OBJECTS) { + lpesatellites.clear(); + } + sp_lpe_item_enable_path_effects(sp_lpe_item, true); +} + + +gboolean +Effect::_processObjectsTimeout(gpointer data) +{ + Effect *effect=reinterpret_cast(data); + effect->_processObjects(effect->_lpe_action); + return false; +} + +// we delay till current operation is done to aboid deleted items crashes +void +Effect::processObjectsOK(LPEAction lpe_action) +{ + SPDocument *document = getSPDoc(); + if (!document) { + return; + } + SPLPEItem *sp_lpe_item = dynamic_cast(*getLPEObj()->hrefList.begin()); + if (!document || !sp_lpe_item) { + return; + } + // we check the items are not deleted + lpesatellites.param_readSVGValue(lpesatellites.param_getSVGValue().c_str()); + // end + for (auto &iter : lpesatellites._vector) { + SPObject *elemref; + if (iter && iter->isAttached() && (elemref = iter->getObject())) { + SPItem *item = dynamic_cast(elemref); + if (item) { + SPLPEItem *lpeitem = dynamic_cast(item); + switch (lpe_action){ + case LPE_TO_OBJECTS: + if (lpeitem && item->isHidden()) { + lpeitem->removeAllPathEffects(false); + } + break; + case LPE_ERASE: + if (lpeitem) { + lpeitem->removeAllPathEffects(false); + } + break; + case LPE_ERASE_UNREF: + if (lpeitem && item->hrefList.size() == 1) { + lpeitem->removeAllPathEffects(false); + } + break; + default: + break; + } + } + } + } + _lpe_action = lpe_action; + g_timeout_add_full(G_PRIORITY_HIGH,1, &Effect::_processObjectsTimeout, this,nullptr); + if (!sp_lpe_item->on_ungroup) { + while (gtk_events_pending ()) + gtk_main_iteration(); + } +} + void Effect::processObjects(LPEAction lpe_action) { @@ -1339,6 +1475,19 @@ Effect::acceptParamPath (SPPath const*/*param_path*/) { setReady(); } +void +Effect::doOnFork_impl(SPLPEItem const *lpeitem, Effect const *preveffect) +{ + doOnFork(lpeitem, preveffect); +} + +/* + * Do nothing for simple lpe + */ +void +Effect::doOnFork(SPLPEItem const *lpeitem, Effect const *preveffect) +{ +} /* * Here be the doEffect function chain: */ diff --git a/src/live_effects/effect.h b/src/live_effects/effect.h index 977fc7d119a2da450bc3434c4894a4bd8ab8d2ea..c3dfe74912f080157db1635f2544b59098485f24 100644 --- a/src/live_effects/effect.h +++ b/src/live_effects/effect.h @@ -11,6 +11,7 @@ #include "effect-enum.h" #include "parameter/bool.h" #include "parameter/hidden.h" +#include "parameter/originalitemarrayhidden.h" #include "ui/widget/registry.h" #include <2geom/forward.h> #include @@ -51,7 +52,8 @@ enum LPEPathFlashType { enum LPEAction { LPE_ERASE = 0, LPE_TO_OBJECTS, - LPE_VISIBILITY + LPE_VISIBILITY, + LPE_ERASE_UNREF }; class Effect { @@ -70,12 +72,14 @@ public: //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 doOnFork_impl(SPLPEItem const *lpeitem, Effect const *preveffect); 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 doOnFork (SPLPEItem const *lpeitem, Effect const *preveffect); virtual void doBeforeEffect (SPLPEItem const* lpeitem); std::vector getCurrrentLPEItems() const; @@ -96,6 +100,9 @@ public: SPShape * getCurrentShape() const { return current_shape; }; void setCurrentShape(SPShape * shape) { current_shape = shape; } void processObjects(LPEAction lpe_action); + static int _processObjectsTimeout(gpointer data); + void _processObjects(LPEAction lpe_action); + void processObjectsOK(LPEAction lpe_action); /* * isReady() indicates whether all preparations which are necessary to apply the LPE are done, @@ -155,9 +162,12 @@ 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. + OriginalItemArrayHiddenParam lpesatellites; //replacement for items at finish move + std::vector items; + std::vector param_vector; protected: Effect(LivePathEffectObject *lpeobject); - + friend class OriginalItemArrayHiddenParam; // provide a set of doEffect functions so the developer has a choice // of what kind of input/output parameters he desires. // the order in which they appear is the order in which they are @@ -175,7 +185,6 @@ public: virtual void addCanvasIndicators(SPLPEItem const* lpeitem, std::vector &hp_vec); - std::vector param_vector; bool _provides_knotholder_entities; int oncanvasedit_it; @@ -190,7 +199,6 @@ public: // 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; @@ -201,7 +209,8 @@ 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 - + + LPEAction _lpe_action; bool is_ready; bool defaultsopen; }; diff --git a/src/live_effects/lpe-bool.cpp b/src/live_effects/lpe-bool.cpp index f1d02b9ced57f3e55a5b343d7c515a9206f0038e..ee5202c5c5315e4f34c2348655e5eb371cb21de2 100644 --- a/src/live_effects/lpe-bool.cpp +++ b/src/live_effects/lpe-bool.cpp @@ -94,7 +94,6 @@ LPEBool::LPEBool(LivePathEffectObject *lpeobject) registerParameter(&filter); registerParameter(&fill_type_operand); show_orig_path = true; - is_load = true; prev_affine = Geom::identity(); operand = dynamic_cast(operand_path.getObject()); if (operand) { @@ -110,6 +109,36 @@ 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; } +void +LPEBool::doOnFork(SPLPEItem const *lpeitem, Effect const *preveffect) +{ + if (!preveffect) { + return; + } + std::vector lpeitems = preveffect->getCurrrentLPEItems(); + if (!lpeitems.size()) { + return; + } + SPLPEItem *previous = nullptr; + previous = lpeitems.back(); + if (!previous) { + return; + } + operand_path.remove_link(); + LPEBool const *prevbool = reinterpret_cast(preveffect); + if (!prevbool) { + return; + } + if (!prevbool->operand_path.ref.getObject()) { + return; + } + SPObject *elemref = prevbool->operand_path.ref.getObject(); + std::cout << elemref->forked_id << std::endl; + if (elemref && elemref->forked_id != "") { + operand_path.linkitem(elemref->forked_id); + } +} + Geom::PathVector sp_pathvector_boolop_slice_intersect(Geom::PathVector const &pathva, Geom::PathVector const &pathvb, bool inside, fill_typ fra, fill_typ frb) { @@ -367,6 +396,7 @@ static fill_typ GetFillTyp(SPItem *item) void LPEBool::add_filter() { + SPItem *operand = dynamic_cast(operand_path.getObject()); if (operand) { Inkscape::XML::Node *repr = operand->getRepr(); if (!repr) { @@ -387,6 +417,7 @@ void LPEBool::add_filter() void LPEBool::remove_filter() { + SPObject *operand = operand_path.getObject(); if (operand) { Inkscape::XML::Node *repr = operand->getRepr(); if (!repr) { @@ -460,7 +491,6 @@ void LPEBool::doBeforeEffect(SPLPEItem const *lpeitem) } } } - SPDesktop *desktop = SP_ACTIVE_DESKTOP; SPItem *current_operand = dynamic_cast(operand_path.getObject()); operand = dynamic_cast(lpeitem->document->getObjectById(operand_id)); @@ -469,9 +499,8 @@ void LPEBool::doBeforeEffect(SPLPEItem const *lpeitem) } if (!current_operand) { operand_path.remove_link(); - operand = nullptr; } - if (current_operand && current_operand->getId()) { + if (current_operand) { if (!(document->getObjectById(current_operand->getId()))) { operand_path.remove_link(); operand = nullptr; @@ -481,17 +510,23 @@ void LPEBool::doBeforeEffect(SPLPEItem const *lpeitem) operand_id = current_operand->getId(); } } + SPDesktop *desktop = SP_ACTIVE_DESKTOP; SPLPEItem *operandlpe = dynamic_cast(operand_path.getObject()); - if (desktop && - operand && - sp_lpe_item && - desktop->getSelection()->includes(operand) && - desktop->getSelection()->includes(sp_lpe_item)) - { - if (operandlpe && operandlpe->hasPathEffectOfType(Inkscape::LivePathEffect::EffectType::BOOL_OP)) { - sp_lpe_item_update_patheffect(operandlpe, false, false); + if (desktop) { + Inkscape::Selection *selection = desktop->getSelection(); + if (selection && + operand && + sp_lpe_item && + selection->includes(operand) && + selection->includes(sp_lpe_item)) + { + if (operandlpe && operandlpe->hasPathEffectOfType(Inkscape::LivePathEffect::EffectType::BOOL_OP)) { + sp_lpe_item_update_patheffect(operandlpe, false, false); + } + if (sp_lpe_item->on_align_distribute) { + selection->remove(current_operand); + } } - desktop->getSelection()->remove(operand); } if (!current_operand) { if (operand) { @@ -511,24 +546,54 @@ void LPEBool::doBeforeEffect(SPLPEItem const *lpeitem) sp_lpe_item_update_patheffect(sp_lpe_item, true, true); } } - if (operand) { + if (current_operand) { if (is_visible) { add_filter(); - if (operand->getPosition() - 1 != sp_lpe_item->getPosition()) { - sp_lpe_item->parent->reorder(operand,sp_lpe_item); + if (current_operand->getPosition() - 1 != sp_lpe_item->getPosition()) { + sp_lpe_item->parent->reorder(current_operand,sp_lpe_item); } } else { remove_filter(); } } + /* Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (prefs->getBool("/live_effects/satelleitesiddle", false)) { + remove_filter(); + } */ + if (sp_lpe_item->on_ungroup) { + remove_filter(); + } +} + +gboolean relink(gpointer data) +{ + static gint counter = 0; + counter++; + LPEBool *boollpe = reinterpret_cast(data); + boollpe->operand_path.param_relink(); + if (!boollpe->operand_path.getObject()) { + gboolean ret = counter > 10 ? FALSE : TRUE; + counter = 0; + return ret; + } + return FALSE; } void LPEBool::transform_multiply(Geom::Affine const &postmul, bool /*set*/) { operand = dynamic_cast(sp_lpe_item->document->getObjectById(operand_id)); if (operand && !isOnClipboard()) { + if (!operand_path.getObject()) { + g_timeout_add(100, &relink, this); + return; + } SPDesktop *desktop = SP_ACTIVE_DESKTOP; - if (desktop && !desktop->getSelection()->includes(operand)) { + std::cout << sp_lpe_item->forked_id << std::endl; + std::cout << operand->forked_id << std::endl; + if (sp_lpe_item->forked_id != "" && operand->forked_id == "") { + return; + } + if (sp_lpe_item && desktop && operand && !desktop->getSelection()->includes(operand)) { prev_affine = operand->transform * sp_item_transform_repr(sp_lpe_item).inverse() * postmul; operand->doWriteTransform(prev_affine); } @@ -601,18 +666,18 @@ Geom::PathVector LPEBool::get_union(SPObject *object) void LPEBool::doEffect(SPCurve *curve) { Geom::PathVector path_in = curve->get_pathvector(); - if (operand == current_shape) { + SPItem *current_operand = dynamic_cast(operand_path.getObject()); + if (current_operand == current_shape) { g_warning("operand and current shape are the same"); operand_path.param_set_default(); return; } - if (operand_path.getObject() && operand) { + if (current_operand) { bool_op_ex op = bool_operation.get_value(); bool swap = swap_operands.get_value(); - Geom::Affine current_affine = sp_lpe_item->transform; - Geom::Affine operand_affine = operand->transform; - Geom::PathVector operand_pv = get_union(operand); + Geom::Affine operand_affine = current_operand->transform; + Geom::PathVector operand_pv = get_union(current_operand); if (operand_pv.empty()) { return; } diff --git a/src/live_effects/lpe-bool.h b/src/live_effects/lpe-bool.h index f018390b0b21e774e5b62457d778aff24db90e67..8788d3df04cd248a4e06209a0bdb0f868d256cfd 100644 --- a/src/live_effects/lpe-bool.h +++ b/src/live_effects/lpe-bool.h @@ -32,6 +32,7 @@ public: void transform_multiply(Geom::Affine const &postmul, bool set) override; void doOnVisibilityToggled(SPLPEItem const * /*lpeitem*/) override; void doOnRemove(SPLPEItem const * /*lpeitem*/) override; + void doOnFork(SPLPEItem const *lpeitem, Effect const *preveffect) override; void add_filter(); Geom::PathVector get_union(SPObject *object); void remove_filter(); @@ -54,12 +55,11 @@ public: assert(val <= bool_op_ex_cut); return (bool_op) val; } - + OriginalItemParam operand_path; private: LPEBool(const LPEBool &) = delete; LPEBool &operator=(const LPEBool &) = delete; - OriginalItemParam operand_path; EnumParam bool_operation; EnumParam fill_type_this; EnumParam fill_type_operand; diff --git a/src/live_effects/lpe-copy_rotate.cpp b/src/live_effects/lpe-copy_rotate.cpp index 702ec44ee9e7576c0e8c8fd3ffc735517cd18ee2..afc4b5ee4fdb61414da9d70a01fbe60a31212468 100644 --- a/src/live_effects/lpe-copy_rotate.cpp +++ b/src/live_effects/lpe-copy_rotate.cpp @@ -105,11 +105,45 @@ LPECopyRotate::LPECopyRotate(LivePathEffectObject *lpeobject) : previous_start_point = Geom::Point(0,0); starting_point.param_widget_is_visible(false); reset = false; + lpesatellites.setPreserveSlots(true); + fixLegacy(); } LPECopyRotate::~LPECopyRotate() = default; +void +LPECopyRotate::fixLegacy() +{ + if (!is_load) { + return; + } + Glib::ustring version = lpeversion.param_getSVGValue(); + if (version < "1.2") { + if (split_items) { + for (size_t i = 0; i< num_copies; i++) { + Glib::ustring id = Glib::ustring("rotated-"); + id += std::to_string(i); + id += "-"; + id += this->lpeobj->getId(); + if (id.empty()) { + return; + } + SPObject *elemref = SP_ACTIVE_DOCUMENT->getObjectById(id.c_str()); + if (elemref) { + lpesatellites.link(elemref, i); + } + } + std::vector lpeitems = getCurrrentLPEItems(); + if (lpeitems.size() == 1) { + sp_lpe_item = lpeitems[0]; + sp_lpe_item_update_patheffect(sp_lpe_item, false, false); + } + } + lpeversion.param_setValue("1.2", true); + } +} + void LPECopyRotate::doAfterEffect (SPLPEItem const* lpeitem, SPCurve *curve) { @@ -118,23 +152,26 @@ LPECopyRotate::doAfterEffect (SPLPEItem const* lpeitem, SPCurve *curve) if (!document) { return; } - items.clear(); + /* Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (prefs->getBool("/live_effects/satelleitesiddle", false)) { + return; + } */ + if (lpeitem->on_ungroup) { + return; + } container = dynamic_cast(sp_lpe_item->parent); if (previous_num_copies != num_copies) { gint numcopies_gap = previous_num_copies - num_copies; if (numcopies_gap > 0 && num_copies != 0) { guint counter = num_copies - 1; - while (numcopies_gap > 0) { - Glib::ustring id = Glib::ustring("rotated-"); - id += std::to_string(counter); - id += "-"; - id += this->lpeobj->getId(); - if (id.empty()) { - return; - } - SPObject *elemref = document->getObjectById(id.c_str()); - if (elemref) { - SP_ITEM(elemref)->setHidden(true); + for (auto obj: lpesatellites._vector) { + if (obj) { + if (numcopies_gap > 0) { + SPItem *tohide = dynamic_cast(obj->getObject()); + if (tohide) { + tohide->setHidden(true); + } + } } counter++; numcopies_gap--; @@ -142,20 +179,7 @@ LPECopyRotate::doAfterEffect (SPLPEItem const* lpeitem, SPCurve *curve) } previous_num_copies = num_copies; } - 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(); - if (SP_ITEM(elemref)->isHidden()) { - items.push_back(id); - } - counter++; - } + Geom::Affine m = Geom::Translate(-origin) * Geom::Rotate(-(Geom::rad_from_deg(starting_angle))); for (size_t i = 1; i < num_copies; ++i) { Geom::Affine r = Geom::identity(); @@ -181,8 +205,39 @@ LPECopyRotate::doAfterEffect (SPLPEItem const* lpeitem, SPCurve *curve) } reset = false; } else { - processObjects(LPE_ERASE); - items.clear(); + processObjectsOK(LPE_ERASE); + lpesatellites.clear(); + } +} + +void +LPECopyRotate::doOnFork(SPLPEItem const *lpeitem, Effect const *preveffect) +{ + if (!preveffect) { + return; + } + std::vector lpeitems = preveffect->getCurrrentLPEItems(); + if (!lpeitems.size()) { + return; + } + SPLPEItem *previous = nullptr; + previous = lpeitems.back(); + if (!previous) { + return; + } + lpesatellites.clear(); + size_t counter = 0; + for (auto itemref : preveffect->lpesatellites._vector) { + if (!itemref) { + counter++; + continue; + } + SPObject *elemref = itemref->getObject(); + SPObject *forked_obj = elemref->document->getObjectById(elemref->forked_id); + if (elemref && forked_obj) { + lpesatellites.link(forked_obj,counter); + } + counter++; } } @@ -298,18 +353,19 @@ LPECopyRotate::toItem(Geom::Affine transform, size_t i, bool reset) 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(); - items.push_back(elemref_id); - SPObject *elemref = document->getObjectById(elemref_id.c_str()); + SPObject *elemref = nullptr; + if (lpesatellites._vector.size() > i) { + if (lpesatellites._vector[i]) { + elemref = lpesatellites._vector[i]->getObject(); + } + } Inkscape::XML::Node *phantom = nullptr; + bool cration = false; if (elemref) { phantom = elemref->getRepr(); } else { + cration = true; phantom = createPathBase(sp_lpe_item); - phantom->setAttribute("id", elemref_id); reset = true; elemref = container->appendChildRepr(phantom); elemref->parent->reorder(elemref, sp_lpe_item); @@ -319,11 +375,18 @@ LPECopyRotate::toItem(Geom::Affine transform, size_t i, bool reset) elemref->getRepr()->setAttributeOrRemoveIfEmpty("transform", sp_svg_transform_write(transform)); SP_ITEM(elemref)->setHidden(false); if (elemref->parent != container) { + if (!cration) { + lpesatellites.remove_link(elemref); + } Inkscape::XML::Node *copy = phantom->duplicate(xml_doc); - copy->setAttribute("id", elemref_id); - container->appendChildRepr(copy); + copy->setAttribute("id", elemref->getId()); + lpesatellites.link(container->appendChildRepr(copy), i); Inkscape::GC::release(copy); elemref->deleteObject(); + } else { + if (cration) { + lpesatellites.link(elemref, i); + } } } @@ -386,12 +449,14 @@ 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.2", true); } void LPECopyRotate::doBeforeEffect (SPLPEItem const* lpeitem) { using namespace Geom; + Glib::ustring version = lpeversion.param_getSVGValue(); original_bbox(lpeitem, false, true); if (copies_to_360 && num_copies > 2) { rotation_angle.param_set_value(360.0/(double)num_copies); @@ -661,7 +726,7 @@ LPECopyRotate::resetDefaults(SPItem const* item) void LPECopyRotate::doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/) { - processObjects(LPE_VISIBILITY); + processObjectsOK(LPE_VISIBILITY); } void @@ -669,17 +734,20 @@ LPECopyRotate::doOnRemove (SPLPEItem const* lpeitem) { std::vector lpeitems = getCurrrentLPEItems(); if (lpeitems.size() == 1) { + if (lpeitem->on_ungroup) { + return; + } sp_lpe_item = lpeitems[0]; if (!sp_lpe_item->path_effects_enabled) { return; } //set "keep paths" hook on sp-lpe-item.cpp if (keep_paths) { - processObjects(LPE_TO_OBJECTS); - items.clear(); + processObjectsOK(LPE_TO_OBJECTS); + lpesatellites.clear(); return; } - processObjects(LPE_ERASE); + processObjectsOK(LPE_ERASE); } } diff --git a/src/live_effects/lpe-copy_rotate.h b/src/live_effects/lpe-copy_rotate.h index ecfe1fed5a9e88a1884e37d060be5cb6d46c85ef..ab259bda48909a634c41af12debffd80fa307542 100644 --- a/src/live_effects/lpe-copy_rotate.h +++ b/src/live_effects/lpe-copy_rotate.h @@ -50,9 +50,11 @@ public: void doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/) override; Gtk::Widget * newWidget() override; void cloneStyle(SPObject *orig, SPObject *dest); + void doOnFork(SPLPEItem const *lpeitem, Effect const *preveffect) override; Geom::PathVector doEffect_path_post (Geom::PathVector const & path_in, FillRuleBool fillrule); void toItem(Geom::Affine transform, size_t i, bool reset); void cloneD(SPObject *orig, SPObject *dest, Geom::Affine transform, bool reset); + void fixLegacy(); Inkscape::XML::Node * createPathBase(SPObject *elemref); void resetStyles(); //virtual void setFusion(Geom::PathVector &path_in, Geom::Path divider, double sizeDivider); diff --git a/src/live_effects/lpe-offset.cpp b/src/live_effects/lpe-offset.cpp index 787d9b9780566e46a5b3e584e6a0022e0131227b..918bcae4288dfd07da8578287724b21fde77607b 100644 --- a/src/live_effects/lpe-offset.cpp +++ b/src/live_effects/lpe-offset.cpp @@ -271,7 +271,6 @@ void LPEOffset::doAfterEffect(SPLPEItem const * /*lpeitem*/, SPCurve *curve) _knot_entity->knot_get(); } } - is_load = false; } // TODO: find a way to not remove wanted self intersections diff --git a/src/live_effects/lpe-slice.cpp b/src/live_effects/lpe-slice.cpp index 3db6500d43491dbfcdbca034825517700a506e2c..994ac25f4b34683145c8d2c5decef07713437f5e 100644 --- a/src/live_effects/lpe-slice.cpp +++ b/src/live_effects/lpe-slice.cpp @@ -66,6 +66,7 @@ LPESlice::LPESlice(LivePathEffectObject *lpeobject) : allow_transforms_prev = allow_transforms; on_remove_all = false; parentlpe = nullptr; + lpesatellites.setPreserveSlots(true); } LPESlice::~LPESlice() @@ -219,103 +220,130 @@ LPESlice::originalDtoD(SPItem *item) void LPESlice::reloadOriginal(SPLPEItem const* lpeitem) { SPLPEItem *originallpeitem = getOriginal(lpeitem); + is_applied = false; if (originallpeitem) { - is_applied = false; - sp_lpe_item_update_patheffect(originallpeitem, false, true); + //sp_lpe_item_update_patheffect(originallpeitem, false, true); } } SPLPEItem *LPESlice::getOriginal(SPLPEItem const* lpeitem) { SPLPEItem *lpeparent = nullptr; - if (lpeitem->getAttribute("class")) { - gchar **strarray = g_strsplit(lpeitem->getAttribute("class"), " ", 0); - gchar **iter = strarray; - while (*iter != nullptr) { - Glib::ustring classsplited = *iter; - size_t pos = classsplited.rfind("-slice"); - if (pos != std::string::npos) { - classsplited = classsplited.replace(pos, 6, ""); - lpeparent = dynamic_cast(getSPDoc()->getObjectById(classsplited)); - if (lpeparent && lpeitem != lpeparent) { - g_strfreev(strarray); - return lpeparent; - } + std::vector result; + auto hreflist = lpeitem->hrefList; + for (auto obj : hreflist) { + LivePathEffectObject *lpeobject = dynamic_cast(obj); + if (lpeobject && lpeobject->get_lpe() && lpeobject->get_lpe()->getName() == "Slice") { + std::vector items = lpeobject->get_lpe()->getCurrrentLPEItems(); + if (items.size() > 0) { + lpeparent = items[0]; } - iter++; } - g_strfreev(strarray); } return lpeparent; } -gboolean allowreset(gpointer data) -{ - LPESlice *slice = reinterpret_cast(data); - sp_lpe_item_update_patheffect(slice->sp_lpe_item, false, false); - return FALSE; -} - -gboolean delayupdate(gpointer data) +void +LPESlice::doOnFork(SPLPEItem const *lpeitem, Effect const *preveffect) { - LPESlice *slice = reinterpret_cast(data); - sp_lpe_item_update_patheffect(slice->sp_lpe_item, false, false); - return FALSE; + if (!preveffect) { + return; + } + std::vector lpeitems = preveffect->getCurrrentLPEItems(); + if (!lpeitems.size()) { + return; + } + SPLPEItem *previous = nullptr; + previous = lpeitems.back(); + if (!previous) { + return; + } + SPLPEItem *sp_lpe_item = const_cast(lpeitem); + if (!sp_lpe_item) { + return; + } + //sp_lpe_item_enable_path_effects(sp_lpe_item, false); + lpesatellites.clear(); + lpesatellites.setUpdating(true); + size_t counter = 0; + for (auto itemref : preveffect->lpesatellites._vector) { + if (!itemref) { + counter++; + continue; + } + + SPObject *elemref = itemref->getObject(); + if (elemref) { + SPObject *forked_obj = elemref->document->getObjectById(elemref->forked_id); + if (!forked_obj) { + Inkscape::XML::Node *phantom = createPathBase(elemref); + forked_obj = sp_lpe_item->parent->appendChildRepr(phantom); + Glib::ustring unoptimiced = "UnoptimicedTransforms"; + phantom->setAttribute("class", unoptimiced.c_str()); + phantom->setAttribute("d", nullptr); + Inkscape::GC::release(phantom); + } + lpesatellites.link(forked_obj, counter); + } + counter++; + } + lpesatellites.setUpdating(false); + //sp_lpe_item_enable_path_effects(sp_lpe_item, true); } void LPESlice::doAfterEffect (SPLPEItem const* lpeitem, SPCurve *curve) { bool cleanup = is_load && SP_ACTIVE_DESKTOP; // don't crash on tests + bool is_applied_on = false; if (is_applied) { - cleanup = true; - reloadOriginal(lpeitem); + is_applied_on = true; + is_applied = false; + //reloadOriginal(lpeitem); } LPESlice *nextslice = dynamic_cast(sp_lpe_item->getNextLPE(this)); - if (!nextslice || !nextslice->is_visible) { - if (boundingbox_X.isSingular() || boundingbox_Y.isSingular()) { - return; - } - std::vector lpeitems = getCurrrentLPEItems(); - if (lpeitems.size() != 1) { - return; + if (is_visible && (!nextslice || !nextslice->is_visible)) { + LPESlice *prevslice = dynamic_cast(sp_lpe_item->getPrevLPE(this)); + if (prevslice && is_applied_on) { + /* sp_lpe_item_enable_path_effects(sp_lpe_item, false); + lpesatellites.param_readSVGValue(prevslice->lpesatellites.param_getSVGValue().c_str()); + prevslice->lpesatellites.clear(); */ } - Glib::ustring theclass = lpeitem->getId(); - theclass += "-slice"; - //ungroup - if (!is_load && parentlpe && parentlpe != sp_lpe_item->parent && parentlpe != sp_lpe_item->parent->parent) { - parentlpe = sp_lpe_item->parent; - g_timeout_add(250, &delayupdate, this); + if (boundingbox_X.isSingular() || boundingbox_Y.isSingular()) { + for (auto & iter : lpesatellites._vector) { + SPObject *elemref; + if (iter && iter->isAttached() && (elemref = iter->getObject())) { + SPLPEItem *splpeitem = dynamic_cast(elemref); + if (splpeitem) { + splpeitem->setHidden(true); + } + } + } return; - } else if (!is_load && parentlpe && parentlpe != sp_lpe_item->parent) { // group - g_timeout_add(250, &allowreset, this); - cleanup = true; - } - parentlpe = sp_lpe_item->parent; - items.clear(); + } + std::vector > slicer = getSplitLines(); if (!slicer.size()) { return; } - for (auto item : getSPDoc()->getObjectsByClass(theclass)) { - SPItem *extraitem = dynamic_cast(item); - if (extraitem) { - extraitem->setHidden("true"); - } - } + objindex = 0; + legacy = false; split(sp_lpe_item, curve, slicer, 0); - std::vector newitemstmp; - newitemstmp.assign(items.begin(), items.end()); - items.clear(); + parentlpe = lpeitem->parent; bool maindata = sp_has_path_data(sp_lpe_item, false); - if (!maindata) { - Glib::ustring theclass = lpeitem->getId(); - theclass += "-slice"; - for (auto item : getSPDoc()->getObjectsByClass(theclass)) { - SPLPEItem *splpeitem = dynamic_cast(item); - splpeitem->setHidden(true); - sp_lpe_item_update_patheffect(splpeitem, false, false); + for (auto & iter : lpesatellites._vector) { + SPObject *elemref; + if (iter && iter->isAttached() && (elemref = iter->getObject())) { + SPLPEItem *splpeitem = dynamic_cast(elemref); + if (splpeitem || lpeitem->isHidden()) { + if (!maindata || lpeitem->isHidden()) { + splpeitem->setHidden(true); + } + sp_lpe_item_update_patheffect(splpeitem, false, false); + } } + } + if (!maindata) { if (!curve) { // group originalDtoD(sp_lpe_item); } else { @@ -323,108 +351,139 @@ LPESlice::doAfterEffect (SPLPEItem const* lpeitem, SPCurve *curve) } return; } - bool hidden = sp_lpe_item->isHidden(); - for (auto item: newitemstmp) { - SPItem *spitem = dynamic_cast(getSPDoc()->getObjectById(item.c_str())); - SPLPEItem *splpeitem = dynamic_cast(spitem); - if (hidden) { - splpeitem->setHidden("true"); - } - if (spitem && sp_has_path_data(spitem, false)) { - items.push_back(item); - sp_lpe_item_update_patheffect(splpeitem, false, false); - } - } - for (auto item : getSPDoc()->getObjectsByClass(theclass)) { - SPItem *extraitem = dynamic_cast(item); - if (extraitem) { - SPLPEItem *spitem = dynamic_cast(extraitem); - if (spitem && !sp_has_path_data(spitem, false)) { - if (cleanup) { - sp_lpe_item_update_patheffect(spitem, false, false); - spitem->deleteObject(true); - } else { - originalDtoD(spitem); + reset = false; + if (is_applied_on && prevslice) { + sp_lpe_item_update_patheffect(sp_lpe_item, false, false); + for (auto link : prevslice->lpesatellites._vector) { + if (link) { + SPGroup *spgrp = dynamic_cast(link->getObject()); + SPShape *spit = dynamic_cast(link->getObject()); + Glib::ustring transform = ""; + Glib::ustring patheffects = ""; + Geom::OptRect _gbbox = Geom::OptRect(); + if (spgrp) { + if (spgrp->getAttribute("transform")) { + transform = spgrp->getAttribute("transform"); + } + if (spgrp->getAttribute("inkscape:path-effect")) { + patheffects = spgrp->getAttribute("inkscape:path-effect"); + } + spgrp->setAttribute("transform", nullptr); + spgrp->setAttribute("inkscape:path-effect", nullptr); + _gbbox = spgrp->geometricBounds(); } - } else { - SPLPEItem *splpeitem = dynamic_cast(extraitem); - if (splpeitem && splpeitem->hasPathEffectOfType(SLICE)) { - sp_lpe_item_update_patheffect(splpeitem, false, false); + if (spit || spgrp) { + for (auto link2 : lpesatellites._vector) { + if (link2) { + SPGroup *spgrp2 = dynamic_cast(link2->getObject()); + SPShape *spit2 = dynamic_cast(link2->getObject()); + if (spit && spit2) { + auto edit = SPCurve::copy(spit->curveForEdit()); + auto edit2 = SPCurve::copy(spit2->curveForEdit()); + Geom::OptRect _bbox = edit->get_pathvector().boundsFast(); + Geom::OptRect _bbox2 = edit2->get_pathvector().boundsFast(); + if (_bbox && _bbox2) { + if ((*_bbox).roundOutwards() == (*_bbox2).roundOutwards()) { + spit2->setAttribute("transform", spit->getAttribute("transform")); + spit2->setAttribute("inkscape:path-effect", spit->getAttribute("inkscape:path-effect")); + spit2->setAttribute("style", spit->getAttribute("style")); + break; + } + } + } else if (spgrp && spgrp2) { + Geom::OptRect _gbbox2 = spgrp2->geometricBounds(); + if (_gbbox && _gbbox2) { + if ((*_gbbox).roundOutwards() == (*_gbbox2).roundOutwards()) { + spgrp2->setAttribute("transform", transform); + spgrp2->setAttribute("inkscape:path-effect", patheffects); + cloneStyle(spgrp, spgrp2); + break; + } + } + } + } + } + if (spgrp) { + spgrp->setAttribute("transform", transform); + spgrp->setAttribute("inkscape:path-effect", patheffects); + } } } } } - reset = false; + } else { + for (auto itemrf : lpesatellites._vector) { + if (itemrf) { + SPLPEItem *splpeitem = dynamic_cast(itemrf->getObject()); + if (splpeitem) { + splpeitem->setHidden(true); + sp_lpe_item_update_patheffect(splpeitem, false, false); + } + } + } } } -void +bool LPESlice::split(SPItem* item, SPCurve *curve, std::vector > slicer, size_t splitindex) { + bool splited = false; + size_t nsplits = slicer.size(); SPDocument *document = getSPDoc(); if (!document) { - return; + return splited; } - Glib::ustring elemref_id = Glib::ustring("slice-"); - elemref_id += Glib::ustring::format(slicer[splitindex].second); - elemref_id += "-"; - Glib::ustring clean_id = item->getId(); - SPLPEItem *lpeitem = dynamic_cast(item); - if (!lpeitem) { - return; + + SPObject *elemref = nullptr; + if (objindex < lpesatellites._vector.size() && lpesatellites._vector[objindex]) { + elemref = lpesatellites._vector[objindex]->getObject(); } - //First check is to allow effects on "satellites" - if (!lpeitem->hasPathEffectOfType(SLICE) && clean_id.find("slice-") != Glib::ustring::npos) { - clean_id = clean_id.replace(0,6,""); - elemref_id += clean_id; - } else { - elemref_id += clean_id; - } - - items.push_back(elemref_id); - - SPObject *elemref = getSPDoc()->getObjectById(elemref_id.c_str()); bool prevreset = reset; if (!elemref) { - reset = true; - Inkscape::XML::Node *phantom = createPathBase(item); - phantom->setAttribute("id", elemref_id); - Glib::ustring classes = sp_lpe_item->getId(); - classes += "-slice UnoptimicedTransforms"; - phantom->setAttribute("class", classes.c_str()); - elemref = parentlpe->appendChildRepr(phantom); - Inkscape::GC::release(phantom); - parentlpe->reorder(elemref, sp_lpe_item); - } - Inkscape::XML::Document *xml_doc = getSPDoc()->getReprDoc(); - if (elemref && elemref->parent != parentlpe) { - Inkscape::XML::Node *repr = elemref->getRepr(); - Inkscape::XML::Node *copy = repr->duplicate(xml_doc); - if (copy) { - parentlpe->addChild(copy, sp_lpe_item->getRepr()); - // Retrieve the SPItem of the resulting repr. - SPObject *sucessor = document->getObjectByRepr(copy); - if (sucessor) { - sp_object_ref(elemref); - Inkscape::GC::anchor(repr); - elemref->deleteObject(false); - sucessor->setAttribute("id", elemref_id); - Inkscape::GC::release(repr); - elemref->setSuccessor(sucessor); - sp_object_unref(elemref); - elemref = dynamic_cast(sucessor); - g_assert(item != nullptr); + Glib::ustring elemref_id = Glib::ustring("slice-"); + elemref_id += Glib::ustring::format(slicer[splitindex].second); + elemref_id += "-"; + Glib::ustring clean_id = item->getId(); + //First check is to allow effects on "satellittes" + SPLPEItem *lpeitem = dynamic_cast(item); + if (!lpeitem) { + return splited; + } + if (!lpeitem->hasPathEffectOfType(SLICE) && clean_id.find("slice-") != Glib::ustring::npos) { + clean_id = clean_id.replace(0,6,""); + elemref_id += clean_id; + } else { + elemref_id += clean_id; + } + if (is_load && (elemref = document->getObjectById(elemref_id))) { + legacy = true; + lpesatellites.link(elemref, objindex); + } else { + reset = true; + Inkscape::XML::Node *phantom = createPathBase(item); + if (!parentlpe) { + return splited; } + elemref = parentlpe->appendChildRepr(phantom); + Glib::ustring unoptimiced = "UnoptimicedTransforms"; + phantom->setAttribute("class", unoptimiced.c_str()); + Inkscape::GC::release(phantom); + parentlpe->reorder(elemref, sp_lpe_item); + lpesatellites.link(elemref, objindex); } } + SPItem *other = dynamic_cast(elemref); if (other) { + objindex++; other->setHidden(false); - size_t nsplits = slicer.size(); if (nsplits) { cloneD(item, other, false); reset = prevreset; - splititem(item, curve, slicer[splitindex], true); + splited = splititem(item, curve, slicer[splitindex], true); splititem(other, nullptr, slicer[splitindex], false); + if (!splited) { + other->setHidden(true); + } splitindex++; if (nsplits > splitindex) { SPLPEItem *splpeother = dynamic_cast(other); @@ -438,6 +497,7 @@ LPESlice::split(SPItem* item, SPCurve *curve, std::vector > @@ -447,12 +507,10 @@ LPESlice::getSplitLines() { if (prevslice) { splitlines = prevslice->getSplitLines(); } - if (isVisible()) { - Geom::Line line_separation((Geom::Point)start_point, (Geom::Point)end_point); - size_t index = sp_lpe_item->getLPEIndex(this); - std::pair slice = std::make_pair(line_separation, index); - splitlines.push_back(slice); - } + Geom::Line line_separation((Geom::Point)start_point, (Geom::Point)end_point); + size_t index = sp_lpe_item->getLPEIndex(this); + std::pair slice = std::make_pair(line_separation, index); + splitlines.push_back(slice); return splitlines; } @@ -519,12 +577,7 @@ LPESlice::cloneD(SPObject *orig, SPObject *dest, bool is_original) SPPath * path = SP_PATH(dest); SPLPEItem *splpeitem = dynamic_cast(path); if (path && shape && splpeitem) { - SPCurve const *c; - if (!is_original && shape->hasPathEffectRecursive()) { - c = shape->curve(); - } else { - c = shape->curve(); - } + SPCurve const *c = shape->curve(); if (c && !c->is_empty()) { auto str = sp_svg_write_path(c->get_pathvector()); if (path->hasPathEffectRecursive()) { @@ -582,15 +635,16 @@ static fill_typ GetFillTyp(SPItem *item) } } -void +bool LPESlice::splititem(SPItem* item, SPCurve * curve, std::pair slicer, bool toggle, bool is_original) { + bool splited = false; if (!is_original && !g_strcmp0(sp_lpe_item->getId(), item->getId())) { is_original = true; } Geom::Line line_separation = slicer.first; // check top level split/sp_lpe_item item - SPObject *top = sp_lpe_item->parent; + /* SPObject *top = sp_lpe_item->parent; SPObject *other = item; while (other && other->parent) { if (other->parent != top) { @@ -603,8 +657,8 @@ LPESlice::splititem(SPItem* item, SPCurve * curve, std::pair if (topitem && topitem != item) { Geom::Affine ptransform = item->getRelativeTransform(topitem); ptransform *= item->document->doc2dt(); - line_separation *= ptransform.inverse(); - } + //line_separation *= ptransform.inverse(); + } */ Geom::Point s = line_separation.initialPoint(); Geom::Point e = line_separation.finalPoint(); Geom::Point center = Geom::middle_point(s, e); @@ -614,14 +668,15 @@ LPESlice::splititem(SPItem* item, SPCurve * curve, std::pair for (auto &child : childs) { SPItem *dest_child = dynamic_cast(child); // groups not need update curve - splititem(dest_child, nullptr, slicer, toggle, is_original); + splited = splititem(dest_child, nullptr, slicer, toggle, is_original) ? true : splited; } if (!is_original && group->hasPathEffectRecursive()) { sp_lpe_item_update_patheffect(group, false, false); } - return; + return splited; } SPShape *shape = dynamic_cast(item); + SPPath *path = dynamic_cast(item); if (shape) { SPCurve const *c; c = shape->curve(); @@ -725,7 +780,10 @@ LPESlice::splititem(SPItem* item, SPCurve * curve, std::pair } } if (cs.size() == 0 && position == 1) { - tmp_pathvector.push_back(original); + splited = false; + tmp_pathvector.push_back(original); + } else { + splited = true; } path_out.insert(path_out.end(), tmp_pathvector.begin(), tmp_pathvector.end()); tmp_pathvector.clear(); @@ -742,7 +800,11 @@ LPESlice::splititem(SPItem* item, SPCurve * curve, std::pair auto str = sp_svg_write_path(path_out); if (!is_original && shape->hasPathEffectRecursive()) { sp_lpe_item_enable_path_effects(shape, false); - shape->setAttribute("inkscape:original-d", str); + if (path) { + shape->setAttribute("inkscape:original-d", str); + } else { + shape->setAttribute("d", str); + } sp_lpe_item_enable_path_effects(shape, true); } else { shape->setAttribute("d", str); @@ -750,6 +812,7 @@ LPESlice::splititem(SPItem* item, SPCurve * curve, std::pair } } } + return splited; } void @@ -792,7 +855,7 @@ LPESlice::doBeforeEffect (SPLPEItem const* lpeitem) center_point.param_setValue(previous_center); return; } - if (are_near(previous_center, (Geom::Point)center_point, 0.01)) { + if (are_near(previous_center, (Geom::Point)center_point, 0.001)) { center_point.param_setValue(Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point)); } else { Geom::Point trans = center_point - Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point); @@ -852,39 +915,34 @@ LPESlice::resetStyles(){ } } -//TODO: Migrate the tree next function to effect.cpp/h to avoid duplication void LPESlice::doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/) { - processObjects(LPE_VISIBILITY); + if (!is_visible) { + for (auto itemrf : lpesatellites._vector) { + if (itemrf) { + SPLPEItem *splpeitem = dynamic_cast(itemrf->getObject()); + if (splpeitem) { + splpeitem->setHidden(true); + sp_lpe_item_update_patheffect(splpeitem, false, false); + } + } + } + } } void LPESlice::doOnRemove(SPLPEItem const* lpeitem) { - items.clear(); std::vector lpeitems = getCurrrentLPEItems(); - if (lpeitems.size() == 1) { + if (lpeitems.size() > 0) { sp_lpe_item = lpeitems[0]; - if (!sp_lpe_item->path_effects_enabled) { - return; - } - Glib::ustring theclass = sp_lpe_item->getId(); - theclass += "-slice"; - for (auto item : getSPDoc()->getObjectsByClass(theclass)) { - items.emplace_back(item->getId()); - } if (keep_paths) { - processObjects(LPE_TO_OBJECTS); - items.clear(); + processObjectsOK(LPE_TO_OBJECTS); return; } - if (sp_lpe_item->countLPEOfType(SLICE) == 1 || on_remove_all) { - processObjects(LPE_ERASE); - } else { - sp_lpe_item_update_patheffect(sp_lpe_item, false, false); - } + processObjectsOK(LPE_ERASE_UNREF); } } @@ -908,6 +966,7 @@ LPESlice::doOnApply (SPLPEItem const* lpeitem) center_point.param_setValue(point_c, true); end_point.param_update_default(point_c); previous_center = center_point; + lpeversion.param_setValue("1.2", true); } diff --git a/src/live_effects/lpe-slice.h b/src/live_effects/lpe-slice.h index f89649a69930cf588cf501d1b8721ba6736dea3f..c4bdf7dee0eb0acfbc1c793940fcbf30375d7a91 100644 --- a/src/live_effects/lpe-slice.h +++ b/src/live_effects/lpe-slice.h @@ -36,13 +36,14 @@ public: void doOnApply (SPLPEItem const* lpeitem) override; void doBeforeEffect (SPLPEItem const* lpeitem) override; void doAfterEffect (SPLPEItem const* lpeitem, SPCurve *curve) override; + void doOnFork(SPLPEItem const *lpeitem, Effect const *preveffect) override; Geom::PathVector doEffect_path (Geom::PathVector const & path_in) override; void doOnRemove (SPLPEItem const* /*lpeitem*/) override; void doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/) override; - Gtk::Widget * newWidget() override; + Gtk::Widget *newWidget() override; void cloneStyle(SPObject *orig, SPObject *dest); - void split(SPItem* item, SPCurve *curve, std::vector > slicer, size_t splitindex); - void splititem(SPItem* item, SPCurve * curve, std::pair slicer, bool toggle, bool is_original = false); + bool split(SPItem* item, SPCurve *curve, std::vector > slicer, size_t splitindex); + bool splititem(SPItem* item, SPCurve * curve, std::pair slicer, bool toggle, bool is_original = false); bool haschildslice(SPItem *item); std::vector > getSplitLines(); void cloneD(SPObject *orig, SPObject *dest, bool is_original); @@ -55,6 +56,7 @@ public: void resetStyles(); void centerVert(); void centerHoriz(); + SPObject *parentlpe; protected: void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector &hp_vec) override; @@ -70,7 +72,8 @@ private: bool center_vert; bool center_horiz; bool allow_transforms_prev; - SPObject *parentlpe; + size_t objindex = 0; + bool legacy = false; LPESlice(const LPESlice&) = delete; LPESlice& operator=(const LPESlice&) = delete; }; diff --git a/src/live_effects/parameter/item-reference.h b/src/live_effects/parameter/item-reference.h index 64aaac0a77344d328b73df69dae510b68d76a789..0e8395ad9336f89f158a77ab608b1ea67239eabc 100644 --- a/src/live_effects/parameter/item-reference.h +++ b/src/live_effects/parameter/item-reference.h @@ -11,9 +11,13 @@ */ #include "object/uri-references.h" +#include "object/sp-object.h" +#include +#include class SPItem; namespace Inkscape { + namespace XML { class Node; } namespace LivePathEffect { @@ -37,6 +41,40 @@ private: ItemReference& operator=(const ItemReference&) = delete; }; +class LPEItemRef : public Inkscape::URIReference { +public: + LPEItemRef(SPObject *owner) : URIReference(owner) {}; + ~LPEItemRef() override { + linked_delete_connection.disconnect(); + linked_modified_connection.disconnect(); + linked_transformed_connection.disconnect(); + linked_changed_connection.disconnect(); + owner_release_connection.disconnect(); + if (isAttached()) { + detach(); + } + if (href) { + g_free(href); + href = nullptr; + } + }; + sigc::connection owner_release_connection = getOwner()->connectRelease([this](SPObject *obj) { + // Fully detach to prevent reconnecting with a modified signal + owner_release_connection.disconnect(); + if (isAttached()) { + detach(); + } + }); + sigc::connection linked_changed_connection; + sigc::connection linked_delete_connection; + sigc::connection linked_modified_connection; + sigc::connection linked_transformed_connection; + gchar *href; +private: + LPEItemRef(const LPEItemRef&) = delete; + LPEItemRef& operator=(const LPEItemRef&) = delete; +}; + } // namespace LivePathEffect } // namespace Inkscape diff --git a/src/live_effects/parameter/item.cpp b/src/live_effects/parameter/item.cpp index b31b28120b970f9521d89192538de6b0a55b8e42..7e72f04f11845f61e2eab4b0856761331855ddc3 100644 --- a/src/live_effects/parameter/item.cpp +++ b/src/live_effects/parameter/item.cpp @@ -166,7 +166,23 @@ ItemParam::emit_changed() changed = true; signal_item_changed.emit(); } - +void +ItemParam::param_relink() +{ + const gchar *newhref = param_effect->getLPEObj()->getAttribute(param_key.c_str()); + if (newhref) { + Glib::ustring id = newhref; + id = id.erase(0,1); + if (param_effect->getSPDoc()->getObjectById(id)) { + try { + ref.attach(Inkscape::URI(newhref)); + } catch (Inkscape::BadURIException &e) { + g_warning("%s", e.what()); + ref.detach(); + } + } + } +} void ItemParam::addCanvasIndicators(SPLPEItem const*/*lpeitem*/, std::vector &hp_vec) diff --git a/src/live_effects/parameter/item.h b/src/live_effects/parameter/item.h index 34644519e0e0a2316adcffd3fbb5c2979cf9b8d5..dc9bcafa544180492bc86bd7e25eb815fbb60b94 100644 --- a/src/live_effects/parameter/item.h +++ b/src/live_effects/parameter/item.h @@ -40,6 +40,7 @@ public: void param_update_default(const gchar * default_value) override; void param_set_and_write_default(); SPObject *param_fork(); + void param_relink(); void addCanvasIndicators(SPLPEItem const* lpeitem, std::vector &hp_vec) override; sigc::signal signal_item_pasted; sigc::signal signal_item_changed; diff --git a/src/live_effects/parameter/originalitemarrayhidden.cpp b/src/live_effects/parameter/originalitemarrayhidden.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a1d85ac2e492ebde802ff46feb77cef903c39f6b --- /dev/null +++ b/src/live_effects/parameter/originalitemarrayhidden.cpp @@ -0,0 +1,397 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) Theodore Janeczko 2012 + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include "live_effects/parameter/originalitemarrayhidden.h" +#include "live_effects/lpeobject.h" + +#include +#include +#include +#include +#include + +#include + +#include "inkscape.h" +#include "originalitem.h" +#include "svg/stringstream.h" +#include "svg/svg.h" +#include "ui/clipboard.h" +#include "ui/icon-loader.h" + +#include "object/uri.h" + +#include "live_effects/effect.h" + +#include "verbs.h" +#include "document-undo.h" +#include "document.h" + +namespace Inkscape { + +namespace LivePathEffect { + + +OriginalItemArrayHiddenParam::OriginalItemArrayHiddenParam( const Glib::ustring& label, + const Glib::ustring& tip, + const Glib::ustring& key, + Inkscape::UI::Widget::Registry* wr, + Effect* effect, + bool preserve_slots) +: Parameter(label, tip, key, wr, effect), + _vector(), _preserve_slots(preserve_slots) +{ + param_widget_is_visible(false); +} + +OriginalItemArrayHiddenParam::~OriginalItemArrayHiddenParam() +{ + _updating = true; + while (!_vector.empty()) { + LPEItemRef *w = _vector.back(); + if (w) { + delete w; + } + w = nullptr; + _vector.pop_back(); + } + _updating = false; +} + +void OriginalItemArrayHiddenParam::param_set_default() +{ + +} + +Gtk::Widget * +OriginalItemArrayHiddenParam::param_newWidget() +{ + return nullptr; +} + + +void +OriginalItemArrayHiddenParam::link(SPObject *obj, size_t pos) +{ + _updating = true; + Glib::ustring itemid = ""; + if (obj && obj->getId()) { + itemid = obj->getId(); + itemid.insert(itemid.begin(), '#'); + } + size_t counter = 0; + bool inserted = false; + bool foundOne = false; + Inkscape::SVGOStringStream os; + for (auto &iter : _vector) { + if (counter == pos) { + _last = counter; + if (foundOne) { + os << ";"; + } else { + foundOne = true; + } + os << itemid.c_str(); + inserted = true; + if (iter) { + LPEItemRef *w = iter; + if (w) { + delete w; + } + w = nullptr; + iter = nullptr; + } + } else { + if (foundOne) { + os << ";"; + } else { + foundOne = true; + } + os << (iter == nullptr ? "" : iter->href); + } + counter++; + } + + if (!inserted) { + if (foundOne) { + os << ";"; + } + _last = counter; + os << itemid.c_str(); + } + Glib::ustring val = os.str().erase (os.str().find_last_not_of(';') + 1, std::string::npos ); + _vector.clear(); + param_readSVGValue(val.c_str()); + param_write_to_repr(val.c_str()); + _updating = false; +} + +void +OriginalItemArrayHiddenParam::multilink(std::vector objs) +{ + if (objs.empty()) { + return; + } + _updating = true; + clear(); + bool foundOne = false; + Inkscape::SVGOStringStream os; + for (auto &obj : objs) { + Glib::ustring itemid = ""; + if (obj && obj->getId()) { + itemid = obj->getId(); + itemid.insert(itemid.begin(), '#'); + } + if (foundOne) { + os << ";"; + } else { + foundOne = true; + } + os << itemid; + } + Glib::ustring val = os.str().erase (os.str().find_last_not_of(';') + 1, std::string::npos ); + _vector.clear(); + param_readSVGValue(val.c_str()); + param_write_to_repr(val.c_str()); + _updating = false; +} + +void +OriginalItemArrayHiddenParam::remove_link(SPObject *obj) +{ + if (!obj) { + return; + } + for (std::vector::iterator iter = _vector.begin(); iter != _vector.end(); ++iter) { + LPEItemRef *w = *iter; + if (w && w->getObject() == obj) { + remove_link(w); + } + } +} + +void +OriginalItemArrayHiddenParam::unlink(SPObject *obj) +{ + if (!obj) { + return; + } + for (std::vector::iterator iter = _vector.begin(); iter != _vector.end(); ++iter) { + LPEItemRef *w = *iter; + if (w && w->getObject() == obj) { + unlink(w); + } + } +} + +void OriginalItemArrayHiddenParam::unlink(LPEItemRef* to) +{ + if (!to) { + return; + } + to->linked_delete_connection.disconnect(); + to->linked_modified_connection.disconnect(); + to->linked_transformed_connection.disconnect(); + to->linked_changed_connection.disconnect(); + to->detach(); + if (to->href) { + g_free(to->href); + to->href = nullptr; + } +} + +void OriginalItemArrayHiddenParam::clear() +{ + _updating = true; + for (std::vector::reverse_iterator iter = _vector.rbegin(); iter != _vector.rend(); ++iter) { + LPEItemRef *w = *iter; + delete w; + w = nullptr; + } + _vector.clear(); + _updating = false; +} + +void OriginalItemArrayHiddenParam::remove_link(LPEItemRef* to) +{ + if (!to) { + return; + } + _updating = true; + std::vector _nvect = _vector; + _vector.clear(); + for (auto &w : _nvect) { + if (w == to) { + if (w) { + delete w; + } + if (_preserve_slots) { + _vector.push_back(nullptr); + } + w = nullptr; + } else { + _vector.push_back(w); + } + } + _updating = false; +} + +void OriginalItemArrayHiddenParam::linked_delete(SPObject */*deleted*/, LPEItemRef* to) +{ + if (_updating) { + return; + } + if (!to) { + return; + } + remove_link(to); + auto full = param_getSVGValue(); + param_write_to_repr(full.c_str()); +} + + +void OriginalItemArrayHiddenParam::linked_changed(SPObject *old_obj, SPObject *new_obj, LPEItemRef* to) +{ + if (_updating) { + return; + } + if (!to) { + return; + } + to->linked_delete_connection.disconnect(); + to->linked_transformed_connection.disconnect(); + to->linked_modified_connection.disconnect(); + if (new_obj) { + //param_effect->getLPEObj()->connectRelease(sigc::mem_fun(*this, &OriginalItemArrayHiddenParam::lpeobject_released)); + to->linked_delete_connection = new_obj->connectDelete(sigc::bind(sigc::mem_fun(*this, &OriginalItemArrayHiddenParam::linked_delete), to)); + to->linked_modified_connection = new_obj->connectModified(sigc::bind(sigc::mem_fun(*this, &OriginalItemArrayHiddenParam::linked_modified), to)); + SPItem *item = dynamic_cast(new_obj); + if (item) { + to->linked_transformed_connection = item->connectTransformed(sigc::bind(sigc::mem_fun(*this, &OriginalItemArrayHiddenParam::linked_transformed), to)); + } + linked_modified(new_obj, SP_OBJECT_MODIFIED_FLAG, to); + } else { + param_effect->getLPEObj()->requestModified(SP_OBJECT_MODIFIED_FLAG); + } +} + +void +OriginalItemArrayHiddenParam::linked_transformed(Geom::Affine const *rel_transf, SPItem *item, LPEItemRef* to) +{ + param_effect->getLPEObj()->requestModified(SP_OBJECT_MODIFIED_FLAG); +} + +void OriginalItemArrayHiddenParam::linked_modified(SPObject *linked_obj, guint flags, LPEItemRef* to) +{ + if (_updating) { + return; + } + _updating = true; + if (!to) { + return; + } + if (param_effect->effectType() != SLICE) { + param_effect->getLPEObj()->requestModified(SP_OBJECT_MODIFIED_FLAG); + } + _updating = false; +} + +bool OriginalItemArrayHiddenParam::param_readSVGValue(const gchar* strvalue) +{ + if (strvalue) { + _updating = true; + while (!_vector.empty()) { + if (!_vector.back()) { + _vector.pop_back(); + continue; + } + LPEItemRef *w = _vector.back(); + if (w) { + unlink(w); + } + _vector.pop_back(); + w = nullptr; + } + if (strvalue && strvalue != "") { + gchar ** strarray = g_strsplit(strvalue, ";", 0); + for (gchar ** iter = strarray; *iter != nullptr; iter++) { + bool hrefset = false; + if ((*iter)[0] == '#') { + std::string id(*iter+1); + SPObject *lpeobj = dynamic_cast(param_effect->getLPEObj()); + if (lpeobj) { + if (lpeobj->document->getObjectById(id) || param_effect->is_load) { + LPEItemRef* w = new LPEItemRef(lpeobj); + if (w) { + w->href = g_strdup(*iter); + w->attach(URI(w->href)); + linked_changed(nullptr, w->getObject(), w); + _vector.push_back(w); + hrefset = true; + } + } + } + } + if (!hrefset) { + _vector.push_back(nullptr); + } + } + g_strfreev (strarray); + } + _updating = false; + return true; + } + return false; +} + +Glib::ustring +OriginalItemArrayHiddenParam::param_getSVGValue() const +{ + Inkscape::SVGOStringStream os; + bool foundOne = false; + for (auto iter : _vector) { + if (foundOne) { + os << ";"; + } else { + foundOne = true; + } + os << (iter == nullptr ? "" : iter->href); + } + return os.str(); +} + +Glib::ustring +OriginalItemArrayHiddenParam::param_getDefaultSVGValue() const +{ + return ""; +} + +void OriginalItemArrayHiddenParam::update() +{ + for (auto & iter : _vector) { + SPObject *linked_obj = nullptr; + if (iter) { + linked_obj = iter->getObject(); + } + linked_modified(linked_obj, SP_OBJECT_MODIFIED_FLAG, iter); + } +} + +} /* namespace LivePathEffect */ + +} /* 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 : diff --git a/src/live_effects/parameter/originalitemarrayhidden.h b/src/live_effects/parameter/originalitemarrayhidden.h new file mode 100644 index 0000000000000000000000000000000000000000..8c55b283521d2dc8e8c37b7a333e4bb675abe0e9 --- /dev/null +++ b/src/live_effects/parameter/originalitemarrayhidden.h @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#ifndef INKSCAPE_LIVEPATHEFFECT_PARAMETER_ORIGINALITEMARRAYHIDDEN_H +#define INKSCAPE_LIVEPATHEFFECT_PARAMETER_ORIGINALITEMARRAYHIDDEN_H + +/* + * Inkscape::LivePathEffectParameters + * + * Copyright (C) Theodore Janeczko 2012 + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include + +#include "live_effects/parameter/parameter.h" +#include "live_effects/parameter/item-reference.h" + +#include "svg/svg.h" +#include "svg/stringstream.h" +#include "item-reference.h" + +class SPObject; +namespace Inkscape { + +namespace LivePathEffect { + +class OriginalItemArrayHiddenParam : public Parameter { +public: + class ModelColumns; + + OriginalItemArrayHiddenParam( const Glib::ustring& label, + const Glib::ustring& tip, + const Glib::ustring& key, + Inkscape::UI::Widget::Registry* wr, + Effect* effect, + bool preserve_slots = true); + + ~OriginalItemArrayHiddenParam() override; + Gtk::Widget * param_newWidget() override; + bool param_readSVGValue(const gchar * strvalue) override; + Glib::ustring param_getSVGValue() const override; + Glib::ustring param_getDefaultSVGValue() const override; + void param_set_default() override; + void param_update_default(const gchar * default_value) override{}; + std::vector _vector; + size_t getLastInsertPos() const {return _last;} + void setLastInsertPos(size_t last) {_last = last;} + void clear(); + void setUpdating(bool updating) {_updating = updating;} + bool getUpdating() const {return _updating;} + void setPreserveSlots(bool preserve_slots) {_preserve_slots = preserve_slots;} + bool getPreserveSlots() {return _preserve_slots;} + void setCheckIds(bool check_ids) {_check_ids = check_ids;} + bool getCheckIds() const {return _check_ids;} + void link(SPObject *to, size_t pos = Glib::ustring::npos); + void multilink(std::vector objs); + void unlink(SPObject *to); + void remove_link(SPObject *to); + +protected: + void unlink(LPEItemRef* to); + void remove_link(LPEItemRef* to); + void linked_changed(SPObject *old_obj, SPObject *new_obj, LPEItemRef* to); + void linked_modified(SPObject *linked_obj, guint flags, LPEItemRef* to); + void linked_transformed(Geom::Affine const *, SPItem *, LPEItemRef* to); + void linked_delete(SPObject *deleted, LPEItemRef* to); + +private: + bool _updating = false; + size_t _last = Glib::ustring::npos; + void update(); + bool _preserve_slots = false; + bool _check_ids = false; + OriginalItemArrayHiddenParam(const OriginalItemArrayHiddenParam&) = delete; + OriginalItemArrayHiddenParam& operator=(const OriginalItemArrayHiddenParam&) = delete; +}; + +} //namespace LivePathEffect + +} //namespace Inkscape + +#endif + +/* + 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 : diff --git a/src/live_effects/parameter/originalitemmaphidden.cpp b/src/live_effects/parameter/originalitemmaphidden.cpp new file mode 100644 index 0000000000000000000000000000000000000000..39f7ad079fbbf3d75191cdfaaebe6868ca8d81e0 --- /dev/null +++ b/src/live_effects/parameter/originalitemmaphidden.cpp @@ -0,0 +1,390 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) Theodore Janeczko 2012 + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include "live_effects/parameter/originalitemmaphidden.h" + +#include +#include +#include +#include +#include + +#include + +#include "inkscape.h" +#include "originalitem.h" +#include "svg/stringstream.h" +#include "svg/svg.h" +#include "ui/clipboard.h" +#include "ui/icon-loader.h" + +#include "object/uri.h" + +#include "live_effects/effect.h" + +#include "verbs.h" +#include "document-undo.h" +#include "document.h" + +namespace Inkscape { + +namespace LivePathEffect { + + +OriginalItemMapHiddenParam::OriginalItemMapHiddenParam( const Glib::ustring& label, + const Glib::ustring& tip, + const Glib::ustring& key, + Inkscape::UI::Widget::Registry* wr, + Effect* effect, + bool preserve_slots) +: Parameter(label, tip, key, wr, effect), + _map() +{ + param_widget_is_visible(false); +} + +OriginalItemMapHiddenParam::~OriginalItemMapHiddenParam() +{ + _updating = true; + for (auto &iter : _map) { + LPEItemRef *w = _map.second.second.back(); + if (w) { + unlink(w); + delete w; + } + w = nullptr; + } + _map.clear(); + _updating = false; +} + +void OriginalItemMapHiddenParam::param_set_default() +{ + +} + +Gtk::Widget * +OriginalItemMapHiddenParam::param_newWidget() +{ + return nullptr; +} + + +void +OriginalItemMapHiddenParam::link(Glib::ustring name, SPObject *obj, Glib::ustring previous) +{ + _updating = true; + Glib::ustring itemid = ""; + if (obj && obj->getId()) { + itemid = obj->getId(); + itemid.insert(itemid.begin(), '#'); + } + bool inserted = false; + bool foundOne = false; + Inkscape::SVGOStringStream os; + for (auto &iter : _map) { + if (iter.first == previous) { + if (foundOne) { + os << ";"; + } else { + foundOne = true; + } + os << name << | << itemid.c_str(); + inserted = true; + if (iter.second) { + LPEItemRef *w = iter.second; + if (w) { + unlink(w); + delete w; + } + w = nullptr; + iter.second = nullptr; + } + } else { + if (foundOne) { + os << ";"; + } else { + foundOne = true; + } + os << name << | << (iter == nullptr ? "" : iter.second.ref->href); + } + counter++; + } + + if (!inserted) { + if (foundOne) { + os << ";"; + } + os << name << | << itemid.c_str(); + } + _map.clear(); + param_readSVGValue(val.c_str()); + param_write_to_repr(val.c_str()); + _updating = false; +} + +void +OriginalItemMapHiddenParam::multilink(std::map objs) +{ + if (objs.empty()) { + return; + } + _updating = true; + clear(); + bool foundOne = false; + Inkscape::SVGOStringStream os; + for (auto &obj : objs) { + Glib::ustring itemid = ""; + if (obj.second && obj.second->getId()) { + itemid = obj.second->getId(); + itemid.insert(itemid.begin(), '#'); + } + if (foundOne) { + os << ";"; + } else { + foundOne = true; + } + os << obj.first << | << itemid; + } + _map.clear(); + param_readSVGValue(val.c_str()); + param_write_to_repr(val.c_str()); + _updating = false; +} + +void +OriginalItemMapHiddenParam::remove_link(Glib::ustring name) +{ + if (!obj) { + return; + } + LPEItemRef *refitem = _map.find(name); + if (refitem) { + unlink(refitem); + refitem = nullptr; + _map.erase(name) + } +} + +void +OriginalItemMapHiddenParam::unlink(SPObject *obj) +{ + if (!obj) { + return; + } + LPEItemRef *refitem = _map.find(name); + if (refitem) { + refitem->linked_delete_connection.disconnect(); + refitem->linked_modified_connection.disconnect(); + refitem->linked_transformed_connection.disconnect(); + refitem->linked_changed_connection.disconnect(); + refitem->ref.detach(); + if (refitem->href) { + g_free(to->href); + to->href = nullptr; + } + +} + +void OriginalItemMapHiddenParam::unlink(LPEItemRef* to) +{ + if (!to) { + return; + } + to->linked_delete_connection.disconnect(); + to->linked_modified_connection.disconnect(); + to->linked_transformed_connection.disconnect(); + to->linked_changed_connection.disconnect(); + to->ref.detach(); + if (to->href) { + g_free(to->href); + to->href = nullptr; + } +} + +void OriginalItemMapHiddenParam::clear() +{ + _updating = true; + for (std::vector::reverse_iterator iter = _map.second.rbegin(); iter != _map.second.rend(); ++iter) { + LPEItemRef *w = *iter; + unlink(w); + delete w; + w = nullptr; + } + _map.clear(); + _updating = false; +} + +void OriginalItemMapHiddenParam::remove_link(LPEItemRef* to) +{ + if (!to) { + return; + } + _updating = true; + std::vector _nvect = _map; + _map.clear(); + for (auto &w : _nvect) { + if (w == to) { + if (w) { + unlink(w); + delete w; + } + if (!_preserve_slots) { + _map.second.push_back(nullptr); + } + w = nullptr; + } else { + _map.second.push_back(w); + } + } + _updating = false; +} + +void OriginalItemMapHiddenParam::linked_delete(SPObject */*deleted*/, LPEItemRef* to) +{ + if (_updating) { + return; + } + if (!to) { + return; + } + remove_link(to); + auto full = param_getSVGValue(); + param_write_to_repr(full.c_str()); +} + +void OriginalItemMapHiddenParam::linked_changed(SPObject */*old_obj*/, SPObject *new_obj, LPEItemRef* to) +{ + if (!to) { + return; + } + to->linked_delete_connection.disconnect(); + to->linked_transformed_connection.disconnect(); + to->linked_modified_connection.disconnect(); + if (new_obj) { + //to->linked_release_connection = new_obj->connectRelease(sigc::bind<1>(sigc::ptr_fun(*this, &OriginalItemArrayHiddenParam::linked_released), to)); + to->linked_delete_connection = new_obj->connectDelete(sigc::bind(sigc::mem_fun(*this, &OriginalItemMapHiddenParam::linked_delete), to)); + to->linked_modified_connection = new_obj->connectModified(sigc::bind(sigc::mem_fun(*this, &OriginalItemMapHiddenParam::linked_modified), to)); + SPItem *item = dynamic_cast(new_obj); + if (item) { + to->linked_transformed_connection = item->connectTransformed(sigc::bind(sigc::mem_fun(*this, &OriginalItemMapHiddenParam::linked_transformed), to)); + } + linked_modified(new_obj, SP_OBJECT_MODIFIED_FLAG, to); + } else { + SP_OBJECT(param_effect->getLPEObj())->requestModified(SP_OBJECT_MODIFIED_FLAG); + } +} + +void +OriginalItemMapHiddenParam::linked_transformed(Geom::Affine const *rel_transf, SPItem *item, LPEItemRef* to) +{ + SP_OBJECT(param_effect->getLPEObj())->requestModified(SP_OBJECT_MODIFIED_FLAG); +} + +void OriginalItemMapHiddenParam::linked_modified(SPObject *linked_obj, guint flags, LPEItemRef* to) +{ + if (_updating) { + return; + } + _updating = true; + if (!to) { + return; + } + if (param_effect->effectType() != SLICE) { + SP_OBJECT(param_effect->getLPEObj())->requestModified(SP_OBJECT_MODIFIED_FLAG); + } + _updating = false; +} + +bool OriginalItemMapHiddenParam::param_readSVGValue(const gchar* strvalue) { + if (strvalue) { + _updating = true; + while (!_map.empty()) { + if (!_map.second.back()) { + _map.second.pop_back(); + continue; + } + LPEItemRef *w = _map.second.back(); + if (w) { + unlink(w); + delete w; + } + _map.second.pop_back(); + w = nullptr; + } + gchar ** strarray = g_strsplit(strvalue, ";", 0); + for (gchar ** iter = strarray; *iter != nullptr; iter++) { + if ((*iter)[0] == '#') { + LPEItemRef* w = new LPEItemRef((SPObject *)param_effect->getLPEObj()); + std::string id(*iter+1); + if (w && (!_check_ids || param_effect->getLPEObj()->document->getObjectById(id))) { + w->href = g_strdup(*iter); + w->ref.attach(URI(w->href)); + linked_changed(nullptr, w->ref.getObject(), w); + _map.second.push_back(w); + } else { + _map.second.push_back(nullptr); + } + } else { + _map.second.push_back(nullptr); + } + } + g_strfreev (strarray); + _updating = false; + return true; + } + _updating = false; + return false; +} + +Glib::ustring +OriginalItemMapHiddenParam::param_getSVGValue() const +{ + Inkscape::SVGOStringStream os; + bool foundOne = false; + for (auto iter : _map) { + if (foundOne) { + os << ";"; + } else { + foundOne = true; + } + os << (iter == nullptr ? "" : iter->href); + } + return os.str(); +} + +Glib::ustring +OriginalItemMapHiddenParam::param_getDefaultSVGValue() const +{ + return ""; +} + +void OriginalItemMapHiddenParam::update() +{ + for (auto & iter : _map) { + SPObject *linked_obj = nullptr; + if (iter) { + linked_obj = iter->ref.getObject(); + } + linked_modified(linked_obj, SP_OBJECT_MODIFIED_FLAG, iter); + } +} + +} /* namespace LivePathEffect */ + +} /* 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 : diff --git a/src/live_effects/parameter/originalitemmaphidden.h b/src/live_effects/parameter/originalitemmaphidden.h new file mode 100644 index 0000000000000000000000000000000000000000..6d0d1a4efed277d126bb2c55761b974ea14fe571 --- /dev/null +++ b/src/live_effects/parameter/originalitemmaphidden.h @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#ifndef INKSCAPE_LIVEPATHEFFECT_PARAMETER_ORIGINALITEMARRAYHIDDEN_H +#define INKSCAPE_LIVEPATHEFFECT_PARAMETER_ORIGINALITEMARRAYHIDDEN_H + +/* + * Inkscape::LivePathEffectParameters + * + * Copyright (C) Theodore Janeczko 2012 + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include + +#include "live_effects/parameter/parameter.h" +#include "live_effects/parameter/item-reference.h" + +#include "svg/svg.h" +#include "svg/stringstream.h" +#include "item-reference.h" + +class SPObject; + +namespace Inkscape { + +namespace LivePathEffect { + +class OriginalItemMapHiddenParam : public Parameter { +public: + class ModelColumns; + + OriginalItemMapHiddenParam( const Glib::ustring& label, + const Glib::ustring& tip, + const Glib::ustring& key, + Inkscape::UI::Widget::Registry* wr, + Effect* effect); + + ~OriginalItemMapHiddenParam() override; + Gtk::Widget * param_newWidget() override; + bool param_readSVGValue(const gchar * strvalue) override; + bool param_readIfExist(const gchar* strvalue, bool checkids = false); + Glib::ustring param_getSVGValue() const override; + Glib::ustring param_getDefaultSVGValue() const override; + void param_set_default() override; + void param_update_default(const gchar * default_value) override{}; + std::map _map; + void clear(); + void setUpdating(bool updating) {_updating = updating;} + bool getUpdating() const {return _updating;} + void link(Glib::ustring name, SPObject *to, size_t pos = Glib::ustring::npos); + void setCheckIds(bool check_ids) {_check_ids = check_ids;} + bool getCheckIds() const {return _check_ids;} + void multilink(std::map objs); + void unlink(Glib::ustring name); + void remove_link(Glib::ustring name); +protected: + void linked_changed(SPObject *old_obj, SPObject *new_obj, LPEItemRef* to); + void linked_modified(SPObject *linked_obj, guint flags, LPEItemRef* to); + void linked_transformed(Geom::Affine const *, SPItem *, LPEItemRef* to); + void linked_delete(SPObject *deleted, LPEItemRef* to); + +private: + bool _updating = false; + bool _check_ids = false; + void update(); + OriginalItemMapHiddenParam(const OriginalItemMapHiddenParam&) = delete; + OriginalItemMapHiddenParam& operator=(const OriginalItemMapHiddenParam&) = delete; +}; + +} //namespace LivePathEffect + +} //namespace Inkscape + +#endif + +/* + 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 : diff --git a/src/object/box3d-side.cpp b/src/object/box3d-side.cpp index f79279fdddff8f3e608bdb23f2aeab562095636c..c4a49ceb7f9ee3b0191806556f7f5caa556c79d6 100644 --- a/src/object/box3d-side.cpp +++ b/src/object/box3d-side.cpp @@ -25,6 +25,7 @@ #include "object/box3d.h" #include "ui/tools/box3d-tool.h" #include "desktop-style.h" +#include "helper/geom.h" static void box3d_side_compute_corner_ids(Box3DSide *side, unsigned int corners[4]); @@ -195,13 +196,17 @@ void Box3DSide::set_shape() { * This is very important for LPEs to work properly! (the bbox might be recalculated depending on the curve in shape)*/ SPCurve const *before = curveBeforeLPE(); - if (before && before->get_pathvector() != c->get_pathvector()) { + if (before && !geom_path_compare(before->get_pathvector(),c->get_pathvector(),0.01)) { setCurveBeforeLPE(std::move(c)); sp_lpe_item_update_patheffect(this, true, false); return; } if (hasPathEffectOnClipOrMaskRecursive(this)) { + if (!before && this->getRepr()->attribute("d")) { + Geom::PathVector pv = sp_svg_read_pathv(this->getRepr()->attribute("d")); + setCurveInsync(std::make_unique(pv)); + } setCurveBeforeLPE(std::move(c)); return; } diff --git a/src/object/sp-ellipse.cpp b/src/object/sp-ellipse.cpp index ac216e1e0a7ff61a31b0a2142d6080c63bd8f6b0..8b3c7e4632c2910d7d439400d4a197e37bc54968 100644 --- a/src/object/sp-ellipse.cpp +++ b/src/object/sp-ellipse.cpp @@ -21,12 +21,14 @@ #include "live_effects/effect.h" #include "live_effects/lpeobject.h" #include "live_effects/lpeobject-reference.h" +#include "helper/geom.h" #include <2geom/angle.h> #include <2geom/circle.h> #include <2geom/ellipse.h> #include <2geom/path-sink.h> + #include "attributes.h" #include "display/curve.h" #include "document.h" @@ -476,13 +478,17 @@ void SPGenericEllipse::set_shape() /* Reset the shape's curve to the "original_curve" * This is very important for LPEs to work properly! (the bbox might be recalculated depending on the curve in shape)*/ auto const before = this->curveBeforeLPE(); - if (before && before->get_pathvector() != c->get_pathvector()) { + if (before && !geom_path_compare(before->get_pathvector(),c->get_pathvector(),0.01)) { setCurveBeforeLPE(std::move(c)); - sp_lpe_item_update_patheffect(this, true, false); + sp_lpe_item_update_patheffect(this, false, false); return; } if (hasPathEffectOnClipOrMaskRecursive(this)) { + if (!before && this->getRepr()->attribute("d")) { + Geom::PathVector pv = sp_svg_read_pathv(this->getRepr()->attribute("d")); + setCurveInsync(std::make_unique(pv)); + } setCurveBeforeLPE(std::move(c)); return; } diff --git a/src/object/sp-item-group.cpp b/src/object/sp-item-group.cpp index 9232466374b6d17799dba495a0ec895bfd601a9d..dabc1085e0e49dbbbaf8ebe43e217baac6e75735 100644 --- a/src/object/sp-item-group.cpp +++ b/src/object/sp-item-group.cpp @@ -451,7 +451,6 @@ void sp_item_group_ungroup (SPGroup *group, std::vector &children, bool do_done) { g_return_if_fail (group != nullptr); - SPDocument *doc = group->document; SPRoot *root = doc->getRoot(); SPObject *defs = root->defs; @@ -542,7 +541,6 @@ sp_item_group_ungroup (SPGroup *group, std::vector &children, bool do_d // the group is leaving forever, no heir, clones should take note; its children however are going to reemerge group->deleteObject(true, false); - /* Step 3 - add nonitems */ if (!objects.empty()) { Inkscape::XML::Node *last_def = defs->getRepr()->lastChild(); @@ -556,6 +554,7 @@ sp_item_group_ungroup (SPGroup *group, std::vector &children, bool do_d } /* Step 4 - add items */ + std::vector lpeitems; for (auto *repr : items) { // add item prepr->addChild(repr, insert_after); @@ -565,15 +564,27 @@ sp_item_group_ungroup (SPGroup *group, std::vector &children, bool do_d SPItem *item = static_cast(doc->getObjectByRepr(repr)); if (item) { - item->doWriteTransform(item->transform, nullptr, false); - children.insert(children.begin(),item); - item->requestModified(SP_OBJECT_MODIFIED_FLAG); + SPLPEItem *lpeitem = dynamic_cast(item); + if (lpeitem) { + lpeitems.push_back(lpeitem); + sp_lpe_item_enable_path_effects(lpeitem, false); + children.insert(children.begin(),item); + } else { + item->doWriteTransform(item->transform, nullptr, false); + children.insert(children.begin(),item); + item->requestModified(SP_OBJECT_MODIFIED_FLAG); + } } else { g_assert_not_reached(); } Inkscape::GC::release(repr); } + for (auto lpeitem : lpeitems) { + sp_lpe_item_enable_path_effects(lpeitem, true); + lpeitem->doWriteTransform(lpeitem->transform, nullptr, false); + lpeitem->requestModified(SP_OBJECT_MODIFIED_FLAG); + } if (do_done) { DocumentUndo::done(doc, SP_VERB_NONE, _("Ungroup")); } diff --git a/src/object/sp-lpe-item.cpp b/src/object/sp-lpe-item.cpp index 57f8799978027a77c226810e90d6fc20dec4476c..daf57afbcca3959903a6fe1ee67f397eb409ec98 100755 --- a/src/object/sp-lpe-item.cpp +++ b/src/object/sp-lpe-item.cpp @@ -1396,9 +1396,17 @@ 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; + /* if (lpeobj->get_lpe()->isOnClipboard()) { + + LivePathEffectObject *doclpeobj = dynamic_cast(SP_ACTIVE_DOCUMENT->getObjectById(lpeobj->getId())); + if (doclpeobj) { + lpeobj->get_lpe()->items = doclpeobj->get_lpe()->items; + } + } */ forked_lpeobj->get_lpe()->is_load = true; old_lpeobjs.push_back(lpeobj); new_lpeobjs.push_back(forked_lpeobj); + forked_lpeobj->get_lpe()->doOnFork_impl(this, lpeobj->get_lpe()); } } } @@ -1427,108 +1435,6 @@ bool SPLPEItem::pathEffectsEnabled() const { return path_effects_enabled > 0; } - -// 1.1 COPYPASTECLONESTAMPLPEBUG -bool SPLPEItem::autoFlattenFix() { - if (path_effect_list->empty()) { - return false; - } - for (PathEffectList::const_iterator it = path_effect_list->begin(); it != path_effect_list->end(); ++it) - { - LivePathEffectObject const *lpeobj = (*it)->lpeobject; - if (lpeobj) { - Inkscape::LivePathEffect::Effect const* lpe = lpeobj->get_lpe(); - if (lpe) { - Inkscape::LivePathEffect::LPECopyRotate const *rc = dynamic_cast(lpe); - Inkscape::LivePathEffect::LPEMirrorSymmetry const *ms = dynamic_cast(lpe); - Inkscape::LivePathEffect::LPESlice const *sl = dynamic_cast(lpe); - Inkscape::LivePathEffect::LPEBool const *bo = dynamic_cast(lpe); - if ((rc && rc->split_items) || (ms && ms->split_items)) { - return true; - } else if (sl || bo) { - return true; - } - } - } - } - return false; -} - -void SPLPEItem::removeAllAutoFlatten() -{ - cleanupAutoFlatten(); - if (autoFlattenFix()) { - sp_lpe_item_enable_path_effects(this, false); - } - SPGroup *group = dynamic_cast(this); - if (group) { - std::vector item_list = sp_item_group_item_list(group); - for (auto iter : item_list) { - SPLPEItem *subitem = dynamic_cast(iter); - if (subitem) { - subitem->removeAllAutoFlatten(); - } - } - } - if (autoFlattenFix()) { - SPDocument *doc = this->document; - gchar *id = g_strdup(this->getId()); - removeAllPathEffects(true); - if (doc) { - SPObject *newobj = doc->getObjectById(id); - SPLPEItem *newlpitem = dynamic_cast(newobj); - if (newlpitem && !newlpitem->path_effects_enabled) { - sp_lpe_item_enable_path_effects(newlpitem, true); - } - } - g_free(id); - } -} - -void SPLPEItem::cleanupAutoFlatten() -{ - SPGroup* group = dynamic_cast(this); - if (group) { - std::vector item_list = sp_item_group_item_list(group); - for (auto iter : item_list) { - SPLPEItem * subitem = dynamic_cast(iter); - if (subitem) { - subitem->cleanupAutoFlatten(); - } - } - } - Glib::ustring classes = "-slice"; - if (getAttribute("class")) { - Glib::ustring classupd = getAttribute("class"); - Glib::ustring finalclass = ""; - for (auto classindi : Glib::Regex::split_simple(" ", classupd)) { - size_t pos = classindi.find(classes); - if (pos == Glib::ustring::npos && classindi != "UnoptimicedTransforms") { - if (finalclass != "") { - finalclass += " "; - } - finalclass += classindi; - } - } - setAttribute("class", finalclass == "" ? nullptr : finalclass.c_str()); - } -} - -SPObject * sp_lpe_item_remove_autoflatten(SPItem *item, const gchar *id) { - SPObject *ret = dynamic_cast(item); - SPLPEItem *lpeitem = dynamic_cast(item); - if (lpeitem) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setBool("/live_effects/flattening", true); - lpeitem->removeAllAutoFlatten(); - prefs->setBool("/live_effects/flattening", false); - // we want active document to use clipboard doc - ret = SP_ACTIVE_DOCUMENT->getObjectById(id); - } - return ret; -} -// END COPYPASTECLONESTAMPLPEBUG - /* Local Variables: mode:c++ diff --git a/src/object/sp-lpe-item.h b/src/object/sp-lpe-item.h index 3edc3074827f98a680794e8ea719b2493b597c1e..7e15af2f65591d19a4d0ce8457a26d8b7a57b24c 100644 --- a/src/object/sp-lpe-item.h +++ b/src/object/sp-lpe-item.h @@ -42,6 +42,8 @@ public: ~SPLPEItem() override; int path_effects_enabled; + bool on_align_distribute = false; + bool on_ungroup = false; PathEffectList* path_effect_list; std::list *lpe_modified_connection_list; // this list contains the connections for listening to lpeobject parameter changes @@ -60,9 +62,6 @@ public: void update(SPCtx* ctx, unsigned int flags) override; void modified(unsigned int flags) override; - bool autoFlattenFix(); - void removeAllAutoFlatten(); - void cleanupAutoFlatten(); void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref) override; void remove_child(Inkscape::XML::Node* child) override; @@ -112,7 +111,6 @@ public: }; 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); -SPObject * sp_lpe_item_remove_autoflatten(SPItem *item, const gchar *id); MAKE_SP_OBJECT_DOWNCAST_FUNCTIONS(SP_LPE_ITEM, SPLPEItem) MAKE_SP_OBJECT_TYPECHECK_FUNCTIONS(SP_IS_LPE_ITEM, SPLPEItem) diff --git a/src/object/sp-object.cpp b/src/object/sp-object.cpp index 9b76368f12b8d2cfeba738d0f6bdce78e7c45d3f..89cfea544eb010be86854619cf8b44c76ca70ab6 100644 --- a/src/object/sp-object.cpp +++ b/src/object/sp-object.cpp @@ -23,6 +23,8 @@ #include +#include "bad-uri-exception.h" + #include "helper/sp-marshal.h" #include "xml/node-event-vector.h" #include "attributes.h" @@ -116,7 +118,7 @@ SPObject::SPObject() : cloned(0), clone_original(nullptr), uflags(0), mflags(0), hrefcount(0), _total_hrefcount(0), document(nullptr), parent(nullptr), id(nullptr), repr(nullptr), refCount(1), hrefList(std::list()), _successor(nullptr), _collection_policy(SPObject::COLLECT_WITH_PARENT), - _label(nullptr), _default_label(nullptr) + _label(nullptr), _default_label(nullptr), forked_id("") { debug("id=%p, typename=%s",this, g_type_name_from_instance((GTypeInstance*)this)); @@ -151,6 +153,7 @@ SPObject::~SPObject() { parent->children.erase(parent->children.iterator_to(*this)); } + forked_id = ""; if( style == nullptr ) { // style pointer could be NULL if unreffed too many times. // Conjecture: style pointer is never NULL. @@ -288,6 +291,36 @@ void SPObject::hrefObject(SPObject* owner) hrefList.push_front(owner); } +void SPObject::setForkedTo(SPObject *forked_to) { + SPGroup *fgroup = dynamic_cast(forked_to); + SPGroup *group = dynamic_cast(this); + if (group && fgroup) { + size_t pos = 0; + std::vector fitems = sp_item_group_item_list(fgroup); + for (auto& child: group->children) { + child.setForkedTo(fitems[pos]); + pos ++; + } + } + if ( forked_to->getId()) { + forked_id = forked_to->getId(); + } else { + forked_id = ""; + } +} + +void SPObject::releaseForkedTo() { + SPGroup *group = dynamic_cast(this); + if (group) { + size_t pos = 0; + for (auto& child: group->children) { + child.releaseForkedTo(); + pos ++; + } + } + forked_id = ""; +} + void SPObject::unhrefObject(SPObject* owner) { g_return_if_fail(hrefcount > 0); diff --git a/src/object/sp-object.h b/src/object/sp-object.h index 43cd9c2decf03c0fe570f995eb1be4741216cc22..28308bc2055a40ebe49c2047d57808de31bf1d86 100644 --- a/src/object/sp-object.h +++ b/src/object/sp-object.h @@ -248,6 +248,10 @@ public: } }; + void setForkedTo(SPObject *forked_to); + + void releaseForkedTo(); + typedef Inkscape::Util::ForwardPointerIterator ParentIterator; typedef Inkscape::Util::ForwardPointerIterator ConstParentIterator; @@ -832,6 +836,9 @@ public: void recursivePrintTree(unsigned level = 0); // For debugging static unsigned indent_level; void objectTrace( std::string const &, bool in=true, unsigned flags=0 ); + + /* Temporary store reference to a copyed/clone/stamped/dupled object */ + Glib::ustring forked_id; }; std::ostream &operator<<(std::ostream &out, const SPObject &o); diff --git a/src/object/sp-path.cpp b/src/object/sp-path.cpp index 83b9c7c9ce7bb461363d8bc4eef08e0e20a317eb..180a9ed7ab618df9e256c14b9dbeeee916edd76c 100644 --- a/src/object/sp-path.cpp +++ b/src/object/sp-path.cpp @@ -239,12 +239,14 @@ void SPPath::set(SPAttr key, const gchar* value) { } } // In 2020-8-15 next line is commented and added - // a todo to see regressions, after this in a commit this line is uncommented - // again this line in a MR that near 1.1 release is finally rollbacked. - // This rollback happends near release (1.1) and think is better leave - // uncommented for release as all check are done this way - // TODO: Comment on 1.2 branching to see issues - sp_lpe_item_update_patheffect(this, true, true); + // a todo to see regressions, after this in a commit this line is uncomented + // again this line in a MR that near 1.1 release is finaly rollbacked. + // This rollback happends near release (1.1) and think is beter leave + // uncomented for release as all check are done this way + // Commentesd near 1.2 branching to seee isues + // If we find necesary and readd it agasin all plesse format the commments + // abobe to nor comment again in the future + // sp_lpe_item_update_patheffect(this, true, true); break; case SPAttr::D: diff --git a/src/object/sp-rect.cpp b/src/object/sp-rect.cpp index 641c3069d18304d066b5f1cc48d11fb0380b756f..07b0d850f76bc69f2d00b6bda9fdcb1e4f504de3 100644 --- a/src/object/sp-rect.cpp +++ b/src/object/sp-rect.cpp @@ -22,6 +22,7 @@ #include "sp-guide.h" #include "preferences.h" #include "svg/svg.h" +#include "helper/geom.h" #include #define noRECT_VERBOSE @@ -287,19 +288,23 @@ void SPRect::set_shape() { * This is very important for LPEs to work properly! (the bbox might be recalculated depending on the curve in shape)*/ auto const before = this->curveBeforeLPE(); - if (before && before->get_pathvector() != c->get_pathvector()) { + if (before && !geom_path_compare(before->get_pathvector(), c->get_pathvector(),0.01)) { setCurveBeforeLPE(std::move(c)); sp_lpe_item_update_patheffect(this, true, false); return; } if (this->hasPathEffectOnClipOrMaskRecursive(this)) { + if (!before && this->getRepr()->attribute("d")) { + Geom::PathVector pv = sp_svg_read_pathv(this->getRepr()->attribute("d")); + setCurveInsync(std::make_unique(pv)); + } setCurveBeforeLPE(std::move(c)); - Inkscape::XML::Node *rectrepr = this->getRepr(); if (strcmp(rectrepr->name(), "svg:rect") == 0) { sp_lpe_item_update_patheffect(this, true, false); this->write(rectrepr->document(), rectrepr, SP_OBJECT_MODIFIED_FLAG); } + return; } diff --git a/src/object/sp-shape.cpp b/src/object/sp-shape.cpp index 4c0d2d0ca52959f57f1699680ccb380d070bd2e5..6a3c26ec181ec13053ce2a69e50e3ef843337d65 100644 --- a/src/object/sp-shape.cpp +++ b/src/object/sp-shape.cpp @@ -462,10 +462,9 @@ void SPShape::modified(unsigned int flags) { } } - if (flags != 29 && flags != 253 && !_curve) { + //we must do a LPE cicle on SPShapes not paths + if (!_curve) { sp_lpe_item_update_patheffect(this, true, false); - } else if (!_curve) { - this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } } diff --git a/src/object/sp-spiral.cpp b/src/object/sp-spiral.cpp index 10872057040ed4dc901129f628bd0425b807ce69..08501f60bbe1bfa7aa7e502f63ee9f820b9dc41d 100644 --- a/src/object/sp-spiral.cpp +++ b/src/object/sp-spiral.cpp @@ -24,7 +24,7 @@ #include #include "xml/repr.h" #include "document.h" - +#include "helper/geom.h" #include "sp-spiral.h" SPSpiral::SPSpiral() @@ -345,13 +345,17 @@ void SPSpiral::set_shape() { * This is very important for LPEs to work properly! (the bbox might be recalculated depending on the curve in shape)*/ auto const before = this->curveBeforeLPE(); - if (before && before->get_pathvector() != c->get_pathvector()) { + if (before && !geom_path_compare(before->get_pathvector(), c->get_pathvector(),0.01)) { setCurveBeforeLPE(std::move(c)); sp_lpe_item_update_patheffect(this, true, false); return; } if (hasPathEffectOnClipOrMaskRecursive(this)) { + if (!before && this->getRepr()->attribute("d")) { + Geom::PathVector pv = sp_svg_read_pathv(this->getRepr()->attribute("d")); + setCurveInsync(std::make_unique(pv)); + } setCurveBeforeLPE(std::move(c)); return; } diff --git a/src/object/sp-star.cpp b/src/object/sp-star.cpp index 0fa820cca01960075e4521e16b5cde4b62addfbe..e252fcd3d059aa735d20ca774ef9f6b128c3690c 100644 --- a/src/object/sp-star.cpp +++ b/src/object/sp-star.cpp @@ -26,6 +26,7 @@ #include "document.h" #include "sp-star.h" +#include "helper/geom.h" #include SPStar::SPStar() : SPShape() , @@ -427,13 +428,17 @@ void SPStar::set_shape() { * This is very important for LPEs to work properly! (the bbox might be recalculated depending on the curve in shape)*/ auto const before = this->curveBeforeLPE(); - if (before && before->get_pathvector() != c->get_pathvector()) { + if (before && !geom_path_compare(before->get_pathvector(), c->get_pathvector(),0.01)) { setCurveBeforeLPE(std::move(c)); sp_lpe_item_update_patheffect(this, true, false); return; } if (hasPathEffectOnClipOrMaskRecursive(this)) { + if (!before && this->getRepr()->attribute("d")) { + Geom::PathVector pv = sp_svg_read_pathv(this->getRepr()->attribute("d")); + setCurveInsync(std::make_unique(pv)); + } setCurveBeforeLPE(std::move(c)); return; } diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 99ed5f5302671ed77f8a2f64cbf10bd1044b8ccd..e5ed2df09c9db2605f17ce5da2acd68e6d74a20c 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -62,7 +62,6 @@ #include "live_effects/effect.h" #include "live_effects/parameter/originalpath.h" -#include "filter-chemistry.h" #include "object/box3d.h" #include "object/object-set.h" #include "object/persp3d.h" @@ -500,15 +499,9 @@ void ObjectSet::duplicate(bool suppressDone, bool duplicateLayer) if (!duplicateLayer || sp_repr_is_def(old_repr)) { parent->appendChild(copy); - // 1.1 COPYPASTECLONESTAMPLPEBUG - SPItem *newitem = dynamic_cast(doc->getObjectByRepr(copy)); - if (_desktop && newitem) { - remove_hidder_filter(newitem); - gchar * id = strdup(copy->attribute("id")); - copy = sp_lpe_item_remove_autoflatten(newitem, id)->getRepr(); - g_free(id); - } - // END 1.1 COPYPASTECLONESTAMPLPEBUG fix + SPObject *original = doc->getObjectByRepr(old_repr); + SPObject *newobj = doc->getObjectByRepr(copy); + original->setForkedTo(newobj); } else if (sp_repr_is_layer(old_repr)) { parent->addChild(copy, old_repr); } else { @@ -525,18 +518,22 @@ void ObjectSet::duplicate(bool suppressDone, bool duplicateLayer) add_ids_recursive(new_ids, new_obj); } + copies.push_back(copy); + Inkscape::GC::release(copy); + } + for (auto copy : copies) { if (fork_livepatheffects) { SPObject *new_obj = doc->getObjectByRepr(copy); - SPLPEItem *newLPEObj = dynamic_cast(new_obj); - if (newLPEObj) { - newLPEObj->forkPathEffectsIfNecessary(1); + SPLPEItem *newLPEItem = dynamic_cast(new_obj); + if (newLPEItem) { + newLPEItem->forkPathEffectsIfNecessary(0); } } - - copies.push_back(copy); - Inkscape::GC::release(copy); } - + for(auto old_repr : reprs) { + SPObject *original = doc->getObjectByRepr(old_repr); + original->releaseForkedTo(); + } // Relink copied text nodes to copied reference shapes text_relink_refs(text_refs, reprs.begin(), reprs.end(), copies.begin()); diff --git a/src/seltrans.cpp b/src/seltrans.cpp index 922b5a80057c1a8b9f7393d7fe5246c3f221a676..dd6fde061b92811316a838adf59bed8ef48b92af 100644 --- a/src/seltrans.cpp +++ b/src/seltrans.cpp @@ -33,7 +33,6 @@ #include "mod360.h" #include "pure-transform.h" #include "selection-chemistry.h" -#include "filter-chemistry.h" #include "selection.h" #include "seltrans-handles.h" #include "verbs.h" @@ -518,7 +517,7 @@ void Inkscape::SelTrans::stamp() sort(l.begin(), l.end(), sp_object_compare_position_bool); _stamp_cache = l; } - + std::vector newitems; for(auto original_item : l) { Inkscape::XML::Node *original_repr = original_item->getRepr(); @@ -530,39 +529,39 @@ void Inkscape::SelTrans::stamp() // add the new repr to the parent parent->addChild(copy_repr, original_repr->prev()); - SPItem *copy_item = (SPItem *) _desktop->getDocument()->getObjectByRepr(copy_repr); - // 1.1 COPYPASTECLONESTAMPLPEBUG - SPItem *newitem = dynamic_cast(_desktop->getDocument()->getObjectByRepr(copy_repr)); - if (newitem) { - remove_hidder_filter(newitem); - gchar * id = strdup(copy_item->getId()); - copy_item = (SPItem *) sp_lpe_item_remove_autoflatten(newitem, id); - copy_repr = copy_item->getRepr(); - g_free(id); - } - // END COPYPASTECLONESTAMPLPEBUG - Geom::Affine const *new_affine; - if (_show == SHOW_OUTLINE) { - Geom::Affine const i2d(original_item->i2dt_affine()); - Geom::Affine const i2dnew( i2d * _current_relative_affine ); - copy_item->set_i2d_affine(i2dnew); - new_affine = ©_item->transform; - } else { - new_affine = &original_item->transform; - } + SPItem *copy_item = dynamic_cast(_desktop->getDocument()->getObjectByRepr(copy_repr)); + original_item->setForkedTo(copy_item); + + newitems.push_back(copy_item); + if (copy_item) { + Geom::Affine const *new_affine; + if (_show == SHOW_OUTLINE) { + Geom::Affine const i2d(original_item->i2dt_affine()); + Geom::Affine const i2dnew( i2d * _current_relative_affine ); + copy_item->set_i2d_affine(i2dnew); + new_affine = ©_item->transform; + } else { + new_affine = &original_item->transform; + } - copy_item->doWriteTransform(*new_affine); + copy_item->doWriteTransform(*new_affine); - if ( copy_item->isCenterSet() && _center ) { - copy_item->setCenter(*_center * _current_relative_affine); + if ( copy_item->isCenterSet() && _center ) { + copy_item->setCenter(*_center * _current_relative_affine); + } } Inkscape::GC::release(copy_repr); - SPLPEItem * lpeitem = dynamic_cast(copy_item); + } + for (auto item : newitems) { + SPLPEItem * lpeitem = dynamic_cast(item); if(lpeitem && lpeitem->hasPathEffectRecursive()) { - lpeitem->forkPathEffectsIfNecessary(1); + lpeitem->forkPathEffectsIfNecessary(0); sp_lpe_item_update_patheffect(lpeitem, true, true); } } + for(auto original_item : l) { + original_item->releaseForkedTo(); + } DocumentUndo::done(_desktop->getDocument(), SP_VERB_CONTEXT_SELECT, _("Stamp")); } diff --git a/src/ui/clipboard.cpp b/src/ui/clipboard.cpp index 5172173a0f39b537daf73fa91d4ace459a2d32b9..0f71a69951d3fb76a136ef2934c0d3ccf734d453 100644 --- a/src/ui/clipboard.cpp +++ b/src/ui/clipboard.cpp @@ -30,6 +30,7 @@ #include "desktop-style.h" // for sp_desktop_set_style, used in _pasteStyle #include "desktop.h" #include "document.h" +#include "id-clash.h" #include "file.h" // for file_import, used in _pasteImage #include "gradient-drag.h" #include "inkscape.h" @@ -501,7 +502,7 @@ bool ClipboardManagerImpl::paste(SPDesktop *desktop, bool in_place) return true; } } - + prevent_id_clashes(tempdoc.get(), desktop->getDocument(), true); sp_import_document(desktop, tempdoc.get(), in_place); // _copySelection() has put all items in groups, now ungroup them (preserves transform @@ -909,20 +910,6 @@ void ClipboardManagerImpl::_copySelection(ObjectSet *selection) } sp_repr_css_set(obj_copy, css, "style"); sp_repr_css_attr_unref(css); - - // 1.1 COPYPASTECLONESTAMPLPEBUG - if (_clipboardSPDoc) { - SPItem *newitem = dynamic_cast(_clipboardSPDoc->getObjectByRepr(obj_copy)); - if (newitem) { - remove_hidder_filter(newitem); - gchar *id = strdup(newitem->getId()); - newitem = (SPItem *)sp_lpe_item_remove_autoflatten(newitem, id); - obj_copy = newitem->getRepr(); - g_free(id); - } - } - // END COPYPASTECLONESTAMPLPEBUG - } } // copy style for Paste Style action diff --git a/src/ui/dialog/align-and-distribute.cpp b/src/ui/dialog/align-and-distribute.cpp index c5e09baaa5d441979cd03854deef810cc3e0fa17..3bcd7436b3bfc29cd20f76627e82b63b2e60fef3 100644 --- a/src/ui/dialog/align-and-distribute.cpp +++ b/src/ui/dialog/align-and-distribute.cpp @@ -126,7 +126,9 @@ void ActionAlign::do_action(SPDesktop *desktop, int index) for (auto itemlist = list.begin(); itemlist != list.end(); ++itemlist) { SPLPEItem *lpeitem = dynamic_cast(*itemlist); if (lpeitem && lpeitem->hasPathEffectOfType(Inkscape::LivePathEffect::EffectType::BOOL_OP)) { + lpeitem->on_align_distribute = true; sp_lpe_item_update_patheffect(lpeitem, false, false); + lpeitem->on_align_distribute = false; } } std::vector selected(selection->items().begin(), selection->items().end()); @@ -314,7 +316,16 @@ private : std::vector selected(selection->items().begin(), selection->items().end()); if (selected.empty()) return; - + // We force unselect operand in bool LPE + auto list = selection->items(); + for (auto itemlist = list.begin(); itemlist != list.end(); ++itemlist) { + SPLPEItem *lpeitem = dynamic_cast(*itemlist); + if (lpeitem && lpeitem->hasPathEffectOfType(Inkscape::LivePathEffect::EffectType::BOOL_OP)){ + lpeitem->on_align_distribute = true; + sp_lpe_item_update_patheffect(lpeitem, false, false); + lpeitem->on_align_distribute = false; + } + } //Check 2 or more selected objects std::vector::iterator second(selected.begin()); ++second; diff --git a/src/ui/dialog/livepatheffect-editor.cpp b/src/ui/dialog/livepatheffect-editor.cpp index 835ae0839c5d3c64892546c60de44a0c488279d8..4d08d78eb56e99400b72e24b85e70f3d220c8748 100644 --- a/src/ui/dialog/livepatheffect-editor.cpp +++ b/src/ui/dialog/livepatheffect-editor.cpp @@ -519,7 +519,7 @@ void LivePathEffectEditor::on_effect_selection_changed() if (lperef && current_lpeitem && current_lperef != lperef) { // The last condition ignore Gtk::TreeModel may occasionally be changed emitted when nothing has happened - if (lperef->getObject()) { + if (current_lpeitem->pathEffectsEnabled() && lperef->getObject()) { lpe_list_locked = true; // prevent reload of the list which would lose selection current_lpeitem->setCurrentPathEffect(lperef); current_lperef = lperef;