index a92cb1a73d8eff147d5aafe8e19f50067c0b811a..4da9b33b86e15680b3588c2cee35c1ab2826a41d 100644 (file)
#include "file.h"
#include "layer-fns.h"
#include "context-fns.h"
-#include <set>
+#include <map>
using NR::X;
using NR::Y;
GSList *clipboard = NULL;
GSList *defs_clipboard = NULL;
SPCSSAttr *style_clipboard = NULL;
+NR::Rect size_clipboard(NR::Point(0,0), NR::Point(0,0));
static void sp_copy_stuff_used_by_item(GSList **defs_clip, SPItem *item, const GSList *items);
}
}
-void sp_copy_marker (GSList **defs_clip, SPMarker *marker)
+void sp_copy_single (GSList **defs_clip, SPObject *thing)
{
- Inkscape::XML::Node *marker_repr = SP_OBJECT_REPR(marker)->duplicate();
- *defs_clip = g_slist_prepend (*defs_clip, marker_repr);
+ Inkscape::XML::Node *duplicate_repr = SP_OBJECT_REPR(thing)->duplicate();
+ *defs_clip = g_slist_prepend (*defs_clip, duplicate_repr);
}
SPShape *shape = SP_SHAPE (item);
for (int i = 0 ; i < SP_MARKER_LOC_QTY ; i++) {
if (shape->marker[i]) {
- sp_copy_marker (defs_clip, SP_MARKER (shape->marker[i]));
+ sp_copy_single (defs_clip, SP_OBJECT (shape->marker[i]));
}
}
}
@@ -893,6 +894,20 @@ void sp_copy_stuff_used_by_item (GSList **defs_clip, SPItem *item, const GSList
sp_copy_textpath_path (defs_clip, SP_TEXTPATH(sp_object_first_child(SP_OBJECT(item))), items);
}
+ if (item->clip_ref->getObject()) {
+ sp_copy_single (defs_clip, item->clip_ref->getObject());
+ }
+
+ if (item->mask_ref->getObject()) {
+ SPObject *mask = item->mask_ref->getObject();
+ sp_copy_single (defs_clip, mask);
+ // recurse into the mask for its gradients etc.
+ for (SPObject *o = SP_OBJECT(mask)->children; o != NULL; o = o->next) {
+ if (SP_IS_ITEM(o))
+ sp_copy_stuff_used_by_item (defs_clip, SP_ITEM (o), items);
+ }
+ }
+
// recurse
for (SPObject *o = SP_OBJECT(item)->children; o != NULL; o = o->next) {
if (SP_IS_ITEM(o))
g_free (query);
}
+ size_clipboard = selection->bounds();
+
g_slist_free ((GSList *) items);
}
sp_document_done(SP_DT_DOCUMENT (desktop));
}
+void sp_selection_paste_size (bool apply_x, bool apply_y)
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ if (desktop == NULL) return;
+
+ Inkscape::Selection *selection = SP_DT_SELECTION(desktop);
+
+ // check if something is in the clipboard
+ if (size_clipboard.extent(NR::X) < 1e-6 || size_clipboard.extent(NR::Y) < 1e-6) {
+ desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Nothing on the clipboard."));
+ return;
+ }
+
+ // check if something is selected
+ if (selection->isEmpty()) {
+ desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to paste size to."));
+ return;
+ }
+
+ NR::Rect current = selection->bounds();
+ if (current.extent(NR::X) < 1e-6 || current.extent(NR::Y) < 1e-6) {
+ return;
+ }
+
+ double scale_x = size_clipboard.extent(NR::X) / current.extent(NR::X);
+ double scale_y = size_clipboard.extent(NR::Y) / current.extent(NR::Y);
+
+ sp_selection_scale_relative (selection, current.midpoint(),
+ NR::scale(
+ apply_x? scale_x : (desktop->isToolboxButtonActive ("lock")? scale_y : 1.0),
+ apply_y? scale_y : (desktop->isToolboxButtonActive ("lock")? scale_x : 1.0)));
+
+ sp_document_done(SP_DT_DOCUMENT (desktop));
+}
+
+void sp_selection_paste_size_separately (bool apply_x, bool apply_y)
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ if (desktop == NULL) return;
+
+ Inkscape::Selection *selection = SP_DT_SELECTION(desktop);
+
+ // check if something is in the clipboard
+ if (size_clipboard.extent(NR::X) < 1e-6 || size_clipboard.extent(NR::Y) < 1e-6) {
+ desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Nothing on the clipboard."));
+ return;
+ }
+
+ // check if something is selected
+ if (selection->isEmpty()) {
+ desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to paste size to."));
+ return;
+ }
+
+ for (GSList const *l = selection->itemList(); l != NULL; l = l->next) {
+ SPItem *item = SP_ITEM(l->data);
+
+ NR::Rect current = sp_item_bbox_desktop(item);
+ if (current.extent(NR::X) < 1e-6 || current.extent(NR::Y) < 1e-6) {
+ continue;
+ }
+
+ double scale_x = size_clipboard.extent(NR::X) / current.extent(NR::X);
+ double scale_y = size_clipboard.extent(NR::Y) / current.extent(NR::Y);
+
+ sp_item_scale_rel (item,
+ NR::scale(
+ apply_x? scale_x : (desktop->isToolboxButtonActive ("lock")? scale_y : 1.0),
+ apply_y? scale_y : (desktop->isToolboxButtonActive ("lock")? scale_x : 1.0)));
+
+ }
+
+ sp_document_done(SP_DT_DOCUMENT (desktop));
+}
+
void sp_selection_to_next_layer ()
{
SPDesktop *dt = SP_ACTIVE_DESKTOP;
@@ -1436,7 +1528,7 @@ sp_selection_rotate(Inkscape::Selection *selection, gdouble const angle_degrees)
if (selection->isEmpty())
return;
- NR::Point const center(selection->bounds().midpoint());
+ NR::Point center = selection->center();
sp_selection_rotate_relative(selection, center, angle_degrees);
return;
NR::Rect const bbox(selection->bounds());
- NR::Point const center(bbox.midpoint());
+
+ NR::Point center = selection->center();
gdouble const zoom = selection->desktop()->current_zoom();
gdouble const zmove = angle / zoom;
sp_repr_set_attr(clone, "x", "0");
sp_repr_set_attr(clone, "y", "0");
sp_repr_set_attr(clone, "xlink:href", g_strdup_printf("#%s", sel_repr->attribute("id")));
+
+ sp_repr_set_attr(clone, "inkscape:transform-center-x", sel_repr->attribute("inkscape:transform-center-x"));
+ sp_repr_set_attr(clone, "inkscape:transform-center-y", sel_repr->attribute("inkscape:transform-center-y"));
// add the new clone to the top of the original's parent
parent->appendChild(clone);
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()));
+ apply_to_items = g_slist_prepend (apply_to_items, desktop->currentLayer());
for (GSList *i = items; i != NULL; i = i->next) {
Inkscape::XML::Node *dup = (SP_OBJECT_REPR (i->data))->duplicate();
}
for (i = i->next; i != NULL; i = i->next) {
- apply_to_items = g_slist_prepend (apply_to_items, SP_OBJECT_REPR (i->data));
+ apply_to_items = g_slist_prepend (apply_to_items, 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));
+ apply_to_items = g_slist_prepend (apply_to_items, i->data);
}
Inkscape::XML::Node *dup = (SP_OBJECT_REPR (i->data))->duplicate();
}
g_slist_free (items);
+ items = NULL;
- 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));
+ SPItem *item = reinterpret_cast<SPItem *>(i->data);
+ // inverted object transform should be applied to a mask object,
+ // as mask is calculated in user space (after applying transform)
+ NR::Matrix maskTransform (item->transform.inverse());
+
+ GSList *mask_items_dup = NULL;
+ for (GSList *mask_item = mask_items; NULL != mask_item; mask_item = mask_item->next) {
+ Inkscape::XML::Node *dup = reinterpret_cast<Inkscape::XML::Node *>(mask_item->data)->duplicate();
+ mask_items_dup = g_slist_prepend (mask_items_dup, dup);
+ }
+
+ const gchar *mask_id = NULL;
+ if (apply_clip_path) {
+ mask_id = sp_clippath_create(mask_items_dup, document, &maskTransform);
+ } else {
+ mask_id = sp_mask_create(mask_items_dup, document, &maskTransform);
+ }
+
+ g_slist_free (mask_items_dup);
+ mask_items_dup = NULL;
+
+ SP_OBJECT_REPR(i->data)->setAttribute(attributeName, g_strdup_printf("url(#%s)", mask_id));
}
+ g_slist_free (mask_items);
g_slist_free (apply_to_items);
sp_document_done (document);
sp_document_ensure_up_to_date(document);
gchar const* attributeName = apply_clip_path ? "clip-path" : "mask";
- std::set<SPObject*> referenced_objects;
+ std::map<SPObject*,SPItem*> 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
} 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());
+
+ // collect distinct mask object (and associate with item to apply transform)
+ if (NULL != uri_ref && NULL != uri_ref->getObject()) {
+ referenced_objects[uri_ref->getObject()] = item;
}
}
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);
+ // restore mask objects into a document
+ for ( std::map<SPObject*,SPItem*>::iterator it = referenced_objects.begin() ; it != referenced_objects.end() ; ++it) {
+ SPObject *obj = (*it).first;
+ 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);
+ }
+
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);
- }
-
+ // delete from defs if no other object references this mask
obj->deleteObject(false);
+ }
- for (GSList *i = items_to_move; NULL != i; i = i->next) {
- desktop->currentLayer()->appendChildRepr((Inkscape::XML::Node *)i->data);
- }
+ for (GSList *i = items_to_move; NULL != i; i = i->next) {
+ SPItem *item = SP_ITEM(desktop->currentLayer()->appendChildRepr((Inkscape::XML::Node *)i->data));
+ selection->add((Inkscape::XML::Node *)i->data);
- g_slist_free (items_to_move);
+ // transform mask, so it is moved the same spot there mask was applied
+ NR::Matrix transform (item->transform);
+ transform *= (*it).second->transform;
+ sp_item_write_transform(item, SP_OBJECT_REPR(item), transform);
}
+
+ g_slist_free (items_to_move);
}
sp_document_done (document);