summaryrefslogtreecommitdiffstats
path: root/src/selection-chemistry.cpp
diff options
context:
space:
mode:
authorJabier Arraiza Cenoz <jabier.arraiza@marker.es>2014-02-26 21:30:12 +0000
committerJabiertxof <jtx@jtx.marker.es>2014-02-26 21:30:12 +0000
commit802a1a7537a691e36a6f41d50714905ba809e289 (patch)
tree6af369bfc55a66c2b3461dae064f7a62d636f794 /src/selection-chemistry.cpp
parentFixed some/all bugs related to continuing bspline/spiro curves advertaising b... (diff)
parentAdded template functions as a casting-macro replacement. (diff)
downloadinkscape-802a1a7537a691e36a6f41d50714905ba809e289.tar.gz
inkscape-802a1a7537a691e36a6f41d50714905ba809e289.zip
update to trunk
(bzr r11950.1.258)
Diffstat (limited to 'src/selection-chemistry.cpp')
-rw-r--r--src/selection-chemistry.cpp223
1 files changed, 144 insertions, 79 deletions
diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp
index ecf814f60..c3d37af72 100644
--- a/src/selection-chemistry.cpp
+++ b/src/selection-chemistry.cpp
@@ -2934,96 +2934,145 @@ void sp_selection_to_guides(SPDesktop *desktop)
}
/*
- * Convert <g> to <symbol>, leaving all <use> elements referencing group unchanged.
+ * Convert objects to <symbol>. How that happens depends on what is selected:
+ *
+ * 1) A random selection of objects will be embedded into a single <symbol> element.
+ *
+ * 2) Except, a single <g> will have its content directly embedded into a <symbol>; the 'id' and
+ * 'style' of the <g> are transferred to the <symbol>.
+ *
+ * 3) Except, a single <g> with a transform that isn't a translation will keep the group when
+ * embedded into a <symbol> (with 'id' and 'style' transferred to <symbol>). This is because a
+ * <symbol> cannot have a transform. (If the transform is a pure translation, the translation
+ * is moved to the referencing <use> element that is created.)
+ *
+ * Possible improvements:
+ *
+ * Move objects inside symbol so bbox corner at 0,0 (see marker/pattern)
+ *
+ * For SVG2, set 'refX' 'refY' to object center (with compensating shift in <use>
+ * transformation).
*/
-void sp_selection_symbols(SPDesktop *desktop, bool /*apply*/ )
+void sp_selection_symbol(SPDesktop *desktop, bool /*apply*/ )
{
if (desktop == NULL) {
return;
}
SPDocument *doc = sp_desktop_document(desktop);
- doc->ensureUpToDate();
+ Inkscape::XML::Document *xml_doc = doc->getReprDoc();
Inkscape::Selection *selection = sp_desktop_selection(desktop);
// Check if something is selected.
if (selection->isEmpty()) {
- desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>groups</b> to convert to symbols."));
+ desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>objects</b> to convert to symbol."));
return;
}
- GSList *items = g_slist_copy(const_cast<GSList *>(selection->list()));
- bool hasWorked = false;
+ doc->ensureUpToDate();
- for ( GSList const *iter=items; iter != NULL ; iter = iter->next ) {
- SPObject *object = reinterpret_cast<SPObject *>( iter->data );
+ GSList *items = g_slist_copy(const_cast<GSList *>(selection->list()));
- // Require that we really have a group.
- if( SP_IS_GROUP( object ) ) {
- sp_selection_symbol( doc, object );
- hasWorked = true;
- }
+ // Keep track of parent, this is where <use> will be inserted.
+ Inkscape::XML::Node *the_first_repr = reinterpret_cast<SPObject *>( items->data )->getRepr();
+ Inkscape::XML::Node *the_parent_repr = the_first_repr->parent();
+
+ // Find out if we have a single group
+ bool single_group = false;
+ SPObject *the_group = NULL;
+ Geom::Affine transform;
+ if( g_slist_length( items ) == 1 ) {
+ SPObject *object = reinterpret_cast<SPObject *>( items->data );
+ if( SP_IS_GROUP( object ) ) {
+ single_group = true;
+ the_group = object;
+
+ if( !sp_svg_transform_read( object->getAttribute("transform"), &transform ))
+ transform = Geom::identity();
+
+ if( transform.isTranslation() ) {
+
+ // Create new list from group children.
+ g_slist_free(items);
+ items = object->childList(false);
+
+ // Hack: Temporarily set clone compensation to unmoved, so that we can move clone-originals
+ // without disturbing clones.
+ // See ActorAlign::on_button_click() in src/ui/dialog/align-and-distribute.cpp
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ int saved_compensation = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED);
+ prefs->setInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED);
+
+ // Remove transform on group, updating clones.
+ SP_ITEM(object)->doWriteTransform(object->getRepr(), Geom::identity());
+
+ // restore compensation setting
+ prefs->setInt("/options/clonecompensation/value", saved_compensation);
+ }
+ }
}
- g_slist_free(items);
+ // Create new <symbol>
+ Inkscape::XML::Node *defsrepr = doc->getDefs()->getRepr();
+ Inkscape::XML::Node *symbol_repr = xml_doc->createElement("svg:symbol");
+ defsrepr->appendChild(symbol_repr);
- if( !hasWorked ) {
- desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("No <b>groups</b> converted to symbols."));
- return;
- }
+ // For a single group, copy relevant attributes.
+ if( single_group ) {
- selection->clear();
- // Group just disappears, nothing to select.
+ symbol_repr->setAttribute("style", the_group->getAttribute("style"));
+ symbol_repr->setAttribute("class", the_group->getAttribute("class"));
+ symbol_repr->setAttribute("id", the_group->getAttribute("id") );
- DocumentUndo::done(doc, SP_VERB_EDIT_SYMBOL, _("Group to symbol"));
-}
+ // This should eventually be replaced by 'refX' and 'refY' once SVG WG approves it.
+ // It is done here for round-tripping
+ symbol_repr->setAttribute("inkscape:transform-center-x",
+ the_group->getAttribute("inkscape:transform-center-x"));
+ symbol_repr->setAttribute("inkscape:transform-center-y",
+ the_group->getAttribute("inkscape:transform-center-y"));
-void sp_selection_symbol(SPDocument *doc, SPObject *group)
-{
- Inkscape::XML::Document *xml_doc = doc->getReprDoc();
+ the_group->setAttribute("style", NULL);
+ std::string id = symbol_repr->attribute("id");
+ id += "_transform";
+ the_group->setAttribute("id", id.c_str());
- Inkscape::XML::Node *symbol = xml_doc->createElement("svg:symbol");
- symbol->setAttribute("style", group->getAttribute("style"));
- symbol->setAttribute("title", group->getAttribute("title"));
- symbol->setAttribute("transform", group->getAttribute("transform"));
-
- Glib::ustring id = group->getAttribute("id");
+ }
- // Now we need to copy all children of group
- GSList* children = group->childList(false);
- children = g_slist_reverse(children);
- for (GSList* i = children; i != NULL; i = i->next ) {
- SPObject* child = SP_OBJECT(i->data);
- Inkscape::XML::Node *dup = child->getRepr()->duplicate(xml_doc);
- symbol->appendChild(dup);
- child->deleteObject(true);
+ // Move selected items to new <symbol>
+ for (GSList *i = items; i != NULL; i = i->next) {
+ Inkscape::XML::Node *repr = SP_OBJECT(i->data)->getRepr();
+ repr->parent()->removeChild(repr);
+ symbol_repr->addChild(repr,NULL);
}
- // Need to delete <g>; all <use> elements that referenced <g> should
- // auto-magically reference <symbol>.
- doc->getDefs()->getRepr()->appendChild(symbol);
- // Mysterious, must set symbol ID before deleting group or all <use> items
- // get turned into groups. (Linked to unlinking clones?)
- symbol->setAttribute("id",id.c_str());
+ if( single_group && transform.isTranslation() ) {
+ the_group->deleteObject(true);
+ }
- // Create a clone of the symbol to replace the deleted group.
+ // Create <use> pointing to new symbol (to replace the moved objects).
Inkscape::XML::Node *clone = xml_doc->createElement("svg:use");
- clone->setAttribute("x", "0", false);
- clone->setAttribute("y", "0", false);
- gchar *href_str = g_strdup_printf("#%s", id.c_str());
+
+ const gchar *symbol_id = symbol_repr->attribute("id");
+ gchar *href_str = g_strdup_printf("#%s", symbol_id);
clone->setAttribute("xlink:href", href_str, false);
g_free(href_str);
- clone->setAttribute("inkscape:transform-center-x", group->getAttribute("inkscape:transform-center-x"), false);
- clone->setAttribute("inkscape:transform-center-y", group->getAttribute("inkscape:transform-center-y"), false);
- group->parent->getRepr()->appendChild(clone);
+ the_parent_repr->appendChild(clone);
- group->deleteObject(true);
+ if( single_group && transform.isTranslation() ) {
+ if( !transform.isIdentity() )
+ clone->setAttribute("transform", sp_svg_transform_write( transform ));
+ }
- g_slist_free(children);
+ // Change selection to new <use> element.
+ selection->set(clone);
+
+ // Clean up
+ Inkscape::GC::release(symbol_repr);
+ g_slist_free(items);
- Inkscape::GC::release(symbol);
+ DocumentUndo::done(doc, SP_VERB_EDIT_SYMBOL, _("Group to symbol"));
}
/*
@@ -3049,48 +3098,64 @@ void sp_selection_unsymbol(SPDesktop *desktop)
SPObject* symbol = selection->single();
// Make sure we have only one object in selection.
- // Require that we really have a <use> that references a <symbol>.
+ // Require that we really have a <symbol>.
if( symbol == NULL || !SP_IS_SYMBOL( symbol )) {
- desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select only one <b>symbol</b> to convert to group."));
+ desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select only one <b>symbol</b> in Symbol dialog to convert to group."));
return;
}
doc->ensureUpToDate();
+ // Create new <g> and insert in current layer
Inkscape::XML::Node *group = xml_doc->createElement("svg:g");
- group->setAttribute("style", symbol->getAttribute("style"));
- group->setAttribute("title", symbol->getAttribute("title"));
- group->setAttribute("transform", symbol->getAttribute("transform"));
-
- Glib::ustring id = symbol->getAttribute("id");
+ desktop->currentLayer()->getRepr()->appendChild(group);
- // Now we need to copy all children of symbol
+ // Move all children of symbol to group
GSList* children = symbol->childList(false);
- children = g_slist_reverse(children);
+
+ // Converting a group to a symbol inserts a group for non-translational transform.
+ // In converting a symbol back to a group we strip out the inserted group (or any other
+ // group that only adds a transform to the symbol content).
+ if( g_slist_length( children ) == 1 ) {
+ SPObject *object = reinterpret_cast<SPObject *>( children->data );
+ if( SP_IS_GROUP( object ) ) {
+ if( object->getAttribute("style") == NULL ||
+ object->getAttribute("class") == NULL ) {
+
+ group->setAttribute("transform", object->getAttribute("transform"));
+ g_slist_free(children);
+ children = object->childList(false);
+ }
+ }
+ }
+
for (GSList* i = children; i != NULL; i = i->next ) {
- SPObject* child = SP_OBJECT(i->data);
- Inkscape::XML::Node *dup = child->getRepr()->duplicate(xml_doc);
- group->appendChild(dup);
- child->deleteObject(true);
+ Inkscape::XML::Node *repr = SP_OBJECT(i->data)->getRepr();
+ repr->parent()->removeChild(repr);
+ group->addChild(repr,NULL);
}
- // So we insert <g> inside the current layer
- SPObject *parent = desktop->currentLayer();
+ // Copy relevant attributes
+ group->setAttribute("style", symbol->getAttribute("style"));
+ group->setAttribute("class", symbol->getAttribute("class"));
+ group->setAttribute("inkscape:transform-center-x",
+ symbol->getAttribute("inkscape:transform-center-x"));
+ group->setAttribute("inkscape:transform-center-y",
+ symbol->getAttribute("inkscape:transform-center-y"));
+
- // Need to delete <symbol>; all other <use> elements that referenced <symbol> should
- // auto-magically reference <g>.
- symbol->setAttribute("id","todelete");
- group->setAttribute("id",id.c_str()); // After we delete symbol with same id.
+ // Need to delete <symbol>; all <use> elements that referenced <symbol> should
+ // auto-magically reference <g> (if <symbol> deleted after setting <g> 'id').
+ Glib::ustring id = symbol->getAttribute("id");
+ group->setAttribute("id",id.c_str());
symbol->deleteObject(true);
- parent->getRepr()->appendChild(group);
+ // Change selection to new <g> element.
SPItem *group_item = static_cast<SPItem *>(sp_desktop_document(desktop)->getObjectByRepr(group));
- Inkscape::GC::release(group);
- selection->clear();
selection->set(group_item);
- // Need to signal Symbol dialog to update
-
+ // Clean up
+ Inkscape::GC::release(group);
g_slist_free(children);
DocumentUndo::done(doc, SP_VERB_EDIT_UNSYMBOL, _("Group from symbol"));