index 0f92f96805aa93f1907f795fe1b2000d3c48cba8..3e0da0571e92f24f9edb3d97058a8da659906d1c 100644 (file)
#include <gtkmm/clipboard.h>
#include "svg/svg.h"
-#include "inkscape.h"
#include "desktop.h"
#include "desktop-style.h"
#include "selection.h"
#include "libnr/nr-matrix-translate-ops.h"
#include "libnr/nr-rotate-fns.h"
#include "libnr/nr-scale-ops.h"
+#include <libnr/nr-matrix-ops.h>
+#include <libnr/nr-rotate-ops.h>
#include "libnr/nr-scale-translate-ops.h"
#include "libnr/nr-translate-matrix-ops.h"
#include "libnr/nr-translate-scale-ops.h"
#include "gradient-drag.h"
#include "uri-references.h"
#include "libnr/nr-convert2geom.h"
+#include "display/curve.h"
+#include "display/canvas-bpath.h"
// For clippath editing
#include "tools-switch.h"
@@ -130,7 +133,7 @@ void sp_selection_copy_impl (GSList const *items, GSList **clip, Inkscape::XML::
// Copy item reprs:
for (GSList *i = (GSList *) sorted_items; i != NULL; i = i->next) {
- sp_selection_copy_one (SP_OBJECT_REPR (i->data), from_2geom(sp_item_i2doc_affine(SP_ITEM (i->data))), clip, xml_doc);
+ sp_selection_copy_one (SP_OBJECT_REPR (i->data), sp_item_i2doc_affine(SP_ITEM (i->data)), clip, xml_doc);
}
*clip = g_slist_reverse(*clip);
@@ -148,10 +151,10 @@ GSList *sp_selection_paste_impl (SPDocument *doc, SPObject *parent, GSList **cli
Inkscape::XML::Node *copy = repr->duplicate(xml_doc);
// premultiply the item transform by the accumulated parent transform in the paste layer
- NR::Matrix local = from_2geom(sp_item_i2doc_affine(SP_ITEM(parent)));
+ NR::Matrix local (sp_item_i2doc_affine(SP_ITEM(parent)));
if (!local.test_identity()) {
gchar const *t_str = copy->attribute("transform");
- NR::Matrix item_t (NR::identity());
+ Geom::Matrix item_t (NR::identity());
if (t_str)
sp_svg_transform_read(t_str, &item_t);
item_t *= local.inverse();
@@ -181,9 +184,8 @@ void sp_selection_delete_impl(GSList const *items, bool propagate = true, bool p
}
-void sp_selection_delete()
+void sp_selection_delete(SPDesktop *desktop)
{
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
if (desktop == NULL) {
return;
}
_("Delete"));
}
-/* fixme: sequencing */
-void sp_selection_duplicate(bool suppressDone)
+void add_ids_recursive (std::vector<const gchar *> &ids, SPObject *obj)
+{
+ if (!obj)
+ return;
+
+ ids.push_back(SP_OBJECT_ID(obj));
+
+ if (SP_IS_GROUP(obj)) {
+ for (SPObject *child = sp_object_first_child(obj) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
+ add_ids_recursive (ids, child);
+ }
+ }
+}
+
+void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone)
{
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
if (desktop == NULL)
return;
- Inkscape::XML::Document* xml_doc = sp_document_repr_doc(desktop->doc());
+ SPDocument *doc = desktop->doc();
+ Inkscape::XML::Document* xml_doc = sp_document_repr_doc(doc);
Inkscape::Selection *selection = sp_desktop_selection(desktop);
// check if something is selected
selection->clear();
- // sorting items from different parents sorts each parent's subset without possibly mixing them, just what we need
+ // sorting items from different parents sorts each parent's subset without possibly mixing
+ // them, just what we need
reprs = g_slist_sort(reprs, (GCompareFunc) sp_repr_compare_position);
GSList *newsel = NULL;
+ std::vector<const gchar *> old_ids;
+ std::vector<const gchar *> new_ids;
+ bool relink_clones = prefs_get_int_attribute ("options.relinkclonesonduplicate", "value", 0);
+
while (reprs) {
- Inkscape::XML::Node *parent = ((Inkscape::XML::Node *) reprs->data)->parent();
- Inkscape::XML::Node *copy = ((Inkscape::XML::Node *) reprs->data)->duplicate(xml_doc);
+ Inkscape::XML::Node *old_repr = (Inkscape::XML::Node *) reprs->data;
+ Inkscape::XML::Node *parent = old_repr->parent();
+ Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc);
parent->appendChild(copy);
+ if (relink_clones) {
+ SPObject *old_obj = doc->getObjectByRepr(old_repr);
+ SPObject *new_obj = doc->getObjectByRepr(copy);
+ add_ids_recursive (old_ids, old_obj);
+ add_ids_recursive (new_ids, new_obj);
+ }
+
newsel = g_slist_prepend(newsel, copy);
reprs = g_slist_remove(reprs, reprs->data);
Inkscape::GC::release(copy);
}
+ if (relink_clones) {
+
+ g_assert (old_ids.size() == new_ids.size());
+
+ for(unsigned int i = 0; i < old_ids.size(); i++) {
+ const gchar *id = old_ids[i];
+ SPObject *old_clone = doc->getObjectById(id);
+ if (SP_IS_USE(old_clone)) {
+ SPItem *orig = sp_use_get_original(SP_USE(old_clone));
+ for(unsigned int j = 0; j < old_ids.size(); j++) {
+ if (!strcmp(SP_OBJECT_ID(orig), old_ids[j])) {
+ // we have both orig and clone in selection, relink
+ // std::cout << id << " old, its ori: " << SP_OBJECT_ID(orig) << "; will relink:" << new_ids[i] << " to " << new_ids[j] << "\n";
+ gchar *newref = g_strdup_printf ("#%s", new_ids[j]);
+ SPObject *new_clone = doc->getObjectById(new_ids[i]);
+ SP_OBJECT_REPR(new_clone)->setAttribute("xlink:href", newref);
+ new_clone->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ g_free (newref);
+ }
+ }
+ }
+ }
+ }
+
+
if ( !suppressDone ) {
sp_document_done(sp_desktop_document(desktop), SP_VERB_EDIT_DUPLICATE,
_("Duplicate"));
g_slist_free(newsel);
}
-void sp_edit_clear_all()
+void sp_edit_clear_all(SPDesktop *dt)
{
- SPDesktop *dt = SP_ACTIVE_DESKTOP;
if (!dt)
return;
@@ -309,9 +361,8 @@ get_all_items (GSList *list, SPObject *from, SPDesktop *desktop, bool onlyvisibl
return list;
}
-void sp_edit_select_all_full (bool force_all_layers, bool invert)
+void sp_edit_select_all_full (SPDesktop *dt, bool force_all_layers, bool invert)
{
- SPDesktop *dt = SP_ACTIVE_DESKTOP;
if (!dt)
return;
}
}
-void sp_edit_select_all ()
+void sp_edit_select_all (SPDesktop *desktop)
{
- sp_edit_select_all_full (false, false);
+ sp_edit_select_all_full (desktop, false, false);
}
-void sp_edit_select_all_in_all_layers ()
+void sp_edit_select_all_in_all_layers (SPDesktop *desktop)
{
- sp_edit_select_all_full (true, false);
+ sp_edit_select_all_full (desktop, true, false);
}
-void sp_edit_invert ()
+void sp_edit_invert (SPDesktop *desktop)
{
- sp_edit_select_all_full (false, true);
+ sp_edit_select_all_full (desktop, false, true);
}
-void sp_edit_invert_in_all_layers ()
+void sp_edit_invert_in_all_layers (SPDesktop *desktop)
{
- sp_edit_select_all_full (true, true);
+ sp_edit_select_all_full (desktop, true, true);
}
-void sp_selection_group()
+void sp_selection_group(SPDesktop *desktop)
{
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
if (desktop == NULL)
return;
// At this point, current may already have no item, due to its being a clone whose original is already moved away
// So we copy it artificially calculating the transform from its repr->attr("transform") and the parent transform
gchar const *t_str = current->attribute("transform");
- NR::Matrix item_t (NR::identity());
+ Geom::Matrix item_t (NR::identity());
if (t_str)
sp_svg_transform_read(t_str, &item_t);
- item_t *= from_2geom(sp_item_i2doc_affine(SP_ITEM(doc->getObjectByRepr(current->parent()))));
+ item_t *= sp_item_i2doc_affine(SP_ITEM(doc->getObjectByRepr(current->parent())));
//FIXME: when moving both clone and original from a transformed group (either by
//grouping into another parent, or by cut/paste) the transform from the original's
//parent becomes embedded into original itself, and this affects its clones. Fix
Inkscape::GC::release(group);
}
-void sp_selection_ungroup()
+void sp_selection_ungroup(SPDesktop *desktop)
{
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
if (desktop == NULL)
return;
}
/** Finds out the minimum common bbox of the selected items. */
-static NR::Maybe<NR::Rect>
+static boost::optional<NR::Rect>
enclose_items(GSList const *items)
{
g_assert(items != NULL);
- NR::Maybe<NR::Rect> r = NR::Nothing();
+ boost::optional<NR::Rect> r;
for (GSList const *i = items; i; i = i->next) {
r = NR::union_bounds(r, sp_item_bbox_desktop((SPItem *) i->data));
}
}
void
-sp_selection_raise()
+sp_selection_raise(SPDesktop *desktop)
{
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
if (!desktop)
return;
rev = g_slist_sort(rev, (GCompareFunc) sp_item_repr_compare_position);
// Determine the common bbox of the selected items.
- NR::Maybe<NR::Rect> selected = enclose_items(items);
+ boost::optional<NR::Rect> selected = enclose_items(items);
// Iterate over all objects in the selection (starting from top).
if (selected) {
for (SPObject *newref = child->next; newref; newref = newref->next) {
// if the sibling is an item AND overlaps our selection,
if (SP_IS_ITEM(newref)) {
- NR::Maybe<NR::Rect> newref_bbox = sp_item_bbox_desktop(SP_ITEM(newref));
+ boost::optional<NR::Rect> newref_bbox = sp_item_bbox_desktop(SP_ITEM(newref));
if ( newref_bbox && selected->intersects(*newref_bbox) ) {
// AND if it's not one of our selected objects,
if (!g_slist_find((GSList *) items, newref)) {
Q_("undo_action|Raise"));
}
-void sp_selection_raise_to_top()
+void sp_selection_raise_to_top(SPDesktop *desktop)
{
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
if (desktop == NULL)
return;
}
void
-sp_selection_lower()
+sp_selection_lower(SPDesktop *desktop)
{
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
if (desktop == NULL)
return;
Inkscape::XML::Node *grepr = SP_OBJECT_REPR(group);
// Determine the common bbox of the selected items.
- NR::Maybe<NR::Rect> selected = enclose_items(items);
+ boost::optional<NR::Rect> selected = enclose_items(items);
/* Construct direct-ordered list of selected children. */
GSList *rev = g_slist_copy((GSList *) items);
for (SPObject *newref = prev_sibling(child); newref; newref = prev_sibling(newref)) {
// if the sibling is an item AND overlaps our selection,
if (SP_IS_ITEM(newref)) {
- NR::Maybe<NR::Rect> ref_bbox = sp_item_bbox_desktop(SP_ITEM(newref));
+ boost::optional<NR::Rect> ref_bbox = sp_item_bbox_desktop(SP_ITEM(newref));
if ( ref_bbox && selected->intersects(*ref_bbox) ) {
// AND if it's not one of our selected objects,
if (!g_slist_find((GSList *) items, newref)) {
_("Lower"));
}
-void sp_selection_lower_to_bottom()
+void sp_selection_lower_to_bottom(SPDesktop *desktop)
{
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
if (desktop == NULL)
return;
desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Nothing to redo."));
}
-void sp_selection_cut()
+void sp_selection_cut(SPDesktop *desktop)
{
sp_selection_copy();
- sp_selection_delete();
+ sp_selection_delete(desktop);
}
/**
}
// FIXME: also transform gradient/pattern fills, by forking? NO, this must be nondestructive
- double ex = NR::expansion(from_2geom(sp_item_i2doc_affine(item)));
+ double ex = NR::expansion(sp_item_i2doc_affine(item));
if (ex != 1.0) {
css = sp_css_attr_scale (css, ex);
}
cm->copy();
}
-void sp_selection_paste(bool in_place)
+void sp_selection_paste(SPDesktop *desktop, bool in_place)
{
Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get();
if(cm->paste(in_place))
- sp_document_done(SP_ACTIVE_DOCUMENT, SP_VERB_EDIT_PASTE, _("Paste"));
+ sp_document_done(sp_desktop_document(desktop), SP_VERB_EDIT_PASTE, _("Paste"));
}
-void sp_selection_paste_style()
+void sp_selection_paste_style(SPDesktop *desktop)
{
Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get();
if(cm->pasteStyle())
- sp_document_done(SP_ACTIVE_DOCUMENT, SP_VERB_EDIT_PASTE_STYLE, _("Paste style"));
+ sp_document_done(sp_desktop_document(desktop), SP_VERB_EDIT_PASTE_STYLE, _("Paste style"));
}
-void sp_selection_paste_livepatheffect()
+void sp_selection_paste_livepatheffect(SPDesktop *desktop)
{
Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get();
if(cm->pastePathEffect())
- sp_document_done(SP_ACTIVE_DOCUMENT, SP_VERB_EDIT_PASTE_LIVEPATHEFFECT,
+ sp_document_done(sp_desktop_document(desktop), SP_VERB_EDIT_PASTE_LIVEPATHEFFECT,
_("Paste live path effect"));
}
}
}
-void sp_selection_remove_livepatheffect()
+void sp_selection_remove_livepatheffect(SPDesktop *desktop)
{
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
if (desktop == NULL) return;
Inkscape::Selection *selection = sp_desktop_selection(desktop);
_("Remove live path effect"));
}
-void sp_selection_remove_filter ()
+void sp_selection_remove_filter (SPDesktop *desktop)
{
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
if (desktop == NULL) return;
Inkscape::Selection *selection = sp_desktop_selection(desktop);
}
-void sp_selection_paste_size (bool apply_x, bool apply_y)
+void sp_selection_paste_size (SPDesktop *desktop, bool apply_x, bool apply_y)
{
Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get();
if(cm->pasteSize(false, apply_x, apply_y))
- sp_document_done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_EDIT_PASTE_SIZE,
+ sp_document_done(sp_desktop_document(desktop), SP_VERB_EDIT_PASTE_SIZE,
_("Paste size"));
}
-void sp_selection_paste_size_separately (bool apply_x, bool apply_y)
+void sp_selection_paste_size_separately (SPDesktop *desktop, bool apply_x, bool apply_y)
{
Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get();
if(cm->pasteSize(true, apply_x, apply_y))
- sp_document_done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_EDIT_PASTE_SIZE_SEPARATELY,
+ sp_document_done(sp_desktop_document(desktop), SP_VERB_EDIT_PASTE_SIZE_SEPARATELY,
_("Paste size separately"));
}
-void sp_selection_to_next_layer(bool suppressDone)
+void sp_selection_to_next_layer(SPDesktop *dt, bool suppressDone)
{
- SPDesktop *dt = SP_ACTIVE_DESKTOP;
-
Inkscape::Selection *selection = sp_desktop_selection(dt);
// check if something is selected
g_slist_free ((GSList *) items);
}
-void sp_selection_to_prev_layer(bool suppressDone)
+void sp_selection_to_prev_layer(SPDesktop *dt, bool suppressDone)
{
- SPDesktop *dt = SP_ACTIVE_DESKTOP;
-
Inkscape::Selection *selection = sp_desktop_selection(dt);
// check if something is selected
@@ -1178,9 +1217,9 @@ void sp_selection_apply_affine(Inkscape::Selection *selection, NR::Matrix const
sp_object_read_attr (SP_OBJECT (item), "transform");
// calculate the matrix we need to apply to the clone to cancel its induced transform from its original
- NR::Matrix parent_transform = from_2geom(sp_item_i2root_affine(SP_ITEM(SP_OBJECT_PARENT (item))));
- NR::Matrix t = parent_transform * from_2geom(matrix_to_desktop (matrix_from_desktop (to_2geom(affine), item), item)) * parent_transform.inverse();
- NR::Matrix t_inv =parent_transform * from_2geom(matrix_to_desktop (matrix_from_desktop (to_2geom(affine.inverse()), item), item)) * parent_transform.inverse();
+ NR::Matrix parent_transform = sp_item_i2root_affine(SP_ITEM(SP_OBJECT_PARENT (item)));
+ NR::Matrix t = parent_transform * from_2geom(matrix_to_desktop (matrix_from_desktop (affine, item), item)) * parent_transform.inverse();
+ NR::Matrix t_inv =parent_transform * from_2geom(matrix_to_desktop (matrix_from_desktop (affine.inverse(), item), item)) * parent_transform.inverse();
NR::Matrix result = t_inv * item->transform * t;
if ((prefs_parallel || prefs_unmoved) && affine.is_translation()) {
@@ -1208,7 +1247,7 @@ void sp_selection_apply_affine(Inkscape::Selection *selection, NR::Matrix const
} else {
if (set_i2d) {
- sp_item_set_i2d_affine(item, sp_item_i2d_affine(item) * to_2geom(affine));
+ sp_item_set_i2d_affine(item, sp_item_i2d_affine(item) * (Geom::Matrix)affine);
}
sp_item_write_transform(item, SP_OBJECT_REPR(item), item->transform, NULL);
}
@@ -1222,9 +1261,8 @@ void sp_selection_apply_affine(Inkscape::Selection *selection, NR::Matrix const
}
}
-void sp_selection_remove_transform()
+void sp_selection_remove_transform(SPDesktop *desktop)
{
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
if (desktop == NULL)
return;
if (selection->isEmpty())
return;
- NR::Maybe<NR::Rect> const bbox(selection->bounds());
+ boost::optional<NR::Rect> const bbox(selection->bounds());
if ( !bbox || bbox->isEmpty() ) {
return;
}
@@ -1270,7 +1308,7 @@ void sp_selection_scale_relative(Inkscape::Selection *selection, NR::Point const
if (selection->isEmpty())
return;
- NR::Maybe<NR::Rect> const bbox(selection->bounds());
+ boost::optional<NR::Rect> const bbox(selection->bounds());
if ( !bbox || bbox->isEmpty() ) {
return;
@@ -1329,10 +1367,8 @@ void sp_selection_move_relative(Inkscape::Selection *selection, double dx, doubl
*
*/
-void sp_selection_rotate_90_cw()
+void sp_selection_rotate_90_cw(SPDesktop *desktop)
{
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
-
Inkscape::Selection *selection = sp_desktop_selection(desktop);
if (selection->isEmpty())
/**
* @brief Rotates selected objects 90 degrees counter-clockwise.
*/
-void sp_selection_rotate_90_ccw()
+void sp_selection_rotate_90_ccw(SPDesktop *desktop)
{
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
-
Inkscape::Selection *selection = sp_desktop_selection(desktop);
if (selection->isEmpty())
@@ -1379,7 +1413,7 @@ sp_selection_rotate(Inkscape::Selection *selection, gdouble const angle_degrees)
if (selection->isEmpty())
return;
- NR::Maybe<NR::Point> center = selection->center();
+ boost::optional<NR::Point> center = selection->center();
if (!center) {
return;
}
if (selection->isEmpty())
return;
- NR::Maybe<NR::Rect> const bbox(selection->bounds());
- NR::Maybe<NR::Point> center = selection->center();
+ boost::optional<NR::Rect> const bbox(selection->bounds());
+ boost::optional<NR::Point> center = selection->center();
if ( !bbox || !center ) {
return;
if (selection->isEmpty())
return;
- NR::Maybe<NR::Rect> const bbox(selection->bounds());
+ boost::optional<NR::Rect> const bbox(selection->bounds());
if (!bbox) {
return;
}
if (selection->isEmpty())
return;
- NR::Maybe<NR::Rect> sel_bbox = selection->bounds();
+ boost::optional<NR::Rect> sel_bbox = selection->bounds();
if (!sel_bbox) {
return;
}
void
-sp_selection_move(gdouble dx, gdouble dy)
+sp_selection_move(SPDesktop *desktop, gdouble dx, gdouble dy)
{
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
Inkscape::Selection *selection = sp_desktop_selection(desktop);
if (selection->isEmpty()) {
return;
}
void
-sp_selection_move_screen(gdouble dx, gdouble dy)
+sp_selection_move_screen(SPDesktop *desktop, gdouble dx, gdouble dy)
{
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
-
Inkscape::Selection *selection = sp_desktop_selection(desktop);
if (selection->isEmpty()) {
return;
}
void
-sp_selection_item_next(void)
+sp_selection_item_next(SPDesktop *desktop)
{
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
g_return_if_fail(desktop != NULL);
Inkscape::Selection *selection = sp_desktop_selection(desktop);
}
void
-sp_selection_item_prev(void)
+sp_selection_item_prev(SPDesktop *desktop)
{
- SPDocument *document = SP_ACTIVE_DOCUMENT;
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ SPDocument *document = sp_desktop_document(desktop);
g_return_if_fail(document != NULL);
g_return_if_fail(desktop != NULL);
Inkscape::Selection *selection = sp_desktop_selection(desktop);
}
ShapeEditor * shape_editor = SP_NODE_CONTEXT( dt->event_context )->shape_editor;
- shape_editor->set_item(SP_ITEM(child));
+ // TODO: should we set the item for nodepath or knotholder or both? seems to work with both.
+ shape_editor->set_item(SP_ITEM(child), SH_NODEPATH);
+ shape_editor->set_item(SP_ITEM(child), SH_KNOTHOLDER);
Inkscape::NodePath::Path *np = shape_editor->get_nodepath();
if (np) {
// take colors from prefs (same as used in outline mode)
void scroll_to_show_item(SPDesktop *desktop, SPItem *item)
{
NR::Rect dbox = desktop->get_display_area();
- NR::Maybe<NR::Rect> sbox = sp_item_bbox_desktop(item);
+ boost::optional<NR::Rect> sbox = sp_item_bbox_desktop(item);
if ( sbox && dbox.contains(*sbox) == false ) {
NR::Point const s_dt = sbox->midpoint();
void
-sp_selection_clone()
+sp_selection_clone(SPDesktop *desktop)
{
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
if (desktop == NULL)
return;
}
void
-sp_selection_unlink()
+sp_selection_relink(SPDesktop *desktop)
{
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
if (!desktop)
return;
Inkscape::Selection *selection = sp_desktop_selection(desktop);
if (selection->isEmpty()) {
- desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select a <b>clone</b> to unlink."));
+ desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>clones</b> to relink."));
+ return;
+ }
+
+ Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get();
+ const gchar *newid = cm->getFirstObjectID();
+ if (!newid) {
+ desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Copy an <b>object</b> to clipboard to relink clones to."));
+ return;
+ }
+ gchar *newref = g_strdup_printf ("#%s", newid);
+
+ // Get a copy of current selection.
+ bool relinked = false;
+ for (GSList *items = (GSList *) selection->itemList();
+ items != NULL;
+ items = items->next)
+ {
+ SPItem *item = (SPItem *) items->data;
+
+ if (!SP_IS_USE(item))
+ continue;
+
+ SP_OBJECT_REPR(item)->setAttribute("xlink:href", newref);
+ SP_OBJECT(item)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ relinked = true;
+ }
+
+ g_free(newref);
+
+ if (!relinked) {
+ desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("<b>No clones to relink</b> in the selection."));
+ } else {
+ sp_document_done(sp_desktop_document(desktop), SP_VERB_EDIT_UNLINK_CLONE,
+ _("Relink clone"));
+ }
+}
+
+
+void
+sp_selection_unlink(SPDesktop *desktop)
+{
+ if (!desktop)
+ return;
+
+ Inkscape::Selection *selection = sp_desktop_selection(desktop);
+
+ if (selection->isEmpty()) {
+ desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>clones</b> to unlink."));
return;
}
}
void
-sp_select_clone_original()
+sp_select_clone_original(SPDesktop *desktop)
{
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
if (desktop == NULL)
return;
}
if (original) {
+
+ bool highlight = prefs_get_int_attribute ("options.highlightoriginal", "value", 0);
+ if (highlight) {
+ boost::optional<NR::Rect> a = item->getBounds(sp_item_i2d_affine(item));
+ boost::optional<NR::Rect> b = original->getBounds(sp_item_i2d_affine(original));
+ if ( a && b ) {
+ // draw a flashing line between the objects
+ SPCurve *curve = new SPCurve();
+ curve->moveto(a->midpoint());
+ curve->lineto(b->midpoint());
+
+ SPCanvasItem * canvasitem = sp_canvas_bpath_new(sp_desktop_tempgroup(desktop), curve);
+ sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(canvasitem), 0x0000ddff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT, 5, 3);
+ sp_canvas_item_show(canvasitem);
+ curve->unref();
+ desktop->add_temporary_canvasitem (canvasitem, 1000);
+ }
+ }
+
selection->clear();
selection->set(original);
if (SP_CYCLING == SP_CYCLE_FOCUS) {
}
-void sp_selection_to_marker(bool apply)
+void sp_selection_to_marker(SPDesktop *desktop, bool apply)
{
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
if (desktop == NULL)
return;
}
sp_document_ensure_up_to_date(doc);
- NR::Maybe<NR::Rect> r = selection->bounds();
- NR::Maybe<NR::Point> c = selection->center();
+ boost::optional<NR::Rect> r = selection->bounds();
+ boost::optional<NR::Point> c = selection->center();
if ( !r || !c || r->isEmpty() ) {
return;
}
// bottommost object, after sorting
SPObject *parent = SP_OBJECT_PARENT (items->data);
- NR::Matrix parent_transform = from_2geom(sp_item_i2root_affine(SP_ITEM(parent)));
+ NR::Matrix parent_transform (sp_item_i2root_affine(SP_ITEM(parent)));
// remember the position of the first item
gint pos = SP_OBJECT_REPR (items->data)->position();
@@ -2081,9 +2175,8 @@ static void sp_selection_to_guides_recursive(SPItem *item, bool deleteitem, bool
}
}
-void sp_selection_to_guides()
+void sp_selection_to_guides(SPDesktop *desktop)
{
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
if (desktop == NULL)
return;
}
void
-sp_selection_tile(bool apply)
+sp_selection_tile(SPDesktop *desktop, bool apply)
{
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
if (desktop == NULL)
return;
}
sp_document_ensure_up_to_date(doc);
- NR::Maybe<NR::Rect> r = selection->bounds();
+ boost::optional<NR::Rect> r = selection->bounds();
if ( !r || r->isEmpty() ) {
return;
}
// bottommost object, after sorting
SPObject *parent = SP_OBJECT_PARENT (items->data);
- NR::Matrix parent_transform = from_2geom(sp_item_i2root_affine(SP_ITEM(parent)));
+ NR::Matrix parent_transform (sp_item_i2root_affine(SP_ITEM(parent)));
// remember the position of the first item
gint pos = SP_OBJECT_REPR (items->data)->position();
}
void
-sp_selection_untile()
+sp_selection_untile(SPDesktop *desktop)
{
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
if (desktop == NULL)
return;
@@ -2354,9 +2445,8 @@ sp_document_get_export_hints (SPDocument *doc, char const **filename, float *xdp
}
void
-sp_selection_create_bitmap_copy ()
+sp_selection_create_bitmap_copy (SPDesktop *desktop)
{
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
if (desktop == NULL)
return;
}
// Calculate the matrix that will be applied to the image so that it exactly overlaps the source objects
- NR::Matrix eek = from_2geom(sp_item_i2d_affine (SP_ITEM(parent_object)));
+ NR::Matrix eek (sp_item_i2d_affine (SP_ITEM(parent_object)));
NR::Matrix t;
double shift_x = bbox.x0;
// Run filter, if any
if (run) {
g_print ("Running external filter: %s\n", run);
- system (run);
+ int retval;
+ retval = system (run);
}
// Import the image back
*
*/
void
-sp_selection_set_mask(bool apply_clip_path, bool apply_to_layer)
+sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_to_layer)
{
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
if (desktop == NULL)
return;
sp_document_done (doc, SP_VERB_OBJECT_SET_MASK, _("Set mask"));
}
-void sp_selection_unset_mask(bool apply_clip_path) {
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) {
if (desktop == NULL)
return;
sp_document_ensure_up_to_date(doc);
gchar const *attributeName = apply_clip_path ? "clip-path" : "mask";
- std::map<SPObject*,SPItem*> referenced_objects;
+ std::map<SPObject*,SPItem*> referenced_objects;
+ // 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) {
if (remove_original) {
// remember referenced mask/clippath, so orphaned masks can be moved back to document
// 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;
+ SPObject *obj = (*it).first; // Group containing the clipped paths or masks
GSList *items_to_move = NULL;
for (SPObject *child = sp_object_first_child(obj) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
+ // Collect all clipped paths and masks within a single group
Inkscape::XML::Node *copy = SP_OBJECT_REPR(child)->duplicate(xml_doc);
items_to_move = g_slist_prepend (items_to_move, copy);
}
Inkscape::XML::Node *parent = SP_OBJECT_REPR((*it).second)->parent();
gint pos = SP_OBJECT_REPR((*it).second)->position();
+ // Iterate through all clipped paths / masks
for (GSList *i = items_to_move; NULL != i; i = i->next) {
Inkscape::XML::Node *repr = (Inkscape::XML::Node *)i->data;
sp_document_done (doc, SP_VERB_OBJECT_UNSET_MASK, _("Release mask"));
}
-void fit_canvas_to_selection(SPDesktop *desktop) {
- g_return_if_fail(desktop != NULL);
+/**
+ * Returns true if an undoable change should be recorded.
+ */
+bool
+fit_canvas_to_selection(SPDesktop *desktop)
+{
+ g_return_val_if_fail(desktop != NULL, false);
SPDocument *doc = sp_desktop_document(desktop);
- g_return_if_fail(doc != NULL);
- g_return_if_fail(desktop->selection != NULL);
+ g_return_val_if_fail(doc != NULL, false);
+ g_return_val_if_fail(desktop->selection != NULL, false);
if (desktop->selection->isEmpty()) {
desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to fit canvas to."));
- return;
+ return false;
}
- NR::Maybe<NR::Rect> const bbox(desktop->selection->bounds());
+ boost::optional<NR::Rect> const bbox(desktop->selection->bounds());
if (bbox && !bbox->isEmpty()) {
doc->fitToRect(*bbox);
+ return true;
+ } else {
+ return false;
}
-};
+}
-void fit_canvas_to_drawing(SPDocument *doc) {
- g_return_if_fail(doc != NULL);
+/**
+ * Fit canvas to the bounding box of the selection, as an undoable action.
+ */
+void
+verb_fit_canvas_to_selection(SPDesktop *const desktop)
+{
+ if (fit_canvas_to_selection(desktop)) {
+ sp_document_done(sp_desktop_document(desktop), SP_VERB_FIT_CANVAS_TO_SELECTION,
+ _("Fit Page to Selection"));
+ }
+}
+
+bool
+fit_canvas_to_drawing(SPDocument *doc)
+{
+ g_return_val_if_fail(doc != NULL, false);
sp_document_ensure_up_to_date(doc);
SPItem const *const root = SP_ITEM(doc->root);
- NR::Maybe<NR::Rect> const bbox(root->getBounds(from_2geom(sp_item_i2r_affine(root))));
+ boost::optional<NR::Rect> const bbox(root->getBounds(sp_item_i2r_affine(root)));
if (bbox && !bbox->isEmpty()) {
doc->fitToRect(*bbox);
+ return true;
+ } else {
+ return false;
}
-};
+}
+
+void
+verb_fit_canvas_to_drawing(SPDesktop *desktop)
+{
+ if (fit_canvas_to_drawing(sp_desktop_document(desktop))) {
+ sp_document_done(sp_desktop_document(desktop), SP_VERB_FIT_CANVAS_TO_DRAWING,
+ _("Fit Page to Drawing"));
+ }
+}
void fit_canvas_to_selection_or_drawing(SPDesktop *desktop) {
g_return_if_fail(desktop != NULL);
g_return_if_fail(doc != NULL);
g_return_if_fail(desktop->selection != NULL);
- if (desktop->selection->isEmpty()) {
- fit_canvas_to_drawing(doc);
- } else {
- fit_canvas_to_selection(desktop);
+ bool const changed = ( desktop->selection->isEmpty()
+ ? fit_canvas_to_drawing(doc)
+ : fit_canvas_to_selection(desktop) );
+ if (changed) {
+ sp_document_done(sp_desktop_document(desktop), SP_VERB_FIT_CANVAS_TO_SELECTION_OR_DRAWING,
+ _("Fit Page to Selection or Drawing"));
}
-
- sp_document_done(doc, SP_VERB_FIT_CANVAS_TO_DRAWING,
- _("Fit page to selection"));
};
static void itemtree_map(void (*f)(SPItem *, SPDesktop *), SPObject *root, SPDesktop *desktop) {