diff options
| author | Tavmjong Bah <tavmjong@free.fr> | 2014-02-25 16:08:30 +0000 |
|---|---|---|
| committer | tavmjong-free <tavmjong@free.fr> | 2014-02-25 16:08:30 +0000 |
| commit | 903d68d4df1de1ae21e124d6e9c12770085ea087 (patch) | |
| tree | 1c1c649d40c2ed9c81c97405c1a590898971cad3 | |
| parent | Move filter reordering closer to the layers.cpp patern of reordering xml (diff) | |
| download | inkscape-903d68d4df1de1ae21e124d6e9c12770085ea087.tar.gz inkscape-903d68d4df1de1ae21e124d6e9c12770085ea087.zip | |
Rewrite of symbol creation code. Partial fix for 1201325.
Symbols cannot have 'tranform' attribute. The old code copied the group
'transform' attribute to the symbol. The new code creates an intermediate
group with the required 'transform' if it is not a simple translation. A
simple translation is removed and applied instead to the new <use> element.
Multiple objects can now be turned into a symbol without first grouping the
objects. (At the cost that multiple groups can no longer be turned into
multiple symbols at one go.) This better matches marker and pattern creation.
(bzr r13057)
| -rw-r--r-- | configure.ac | 2 | ||||
| -rw-r--r-- | src/extension/internal/cairo-renderer.cpp | 6 | ||||
| -rw-r--r-- | src/selection-chemistry.cpp | 223 | ||||
| -rw-r--r-- | src/selection-chemistry.h | 3 | ||||
| -rw-r--r-- | src/verbs.cpp | 2 |
5 files changed, 150 insertions, 86 deletions
diff --git a/configure.ac b/configure.ac index dbffcfbde..529ac24f9 100644 --- a/configure.ac +++ b/configure.ac @@ -101,7 +101,7 @@ if test "$GCC" = "yes"; then fi # Uncomment for SVG2 stuff - # CPPFLAGS="-DWITH_MESH -DWITH_CSSBLEND -DWITH_CSSCOMPOSITE $CPPFLAGS" + CPPFLAGS="-DWITH_MESH -DWITH_CSSBLEND -DWITH_CSSCOMPOSITE -DWITH_SVG2 $CPPFLAGS" #### # C-specific flags... diff --git a/src/extension/internal/cairo-renderer.cpp b/src/extension/internal/cairo-renderer.cpp index 6fbc85c05..aa47d8169 100644 --- a/src/extension/internal/cairo-renderer.cpp +++ b/src/extension/internal/cairo-renderer.cpp @@ -77,8 +77,8 @@ #include <cairo-ps.h> #endif -//#define TRACE(_args) g_printf _args -#define TRACE(_args) +#define TRACE(_args) g_printf _args +//#define TRACE(_args) //#define TEST(_args) _args #define TEST(_args) @@ -628,7 +628,7 @@ CairoRenderer::setupDocument(CairoRenderContext *ctx, SPDocument *doc, bool page ctx->_width = d.width(); ctx->_height = d.height(); - TRACE(("setupDocument: %f x %f\n", ctx->_width, ctx->_height)); + TRACE(("Cairo Renderer: setupDocument: %f x %f\n", ctx->_width, ctx->_height)); bool ret = ctx->setupSurface(ctx->_width, ctx->_height); 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")); diff --git a/src/selection-chemistry.h b/src/selection-chemistry.h index e86000f70..d76a67a9d 100644 --- a/src/selection-chemistry.h +++ b/src/selection-chemistry.h @@ -69,8 +69,7 @@ void sp_selection_clone_original_path_lpe(SPDesktop *desktop); void sp_selection_to_marker(SPDesktop *desktop, bool apply = true); void sp_selection_to_guides(SPDesktop *desktop); -void sp_selection_symbols(SPDesktop *desktop, bool apply = true); -void sp_selection_symbol(SPDocument *doc, SPObject *group); +void sp_selection_symbol(SPDesktop *desktop, bool apply = true); void sp_selection_unsymbol(SPDesktop *desktop); void sp_selection_tile(SPDesktop *desktop, bool apply = true); diff --git a/src/verbs.cpp b/src/verbs.cpp index 8b333383f..653d5f892 100644 --- a/src/verbs.cpp +++ b/src/verbs.cpp @@ -996,7 +996,7 @@ void EditVerb::perform(SPAction *action, void *data) sp_selection_untile(dt); break; case SP_VERB_EDIT_SYMBOL: - sp_selection_symbols(dt); + sp_selection_symbol(dt); break; case SP_VERB_EDIT_UNSYMBOL: sp_selection_unsymbol(dt); |
