diff options
| author | Martin Owens <doctormo@gmail.com> | 2014-02-25 17:29:47 +0000 |
|---|---|---|
| committer | Martin Owens <doctormo@gmail.com> | 2014-02-25 17:29:47 +0000 |
| commit | 8768316cc055aabfd17eb1a78a051f2697fab7b7 (patch) | |
| tree | 96b99d92d641a5d7c5b7f73e321f0d34706b7573 /src | |
| parent | Merge from trunk (diff) | |
| parent | Allow 'transform' on flowRoot, flowPara, and flowSpan. (diff) | |
| download | inkscape-8768316cc055aabfd17eb1a78a051f2697fab7b7.tar.gz inkscape-8768316cc055aabfd17eb1a78a051f2697fab7b7.zip | |
Merge from trunk
(bzr r13047.1.4)
Diffstat (limited to 'src')
| -rw-r--r-- | src/selection-chemistry.cpp | 223 | ||||
| -rw-r--r-- | src/selection-chemistry.h | 3 | ||||
| -rw-r--r-- | src/ui/dialog/filter-effects-dialog.cpp | 11 | ||||
| -rw-r--r-- | src/ui/dialog/filter-effects-dialog.h | 2 | ||||
| -rw-r--r-- | src/verbs.cpp | 2 |
5 files changed, 153 insertions, 88 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")); 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/ui/dialog/filter-effects-dialog.cpp b/src/ui/dialog/filter-effects-dialog.cpp index e8b09db8b..b763776c6 100644 --- a/src/ui/dialog/filter-effects-dialog.cpp +++ b/src/ui/dialog/filter-effects-dialog.cpp @@ -1363,11 +1363,9 @@ FilterEffectsDialog::FilterModifier::FilterModifier(FilterEffectsDialog& d) sw->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); _list.get_column(1)->set_resizable(true); _list.set_reorderable(true); + _list.enable_model_drag_dest (Gdk::ACTION_MOVE); - // We can track the drag/drop reordering from the row_delete (occurs after - // row_inserted and may occur many times when adding a new item) - _model->signal_row_deleted().connect( - sigc::mem_fun(*this, &FilterModifier::on_filter_reorder)); + _list.signal_drag_drop().connect( sigc::mem_fun(*this, &FilterModifier::on_filter_move), false ); sw->set_shadow_type(Gtk::SHADOW_IN); show_all_children(); @@ -1514,7 +1512,9 @@ void FilterEffectsDialog::FilterModifier::on_name_edited(const Glib::ustring& pa } } -void FilterEffectsDialog::FilterModifier::on_filter_reorder(const Gtk::TreeModel::Path& /*path*/) { +bool FilterEffectsDialog::FilterModifier::on_filter_move(const Glib::RefPtr<Gdk::DragContext>& /*context*/, int x, int y, guint /*time*/) { + +//const Gtk::TreeModel::Path& /*path*/) { /* The code below is bugged. Use of "object->getRepr()->setPosition(0)" is dangerous! Writing back the reordered list to XML (reordering XML nodes) should be implemented differently. Note that the dialog does also not update its list of filters when the order is manually changed @@ -1525,6 +1525,7 @@ void FilterEffectsDialog::FilterModifier::on_filter_reorder(const Gtk::TreeModel object->getRepr()->setPosition(0); } */ + return false; } void FilterEffectsDialog::FilterModifier::on_selection_toggled(const Glib::ustring& path) diff --git a/src/ui/dialog/filter-effects-dialog.h b/src/ui/dialog/filter-effects-dialog.h index ccf79e60d..3fc19e7de 100644 --- a/src/ui/dialog/filter-effects-dialog.h +++ b/src/ui/dialog/filter-effects-dialog.h @@ -86,7 +86,7 @@ private: void on_filter_selection_changed(); void on_name_edited(const Glib::ustring&, const Glib::ustring&); - void on_filter_reorder(const Gtk::TreeModel::Path& path); + bool on_filter_move(const Glib::RefPtr<Gdk::DragContext>& /*context*/, int x, int y, guint /*time*/); void on_selection_toggled(const Glib::ustring&); void update_filters(); 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); |
