From: buliabyak Date: Sun, 19 Mar 2006 23:19:10 +0000 (+0000) Subject: patch by Andrius R. for (un)clip and (un)mask commands X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=b3f56023dab178fd94e7b5809f9e33bbfada7fc9;hp=769e2ebfd64f566a545bd8bf16b9597690c0e230;p=inkscape.git patch by Andrius R. for (un)clip and (un)mask commands --- diff --git a/src/menus-skeleton.h b/src/menus-skeleton.h index 0ecfb7cef..7d8a5803d 100644 --- a/src/menus-skeleton.h +++ b/src/menus-skeleton.h @@ -149,6 +149,15 @@ static char const menus_skeleton[] = " \n" " \n" " \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" " \n" " \n" " \n" diff --git a/src/preferences-skeleton.h b/src/preferences-skeleton.h index 688a080fa..5873622dd 100644 --- a/src/preferences-skeleton.h +++ b/src/preferences-skeleton.h @@ -181,6 +181,7 @@ static char const preferences_skeleton[] = " \n" " \n" " \n" +" \n" " \n" "\n" " " diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index cd6fb2823..a92cb1a73 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -8,8 +8,9 @@ * Frank Felfe * MenTaLguY * bulia byak + * Andrius R. * - * Copyright (C) 1999-2005 authors + * Copyright (C) 1999-2006 authors * Copyright (C) 2001-2002 Ximian, Inc. * * Released under GNU GPL, read the file 'COPYING' for more information @@ -58,9 +59,12 @@ #include "sp-namedview.h" #include "prefs-utils.h" #include "sp-offset.h" +#include "sp-clippath.h" +#include "sp-mask.h" #include "file.h" #include "layer-fns.h" #include "context-fns.h" +#include using NR::X; using NR::Y; @@ -786,14 +790,14 @@ void sp_selection_lower_to_bottom() } void -sp_undo(SPDesktop *desktop, SPDocument *doc) +sp_undo(SPDesktop *desktop, SPDocument *) { if (!sp_document_undo(SP_DT_DOCUMENT(desktop))) desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Nothing to undo.")); } void -sp_redo(SPDesktop *desktop, SPDocument *doc) +sp_redo(SPDesktop *desktop, SPDocument *) { if (!sp_document_redo(SP_DT_DOCUMENT(desktop))) desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Nothing to redo.")); @@ -2231,6 +2235,172 @@ sp_selection_create_bitmap_copy () g_free (filepath); } +/** + * \brief sp_selection_set_mask + * + * This function creates a mask or clipPath from selection + * Two different modes: + * if applyToLayer, all selection is moved to DEFS as mask/clippath + * and is applied to current layer + * otherwise, topmost object is used as mask for other objects + * If \a apply_clip_path parameter is true, clipPath is created, otherwise mask + * + */ +void +sp_selection_set_mask(bool apply_clip_path, bool apply_to_layer) +{ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if (desktop == NULL) + return; + + SPDocument *document = SP_DT_DOCUMENT(desktop); + + Inkscape::Selection *selection = SP_DT_SELECTION(desktop); + + // check if something is selected + bool is_empty = selection->isEmpty(); + if ( apply_to_layer && is_empty) { + desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select object(s) to create mask from.")); + return; + } else if (!apply_to_layer && ( is_empty || NULL == selection->itemList()->next )) { + desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select mask object and object(s) to apply mask to.")); + return; + } + + sp_document_ensure_up_to_date(document); + + GSList *items = g_slist_copy((GSList *) selection->itemList()); + + items = g_slist_sort (items, (GCompareFunc) sp_object_compare_position); + + // create a list of duplicates + GSList *mask_items = NULL; + GSList *apply_to_items = NULL; + bool topmost = prefs_get_int_attribute ("options.maskobject", "topmost", 1); + bool remove_original = prefs_get_int_attribute ("options.maskobject", "remove", 1); + + if (apply_to_layer) { + // all selected items are used for mask, which is applied to a layer + apply_to_items = g_slist_prepend (apply_to_items, SP_OBJECT_REPR(desktop->currentLayer())); + + for (GSList *i = items; i != NULL; i = i->next) { + Inkscape::XML::Node *dup = (SP_OBJECT_REPR (i->data))->duplicate(); + mask_items = g_slist_prepend (mask_items, dup); + + if (remove_original) { + SPObject *item = SP_OBJECT (i->data); + item->deleteObject (false); + } + } + } else if (!topmost) { + // topmost item is used as a mask, which is applied to other items in a selection + GSList *i = items; + Inkscape::XML::Node *dup = (SP_OBJECT_REPR (i->data))->duplicate(); + mask_items = g_slist_prepend (mask_items, dup); + + if (remove_original) { + SPObject *item = SP_OBJECT (i->data); + item->deleteObject (false); + } + + for (i = i->next; i != NULL; i = i->next) { + apply_to_items = g_slist_prepend (apply_to_items, SP_OBJECT_REPR (i->data)); + } + } else { + GSList *i = NULL; + for (i = items; NULL != i->next; i = i->next) { + apply_to_items = g_slist_prepend (apply_to_items, SP_OBJECT_REPR (i->data)); + } + + Inkscape::XML::Node *dup = (SP_OBJECT_REPR (i->data))->duplicate(); + mask_items = g_slist_prepend (mask_items, dup); + + if (remove_original) { + SPObject *item = SP_OBJECT (i->data); + item->deleteObject (false); + } + } + + g_slist_free (items); + + const gchar *mask_id = NULL; + if (apply_clip_path) { + mask_id = sp_clippath_create(mask_items, document); + } else { + mask_id = sp_mask_create(mask_items, document); + } + g_slist_free (mask_items); + + gchar const* attributeName = apply_clip_path ? "clip-path" : "mask"; + for (GSList *i = apply_to_items; NULL != i; i = i->next) { + ((Inkscape::XML::Node *)i->data)->setAttribute(attributeName, g_strdup_printf("url(#%s)", mask_id)); + } + + g_slist_free (apply_to_items); + + sp_document_done (document); +} + +void sp_selection_unset_mask(bool apply_clip_path) { + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if (desktop == NULL) + return; + + SPDocument *document = SP_DT_DOCUMENT(desktop); + Inkscape::Selection *selection = SP_DT_SELECTION(desktop); + + // check if something is selected + if (selection->isEmpty()) { + desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select object(s) to remove mask from.")); + return; + } + + bool remove_original = prefs_get_int_attribute ("options.maskobject", "remove", 1); + sp_document_ensure_up_to_date(document); + + gchar const* attributeName = apply_clip_path ? "clip-path" : "mask"; + std::set referenced_objects; + for (GSList const*i = selection->itemList(); NULL != i; i = i->next) { + if (remove_original) { + // remember referenced mask/clippath, so orphaned masks can be moved back to document + SPItem *item = reinterpret_cast(i->data); + Inkscape::URIReference *uri_ref = NULL; + + if (apply_clip_path) { + uri_ref = item->clip_ref; + } else { + uri_ref = item->mask_ref; + } + + if (NULL != uri_ref && referenced_objects.end() == referenced_objects.find(uri_ref->getObject())) { + referenced_objects.insert(uri_ref->getObject()); + } + } + + SP_OBJECT_REPR(i->data)->setAttribute(attributeName, "none"); + } + + for ( std::set::iterator it = referenced_objects.begin() ; it != referenced_objects.end() ; ++it) { + SPObject *obj = (*it); + if (!obj->isReferenced()) { + GSList *items_to_move = NULL; + for (SPObject *child = sp_object_first_child(obj) ; child != NULL; child = SP_OBJECT_NEXT(child) ) { + Inkscape::XML::Node *copy = SP_OBJECT_REPR(child)->duplicate(); + items_to_move = g_slist_prepend (items_to_move, copy); + } + + obj->deleteObject(false); + + for (GSList *i = items_to_move; NULL != i; i = i->next) { + desktop->currentLayer()->appendChildRepr((Inkscape::XML::Node *)i->data); + } + + g_slist_free (items_to_move); + } + } + + sp_document_done (document); +} /* Local Variables: diff --git a/src/selection-chemistry.h b/src/selection-chemistry.h index 9fbeaa9ec..df8b69931 100644 --- a/src/selection-chemistry.h +++ b/src/selection-chemistry.h @@ -87,6 +87,9 @@ void sp_redo (SPDesktop *desktop, SPDocument *doc); void sp_selection_create_bitmap_copy (); +void sp_selection_set_mask(bool apply_clip_path, bool apply_to_layer); +void sp_selection_unset_mask(bool apply_clip_path); + /* selection cycling */ typedef enum diff --git a/src/sp-clippath.cpp b/src/sp-clippath.cpp index 086b6dcfa..33feea8ce 100644 --- a/src/sp-clippath.cpp +++ b/src/sp-clippath.cpp @@ -21,6 +21,7 @@ #include "enums.h" #include "attributes.h" #include "document.h" +#include "document-private.h" #include "sp-item.h" #include "sp-clippath.h" @@ -368,6 +369,27 @@ sp_clippath_view_list_remove(SPClipPathView *list, SPClipPathView *view) return list; } +// Create a mask element (using passed elements), add it to +const gchar * +sp_clippath_create (GSList *reprs, SPDocument *document) +{ + Inkscape::XML::Node *defsrepr = SP_OBJECT_REPR (SP_DOCUMENT_DEFS (document)); + + Inkscape::XML::Node *repr = sp_repr_new ("svg:clipPath"); + repr->setAttribute("clipPathUnits", "userSpaceOnUse"); + + defsrepr->appendChild(repr); + const gchar *id = repr->attribute("id"); + SPObject *clip_path_object = document->getObjectById(id); + + for (GSList *it = reprs; it != NULL; it = it->next) { + Inkscape::XML::Node *node = (Inkscape::XML::Node *)(it->data); + clip_path_object->appendChildRepr(node); + } + + Inkscape::GC::release(repr); + return id; +} /* Local Variables: diff --git a/src/sp-clippath.h b/src/sp-clippath.h index 0a8b92fa9..0f977a3e8 100644 --- a/src/sp-clippath.h +++ b/src/sp-clippath.h @@ -59,4 +59,6 @@ void sp_clippath_hide(SPClipPath *cp, unsigned int key); void sp_clippath_set_bbox(SPClipPath *cp, unsigned int key, NRRect *bbox); void sp_clippath_get_bbox(SPClipPath *cp, NRRect *bbox, NR::Matrix const &transform, unsigned const flags); +const gchar *sp_clippath_create (GSList *reprs, SPDocument *document); + #endif diff --git a/src/sp-mask.cpp b/src/sp-mask.cpp index 456dadc5f..773169d68 100644 --- a/src/sp-mask.cpp +++ b/src/sp-mask.cpp @@ -19,6 +19,7 @@ #include "enums.h" #include "attributes.h" #include "document.h" +#include "document-private.h" #include "sp-item.h" #include "sp-mask.h" @@ -266,6 +267,28 @@ sp_mask_write (SPObject *object, Inkscape::XML::Node *repr, guint flags) return repr; } +// Create a mask element (using passed elements), add it to +const gchar * +sp_mask_create (GSList *reprs, SPDocument *document) +{ + Inkscape::XML::Node *defsrepr = SP_OBJECT_REPR (SP_DOCUMENT_DEFS (document)); + + Inkscape::XML::Node *repr = sp_repr_new ("svg:mask"); + repr->setAttribute("maskUnits", "userSpaceOnUse"); + + defsrepr->appendChild(repr); + const gchar *mask_id = repr->attribute("id"); + SPObject *mask_object = document->getObjectById(mask_id); + + for (GSList *it = reprs; it != NULL; it = it->next) { + Inkscape::XML::Node *node = (Inkscape::XML::Node *)(it->data); + mask_object->appendChildRepr(node); + } + + Inkscape::GC::release(repr); + return mask_id; +} + NRArenaItem * sp_mask_show (SPMask *mask, NRArena *arena, unsigned int key) { diff --git a/src/sp-mask.h b/src/sp-mask.h index 23239f55d..b17ac8399 100644 --- a/src/sp-mask.h +++ b/src/sp-mask.h @@ -60,4 +60,6 @@ void sp_mask_hide (SPMask *mask, unsigned int key); void sp_mask_set_bbox (SPMask *mask, unsigned int key, NRRect *bbox); +const gchar *sp_mask_create (GSList *reprs, SPDocument *document); + #endif diff --git a/src/sp-object.h b/src/sp-object.h index e853de097..4879e5bea 100644 --- a/src/sp-object.h +++ b/src/sp-object.h @@ -287,6 +287,10 @@ struct SPObject : public GObject { } } + /** @brief Check if object is referenced by any other object. + */ + bool isReferenced() { return ( _total_hrefcount > 0 ); } + /** @brief Deletes an object. * * Detaches the object's repr, and optionally sends notification that the object has been diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp index 54977ac05..b90ed8d98 100644 --- a/src/ui/dialog/inkscape-preferences.cpp +++ b/src/ui/dialog/inkscape-preferences.cpp @@ -511,6 +511,14 @@ void InkscapePreferences::initPageMisc() _misc_overs_bitmap.init("options.bitmapoversample", "value", labels, values, num_items, 1); _page_misc.add_line( false, _("Oversample bitmaps:"), _misc_overs_bitmap, "", "", false); + _page_misc.add_group_header( _("Clipping and masking:")); + _misc_mask_on_top.init ( _("Use the topmost selected object as a clipping path or mask"), "options.maskobject", "topmost", true); + _page_misc.add_line(true, "", _misc_mask_on_top, "", + _("Uncheck this to use the bottom selected object as the clipping path or mask")); + _misc_mask_remove.init ( _("Remove clipping path or mask after applying"), "options.maskobject", "remove", true); + _page_misc.add_line(true, "", _misc_mask_remove, "", + _("Affter applying, remove the object used as the clipping path or mask from the drawing")); + this->AddPage(_page_misc, _("Misc"), PREFS_PAGE_MISC); } diff --git a/src/ui/dialog/inkscape-preferences.h b/src/ui/dialog/inkscape-preferences.h index de2010f12..af3dfa44b 100644 --- a/src/ui/dialog/inkscape-preferences.h +++ b/src/ui/dialog/inkscape-preferences.h @@ -125,6 +125,8 @@ protected: PrefSpinButton _misc_export, _misc_recent, _misc_simpl; PrefCheckButton _misc_imp_bitmap, _misc_comment, _misc_scripts; PrefCombo _misc_overs_bitmap; + PrefCheckButton _misc_mask_on_top; + PrefCheckButton _misc_mask_remove; int _max_dialog_width; int _max_dialog_height; diff --git a/src/verbs.cpp b/src/verbs.cpp index f262b9327..84da8703b 100644 --- a/src/verbs.cpp +++ b/src/verbs.cpp @@ -1196,6 +1196,18 @@ ObjectVerb::perform( SPAction *action, void *data, void *pdata ) } sp_document_done(SP_DT_DOCUMENT(dt)); break; + case SP_VERB_OBJECT_SET_MASK: + sp_selection_set_mask(false, false); + break; + case SP_VERB_OBJECT_UNSET_MASK: + sp_selection_unset_mask(false); + break; + case SP_VERB_OBJECT_SET_CLIPPATH: + sp_selection_set_mask(true, false); + break; + case SP_VERB_OBJECT_UNSET_CLIPPATH: + sp_selection_unset_mask(true); + break; default: break; } @@ -2025,6 +2037,14 @@ Verb *Verb::_base_verbs[] = { new ObjectVerb(SP_VERB_OBJECT_FLIP_VERTICAL, "ObjectFlipVertically", N_("Flip _Vertical"), N_("Flips selected objects vertically"), "object_flip_ver"), + new ObjectVerb(SP_VERB_OBJECT_SET_MASK, "ObjectSetMask", N_("_Set"), + N_("Apply mask to selection (using the topmost object as mask)"), NULL), + new ObjectVerb(SP_VERB_OBJECT_UNSET_MASK, "ObjectUnSetMask", N_("_Release"), + N_("Remove mask from selection"), NULL), + new ObjectVerb(SP_VERB_OBJECT_SET_CLIPPATH, "ObjectSetClipPath", N_("_Set"), + N_("Apply clipping path to selection (using the topmost object as clipping path)"), NULL), + new ObjectVerb(SP_VERB_OBJECT_UNSET_CLIPPATH, "ObjectUnSetClipPath", N_("_Release"), + N_("Remove clipping path from selection"), NULL), /* Tools */ new ContextVerb(SP_VERB_CONTEXT_SELECT, "DrawSelect", N_("Select"), diff --git a/src/verbs.h b/src/verbs.h index acc6d7d17..426b4295f 100644 --- a/src/verbs.h +++ b/src/verbs.h @@ -115,6 +115,10 @@ enum { SP_VERB_OBJECT_FLOWTEXT_TO_TEXT, SP_VERB_OBJECT_FLIP_HORIZONTAL, SP_VERB_OBJECT_FLIP_VERTICAL, + SP_VERB_OBJECT_SET_MASK, + SP_VERB_OBJECT_UNSET_MASK, + SP_VERB_OBJECT_SET_CLIPPATH, + SP_VERB_OBJECT_UNSET_CLIPPATH, /* Tools */ SP_VERB_CONTEXT_SELECT, SP_VERB_CONTEXT_NODE,