selection-chemistry.cpp revision 02ef7a51779058f930a074380d400342ab44d2d0
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński * Miscellanous operations on selected items.
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen * Lauris Kaplinski <lauris@kaplinski.com>
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen * Frank Felfe <innerspace@iname.com>
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen * MenTaLguY <mental@rydia.net>
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen * bulia byak <buliabyak@users.sf.net>
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen * Andrius R. <knutux@gmail.com>
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen * Jon A. Cruz <jon@joncruz.org>
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen * Martin Sucha <martin.sucha-inkscape@jts-sro.sk>
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen * Abhishek Sharma
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen * Kris De Gussem <Kris.DeGussem@gmail.com>
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen * Tavmjong Bah <tavmjong@free.fr> (Symbol additions)
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen * Copyright (C) 1999-2010,2012 authors
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen * Copyright (C) 2001-2002 Ximian, Inc.
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen * Released under GNU GPL, read the file 'COPYING' for more information
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen// TOOD fixme: This should be moved into preference repr
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen#include "live_effects/parameter/originalpath.h"
07bda0b13ae048815f53f21ad1edbe3cc1b7e4e8Johan Engelen// For clippath editing
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen/* The clipboard handling is in ui/clipboard.cpp now. There are some legacy functions left here,
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelenbecause the layer manipulation code uses them. It should be rewritten specifically
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelenfor that purpose. */
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen// helper for printing error messages, regardless of whether we have a GUI or not
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen// If desktop == NULL, errors will be shown on stderr
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelenselection_display_message(SPDesktop *desktop, Inkscape::MessageType msgType, Glib::ustring const &msg)
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen NodeTool *nt = static_cast<NodeTool*>(dt->event_context);
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelenvoid SelectionHelper::selectAllInAll(SPDesktop *dt)
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen NodeTool *nt = static_cast<NodeTool*>(dt->event_context);
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelenvoid SelectionHelper::selectNone(SPDesktop *dt)
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen nt = static_cast<NodeTool*>(dt->event_context);
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen // If nothing selected switch to selection tool
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelenvoid SelectionHelper::selectSameFillStroke(SPDesktop *dt)
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen sp_select_same_fill_stroke_style(dt, true, true, true);
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelenvoid SelectionHelper::selectSameFillColor(SPDesktop *dt)
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen sp_select_same_fill_stroke_style(dt, true, false, false);
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelenvoid SelectionHelper::selectSameStrokeColor(SPDesktop *dt)
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen sp_select_same_fill_stroke_style(dt, false, true, false);
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelenvoid SelectionHelper::selectSameStrokeStyle(SPDesktop *dt)
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelenvoid SelectionHelper::selectSameObjectType(SPDesktop *dt)
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen NodeTool *nt = static_cast<NodeTool*>(dt->event_context);
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelenvoid SelectionHelper::invertAllInAll(SPDesktop *dt)
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen NodeTool *nt = static_cast<NodeTool*>(dt->event_context);
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen // TODO make this a virtual method of event context!
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen NodeTool *nt = static_cast<NodeTool*>(dt->event_context);
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelenvoid SelectionHelper::selectNext(SPDesktop *dt)
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen Inkscape::UI::Tools::ToolBase *ec = dt->event_context;
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen NodeTool *nt = static_cast<NodeTool*>(dt->event_context);
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen Inkscape::UI::Tools::sp_gradient_context_select_next(ec);
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelenvoid SelectionHelper::selectPrev(SPDesktop *dt)
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen Inkscape::UI::Tools::ToolBase *ec = dt->event_context;
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen NodeTool *nt = static_cast<NodeTool*>(dt->event_context);
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen Inkscape::UI::Tools::sp_gradient_context_select_prev(ec);
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen * Fixes the current selection, removing locked objects from it
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelenvoid SelectionHelper::fixSelection(SPDesktop *dt)
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen Inkscape::Selection *selection = dt->getSelection();
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen GSList const *selList = selection->itemList();
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen for( GSList const *i = selList; i; i = i->next ) {
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen SPItem *item = dynamic_cast<SPItem *>(static_cast<SPObject *>(i->data));
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen} // namespace Inkscape
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen * Copies repr and its inherited css style elements, along with the accumulated transform 'full_t',
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen * then prepends the copy to 'clip'.
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelenstatic void sp_selection_copy_one(Inkscape::XML::Node *repr, Geom::Affine full_t, GSList **clip, Inkscape::XML::Document* xml_doc)
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen Inkscape::XML::Node *copy = repr->duplicate(xml_doc);
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen // copy complete inherited style
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen SPCSSAttr *css = sp_repr_css_attr_inherited(repr, "style");
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen // write the complete accumulated transform passed to us
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen // (we're dealing with unattached repr, so we write to its attr
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen // instead of using sp_item_set_transform)
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen gchar *affinestr=sp_svg_transform_write(full_t);
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelenstatic void sp_selection_copy_impl(GSList const *items, GSList **clip, Inkscape::XML::Document* xml_doc)
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen // Sort items:
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen GSList *sorted_items = g_slist_copy(const_cast<GSList *>(items));
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen sorted_items = g_slist_sort(static_cast<GSList *>(sorted_items), (GCompareFunc) sp_object_compare_position);
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński // Copy item reprs:
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen for (GSList *i = sorted_items; i != NULL; i = i->next) {
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen SPItem *item = dynamic_cast<SPItem *>(SP_OBJECT(i->data));
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen sp_selection_copy_one(item->getRepr(), item->i2doc_affine(), clip, xml_doc);
5738b9afc93525510fa01185f7609fd5cbb0ff1aJohan Engelen g_slist_free(static_cast<GSList *>(sorted_items));
// TODO check if parent parameter should be changed to SPItem, of if the code should handle non-items.
if (t_str)
// (we're dealing with unattached repr, so we write to its attr instead of using sp_item_set_transform)
return copied;
static void sp_selection_delete_impl(GSList const *items, bool propagate = true, bool propagate_descendants = true)
if (obj) {
desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to duplicate."));
while (reprs) {
if (relink_clones) {
if (fork_livepatheffects) {
if (newLPEObj) {
if (relink_clones) {
if (use) {
// std::cout << id << " old, its ori: " << orig->getId() << "; will relink:" << new_ids[i] << " to " << new_ids[j] << "\n";
if (offset) {
doc->getObjectById(new_ids[i])->getRepr()->setAttribute("xlink:href", Glib::ustring("#") + new_ids[j]);
if ( !suppressDone ) {
if (!selection)
while (items) {
GSList *get_all_items(GSList *list, SPObject *from, SPDesktop *desktop, bool onlyvisible, bool onlysensitive, bool ingroups, GSList const *exclude)
if (item &&
return list;
if (!dt)
PrefsSelectionContext inlayer = (PrefsSelectionContext) prefs->getInt("/options/kbselection/inlayer", PREFS_SELECTION_LAYER);
if (invert) {
if (force_all_layers)
switch (inlayer) {
case PREFS_SELECTION_LAYER: {
case PREFS_SELECTION_LAYER_RECURSIVE: {
if (items) {
static void sp_selection_group_impl(GSList *p, Inkscape::XML::Node *group, Inkscape::XML::Document *xml_doc, SPDocument *doc) {
Inkscape::XML::Node *topmost_parent = (static_cast<Inkscape::XML::Node *>(g_slist_last(p)->data))->parent();
// 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
if (t_str)
selection_display_message(desktop, Inkscape::WARNING_MESSAGE, _("Select <b>some objects</b> to group."));
selection_display_message(desktop, Inkscape::WARNING_MESSAGE, _("Select a <b>group</b> to ungroup."));
selection_display_message(desktop, Inkscape::ERROR_MESSAGE, _("<b>No groups</b> to ungroup in the selection."));
/** Replace all groups in the list with their member objects, recursively; returns a new list, frees old */
GSList *
bool has_groups = false;
if (!group) {
has_groups = true;
return out;
static SPGroup *
if (!items) {
return NULL;
return NULL;
return NULL;
return prev;
if (!items) {
selection_display_message(desktop, Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to raise."));
if (!group) {
selection_display_message(desktop, Inkscape::ERROR_MESSAGE, _("You cannot raise/lower objects from <b>different groups</b> or <b>layers</b>."));
if (selected) {
while (rev) {
if (newItem) {
selection_display_message(desktop, Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to raise to top."));
if (!group) {
selection_display_message(desktop, Inkscape::ERROR_MESSAGE, _("You cannot raise/lower objects from <b>different groups</b> or <b>layers</b>."));
if (!items) {
selection_display_message(desktop, Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to lower."));
if (!group) {
selection_display_message(desktop, Inkscape::ERROR_MESSAGE, _("You cannot raise/lower objects from <b>different groups</b> or <b>layers</b>."));
if (selected) {
while (rev) {
if (newItem) {
if (put_after)
selection_display_message(desktop, Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to lower to bottom."));
if (!group) {
selection_display_message(desktop, Inkscape::ERROR_MESSAGE, _("You cannot raise/lower objects from <b>different groups</b> or <b>layers</b>."));
minpos = 0;
return NULL;
for (SPObject *last_element = object->lastChild(); last_element != NULL; last_element = last_element->getPrev()) {
if (temp) {
if (!(dynamic_cast<SPText *>(object) || dynamic_cast<SPTSpan *>(object) || dynamic_cast<SPTRef *>(object) || dynamic_cast<SPString *>(object))) {
if (item) {
return css;
desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to remove live path effects from."));
for ( GSList const *itemlist = selection->itemList(); itemlist != NULL; itemlist = g_slist_next(itemlist) ) {
desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to remove filters from."));
if (item) {
item,
dt->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to move to the layer above."));
if (next) {
next=Inkscape::next_layer(dt->currentRoot(), dt->currentLayer()); // Fixes bug 1482973: crash while moving layers
if (next) {
no_more = true;
if ( !suppressDone ) {
no_more = true;
if (no_more) {
dt->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to move to the layer below."));
if (next) {
sp_selection_copy_impl(items, &temp_clip, dt->doc()->getReprDoc()); // we're in the same doc, so no need to copy defs
next=Inkscape::previous_layer(dt->currentRoot(), dt->currentLayer()); // Fixes bug 1482973: crash while moving layers
if (next) {
no_more = true;
if ( !suppressDone ) {
no_more = true;
if (no_more) {
if (moveto) {
sp_selection_copy_impl(items, &temp_clip, dt->doc()->getReprDoc()); // we're in the same doc, so no need to copy defs
if ( !suppressDone ) {
bool contains_original = false;
return contains_original;
bool clone_with_original = false;
if (item) {
if (clone_with_original)
return clone_with_original;
void sp_selection_apply_affine(Inkscape::Selection *selection, Geom::Affine const &affine, bool set_i2d, bool compensate, bool adjust_transf_center)
selection->desktop()->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Cannot transform an embedded SVG."));
bool transform_textpath_with_path = ((dynamic_cast<SPText *>(item) && item->firstChild() && dynamic_cast<SPTextPath *>(item->firstChild()))
&& selection->includes( sp_textpath_get_path_item(dynamic_cast<SPTextPath *>(item->firstChild())) ));
bool transform_flowtext_with_frame = (dynamic_cast<SPFlowtext *>(item) && selection->includes( dynamic_cast<SPFlowtext *>(item)->get_frame(NULL))); // (only the first frame is checked so far)
bool transform_offset_with_source = (dynamic_cast<SPOffset *>(item) && dynamic_cast<SPOffset *>(item)->sourceHref) && selection->includes( sp_offset_get_source(dynamic_cast<SPOffset *>(item)) );
if (path) {
int compensation = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED);
if (transform_textpath_with_path) {
} else if (transform_flowtext_with_frame) {
if ( use ) {
// calculate the matrix we need to apply to the clone to cancel its induced transform from its original
if (parentItem) {
if (use) {
if (prefs_parallel) {
} else if (prefs_unmoved) {
} else if (transform_offset_with_source && (prefs_parallel || prefs_unmoved) && affine.isTranslation()){
if (prefs_parallel) {
} else if (prefs_unmoved) {
if (set_i2d) {
if (adjust_transf_center) { // The transformation center should not be touched in case of pasting or importing, which is allowed by this if clause
while (l != NULL) {
l = l->next;
if ( !bbox ) {
void sp_selection_scale_relative(Inkscape::Selection *selection, Geom::Point const &align, Geom::Scale const &scale)
if ( !bbox ) {
// FIXME: ARBITRARY LIMIT: don't try to scale above 1 Mpx, it won't display properly and will crash sooner or later anyway
sp_selection_rotate_relative(Inkscape::Selection *selection, Geom::Point const ¢er, gdouble const angle_degrees)
sp_selection_skew_relative(Inkscape::Selection *selection, Geom::Point const &align, double dx, double dy)
void sp_selection_move_relative(Inkscape::Selection *selection, Geom::Point const &move, bool compensate)
* Rotates selected objects 90 degrees, either clock-wise or counter-clockwise, depending on the value of ccw.
Geom::Rotate const rot_90(Geom::Point(0, ccw ? 1 : -1)); // pos. or neg. rotation, depending on the value of ccw
if (item) {
if (!center) {
( ( angle_degrees > 0 )
* Selects all the visible items with the same fill and/or stroke color/style as the items in the current selection
void sp_select_same_fill_stroke_style(SPDesktop *desktop, gboolean fill, gboolean stroke, gboolean style)
if (!desktop) {
GSList *all_list = get_all_items(NULL, desktop->currentRoot(), desktop, onlyvisible, onlysensitive, ingroups, NULL);
if (fill) {
if (stroke) {
if (style) {
if (all_matches) {
if (all_list) {
if (!desktop) {
GSList *all_list = get_all_items(NULL, desktop->currentRoot(), desktop, onlyvisible, onlysensitive, ingroups, NULL);
if (sel) {
if (matches) {
if (all_list) {
if (!desktop) {
GSList *all_list = get_all_items(NULL, desktop->currentRoot(), desktop, onlyvisible, onlysensitive, ingroups, NULL);
if (sel) {
if (matches) {
if (all_list) {
if (iter) {
match = false;
if (sel_paint->isColor() && iter_paint->isColor() // color == color comparision doesnt seem to work here.
match = true;
if ((dynamic_cast<SPLinearGradient *>(sel_server) || dynamic_cast<SPRadialGradient *>(sel_server) ||
(dynamic_cast<SPGradient *>(sel_server) && dynamic_cast<SPGradient *>(sel_server)->getVector()->isSwatch()))
(dynamic_cast<SPGradient *>(iter_server) && dynamic_cast<SPGradient *>(iter_server)->getVector()->isSwatch()))) {
match = true;
match = true;
match = true;
match = true;
if (match) {
return matches;
if ( dynamic_cast<SPRect *>(i)) {
return ( dynamic_cast<SPRect *>(j) );
} else if (dynamic_cast<SPGenericEllipse *>(i)) {
return (dynamic_cast<SPGenericEllipse *>(j));
} else if (dynamic_cast<SPSpiral *>(i)) {
return (dynamic_cast<SPSpiral *>(j));
} else if (dynamic_cast<SPPath *>(i) || dynamic_cast<SPLine *>(i) || dynamic_cast<SPPolyLine *>(i)) {
} else if (dynamic_cast<SPText *>(i) || dynamic_cast<SPFlowtext *>(i) || dynamic_cast<SPTSpan *>(i) || dynamic_cast<SPTRef *>(i) || dynamic_cast<SPString *>(i)) {
return (dynamic_cast<SPText *>(j) || dynamic_cast<SPFlowtext *>(j) || dynamic_cast<SPTSpan *>(j) || dynamic_cast<SPTRef *>(j) || dynamic_cast<SPString *>(j));
} else if (dynamic_cast<SPUse *>(i)) {
return (dynamic_cast<SPUse *>(j)) ;
} else if (dynamic_cast<SPImage *>(i)) {
return (dynamic_cast<SPImage *>(j));
} else if (dynamic_cast<SPOffset *>(i) && dynamic_cast<SPOffset *>(i)->sourceHref) { // Linked offset
} else if (dynamic_cast<SPOffset *>(i) && !dynamic_cast<SPOffset *>(i)->sourceHref) { // Dynamic offset
return matches;
if (iter) {
match = false;
if (sel_style_for_width) {
match = true;
for (int i = 0; i < len; i++) {
match = false;
if (match) {
return matches;
return r.corner(i);
\param angle the angle in "angular pixels", i.e. how many visible pixels must move the outermost point of the rotated object
( (angle > 0)
if (!bbox) {
( (grow > 0)
if (!sel_bbox) {
if (dx == 0) {
} else if (dy == 0) {
if (dx == 0) {
} else if (dy == 0) {
struct Forward {
struct ListReverse {
g_slist_free(i);
return list;
PrefsSelectionContext inlayer = (PrefsSelectionContext)prefs->getInt("/options/kbselection/inlayer", PREFS_SELECTION_LAYER);
SPItem *item=next_item_from_list<Forward>(desktop, selection->itemList(), root, SP_CYCLING == SP_CYCLE_VISIBLE, inlayer, onlyvisible, onlysensitive);
if (item) {
PrefsSelectionContext inlayer = (PrefsSelectionContext) prefs->getInt("/options/kbselection/inlayer", PREFS_SELECTION_LAYER);
SPItem *item=next_item_from_list<ListReverse>(desktop, selection->itemList(), root, SP_CYCLING == SP_CYCLE_VISIBLE, inlayer, onlyvisible, onlysensitive);
if (item) {
if (!dt) return;
dt->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("The selection has no applied path effect."));
SPObject *root, bool only_in_viewport, PrefsSelectionContext inlayer, bool onlyvisible, bool onlysensitive)
while (items) {
return next;
if (path) {
found = next_item<D>(desktop, path->next, object, only_in_viewport, inlayer, onlyvisible, onlysensitive);
if ( item &&
return found;
// sorting items from different parents sorts each parent's subset without possibly mixing them, just what we need
while (reprs) {
clone->setAttribute("inkscape:transform-center-x", sel_repr->attribute("inkscape:transform-center-x"), false);
clone->setAttribute("inkscape:transform-center-y", sel_repr->attribute("inkscape:transform-center-y"), false);
if (!desktop)
if (!newid) {
desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Copy an <b>object</b> to clipboard to relink clones to."));
bool relinked = false;
relinked = true;
if (!relinked) {
desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("<b>No clones to relink</b> in the selection."));
if (!desktop)
bool unlinked = false;
if (tspan) {
unlinked = true;
if (use) {
if (!unlink) {
unlinked = true;
if (!unlinked) {
desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("<b>No clones to unlink</b> in the selection."));
gchar const *error = _("Select a <b>clone</b> to go to its original. Select a <b>linked offset</b> to go to its source. Select a <b>text on path</b> to go to the path. Select a <b>flowed text</b> to go to its frame.");
if (use) {
if (flowtext) {
if (lpeItem) {
Inkscape::LivePathEffect::Effect* lpe = lpeItem->getPathEffectOfType(Inkscape::LivePathEffect::CLONE_ORIGINAL);
if (lpe) {
if (Inkscape::LivePathEffect::OriginalPathParam *pathparam = dynamic_cast<Inkscape::LivePathEffect::OriginalPathParam *>(lpeparam)) {
if (!original) {
desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("<b>Cannot find</b> the object to select (orphaned clone, offset, textpath, flowed text?)"));
if (dynamic_cast<SPDefs *>(o)) {
desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("The object you're trying to select is <b>not visible</b> (it is in <defs>)"));
if (original) {
if (highlight) {
sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(canvasitem), 0x0000ddff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT, 5, 3);
if (firstItem) {
if (firstItem) {
desktop->doc()->getDefs()->getRepr()->addChild(lpe_repr, NULL); // adds to <defs> and assigns the 'id' attribute
if (clone_lpeitem) {
DocumentUndo::done(desktop->getDocument(), SP_VERB_EDIT_CLONE_ORIGINAL_PATH_LPE, _("Fill between many"));
desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to convert to marker."));
if (parent) {
if (apply) {
// See ActorAlign::on_button_click() in src/ui/dialog/align-and-distribute.cpp
int saved_compensation = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED);
(void)mark_id;
if (!items) {
desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to convert to guides."));
// If an object is earlier in the selection list than its clone, and it is deleted, then the clone will have changed
if (deleteitems) {
desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>objects</b> to convert to symbol."));
bool single_group = false;
if ( the_group ) {
single_group = true;
// See ActorAlign::on_button_click() in src/ui/dialog/align-and-distribute.cpp
int saved_compensation = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED);
if( single_group ) {
desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select a <b>symbol</b> to extract objects from."));
desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select only one <b>symbol</b> in Symbol dialog to convert to group."));
desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to convert to pattern."));
Geom::Point move_p = Geom::Point(0, doc->getHeight().value("px")) - (r->min() + Geom::Point(0, r->dimensions()[Geom::Y]));
if (parentItem) {
if (apply) {
// See ActorAlign::on_button_click() in src/ui/dialog/align-and-distribute.cpp
int saved_compensation = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED);
if (apply) {
desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select an <b>object with pattern fill</b> to extract objects from."));
bool did = false;
if (!basePat) {
did = true;
if (!did) {
desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("<b>No pattern fills</b> in the selection."));
void sp_selection_get_export_hints(Inkscape::Selection *selection, Glib::ustring &filename, float *xdpi, float *ydpi)
xdpi_search &&
if (filename_search) {
if (tmp){
if (xdpi_search) {
if (ydpi_search) {
void sp_document_get_export_hints(SPDocument *doc, Glib::ustring &filename, float *xdpi, float *ydpi)
if(tmp)
desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to make a bitmap copy."));
if (!bbox) {
return; // exceptional situation, so not bother with a translatable error message, just quit quietly
current);
g_strcanon(basename, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.=+~$#@^&!?", '_');
double res;
if (0 < prefs_res) {
} else if (0 < prefs_min) {
// If minsize is given, look up minimum bitmap size (default 250 pixels) and calculate resolution from it
res = Inkscape::Util::Quantity::convert(prefs_min, "in", "px") / MIN(bbox->width(), bbox->height());
if (hint_xdpi != 0) {
if (hint_xdpi != 0) {
unsigned width = (unsigned) floor(bbox->width() * Inkscape::Util::Quantity::convert(res, "px", "in"));
unsigned height =(unsigned) floor(bbox->height() * Inkscape::Util::Quantity::convert(res, "px", "in"));
// Calculate the matrix that will be applied to the image so that it exactly overlaps the source objects
if (parentItem) {
if (res == Inkscape::Util::Quantity::convert(1, "in", "px")) { // for default 96 dpi, snap it to pixel grid
shift_y = -round(-shift_y); // this gets correct rounding despite coordinate inversion, remove the negations when the inversion is gone
t = Geom::Scale(1, -1) * Geom::Translate(shift_x, shift_y) * eek.inverse(); /// @fixme hardcoded doc2dt transform?
items);
if (run) {
if (pb) {
if (res == Inkscape::Util::Quantity::convert(1, "in", "px")) { // for default 96 dpi, snap it to pixel grid
g_free(c);
desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to create clippath or mask from."));
Inkscape::XML::Node *topmost_parent = (static_cast<Inkscape::XML::Node *>(g_slist_last(p)->data))->parent();
// 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
if (t_str)
clone->setAttribute("inkscape:transform-center-x", inner->attribute("inkscape:transform-center-x"), false);
clone->setAttribute("inkscape:transform-center-y", inner->attribute("inkscape:transform-center-y"), false);
desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to create clippath or mask from."));
desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select mask object and <b>object(s)</b> to apply clippath or mask to."));
if (clone_with_original) {
if (apply_to_layer) {
if (remove_original) {
} else if (!topmost) {
if (remove_original) {
if (remove_original) {
Inkscape::XML::Node *dup = reinterpret_cast<Inkscape::XML::Node *>(mask_item->data)->duplicate(xml_doc);
if (apply_clip_path) {
if (apply_clip_path) {
desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to remove clippath or mask from."));
if (remove_original) {
if (apply_clip_path) {
for ( std::map<SPObject*,SPItem*>::iterator it = referenced_objects.begin() ; it != referenced_objects.end() ; ++it) {
if (group) {
if (apply_clip_path) {
desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to fit canvas to."));
if (bbox) {
if (bbox) {
* ui/dialog/page-sizer.
if (changed) {
if (!dt) return;
if (layer_only) {