summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorbulia byak <buliabyak@gmail.com>2006-03-19 23:19:10 +0000
committerbuliabyak <buliabyak@users.sourceforge.net>2006-03-19 23:19:10 +0000
commit56203e13823d18965321e46218f4d2995287383d (patch)
tree608ea929af1aafc1b820344662881ed52ea34966 /src
parentrestore broken ngettext (diff)
downloadinkscape-56203e13823d18965321e46218f4d2995287383d.tar.gz
inkscape-56203e13823d18965321e46218f4d2995287383d.zip
patch by Andrius R. for (un)clip and (un)mask commands
(bzr r263)
Diffstat (limited to 'src')
-rw-r--r--src/menus-skeleton.h9
-rw-r--r--src/preferences-skeleton.h1
-rw-r--r--src/selection-chemistry.cpp176
-rw-r--r--src/selection-chemistry.h3
-rw-r--r--src/sp-clippath.cpp22
-rw-r--r--src/sp-clippath.h2
-rw-r--r--src/sp-mask.cpp23
-rw-r--r--src/sp-mask.h2
-rw-r--r--src/sp-object.h4
-rw-r--r--src/ui/dialog/inkscape-preferences.cpp8
-rw-r--r--src/ui/dialog/inkscape-preferences.h2
-rw-r--r--src/verbs.cpp20
-rw-r--r--src/verbs.h4
13 files changed, 273 insertions, 3 deletions
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[] =
" <verb verb-id=\"SelectionGroup\" />\n"
" <verb verb-id=\"SelectionUnGroup\" />\n"
" <separator/>\n"
+" <submenu name=\"" N_("Cli_p") "\">\n"
+" <verb verb-id=\"ObjectSetClipPath\" />\n"
+" <verb verb-id=\"ObjectUnSetClipPath\" />\n"
+" </submenu>\n"
+" <submenu name=\"" N_("Mas_k") "\">\n"
+" <verb verb-id=\"ObjectSetMask\" />\n"
+" <verb verb-id=\"ObjectUnSetMask\" />\n"
+" </submenu>\n"
+" <separator/>\n"
" <verb verb-id=\"SelectionRaise\" />\n"
" <verb verb-id=\"SelectionLower\" />\n"
" <verb verb-id=\"SelectionToFront\" />\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[] =
" <group id=\"kbselection\" inlayer=\"1\" onlyvisible=\"1\" onlysensitive=\"1\" />\n"
" <group id=\"createbitmap\" minsize=\"250\"/>\n"
" <group id=\"compassangledisplay\" value=\"0\"/>\n"
+" <group id=\"maskobject\" topmost=\"1\" remove=\"1\"/>\n"
" </group>\n"
"\n"
" <group id=\"extensions\" show-effects-menu=\"0\">"
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 <innerspace@iname.com>
* MenTaLguY <mental@rydia.net>
* bulia byak <buliabyak@users.sf.net>
+ * Andrius R. <knutux@gmail.com>
*
- * 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 <set>
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 <b>object(s)</b> 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 <b>object(s)</b> 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 <b>object(s)</b> 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<SPObject*> 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<SPItem *>(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<SPObject*>::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 <defs>
+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 <defs>
+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,