From fd0823e67a02fbf460fc2e1a14a2752b4d036fde Mon Sep 17 00:00:00 2001 From: Thomas Holder Date: Mon, 18 Mar 2019 12:22:41 +0000 Subject: Keep generic attributes with "Simplify" et. al Keep generic attributes and child nodes when doing path conversion like "Simplify", "Object To Path", "Combine", Inset/Outset or Boolean operations. Fixes https://bugs.launchpad.net/inkscape/+bug/373140 --- src/path-chemistry.cpp | 172 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 118 insertions(+), 54 deletions(-) (limited to 'src/path-chemistry.cpp') diff --git a/src/path-chemistry.cpp b/src/path-chemistry.cpp index 8efd27be8..81bc531c1 100644 --- a/src/path-chemistry.cpp +++ b/src/path-chemistry.cpp @@ -95,9 +95,7 @@ ObjectSet::combine(bool skip_undo) // remember the position, id, transform and style of the topmost path, they will be assigned to the combined one gint position = 0; - char const *id = nullptr; char const *transform = nullptr; - char const *style = nullptr; char const *path_effect = nullptr; SPCurve* curve = nullptr; @@ -126,10 +124,8 @@ ObjectSet::combine(bool skip_undo) first = item; parent = first->getRepr()->parent(); position = first->getRepr()->position(); - id = first->getRepr()->attribute("id"); transform = first->getRepr()->attribute("transform"); // FIXME: merge styles of combined objects instead of using the first one's style - style = first->getRepr()->attribute("style"); path_effect = first->getRepr()->attribute("inkscape:path-effect"); //c->transform(item->transform); curve = c; @@ -149,18 +145,18 @@ ObjectSet::combine(bool skip_undo) if (did) { - first->deleteObject(false); - // delete the topmost. - Inkscape::XML::Document *xml_doc = doc->getReprDoc(); Inkscape::XML::Node *repr = xml_doc->createElement("svg:path"); + Inkscape::copy_object_properties(repr, first->getRepr()); + + // delete the topmost. + first->deleteObject(false); + // restore id, transform, path effect, and style - repr->setAttribute("id", id); if (transform) { repr->setAttribute("transform", transform); } - repr->setAttribute("style", style); repr->setAttribute("inkscape:path-effect", path_effect); @@ -447,14 +443,6 @@ sp_item_list_to_curves(const std::vector &items, std::vector& Inkscape::XML::Node *parent = item->getRepr()->parent(); // remember class char const *class_attr = item->getRepr()->attribute("class"); - // remember title - gchar *title = item->title(); - // remember description - gchar *desc = item->desc(); - // remember highlight color - guint32 highlight_color = 0; - if (item->isHighlightSet()) - highlight_color = item->highlight_color(); // It's going to resurrect, so we delete without notifying listeners. item->deleteObject(false); @@ -465,18 +453,6 @@ sp_item_list_to_curves(const std::vector &items, std::vector& repr->setAttribute("class", class_attr); // add the new repr to the parent parent->appendChild(repr); - SPObject* newObj = document->getObjectByRepr(repr); - if (title && newObj) { - newObj->setTitle(title); - g_free(title); - } - if (desc && newObj) { - newObj->setDesc(desc); - g_free(desc); - } - if (highlight_color && newObj) { - SP_ITEM(newObj)->setHighlightColor( highlight_color ); - } // move to the saved position repr->setPosition(pos > 0 ? pos : 0); @@ -511,17 +487,8 @@ sp_selected_item_to_curved_repr(SPItem *item, guint32 /*text_grouping_policy*/) } g_repr->setAttribute("transform", item->getRepr()->attribute("transform")); - /* Mask */ - gchar *mask_str = (gchar *) item->getRepr()->attribute("mask"); - if ( mask_str ) - g_repr->setAttribute("mask", mask_str); - /* Clip path */ - gchar *clip_path_str = (gchar *) item->getRepr()->attribute("clip-path"); - if ( clip_path_str ) - g_repr->setAttribute("clip-path", clip_path_str); - /* Rotation center */ - g_repr->setAttribute("inkscape:transform-center-x", item->getRepr()->attribute("inkscape:transform-center-x"), false); - g_repr->setAttribute("inkscape:transform-center-y", item->getRepr()->attribute("inkscape:transform-center-y"), false); + + Inkscape::copy_object_properties(g_repr, item->getRepr()); /* Whole text's style */ Glib::ustring style_str = @@ -599,6 +566,9 @@ sp_selected_item_to_curved_repr(SPItem *item, guint32 /*text_grouping_policy*/) } Inkscape::XML::Node *repr = xml_doc->createElement("svg:path"); + + Inkscape::copy_object_properties(repr, item->getRepr()); + /* Transformation */ repr->setAttribute("transform", item->getRepr()->attribute("transform")); @@ -607,20 +577,6 @@ sp_selected_item_to_curved_repr(SPItem *item, guint32 /*text_grouping_policy*/) item->style->write( SP_STYLE_FLAG_IFDIFF, SP_STYLE_SRC_UNSET, item->parent ? item->parent->style : nullptr); // TODO investigate possibility repr->setAttribute("style", style_str.c_str()); - /* Mask */ - gchar *mask_str = (gchar *) item->getRepr()->attribute("mask"); - if ( mask_str ) - repr->setAttribute("mask", mask_str); - - /* Clip path */ - gchar *clip_path_str = (gchar *) item->getRepr()->attribute("clip-path"); - if ( clip_path_str ) - repr->setAttribute("clip-path", clip_path_str); - - /* Rotation center */ - repr->setAttribute("inkscape:transform-center-x", item->getRepr()->attribute("inkscape:transform-center-x"), false); - repr->setAttribute("inkscape:transform-center-y", item->getRepr()->attribute("inkscape:transform-center-y"), false); - /* Definition */ gchar *def_str = sp_svg_write_path(curve->get_pathvector()); repr->setAttribute("d", def_str); @@ -688,6 +644,114 @@ ObjectSet::pathReverse() } } + +/** + * Copy generic attributes, like those from the "Object Properties" dialog, + * but also style and transformation center. + * + * @param dest XML node to copy attributes to + * @param src XML node to copy attributes from + */ +static void ink_copy_generic_attributes( // + Inkscape::XML::Node *dest, // + Inkscape::XML::Node const *src) +{ + static char const *const keys[] = { + // core + "id", + + // clip & mask + "clip-path", + "mask", + + // style + "style", + + // inkscape + "inkscape:highlight-color", + "inkscape:label", + "inkscape:transform-center-x", + "inkscape:transform-center-y", + + // interactivity + "onclick", + "onmouseover", + "onmouseout", + "onmousedown", + "onmouseup", + "onmousemove", + "onfocusin", + "onfocusout", + "onload", + }; + + for (auto *key : keys) { + auto *value = src->attribute(key); + if (value) { + dest->setAttribute(key, value); + } + } +} + + +/** + * Copy generic child elements, like those from the "Object Properties" dialog + * (title and description) but also XML comments. + * + * Does not check if children of the same type already exist in dest. + * + * @param dest XML node to copy children to + * @param src XML node to copy children from + */ +static void ink_copy_generic_children( // + Inkscape::XML::Node *dest, // + Inkscape::XML::Node const *src) +{ + static std::set const names{ + // descriptive elements + "svg:title", + "svg:desc", + }; + + for (const auto *child = src->firstChild(); child != nullptr; child = child->next()) { + // check if this child should be copied + if (!(child->type() == Inkscape::XML::COMMENT_NODE || // + (child->name() && names.count(child->name())))) { + continue; + } + + auto dchild = child->duplicate(dest->document()); + dest->appendChild(dchild); + dchild->release(); + } +} + + +/** + * Copy generic object properties, like: + * - id + * - label + * - title + * - description + * - style + * - clip + * - mask + * - transformation center + * - highlight color + * - interactivity (event attributes) + * + * @param dest XML node to copy to + * @param src XML node to copy from + */ +void Inkscape::copy_object_properties( // + Inkscape::XML::Node *dest, // + Inkscape::XML::Node const *src) +{ + ink_copy_generic_attributes(dest, src); + ink_copy_generic_children(dest, src); +} + + /* Local Variables: mode:c++ -- cgit v1.2.3