diff options
Diffstat (limited to 'src/selection-chemistry.cpp')
| -rw-r--r-- | src/selection-chemistry.cpp | 146 |
1 files changed, 119 insertions, 27 deletions
diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index e81d133c2..a5c6ae961 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -94,6 +94,9 @@ SPCycleType SP_CYCLING = SP_CYCLE_FOCUS; #include "ui/tool/control-point-selection.h" #include "ui/tool/multi-path-manipulator.h" +#include "enums.h" +#include "sp-item-group.h" + // For clippath editing #include "tools-switch.h" #include "ui/tool/node-tool.h" @@ -551,36 +554,15 @@ void sp_edit_invert_in_all_layers(SPDesktop *desktop) sp_edit_select_all_full(desktop, true, true); } -void sp_selection_group(SPDesktop *desktop) -{ - if (desktop == NULL) - return; - - SPDocument *doc = sp_desktop_document(desktop); - Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc); - - Inkscape::Selection *selection = sp_desktop_selection(desktop); - - // Check if something is selected. - if (selection->isEmpty()) { - desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>some objects</b> to group.")); - return; - } - - GSList const *l = (GSList *) selection->reprList(); - - GSList *p = g_slist_copy((GSList *) l); - - selection->clear(); - +void sp_selection_group_impl(GSList const *reprs_to_group, Inkscape::XML::Node *group, Inkscape::XML::Document *xml_doc, SPDocument *doc) { + GSList *p = g_slist_copy((GSList *) reprs_to_group); + p = g_slist_sort(p, (GCompareFunc) sp_repr_compare_position); - + // Remember the position and parent of the topmost object. gint topmost = ((Inkscape::XML::Node *) g_slist_last(p)->data)->position(); Inkscape::XML::Node *topmost_parent = ((Inkscape::XML::Node *) g_slist_last(p)->data)->parent(); - - Inkscape::XML::Node *group = xml_doc->createElement("svg:g"); - + while (p) { Inkscape::XML::Node *current = (Inkscape::XML::Node *) p->data; @@ -634,10 +616,35 @@ void sp_selection_group(SPDesktop *desktop) // Move to the position of the topmost, reduced by the number of items deleted from topmost_parent group->setPosition(topmost + 1); +} + +void sp_selection_group(SPDesktop *desktop) +{ + if (desktop == NULL) + return; + + SPDocument *doc = sp_desktop_document(desktop); + Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc); + + Inkscape::Selection *selection = sp_desktop_selection(desktop); + + // Check if something is selected. + if (selection->isEmpty()) { + desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>some objects</b> to group.")); + return; + } + + GSList const *l = (GSList *) selection->reprList(); + + + Inkscape::XML::Node *group = xml_doc->createElement("svg:g"); + + sp_selection_group_impl(l, group, xml_doc, doc); sp_document_done(sp_desktop_document(desktop), SP_VERB_SELECTION_GROUP, _("Group")); + selection->clear(); selection->set(group); Inkscape::GC::release(group); } @@ -2856,6 +2863,7 @@ sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_to_la Inkscape::Preferences *prefs = Inkscape::Preferences::get(); bool topmost = prefs->getBool("/options/maskobject/topmost", true); bool remove_original = prefs->getBool("/options/maskobject/remove", true); + int grouping = prefs->getInt("/options/maskobject/grouping", PREFS_MASKOBJECT_GROUPING_NONE); if (apply_to_layer) { // all selected items are used for mask, which is applied to a layer @@ -2901,6 +2909,36 @@ sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_to_la g_slist_free(items); items = NULL; + + if (apply_to_items && grouping == PREFS_MASKOBJECT_GROUPING_ALL) { + // group all those objects into one group + // and apply mask to that + Inkscape::XML::Node *group = xml_doc->createElement("svg:g"); + + // make a note we should ungroup this when unsetting mask + group->setAttribute("inkscape:groupmode", "maskhelper"); + + GSList *reprs_to_group = NULL; + + for (GSList *i = apply_to_items ; NULL != i ; i = i->next) { + reprs_to_group = g_slist_prepend(reprs_to_group, SP_OBJECT_REPR(i->data)); + selection->remove(SP_OBJECT(i->data)); + } + reprs_to_group = g_slist_reverse(reprs_to_group); + + sp_selection_group_impl(reprs_to_group, group, xml_doc, doc); + + g_slist_free(reprs_to_group); + + // apply clip/mask only to newly created group + g_slist_free(apply_to_items); + apply_to_items = NULL; + apply_to_items = g_slist_prepend(apply_to_items, doc->getObjectByRepr(group)); + + selection->add(group); + + Inkscape::GC::release(group); + } gchar const *attributeName = apply_clip_path ? "clip-path" : "mask"; for (GSList *i = apply_to_items; NULL != i; i = i->next) { @@ -2925,7 +2963,34 @@ sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_to_la g_slist_free(mask_items_dup); mask_items_dup = NULL; - SP_OBJECT_REPR(i->data)->setAttribute(attributeName, g_strdup_printf("url(#%s)", mask_id)); + Inkscape::XML::Node *current = SP_OBJECT_REPR(i->data); + // Node to apply mask to + Inkscape::XML::Node *apply_mask_to = current; + + if (grouping == PREFS_MASKOBJECT_GROUPING_SEPARATE) { + // enclose current node in group, and apply crop/mask on that + Inkscape::XML::Node *group = xml_doc->createElement("svg:g"); + // make a note we should ungroup this when unsetting mask + group->setAttribute("inkscape:groupmode", "maskhelper"); + + Inkscape::XML::Node *spnew = current->duplicate(xml_doc); + gint position = current->position(); + selection->remove(current); + current->parent()->appendChild(group); + sp_repr_unparent(current); + group->appendChild(spnew); + group->setPosition(position); + + // Apply clip/mask to group instead + apply_mask_to = group; + + selection->add(group); + Inkscape::GC::release(spnew); + Inkscape::GC::release(group); + } + + apply_mask_to->setAttribute(attributeName, g_strdup_printf("url(#%s)", mask_id)); + } g_slist_free(mask_items); @@ -2959,10 +3024,14 @@ void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); bool remove_original = prefs->getBool("/options/maskobject/remove", true); + bool ungroup_masked = prefs->getBool("/options/maskobject/ungrouping", true); sp_document_ensure_up_to_date(doc); gchar const *attributeName = apply_clip_path ? "clip-path" : "mask"; std::map<SPObject*,SPItem*> referenced_objects; + + GSList *items_to_ungroup = NULL; + // SPObject* refers to a group containing the clipped path or mask itself, // whereas SPItem* refers to the item being clipped or masked for (GSList const *i = selection->itemList(); NULL != i; i = i->next) { @@ -2984,6 +3053,18 @@ void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) { } SP_OBJECT_REPR(i->data)->setAttribute(attributeName, "none"); + + if (ungroup_masked && SP_IS_GROUP(i->data)) { + // if we had previously enclosed masked object in group, + // add it to list so we can ungroup it later + SPGroup *item = SP_GROUP(i->data); + + // ungroup only groups we created when setting clip/mask + if (item->layerMode() == SPGroup::MASK_HELPER) { + items_to_ungroup = g_slist_prepend(items_to_ungroup, item); + } + + } } // restore mask objects into a document @@ -3024,6 +3105,17 @@ void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) { g_slist_free(items_to_move); } + + // ungroup marked groups added when setting mask + for (GSList *i = items_to_ungroup ; NULL != i ; i = i->next) { + selection->remove(SP_GROUP(i->data)); + GSList *children = NULL; + sp_item_group_ungroup(SP_GROUP(i->data), &children, false); + selection->addList(children); + g_slist_free(children); + } + + g_slist_free(items_to_ungroup); if (apply_clip_path) sp_document_done(doc, SP_VERB_OBJECT_UNSET_CLIPPATH, _("Release clipping path")); |
