Merge lp:~mc.../inkscape/mc-selection-transform into lp:~inkscape.dev/inkscape/trunk

Proposed by Mc
Status: Needs review
Proposed branch: lp:~mc.../inkscape/mc-selection-transform
Merge into: lp:~inkscape.dev/inkscape/trunk
Diff against target: 3772 lines (+882/-872)
3 files modified
src/selection-chemistry.cpp (+865/-872)
src/selection.cpp (+7/-0)
src/selection.h (+10/-0)
To merge this branch: bzr merge lp:~mc.../inkscape/mc-selection-transform
Reviewer Review Type Date Requested Status
Jabiertxof code Approve
Review via email: mp+269893@code.launchpad.net

Description of the change

Refactoring of sp_selection_apply_affine, taking care of the case when we select an original and a clone which is present in a selected group (and not directly selected)

To post a comment you must log in.
Revision history for this message
Mc (mc...) wrote :

NB: The diff is huge because i made a clang-format to have all the presentation right, the only non-whitespace parts are lines 1297-1651 and 3728+

Revision history for this message
Jabiertxof (jabiertxof) wrote :

I put three minor things about coding style previouly someone review me. AlsoNathan ping me about dont "clangformat" merges, till become accepted. Anyway I read your comment and help me a lot in the review. I do not a usage review, ping me if you want me to compile to give a second try.

review: Approve (code)

Unmerged revisions

14347. By Mc

more clang-format because i can never get the spacing right

14346. By Mc

final comments and refactor

14345. By Mc

refactor + fixed linked offsets

14344. By Mc

I was not /that/ far yesterday at 4am. Ready to be tested !

14343. By Mc

works better than previously, but there is still some strange behavior

14342. By Mc

Wait a minute, is that really working ? Have those several hours with paper and pen, filling pages with matrix multiplications, not been in vain ?

Just kidding, still WIP. make a clone of clone, move the original and first clone, the second moves unexpectedly.

But still, the fact that the first clone behaves right is already pretty cool !

14341. By Mc

I'm so confused right now.

14340. By Mc

does not break anything yet. I still have to fix the case where i resize a (original+(clone in a group)) selection

14339. By Mc

clang-format src/selection-chemistry.cpp

14338. By Mc

add includes_deeply helper function to test if an object is selected, even indirectly

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/selection-chemistry.cpp'
--- src/selection-chemistry.cpp 2015-05-26 20:27:00 +0000
+++ src/selection-chemistry.cpp 2015-09-02 11:21:15 +0000
@@ -12,15 +12,16 @@
12 * Abhishek Sharma12 * Abhishek Sharma
13 * Kris De Gussem <Kris.DeGussem@gmail.com>13 * Kris De Gussem <Kris.DeGussem@gmail.com>
14 * Tavmjong Bah <tavmjong@free.fr> (Symbol additions)14 * Tavmjong Bah <tavmjong@free.fr> (Symbol additions)
15 * Marc Jeanmougin <marc@jeanmougin.fr>
15 *16 *
16 * Copyright (C) 1999-2010,2012 authors17 * Copyright (C) 1999-2010,2012,2015 authors
17 * Copyright (C) 2001-2002 Ximian, Inc.18 * Copyright (C) 2001-2002 Ximian, Inc.
18 *19 *
19 * Released under GNU GPL, read the file 'COPYING' for more information20 * Released under GNU GPL, read the file 'COPYING' for more information
20 */21 */
2122
22#ifdef HAVE_CONFIG_H23#ifdef HAVE_CONFIG_H
23# include "config.h"24#include "config.h"
24#endif25#endif
2526
26#include <gtkmm/clipboard.h>27#include <gtkmm/clipboard.h>
@@ -131,14 +132,12 @@
131132
132// helper for printing error messages, regardless of whether we have a GUI or not133// helper for printing error messages, regardless of whether we have a GUI or not
133// If desktop == NULL, errors will be shown on stderr134// If desktop == NULL, errors will be shown on stderr
134static void135static void selection_display_message(SPDesktop *desktop, Inkscape::MessageType msgType, Glib::ustring const &msg)
135selection_display_message(SPDesktop *desktop, Inkscape::MessageType msgType, Glib::ustring const &msg)
136{136{
137 if (desktop) {137 if (desktop) {
138 desktop->messageStack()->flash(msgType, msg);138 desktop->messageStack()->flash(msgType, msg);
139 } else {139 } else {
140 if (msgType == Inkscape::IMMEDIATE_MESSAGE ||140 if (msgType == Inkscape::IMMEDIATE_MESSAGE || msgType == Inkscape::WARNING_MESSAGE ||
141 msgType == Inkscape::WARNING_MESSAGE ||
142 msgType == Inkscape::ERROR_MESSAGE) {141 msgType == Inkscape::ERROR_MESSAGE) {
143 g_printerr("%s\n", msg.c_str());142 g_printerr("%s\n", msg.c_str());
144 }143 }
@@ -150,7 +149,7 @@
150void SelectionHelper::selectAll(SPDesktop *dt)149void SelectionHelper::selectAll(SPDesktop *dt)
151{150{
152 if (tools_isactive(dt, TOOLS_NODES)) {151 if (tools_isactive(dt, TOOLS_NODES)) {
153 NodeTool *nt = static_cast<NodeTool*>(dt->event_context);152 NodeTool *nt = static_cast<NodeTool *>(dt->event_context);
154 if (!nt->_multipath->empty()) {153 if (!nt->_multipath->empty()) {
155 nt->_multipath->selectSubpaths();154 nt->_multipath->selectSubpaths();
156 return;155 return;
@@ -162,7 +161,7 @@
162void SelectionHelper::selectAllInAll(SPDesktop *dt)161void SelectionHelper::selectAllInAll(SPDesktop *dt)
163{162{
164 if (tools_isactive(dt, TOOLS_NODES)) {163 if (tools_isactive(dt, TOOLS_NODES)) {
165 NodeTool *nt = static_cast<NodeTool*>(dt->event_context);164 NodeTool *nt = static_cast<NodeTool *>(dt->event_context);
166 nt->_selected_nodes->selectAll();165 nt->_selected_nodes->selectAll();
167 } else {166 } else {
168 sp_edit_select_all_in_all_layers(dt);167 sp_edit_select_all_in_all_layers(dt);
@@ -173,7 +172,7 @@
173{172{
174 NodeTool *nt = NULL;173 NodeTool *nt = NULL;
175 if (tools_isactive(dt, TOOLS_NODES)) {174 if (tools_isactive(dt, TOOLS_NODES)) {
176 nt = static_cast<NodeTool*>(dt->event_context);175 nt = static_cast<NodeTool *>(dt->event_context);
177 }176 }
178177
179 if (nt && !nt->_selected_nodes->empty()) {178 if (nt && !nt->_selected_nodes->empty()) {
@@ -186,35 +185,20 @@
186 }185 }
187}186}
188187
189void SelectionHelper::selectSameFillStroke(SPDesktop *dt)188void SelectionHelper::selectSameFillStroke(SPDesktop *dt) { sp_select_same_fill_stroke_style(dt, true, true, true); }
190{189
191 sp_select_same_fill_stroke_style(dt, true, true, true);190void SelectionHelper::selectSameFillColor(SPDesktop *dt) { sp_select_same_fill_stroke_style(dt, true, false, false); }
192}191
193192void SelectionHelper::selectSameStrokeColor(SPDesktop *dt) { sp_select_same_fill_stroke_style(dt, false, true, false); }
194void SelectionHelper::selectSameFillColor(SPDesktop *dt)193
195{194void SelectionHelper::selectSameStrokeStyle(SPDesktop *dt) { sp_select_same_fill_stroke_style(dt, false, false, true); }
196 sp_select_same_fill_stroke_style(dt, true, false, false);195
197}196void SelectionHelper::selectSameObjectType(SPDesktop *dt) { sp_select_same_object_type(dt); }
198
199void SelectionHelper::selectSameStrokeColor(SPDesktop *dt)
200{
201 sp_select_same_fill_stroke_style(dt, false, true, false);
202}
203
204void SelectionHelper::selectSameStrokeStyle(SPDesktop *dt)
205{
206 sp_select_same_fill_stroke_style(dt, false, false, true);
207}
208
209void SelectionHelper::selectSameObjectType(SPDesktop *dt)
210{
211 sp_select_same_object_type(dt);
212}
213197
214void SelectionHelper::invert(SPDesktop *dt)198void SelectionHelper::invert(SPDesktop *dt)
215{199{
216 if (tools_isactive(dt, TOOLS_NODES)) {200 if (tools_isactive(dt, TOOLS_NODES)) {
217 NodeTool *nt = static_cast<NodeTool*>(dt->event_context);201 NodeTool *nt = static_cast<NodeTool *>(dt->event_context);
218 nt->_multipath->invertSelectionInSubpaths();202 nt->_multipath->invertSelectionInSubpaths();
219 } else {203 } else {
220 sp_edit_invert(dt);204 sp_edit_invert(dt);
@@ -224,7 +208,7 @@
224void SelectionHelper::invertAllInAll(SPDesktop *dt)208void SelectionHelper::invertAllInAll(SPDesktop *dt)
225{209{
226 if (tools_isactive(dt, TOOLS_NODES)) {210 if (tools_isactive(dt, TOOLS_NODES)) {
227 NodeTool *nt = static_cast<NodeTool*>(dt->event_context);211 NodeTool *nt = static_cast<NodeTool *>(dt->event_context);
228 nt->_selected_nodes->invertSelection();212 nt->_selected_nodes->invertSelection();
229 } else {213 } else {
230 sp_edit_invert_in_all_layers(dt);214 sp_edit_invert_in_all_layers(dt);
@@ -235,7 +219,7 @@
235{219{
236 // TODO make this a virtual method of event context!220 // TODO make this a virtual method of event context!
237 if (tools_isactive(dt, TOOLS_NODES)) {221 if (tools_isactive(dt, TOOLS_NODES)) {
238 NodeTool *nt = static_cast<NodeTool*>(dt->event_context);222 NodeTool *nt = static_cast<NodeTool *>(dt->event_context);
239 nt->_multipath->reverseSubpaths();223 nt->_multipath->reverseSubpaths();
240 } else {224 } else {
241 sp_selected_path_reverse(dt);225 sp_selected_path_reverse(dt);
@@ -246,10 +230,9 @@
246{230{
247 Inkscape::UI::Tools::ToolBase *ec = dt->event_context;231 Inkscape::UI::Tools::ToolBase *ec = dt->event_context;
248 if (tools_isactive(dt, TOOLS_NODES)) {232 if (tools_isactive(dt, TOOLS_NODES)) {
249 NodeTool *nt = static_cast<NodeTool*>(dt->event_context);233 NodeTool *nt = static_cast<NodeTool *>(dt->event_context);
250 nt->_multipath->shiftSelection(1);234 nt->_multipath->shiftSelection(1);
251 } else if (tools_isactive(dt, TOOLS_GRADIENT)235 } else if (tools_isactive(dt, TOOLS_GRADIENT) && ec->_grdrag->isNonEmpty()) {
252 && ec->_grdrag->isNonEmpty()) {
253 Inkscape::UI::Tools::sp_gradient_context_select_next(ec);236 Inkscape::UI::Tools::sp_gradient_context_select_next(ec);
254 } else {237 } else {
255 sp_selection_item_next(dt);238 sp_selection_item_next(dt);
@@ -260,10 +243,9 @@
260{243{
261 Inkscape::UI::Tools::ToolBase *ec = dt->event_context;244 Inkscape::UI::Tools::ToolBase *ec = dt->event_context;
262 if (tools_isactive(dt, TOOLS_NODES)) {245 if (tools_isactive(dt, TOOLS_NODES)) {
263 NodeTool *nt = static_cast<NodeTool*>(dt->event_context);246 NodeTool *nt = static_cast<NodeTool *>(dt->event_context);
264 nt->_multipath->shiftSelection(-1);247 nt->_multipath->shiftSelection(-1);
265 } else if (tools_isactive(dt, TOOLS_GRADIENT)248 } else if (tools_isactive(dt, TOOLS_GRADIENT) && ec->_grdrag->isNonEmpty()) {
266 && ec->_grdrag->isNonEmpty()) {
267 Inkscape::UI::Tools::sp_gradient_context_select_prev(ec);249 Inkscape::UI::Tools::sp_gradient_context_select_prev(ec);
268 } else {250 } else {
269 sp_selection_item_prev(dt);251 sp_selection_item_prev(dt);
@@ -273,23 +255,20 @@
273/*255/*
274 * Fixes the current selection, removing locked objects from it256 * Fixes the current selection, removing locked objects from it
275 */257 */
276void SelectionHelper::fixSelection(SPDesktop *dt) 258void SelectionHelper::fixSelection(SPDesktop *dt)
277{259{
278 if(!dt)260 if (!dt)
279 return;261 return;
280262
281 Inkscape::Selection *selection = dt->getSelection();263 Inkscape::Selection *selection = dt->getSelection();
282 264
283 std::vector<SPItem*> items ;265 std::vector<SPItem *> items;
284266
285 std::vector<SPItem*> const selList = selection->itemList();267 std::vector<SPItem *> const selList = selection->itemList();
286268
287 for( std::vector<SPItem*>::const_reverse_iterator i = selList.rbegin(); i != selList.rend(); i++ ) {269 for (std::vector<SPItem *>::const_reverse_iterator i = selList.rbegin(); i != selList.rend(); i++) {
288 SPItem *item = *i;270 SPItem *item = *i;
289 if( item &&271 if (item && !dt->isLayer(item) && (!item->isLocked())) {
290 !dt->isLayer(item) &&
291 (!item->isLocked()))
292 {
293 items.push_back(item);272 items.push_back(item);
294 }273 }
295 }274 }
@@ -304,7 +283,8 @@
304 * Copies repr and its inherited css style elements, along with the accumulated transform 'full_t',283 * Copies repr and its inherited css style elements, along with the accumulated transform 'full_t',
305 * then prepends the copy to 'clip'.284 * then prepends the copy to 'clip'.
306 */285 */
307static void sp_selection_copy_one(Inkscape::XML::Node *repr, Geom::Affine full_t, std::vector<Inkscape::XML::Node*> &clip, Inkscape::XML::Document* xml_doc)286static void sp_selection_copy_one(Inkscape::XML::Node *repr, Geom::Affine full_t,
287 std::vector<Inkscape::XML::Node *> &clip, Inkscape::XML::Document *xml_doc)
308{288{
309 Inkscape::XML::Node *copy = repr->duplicate(xml_doc);289 Inkscape::XML::Node *copy = repr->duplicate(xml_doc);
310290
@@ -316,21 +296,22 @@
316 // write the complete accumulated transform passed to us296 // write the complete accumulated transform passed to us
317 // (we're dealing with unattached repr, so we write to its attr297 // (we're dealing with unattached repr, so we write to its attr
318 // instead of using sp_item_set_transform)298 // instead of using sp_item_set_transform)
319 gchar *affinestr=sp_svg_transform_write(full_t);299 gchar *affinestr = sp_svg_transform_write(full_t);
320 copy->setAttribute("transform", affinestr);300 copy->setAttribute("transform", affinestr);
321 g_free(affinestr);301 g_free(affinestr);
322302
323 clip.insert(clip.begin(),copy);303 clip.insert(clip.begin(), copy);
324}304}
325305
326static void sp_selection_copy_impl(std::vector<SPItem*> const &items, std::vector<Inkscape::XML::Node*> &clip, Inkscape::XML::Document* xml_doc)306static void sp_selection_copy_impl(std::vector<SPItem *> const &items, std::vector<Inkscape::XML::Node *> &clip,
307 Inkscape::XML::Document *xml_doc)
327{308{
328 // Sort items:309 // Sort items:
329 std::vector<SPItem*> sorted_items(items);310 std::vector<SPItem *> sorted_items(items);
330 sort(sorted_items.begin(),sorted_items.end(),sp_object_compare_position_bool);311 sort(sorted_items.begin(), sorted_items.end(), sp_object_compare_position_bool);
331312
332 // Copy item reprs:313 // Copy item reprs:
333 for (std::vector<SPItem*>::const_iterator i = sorted_items.begin(); i != sorted_items.end(); i++) {314 for (std::vector<SPItem *>::const_iterator i = sorted_items.begin(); i != sorted_items.end(); i++) {
334 SPItem *item = *i;315 SPItem *item = *i;
335 if (item) {316 if (item) {
336 sp_selection_copy_one(item->getRepr(), item->i2doc_affine(), clip, xml_doc);317 sp_selection_copy_one(item->getRepr(), item->i2doc_affine(), clip, xml_doc);
@@ -338,20 +319,21 @@
338 g_assert_not_reached();319 g_assert_not_reached();
339 }320 }
340 }321 }
341 reverse(clip.begin(),clip.end());322 reverse(clip.begin(), clip.end());
342}323}
343324
344// TODO check if parent parameter should be changed to SPItem, of if the code should handle non-items.325// TODO check if parent parameter should be changed to SPItem, of if the code should handle non-items.
345static std::vector<Inkscape::XML::Node*> sp_selection_paste_impl(SPDocument *doc, SPObject *parent, std::vector<Inkscape::XML::Node*> &clip)326static std::vector<Inkscape::XML::Node *> sp_selection_paste_impl(SPDocument *doc, SPObject *parent,
327 std::vector<Inkscape::XML::Node *> &clip)
346{328{
347 Inkscape::XML::Document *xml_doc = doc->getReprDoc();329 Inkscape::XML::Document *xml_doc = doc->getReprDoc();
348330
349 SPItem *parentItem = dynamic_cast<SPItem *>(parent);331 SPItem *parentItem = dynamic_cast<SPItem *>(parent);
350 g_assert(parentItem != NULL);332 g_assert(parentItem != NULL);
351333
352 std::vector<Inkscape::XML::Node*> copied;334 std::vector<Inkscape::XML::Node *> copied;
353 // add objects to document335 // add objects to document
354 for (std::vector<Inkscape::XML::Node*>::const_iterator l = clip.begin(); l != clip.end(); l++) {336 for (std::vector<Inkscape::XML::Node *>::const_iterator l = clip.begin(); l != clip.end(); l++) {
355 Inkscape::XML::Node *repr = *l;337 Inkscape::XML::Node *repr = *l;
356 Inkscape::XML::Node *copy = repr->duplicate(xml_doc);338 Inkscape::XML::Node *copy = repr->duplicate(xml_doc);
357339
@@ -364,7 +346,7 @@
364 sp_svg_transform_read(t_str, &item_t);346 sp_svg_transform_read(t_str, &item_t);
365 item_t *= local.inverse();347 item_t *= local.inverse();
366 // (we're dealing with unattached repr, so we write to its attr instead of using sp_item_set_transform)348 // (we're dealing with unattached repr, so we write to its attr instead of using sp_item_set_transform)
367 gchar *affinestr=sp_svg_transform_write(item_t);349 gchar *affinestr = sp_svg_transform_write(item_t);
368 copy->setAttribute("transform", affinestr);350 copy->setAttribute("transform", affinestr);
369 g_free(affinestr);351 g_free(affinestr);
370 }352 }
@@ -376,12 +358,13 @@
376 return copied;358 return copied;
377}359}
378360
379static void sp_selection_delete_impl(std::vector<SPItem*> const &items, bool propagate = true, bool propagate_descendants = true)361static void sp_selection_delete_impl(std::vector<SPItem *> const &items, bool propagate = true,
362 bool propagate_descendants = true)
380{363{
381 for (std::vector<SPItem*>::const_iterator i = items.begin(); i != items.end(); i++) {364 for (std::vector<SPItem *>::const_iterator i = items.begin(); i != items.end(); i++) {
382 sp_object_ref(*i, NULL);365 sp_object_ref(*i, NULL);
383 }366 }
384 for (std::vector<SPItem*>::const_iterator i = items.begin(); i != items.end(); i++) {367 for (std::vector<SPItem *>::const_iterator i = items.begin(); i != items.end(); i++) {
385 SPItem *item = *i;368 SPItem *item = *i;
386 item->deleteObject(propagate, propagate_descendants);369 item->deleteObject(propagate, propagate_descendants);
387 sp_object_unref(item, NULL);370 sp_object_unref(item, NULL);
@@ -397,8 +380,7 @@
397380
398 if (tools_isactive(desktop, TOOLS_TEXT))381 if (tools_isactive(desktop, TOOLS_TEXT))
399 if (Inkscape::UI::Tools::sp_text_delete_selection(desktop->event_context)) {382 if (Inkscape::UI::Tools::sp_text_delete_selection(desktop->event_context)) {
400 DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_TEXT,383 DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_TEXT, _("Delete text"));
401 _("Delete text"));
402 return;384 return;
403 }385 }
404386
@@ -409,7 +391,7 @@
409 desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("<b>Nothing</b> was deleted."));391 desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("<b>Nothing</b> was deleted."));
410 return;392 return;
411 }393 }
412 std::vector<SPItem*> selected(selection->itemList());394 std::vector<SPItem *> selected(selection->itemList());
413 selection->clear();395 selection->clear();
414 sp_selection_delete_impl(selected);396 sp_selection_delete_impl(selected);
415 desktop->currentLayer()->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);397 desktop->currentLayer()->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
@@ -420,10 +402,9 @@
420 * associated selection context. For example: deleting an object402 * associated selection context. For example: deleting an object
421 * while moving it around the canvas.403 * while moving it around the canvas.
422 */404 */
423 tools_switch( desktop, tools_active( desktop ) );405 tools_switch(desktop, tools_active(desktop));
424406
425 DocumentUndo::done(desktop->getDocument(), SP_VERB_EDIT_DELETE,407 DocumentUndo::done(desktop->getDocument(), SP_VERB_EDIT_DELETE, _("Delete"));
426 _("Delete"));
427}408}
428409
429static void add_ids_recursive(std::vector<const gchar *> &ids, SPObject *obj)410static void add_ids_recursive(std::vector<const gchar *> &ids, SPObject *obj)
@@ -432,7 +413,7 @@
432 ids.push_back(obj->getId());413 ids.push_back(obj->getId());
433414
434 if (dynamic_cast<SPGroup *>(obj)) {415 if (dynamic_cast<SPGroup *>(obj)) {
435 for (SPObject *child = obj->firstChild() ; child; child = child->getNext() ) {416 for (SPObject *child = obj->firstChild(); child; child = child->getNext()) {
436 add_ids_recursive(ids, child);417 add_ids_recursive(ids, child);
437 }418 }
438 }419 }
@@ -446,7 +427,7 @@
446 }427 }
447428
448 SPDocument *doc = desktop->doc();429 SPDocument *doc = desktop->doc();
449 Inkscape::XML::Document* xml_doc = doc->getReprDoc();430 Inkscape::XML::Document *xml_doc = doc->getReprDoc();
450 Inkscape::Selection *selection = desktop->getSelection();431 Inkscape::Selection *selection = desktop->getSelection();
451432
452 // check if something is selected433 // check if something is selected
@@ -454,9 +435,9 @@
454 desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to duplicate."));435 desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to duplicate."));
455 return;436 return;
456 }437 }
457 std::vector<Inkscape::XML::Node*> reprs(selection->reprList());438 std::vector<Inkscape::XML::Node *> reprs(selection->reprList());
458439
459 if(duplicateLayer){440 if (duplicateLayer) {
460 reprs.clear();441 reprs.clear();
461 reprs.push_back(desktop->currentLayer()->getRepr());442 reprs.push_back(desktop->currentLayer()->getRepr());
462 }443 }
@@ -465,9 +446,9 @@
465446
466 // sorting items from different parents sorts each parent's subset without possibly mixing447 // sorting items from different parents sorts each parent's subset without possibly mixing
467 // them, just what we need448 // them, just what we need
468 sort(reprs.begin(),reprs.end(),sp_repr_compare_position_bool);449 sort(reprs.begin(), reprs.end(), sp_repr_compare_position_bool);
469450
470 std::vector<Inkscape::XML::Node*> newsel;451 std::vector<Inkscape::XML::Node *> newsel;
471452
472 std::vector<const gchar *> old_ids;453 std::vector<const gchar *> old_ids;
473 std::vector<const gchar *> new_ids;454 std::vector<const gchar *> new_ids;
@@ -475,15 +456,15 @@
475 bool relink_clones = prefs->getBool("/options/relinkclonesonduplicate/value");456 bool relink_clones = prefs->getBool("/options/relinkclonesonduplicate/value");
476 const bool fork_livepatheffects = prefs->getBool("/options/forklpeonduplicate/value", true);457 const bool fork_livepatheffects = prefs->getBool("/options/forklpeonduplicate/value", true);
477458
478 for(std::vector<Inkscape::XML::Node*>::const_iterator i=reprs.begin();i!=reprs.end();i++){459 for (std::vector<Inkscape::XML::Node *>::const_iterator i = reprs.begin(); i != reprs.end(); i++) {
479 Inkscape::XML::Node *old_repr = *i;460 Inkscape::XML::Node *old_repr = *i;
480 Inkscape::XML::Node *parent = old_repr->parent();461 Inkscape::XML::Node *parent = old_repr->parent();
481 Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc);462 Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc);
482463
483 if(! duplicateLayer)464 if (!duplicateLayer)
484 parent->appendChild(copy);465 parent->appendChild(copy);
485 else466 else
486 parent->addChild(copy, old_repr);467 parent->addChild(copy, old_repr);
487468
488 if (relink_clones) {469 if (relink_clones) {
489 SPObject *old_obj = doc->getObjectByRepr(old_repr);470 SPObject *old_obj = doc->getObjectByRepr(old_repr);
@@ -519,7 +500,8 @@
519 for (unsigned int j = 0; j < old_ids.size(); j++) {500 for (unsigned int j = 0; j < old_ids.size(); j++) {
520 if (!strcmp(orig->getId(), old_ids[j])) {501 if (!strcmp(orig->getId(), old_ids[j])) {
521 // we have both orig and clone in selection, relink502 // we have both orig and clone in selection, relink
522 // std::cout << id << " old, its ori: " << orig->getId() << "; will relink:" << new_ids[i] << " to " << new_ids[j] << "\n";503 // std::cout << id << " old, its ori: " << orig->getId() << "; will relink:" << new_ids[i] << "
504 // to " << new_ids[j] << "\n";
523 SPObject *new_clone = doc->getObjectById(new_ids[i]);505 SPObject *new_clone = doc->getObjectById(new_ids[i]);
524 new_clone->getRepr()->setAttribute("xlink:href", Glib::ustring("#") + new_ids[j]);506 new_clone->getRepr()->setAttribute("xlink:href", Glib::ustring("#") + new_ids[j]);
525 new_clone->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);507 new_clone->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
@@ -530,8 +512,9 @@
530 if (offset) {512 if (offset) {
531 for (guint j = 0; j < old_ids.size(); j++) {513 for (guint j = 0; j < old_ids.size(); j++) {
532 gchar *source_href = offset->sourceHref;514 gchar *source_href = offset->sourceHref;
533 if (source_href && source_href[0]=='#' && !strcmp(source_href+1, old_ids[j])) {515 if (source_href && source_href[0] == '#' && !strcmp(source_href + 1, old_ids[j])) {
534 doc->getObjectById(new_ids[i])->getRepr()->setAttribute("xlink:href", Glib::ustring("#") + new_ids[j]);516 doc->getObjectById(new_ids[i])->getRepr()->setAttribute("xlink:href",
517 Glib::ustring("#") + new_ids[j]);
535 }518 }
536 }519 }
537 }520 }
@@ -540,16 +523,15 @@
540 }523 }
541524
542525
543 if ( !suppressDone ) {526 if (!suppressDone) {
544 DocumentUndo::done(desktop->getDocument(), SP_VERB_EDIT_DUPLICATE,527 DocumentUndo::done(desktop->getDocument(), SP_VERB_EDIT_DUPLICATE, _("Duplicate"));
545 _("Duplicate"));
546 }528 }
547 if(!duplicateLayer)529 if (!duplicateLayer)
548 selection->setReprList(newsel);530 selection->setReprList(newsel);
549 else{531 else {
550 SPObject* new_layer = doc->getObjectByRepr(newsel[0]);532 SPObject *new_layer = doc->getObjectByRepr(newsel[0]);
551 gchar* name = g_strdup_printf(_("%s copy"), new_layer->label());533 gchar *name = g_strdup_printf(_("%s copy"), new_layer->label());
552 desktop->layer_manager->renameLayer( new_layer, name, TRUE );534 desktop->layer_manager->renameLayer(new_layer, name, TRUE);
553 g_free(name);535 g_free(name);
554 }536 }
555}537}
@@ -564,14 +546,13 @@
564546
565 SPGroup *group = dynamic_cast<SPGroup *>(selection->layers()->currentLayer());547 SPGroup *group = dynamic_cast<SPGroup *>(selection->layers()->currentLayer());
566 g_return_if_fail(group != NULL);548 g_return_if_fail(group != NULL);
567 std::vector<SPItem*> items = sp_item_group_item_list(group);549 std::vector<SPItem *> items = sp_item_group_item_list(group);
568550
569 for(unsigned int i = 0; i < items.size(); i++){551 for (unsigned int i = 0; i < items.size(); i++) {
570 items[i]->deleteObject();552 items[i]->deleteObject();
571 }553 }
572554
573 DocumentUndo::done(doc, SP_VERB_EDIT_CLEAR_ALL,555 DocumentUndo::done(doc, SP_VERB_EDIT_CLEAR_ALL, _("Delete all"));
574 _("Delete all"));
575}556}
576557
577/*558/*
@@ -584,18 +565,15 @@
584 * onlysensitive - TRUE includes only non-locked items565 * onlysensitive - TRUE includes only non-locked items
585 * ingroups - TRUE to recursively get grouped items children566 * ingroups - TRUE to recursively get grouped items children
586 */567 */
587std::vector<SPItem*> &get_all_items(std::vector<SPItem*> &list, SPObject *from, SPDesktop *desktop, bool onlyvisible, bool onlysensitive, bool ingroups, std::vector<SPItem*> const &exclude)568std::vector<SPItem *> &get_all_items(std::vector<SPItem *> &list, SPObject *from, SPDesktop *desktop, bool onlyvisible,
569 bool onlysensitive, bool ingroups, std::vector<SPItem *> const &exclude)
588{570{
589 for ( SPObject *child = from->firstChild() ; child; child = child->getNext() ) {571 for (SPObject *child = from->firstChild(); child; child = child->getNext()) {
590 SPItem *item = dynamic_cast<SPItem *>(child);572 SPItem *item = dynamic_cast<SPItem *>(child);
591 if (item &&573 if (item && !desktop->isLayer(item) && (!onlysensitive || !item->isLocked()) &&
592 !desktop->isLayer(item) &&
593 (!onlysensitive || !item->isLocked()) &&
594 (!onlyvisible || !desktop->itemIsHidden(item)) &&574 (!onlyvisible || !desktop->itemIsHidden(item)) &&
595 (exclude.empty() || exclude.end() == std::find(exclude.begin(),exclude.end(),child))575 (exclude.empty() || exclude.end() == std::find(exclude.begin(), exclude.end(), child))) {
596 )576 list.insert(list.begin(), item);
597 {
598 list.insert(list.begin(),item);
599 }577 }
600578
601 if (ingroups || (item && desktop->isLayer(item))) {579 if (ingroups || (item && desktop->isLayer(item))) {
@@ -616,13 +594,14 @@
616 g_return_if_fail(dynamic_cast<SPGroup *>(dt->currentLayer()));594 g_return_if_fail(dynamic_cast<SPGroup *>(dt->currentLayer()));
617595
618 Inkscape::Preferences *prefs = Inkscape::Preferences::get();596 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
619 PrefsSelectionContext inlayer = (PrefsSelectionContext) prefs->getInt("/options/kbselection/inlayer", PREFS_SELECTION_LAYER);597 PrefsSelectionContext inlayer =
598 (PrefsSelectionContext)prefs->getInt("/options/kbselection/inlayer", PREFS_SELECTION_LAYER);
620 bool onlyvisible = prefs->getBool("/options/kbselection/onlyvisible", true);599 bool onlyvisible = prefs->getBool("/options/kbselection/onlyvisible", true);
621 bool onlysensitive = prefs->getBool("/options/kbselection/onlysensitive", true);600 bool onlysensitive = prefs->getBool("/options/kbselection/onlysensitive", true);
622601
623 std::vector<SPItem*> items ;602 std::vector<SPItem *> items;
624603
625 std::vector<SPItem*> exclude;604 std::vector<SPItem *> exclude;
626 if (invert) {605 if (invert) {
627 exclude = selection->itemList();606 exclude = selection->itemList();
628 }607 }
@@ -632,73 +611,62 @@
632611
633 switch (inlayer) {612 switch (inlayer) {
634 case PREFS_SELECTION_LAYER: {613 case PREFS_SELECTION_LAYER: {
635 if ( (onlysensitive && dynamic_cast<SPItem *>(dt->currentLayer())->isLocked()) ||614 if ((onlysensitive && dynamic_cast<SPItem *>(dt->currentLayer())->isLocked()) ||
636 (onlyvisible && dt->itemIsHidden(dynamic_cast<SPItem *>(dt->currentLayer()))) )615 (onlyvisible && dt->itemIsHidden(dynamic_cast<SPItem *>(dt->currentLayer()))))
637 return;616 return;
638617
639 std::vector<SPItem*> all_items = sp_item_group_item_list(dynamic_cast<SPGroup *>(dt->currentLayer()));618 std::vector<SPItem *> all_items = sp_item_group_item_list(dynamic_cast<SPGroup *>(dt->currentLayer()));
640619
641 for (std::vector<SPItem*>::const_reverse_iterator i=all_items.rbegin();i!=all_items.rend();i++) {620 for (std::vector<SPItem *>::const_reverse_iterator i = all_items.rbegin(); i != all_items.rend(); i++) {
642 SPItem *item = *i;621 SPItem *item = *i;
643622
644 if (item && (!onlysensitive || !item->isLocked())) {623 if (item && (!onlysensitive || !item->isLocked())) {
645 if (!onlyvisible || !dt->itemIsHidden(item)) {624 if (!onlyvisible || !dt->itemIsHidden(item)) {
646 if (!dt->isLayer(item)) {625 if (!dt->isLayer(item)) {
647 if (!invert || exclude.end() == std::find(exclude.begin(),exclude.end(),item)) {626 if (!invert || exclude.end() == std::find(exclude.begin(), exclude.end(), item)) {
648 items.push_back(item); // leave it in the list627 items.push_back(item); // leave it in the list
628 }
649 }629 }
650 }630 }
651 }631 }
652 }632 }
653 }
654633
655 break;634 break;
656 }635 }
657 case PREFS_SELECTION_LAYER_RECURSIVE: {636 case PREFS_SELECTION_LAYER_RECURSIVE: {
658 std::vector<SPItem*> x;637 std::vector<SPItem *> x;
659 items = get_all_items(x, dt->currentLayer(), dt, onlyvisible, onlysensitive, FALSE, exclude);638 items = get_all_items(x, dt->currentLayer(), dt, onlyvisible, onlysensitive, FALSE, exclude);
660 break;639 break;
661 }640 }
662 default: {641 default: {
663 std::vector<SPItem*> x;642 std::vector<SPItem *> x;
664 items = get_all_items(x, dt->currentRoot(), dt, onlyvisible, onlysensitive, FALSE, exclude);643 items = get_all_items(x, dt->currentRoot(), dt, onlyvisible, onlysensitive, FALSE, exclude);
665 break;644 break;
666 }645 }
667 }646 }
668647
669 selection->setList(items);648 selection->setList(items);
670649}
671}650
672651void sp_edit_select_all(SPDesktop *desktop) { sp_edit_select_all_full(desktop, false, false); }
673void sp_edit_select_all(SPDesktop *desktop)652
674{653void sp_edit_select_all_in_all_layers(SPDesktop *desktop) { sp_edit_select_all_full(desktop, true, false); }
675 sp_edit_select_all_full(desktop, false, false);654
676}655void sp_edit_invert(SPDesktop *desktop) { sp_edit_select_all_full(desktop, false, true); }
677656
678void sp_edit_select_all_in_all_layers(SPDesktop *desktop)657void sp_edit_invert_in_all_layers(SPDesktop *desktop) { sp_edit_select_all_full(desktop, true, true); }
679{658
680 sp_edit_select_all_full(desktop, true, false);659static void sp_selection_group_impl(std::vector<Inkscape::XML::Node *> p, Inkscape::XML::Node *group,
681}660 Inkscape::XML::Document *xml_doc, SPDocument *doc)
682661{
683void sp_edit_invert(SPDesktop *desktop)662
684{663 sort(p.begin(), p.end(), sp_repr_compare_position_bool);
685 sp_edit_select_all_full(desktop, false, true);
686}
687
688void sp_edit_invert_in_all_layers(SPDesktop *desktop)
689{
690 sp_edit_select_all_full(desktop, true, true);
691}
692
693static void sp_selection_group_impl(std::vector<Inkscape::XML::Node*> p, Inkscape::XML::Node *group, Inkscape::XML::Document *xml_doc, SPDocument *doc) {
694
695 sort(p.begin(),p.end(),sp_repr_compare_position_bool);
696664
697 // Remember the position and parent of the topmost object.665 // Remember the position and parent of the topmost object.
698 gint topmost = p.back()->position();666 gint topmost = p.back()->position();
699 Inkscape::XML::Node *topmost_parent = p.back()->parent();667 Inkscape::XML::Node *topmost_parent = p.back()->parent();
700668
701 for(std::vector<Inkscape::XML::Node*>::const_iterator i = p.begin(); i != p.end(); i++){669 for (std::vector<Inkscape::XML::Node *>::const_iterator i = p.begin(); i != p.end(); i++) {
702 Inkscape::XML::Node *current = *i;670 Inkscape::XML::Node *current = *i;
703671
704 if (current->parent() == topmost_parent) {672 if (current->parent() == topmost_parent) {
@@ -706,12 +674,14 @@
706 sp_repr_unparent(current);674 sp_repr_unparent(current);
707 group->appendChild(spnew);675 group->appendChild(spnew);
708 Inkscape::GC::release(spnew);676 Inkscape::GC::release(spnew);
709 topmost --; // only reduce count for those items deleted from topmost_parent677 topmost--; // only reduce count for those items deleted from topmost_parent
710 } else { // move it to topmost_parent first678 } else { // move it to topmost_parent first
711 std::vector<Inkscape::XML::Node*> temp_clip;679 std::vector<Inkscape::XML::Node *> temp_clip;
712680
713 // At this point, current may already have no item, due to its being a clone whose original is already moved away681 // At this point, current may already have no item, due to its being a clone whose original is already moved
714 // So we copy it artificially calculating the transform from its repr->attr("transform") and the parent transform682 // away
683 // So we copy it artificially calculating the transform from its repr->attr("transform") and the parent
684 // transform
715 gchar const *t_str = current->attribute("transform");685 gchar const *t_str = current->attribute("transform");
716 Geom::Affine item_t(Geom::identity());686 Geom::Affine item_t(Geom::identity());
717 if (t_str)687 if (t_str)
@@ -728,8 +698,10 @@
728 sp_repr_unparent(current);698 sp_repr_unparent(current);
729699
730 // paste into topmost_parent (temporarily)700 // paste into topmost_parent (temporarily)
731 std::vector<Inkscape::XML::Node*> copied = sp_selection_paste_impl(doc, doc->getObjectByRepr(topmost_parent), temp_clip);701 std::vector<Inkscape::XML::Node *> copied =
732 if (!temp_clip.empty())temp_clip.clear() ;702 sp_selection_paste_impl(doc, doc->getObjectByRepr(topmost_parent), temp_clip);
703 if (!temp_clip.empty())
704 temp_clip.clear();
733 if (!copied.empty()) { // if success,705 if (!copied.empty()) { // if success,
734 // take pasted object (now in topmost_parent)706 // take pasted object (now in topmost_parent)
735 Inkscape::XML::Node *in_topmost = copied.back();707 Inkscape::XML::Node *in_topmost = copied.back();
@@ -763,7 +735,7 @@
763 return;735 return;
764 }736 }
765737
766 std::vector<Inkscape::XML::Node*> p (selection->reprList());738 std::vector<Inkscape::XML::Node *> p(selection->reprList());
767739
768 selection->clear();740 selection->clear();
769741
@@ -771,14 +743,14 @@
771743
772 sp_selection_group_impl(p, group, xml_doc, doc);744 sp_selection_group_impl(p, group, xml_doc, doc);
773745
774 DocumentUndo::done(doc, SP_VERB_SELECTION_GROUP,746 DocumentUndo::done(doc, SP_VERB_SELECTION_GROUP, C_("Verb", "Group"));
775 C_("Verb", "Group"));
776747
777 selection->set(group);748 selection->set(group);
778 Inkscape::GC::release(group);749 Inkscape::GC::release(group);
779}750}
780751
781static gint clone_depth_descending(gconstpointer a, gconstpointer b) {752static gint clone_depth_descending(gconstpointer a, gconstpointer b)
753{
782 SPUse *use_a = static_cast<SPUse *>(const_cast<gpointer>(a));754 SPUse *use_a = static_cast<SPUse *>(const_cast<gpointer>(a));
783 SPUse *use_b = static_cast<SPUse *>(const_cast<gpointer>(b));755 SPUse *use_b = static_cast<SPUse *>(const_cast<gpointer>(b));
784 int depth_a = use_a->cloneDepth();756 int depth_a = use_a->cloneDepth();
@@ -799,10 +771,10 @@
799 }771 }
800772
801 // first check whether there is anything to ungroup773 // first check whether there is anything to ungroup
802 std::vector<SPItem*> old_select = selection->itemList();774 std::vector<SPItem *> old_select = selection->itemList();
803 std::vector<SPItem*> new_select;775 std::vector<SPItem *> new_select;
804 GSList *groups = NULL;776 GSList *groups = NULL;
805 for (std::vector<SPItem*>::const_iterator item = old_select.begin(); item!=old_select.end(); item++) {777 for (std::vector<SPItem *>::const_iterator item = old_select.begin(); item != old_select.end(); item++) {
806 SPItem *obj = *item;778 SPItem *obj = *item;
807 if (dynamic_cast<SPGroup *>(obj)) {779 if (dynamic_cast<SPGroup *>(obj)) {
808 groups = g_slist_prepend(groups, obj);780 groups = g_slist_prepend(groups, obj);
@@ -815,13 +787,13 @@
815 return;787 return;
816 }788 }
817789
818 std::vector<SPItem*> items(old_select);790 std::vector<SPItem *> items(old_select);
819 selection->clear();791 selection->clear();
820792
821 // If any of the clones refer to the groups, unlink them and replace them with successors793 // If any of the clones refer to the groups, unlink them and replace them with successors
822 // in the items list.794 // in the items list.
823 GSList *clones_to_unlink = NULL;795 GSList *clones_to_unlink = NULL;
824 for (std::vector<SPItem*>::const_iterator item = items.begin(); item != items.end(); item++) {796 for (std::vector<SPItem *>::const_iterator item = items.begin(); item != items.end(); item++) {
825 SPUse *use = dynamic_cast<SPUse *>(*item);797 SPUse *use = dynamic_cast<SPUse *>(*item);
826798
827 SPItem *original = use;799 SPItem *original = use;
@@ -841,21 +813,21 @@
841813
842 for (GSList *item = clones_to_unlink; item; item = item->next) {814 for (GSList *item = clones_to_unlink; item; item = item->next) {
843 SPUse *use = static_cast<SPUse *>(item->data);815 SPUse *use = static_cast<SPUse *>(item->data);
844 std::vector<SPItem*>::iterator items_node = std::find(items.begin(),items.end(), item->data);816 std::vector<SPItem *>::iterator items_node = std::find(items.begin(), items.end(), item->data);
845 *items_node = use->unlink();817 *items_node = use->unlink();
846 }818 }
847 g_slist_free(clones_to_unlink);819 g_slist_free(clones_to_unlink);
848820
849 // do the actual work821 // do the actual work
850 for (std::vector<SPItem*>::iterator item = items.begin(); item != items.end(); item++) {822 for (std::vector<SPItem *>::iterator item = items.begin(); item != items.end(); item++) {
851 SPItem *obj = *item;823 SPItem *obj = *item;
852824
853 // ungroup only the groups marked earlier825 // ungroup only the groups marked earlier
854 if (g_slist_find(groups, *item) != NULL) {826 if (g_slist_find(groups, *item) != NULL) {
855 std::vector<SPItem*> children;827 std::vector<SPItem *> children;
856 sp_item_group_ungroup(dynamic_cast<SPGroup *>(obj), children, false);828 sp_item_group_ungroup(dynamic_cast<SPGroup *>(obj), children, false);
857 // add the items resulting from ungrouping to the selection829 // add the items resulting from ungrouping to the selection
858 new_select.insert(new_select.end(),children.begin(),children.end());830 new_select.insert(new_select.end(), children.begin(), children.end());
859 *item = NULL; // zero out the original pointer, which is no longer valid831 *item = NULL; // zero out the original pointer, which is no longer valid
860 } else {832 } else {
861 // if not a group, keep in the selection833 // if not a group, keep in the selection
@@ -865,24 +837,22 @@
865837
866 selection->addList(new_select);838 selection->addList(new_select);
867839
868 DocumentUndo::done(selection->layers()->getDocument(), SP_VERB_SELECTION_UNGROUP,840 DocumentUndo::done(selection->layers()->getDocument(), SP_VERB_SELECTION_UNGROUP, _("Ungroup"));
869 _("Ungroup"));
870}841}
871842
872/** Replace all groups in the list with their member objects, recursively; returns a new list, frees old */843/** Replace all groups in the list with their member objects, recursively; returns a new list, frees old */
873std::vector<SPItem*>844std::vector<SPItem *> sp_degroup_list(std::vector<SPItem *> &items)
874sp_degroup_list(std::vector<SPItem*> &items)
875{845{
876 std::vector<SPItem*> out;846 std::vector<SPItem *> out;
877 bool has_groups = false;847 bool has_groups = false;
878 for (std::vector<SPItem*>::const_iterator item=items.begin();item!=items.end();item++) {848 for (std::vector<SPItem *>::const_iterator item = items.begin(); item != items.end(); item++) {
879 SPGroup *group = dynamic_cast<SPGroup *>(*item);849 SPGroup *group = dynamic_cast<SPGroup *>(*item);
880 if (!group) {850 if (!group) {
881 out.push_back(*item);851 out.push_back(*item);
882 } else {852 } else {
883 has_groups = true;853 has_groups = true;
884 std::vector<SPItem*> members = sp_item_group_item_list(group);854 std::vector<SPItem *> members = sp_item_group_item_list(group);
885 for (std::vector<SPItem*>::const_iterator member=members.begin();member!=members.end();member++) {855 for (std::vector<SPItem *>::const_iterator member = members.begin(); member != members.end(); member++) {
886 out.push_back(*member);856 out.push_back(*member);
887 }857 }
888 members.clear();858 members.clear();
@@ -898,8 +868,7 @@
898868
899869
900/** If items in the list have a common parent, return it, otherwise return NULL */870/** If items in the list have a common parent, return it, otherwise return NULL */
901static SPGroup *871static SPGroup *sp_item_list_common_parent_group(std::vector<SPItem *> const items)
902sp_item_list_common_parent_group(std::vector<SPItem*> const items)
903{872{
904 if (items.empty()) {873 if (items.empty()) {
905 return NULL;874 return NULL;
@@ -909,8 +878,9 @@
909 if (!dynamic_cast<SPGroup *>(parent)) {878 if (!dynamic_cast<SPGroup *>(parent)) {
910 return NULL;879 return NULL;
911 }880 }
912 for (std::vector<SPItem*>::const_iterator item=items.begin();item!=items.end();item++) {881 for (std::vector<SPItem *>::const_iterator item = items.begin(); item != items.end(); item++) {
913 if((*item)==items[0])continue;882 if ((*item) == items[0])
883 continue;
914 if ((*item)->parent != parent) {884 if ((*item)->parent != parent) {
915 return NULL;885 return NULL;
916 }886 }
@@ -920,13 +890,12 @@
920}890}
921891
922/** Finds out the minimum common bbox of the selected items. */892/** Finds out the minimum common bbox of the selected items. */
923static Geom::OptRect893static Geom::OptRect enclose_items(std::vector<SPItem *> const &items)
924enclose_items(std::vector<SPItem*> const &items)
925{894{
926 g_assert(!items.empty());895 g_assert(!items.empty());
927896
928 Geom::OptRect r;897 Geom::OptRect r;
929 for (std::vector<SPItem*>::const_iterator i = items.begin();i!=items.end();i++) {898 for (std::vector<SPItem *>::const_iterator i = items.begin(); i != items.end(); i++) {
930 r.unionWith((*i)->desktopVisualBounds());899 r.unionWith((*i)->desktopVisualBounds());
931 }900 }
932 return r;901 return r;
@@ -936,7 +905,7 @@
936static SPObject *prev_sibling(SPObject *child)905static SPObject *prev_sibling(SPObject *child)
937{906{
938 SPObject *prev = 0;907 SPObject *prev = 0;
939 if ( child && dynamic_cast<SPGroup *>(child->parent) ) {908 if (child && dynamic_cast<SPGroup *>(child->parent)) {
940 prev = child->getPrev();909 prev = child->getPrev();
941 }910 }
942 return prev;911 return prev;
@@ -944,14 +913,12 @@
944913
945bool sp_item_repr_compare_position_bool(SPObject const *first, SPObject const *second)914bool sp_item_repr_compare_position_bool(SPObject const *first, SPObject const *second)
946{915{
947 return sp_repr_compare_position(((SPItem*)first)->getRepr(),916 return sp_repr_compare_position(((SPItem *)first)->getRepr(), ((SPItem *)second)->getRepr()) < 0;
948 ((SPItem*)second)->getRepr())<0;
949}917}
950918
951void919void sp_selection_raise(Inkscape::Selection *selection, SPDesktop *desktop)
952sp_selection_raise(Inkscape::Selection *selection, SPDesktop *desktop)
953{920{
954 std::vector<SPItem*> items= selection->itemList();921 std::vector<SPItem *> items = selection->itemList();
955 if (items.empty()) {922 if (items.empty()) {
956 selection_display_message(desktop, Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to raise."));923 selection_display_message(desktop, Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to raise."));
957 return;924 return;
@@ -959,22 +926,23 @@
959926
960 SPGroup const *group = sp_item_list_common_parent_group(items);927 SPGroup const *group = sp_item_list_common_parent_group(items);
961 if (!group) {928 if (!group) {
962 selection_display_message(desktop, Inkscape::ERROR_MESSAGE, _("You cannot raise/lower objects from <b>different groups</b> or <b>layers</b>."));929 selection_display_message(desktop, Inkscape::ERROR_MESSAGE,
930 _("You cannot raise/lower objects from <b>different groups</b> or <b>layers</b>."));
963 return;931 return;
964 }932 }
965933
966 Inkscape::XML::Node *grepr = const_cast<Inkscape::XML::Node *>(group->getRepr());934 Inkscape::XML::Node *grepr = const_cast<Inkscape::XML::Node *>(group->getRepr());
967935
968 /* Construct reverse-ordered list of selected children. */936 /* Construct reverse-ordered list of selected children. */
969 std::vector<SPItem*> rev(items);937 std::vector<SPItem *> rev(items);
970 sort(rev.begin(),rev.end(),sp_item_repr_compare_position_bool);938 sort(rev.begin(), rev.end(), sp_item_repr_compare_position_bool);
971939
972 // Determine the common bbox of the selected items.940 // Determine the common bbox of the selected items.
973 Geom::OptRect selected = enclose_items(items);941 Geom::OptRect selected = enclose_items(items);
974942
975 // Iterate over all objects in the selection (starting from top).943 // Iterate over all objects in the selection (starting from top).
976 if (selected) {944 if (selected) {
977 for (std::vector<SPItem*>::const_iterator item=rev.begin();item!=rev.end();item++) {945 for (std::vector<SPItem *>::const_iterator item = rev.begin(); item != rev.end(); item++) {
978 SPObject *child = *item;946 SPObject *child = *item;
979 // for each selected object, find the next sibling947 // for each selected object, find the next sibling
980 for (SPObject *newref = child->next; newref; newref = newref->next) {948 for (SPObject *newref = child->next; newref; newref = newref->next) {
@@ -982,9 +950,9 @@
982 SPItem *newItem = dynamic_cast<SPItem *>(newref);950 SPItem *newItem = dynamic_cast<SPItem *>(newref);
983 if (newItem) {951 if (newItem) {
984 Geom::OptRect newref_bbox = newItem->desktopVisualBounds();952 Geom::OptRect newref_bbox = newItem->desktopVisualBounds();
985 if ( newref_bbox && selected->intersects(*newref_bbox) ) {953 if (newref_bbox && selected->intersects(*newref_bbox)) {
986 // AND if it's not one of our selected objects,954 // AND if it's not one of our selected objects,
987 if ( std::find(items.begin(),items.end(),newref)==items.end()) {955 if (std::find(items.begin(), items.end(), newref) == items.end()) {
988 // move the selected object after that sibling956 // move the selected object after that sibling
989 grepr->changeOrder(child->getRepr(), newref->getRepr());957 grepr->changeOrder(child->getRepr(), newref->getRepr());
990 }958 }
@@ -995,7 +963,7 @@
995 }963 }
996 }964 }
997 DocumentUndo::done(selection->layers()->getDocument(), SP_VERB_SELECTION_RAISE,965 DocumentUndo::done(selection->layers()->getDocument(), SP_VERB_SELECTION_RAISE,
998 //TRANSLATORS: "Raise" means "to raise an object" in the undo history966 // TRANSLATORS: "Raise" means "to raise an object" in the undo history
999 C_("Undo action", "Raise"));967 C_("Undo action", "Raise"));
1000}968}
1001969
@@ -1008,29 +976,29 @@
1008 return;976 return;
1009 }977 }
1010978
1011 std::vector<SPItem*> items = selection->itemList();979 std::vector<SPItem *> items = selection->itemList();
1012980
1013 SPGroup const *group = sp_item_list_common_parent_group(items);981 SPGroup const *group = sp_item_list_common_parent_group(items);
1014 if (!group) {982 if (!group) {
1015 selection_display_message(desktop, Inkscape::ERROR_MESSAGE, _("You cannot raise/lower objects from <b>different groups</b> or <b>layers</b>."));983 selection_display_message(desktop, Inkscape::ERROR_MESSAGE,
984 _("You cannot raise/lower objects from <b>different groups</b> or <b>layers</b>."));
1016 return;985 return;
1017 }986 }
1018987
1019 std::vector<Inkscape::XML::Node*> rl(selection->reprList());988 std::vector<Inkscape::XML::Node *> rl(selection->reprList());
1020 sort(rl.begin(),rl.end(),sp_repr_compare_position_bool);989 sort(rl.begin(), rl.end(), sp_repr_compare_position_bool);
1021990
1022 for (std::vector<Inkscape::XML::Node*>::const_iterator l=rl.begin(); l!=rl.end();l++) {991 for (std::vector<Inkscape::XML::Node *>::const_iterator l = rl.begin(); l != rl.end(); l++) {
1023 Inkscape::XML::Node *repr =(*l);992 Inkscape::XML::Node *repr = (*l);
1024 repr->setPosition(-1);993 repr->setPosition(-1);
1025 }994 }
1026995
1027 DocumentUndo::done(document, SP_VERB_SELECTION_TO_FRONT,996 DocumentUndo::done(document, SP_VERB_SELECTION_TO_FRONT, _("Raise to top"));
1028 _("Raise to top"));
1029}997}
1030998
1031void sp_selection_lower(Inkscape::Selection *selection, SPDesktop *desktop)999void sp_selection_lower(Inkscape::Selection *selection, SPDesktop *desktop)
1032{1000{
1033 std::vector<SPItem*> items = selection->itemList();1001 std::vector<SPItem *> items = selection->itemList();
1034 if (items.empty()) {1002 if (items.empty()) {
1035 selection_display_message(desktop, Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to lower."));1003 selection_display_message(desktop, Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to lower."));
1036 return;1004 return;
@@ -1038,7 +1006,8 @@
10381006
1039 SPGroup const *group = sp_item_list_common_parent_group(items);1007 SPGroup const *group = sp_item_list_common_parent_group(items);
1040 if (!group) {1008 if (!group) {
1041 selection_display_message(desktop, Inkscape::ERROR_MESSAGE, _("You cannot raise/lower objects from <b>different groups</b> or <b>layers</b>."));1009 selection_display_message(desktop, Inkscape::ERROR_MESSAGE,
1010 _("You cannot raise/lower objects from <b>different groups</b> or <b>layers</b>."));
1042 return;1011 return;
1043 }1012 }
10441013
@@ -1048,12 +1017,12 @@
1048 Geom::OptRect selected = enclose_items(items);1017 Geom::OptRect selected = enclose_items(items);
10491018
1050 /* Construct direct-ordered list of selected children. */1019 /* Construct direct-ordered list of selected children. */
1051 std::vector<SPItem*> rev(items);1020 std::vector<SPItem *> rev(items);
1052 sort(rev.begin(),rev.end(),sp_item_repr_compare_position_bool);1021 sort(rev.begin(), rev.end(), sp_item_repr_compare_position_bool);
10531022
1054 // Iterate over all objects in the selection (starting from top).1023 // Iterate over all objects in the selection (starting from top).
1055 if (selected) {1024 if (selected) {
1056 for (std::vector<SPItem*>::const_reverse_iterator item=rev.rbegin();item!=rev.rend();item++) {1025 for (std::vector<SPItem *>::const_reverse_iterator item = rev.rbegin(); item != rev.rend(); item++) {
1057 SPObject *child = *item;1026 SPObject *child = *item;
1058 // for each selected object, find the prev sibling1027 // for each selected object, find the prev sibling
1059 for (SPObject *newref = prev_sibling(child); newref; newref = prev_sibling(newref)) {1028 for (SPObject *newref = prev_sibling(child); newref; newref = prev_sibling(newref)) {
@@ -1061,9 +1030,9 @@
1061 SPItem *newItem = dynamic_cast<SPItem *>(newref);1030 SPItem *newItem = dynamic_cast<SPItem *>(newref);
1062 if (newItem) {1031 if (newItem) {
1063 Geom::OptRect ref_bbox = newItem->desktopVisualBounds();1032 Geom::OptRect ref_bbox = newItem->desktopVisualBounds();
1064 if ( ref_bbox && selected->intersects(*ref_bbox) ) {1033 if (ref_bbox && selected->intersects(*ref_bbox)) {
1065 // AND if it's not one of our selected objects,1034 // AND if it's not one of our selected objects,
1066 if (items.end()==std::find(items.begin(),items.end(),newref)) {1035 if (items.end() == std::find(items.begin(), items.end(), newref)) {
1067 // move the selected object before that sibling1036 // move the selected object before that sibling
1068 SPObject *put_after = prev_sibling(newref);1037 SPObject *put_after = prev_sibling(newref);
1069 if (put_after)1038 if (put_after)
@@ -1079,7 +1048,7 @@
1079 }1048 }
10801049
1081 DocumentUndo::done(selection->layers()->getDocument(), SP_VERB_SELECTION_LOWER,1050 DocumentUndo::done(selection->layers()->getDocument(), SP_VERB_SELECTION_LOWER,
1082 //TRANSLATORS: "Lower" means "to lower an object" in the undo history1051 // TRANSLATORS: "Lower" means "to lower an object" in the undo history
1083 C_("Undo action", "Lower"));1052 C_("Undo action", "Lower"));
1084}1053}
10851054
@@ -1092,18 +1061,19 @@
1092 return;1061 return;
1093 }1062 }
10941063
1095 std::vector<SPItem*> items =selection->itemList();1064 std::vector<SPItem *> items = selection->itemList();
10961065
1097 SPGroup const *group = sp_item_list_common_parent_group(items);1066 SPGroup const *group = sp_item_list_common_parent_group(items);
1098 if (!group) {1067 if (!group) {
1099 selection_display_message(desktop, Inkscape::ERROR_MESSAGE, _("You cannot raise/lower objects from <b>different groups</b> or <b>layers</b>."));1068 selection_display_message(desktop, Inkscape::ERROR_MESSAGE,
1069 _("You cannot raise/lower objects from <b>different groups</b> or <b>layers</b>."));
1100 return;1070 return;
1101 }1071 }
11021072
1103 std::vector<Inkscape::XML::Node*> rl(selection->reprList());1073 std::vector<Inkscape::XML::Node *> rl(selection->reprList());
1104 sort(rl.begin(),rl.end(),sp_repr_compare_position_bool);1074 sort(rl.begin(), rl.end(), sp_repr_compare_position_bool);
11051075
1106 for (std::vector<Inkscape::XML::Node*>::const_reverse_iterator l=rl.rbegin();l!=rl.rend();l++) {1076 for (std::vector<Inkscape::XML::Node *>::const_reverse_iterator l = rl.rbegin(); l != rl.rend(); l++) {
1107 gint minpos;1077 gint minpos;
1108 SPObject *pp, *pc;1078 SPObject *pp, *pc;
1109 Inkscape::XML::Node *repr = (*l);1079 Inkscape::XML::Node *repr = (*l);
@@ -1118,26 +1088,25 @@
1118 repr->setPosition(minpos);1088 repr->setPosition(minpos);
1119 }1089 }
11201090
1121 DocumentUndo::done(document, SP_VERB_SELECTION_TO_BACK,1091 DocumentUndo::done(document, SP_VERB_SELECTION_TO_BACK, _("Lower to bottom"));
1122 _("Lower to bottom"));
1123}1092}
11241093
1125void1094void sp_undo(SPDesktop *desktop, SPDocument *)
1126sp_undo(SPDesktop *desktop, SPDocument *)
1127{1095{
1128 // No re/undo while dragging, too dangerous.1096 // No re/undo while dragging, too dangerous.
1129 if(desktop->getCanvas()->is_dragging) return;1097 if (desktop->getCanvas()->is_dragging)
1098 return;
11301099
1131 if (!DocumentUndo::undo(desktop->getDocument())) {1100 if (!DocumentUndo::undo(desktop->getDocument())) {
1132 desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Nothing to undo."));1101 desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Nothing to undo."));
1133 }1102 }
1134}1103}
11351104
1136void1105void sp_redo(SPDesktop *desktop, SPDocument *)
1137sp_redo(SPDesktop *desktop, SPDocument *)
1138{1106{
1139 // No re/undo while dragging, too dangerous.1107 // No re/undo while dragging, too dangerous.
1140 if(desktop->getCanvas()->is_dragging) return;1108 if (desktop->getCanvas()->is_dragging)
1109 return;
11411110
1142 if (!DocumentUndo::redo(desktop->getDocument())) {1111 if (!DocumentUndo::redo(desktop->getDocument())) {
1143 desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Nothing to redo."));1112 desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Nothing to redo."));
@@ -1153,8 +1122,7 @@
1153/**1122/**
1154 * \pre item != NULL1123 * \pre item != NULL
1155 */1124 */
1156SPCSSAttr *1125SPCSSAttr *take_style_from_item(SPObject *object)
1157take_style_from_item(SPObject *object)
1158{1126{
1159 // CPPIFY:1127 // CPPIFY:
1160 // This function should only take SPItems, but currently SPString is not an Item.1128 // This function should only take SPItems, but currently SPString is not an Item.
@@ -1168,8 +1136,9 @@
1168 (dynamic_cast<SPText *>(object) && object->children && object->children->next == NULL)) {1136 (dynamic_cast<SPText *>(object) && object->children && object->children->next == NULL)) {
1169 // if this is a text with exactly one tspan child, merge the style of that tspan as well1137 // if this is a text with exactly one tspan child, merge the style of that tspan as well
1170 // If this is a group, merge the style of its topmost (last) child with style1138 // If this is a group, merge the style of its topmost (last) child with style
1171 for (SPObject *last_element = object->lastChild(); last_element != NULL; last_element = last_element->getPrev()) {1139 for (SPObject *last_element = object->lastChild(); last_element != NULL;
1172 if ( last_element->style ) {1140 last_element = last_element->getPrev()) {
1141 if (last_element->style) {
1173 SPCSSAttr *temp = sp_css_attr_from_object(last_element, SP_STYLE_FLAG_IFSET);1142 SPCSSAttr *temp = sp_css_attr_from_object(last_element, SP_STYLE_FLAG_IFSET);
1174 if (temp) {1143 if (temp) {
1175 sp_repr_css_merge(css, temp);1144 sp_repr_css_merge(css, temp);
@@ -1183,7 +1152,8 @@
1183 // Remove black-listed properties (those that should not be used in a default style)1152 // Remove black-listed properties (those that should not be used in a default style)
1184 css = sp_css_attr_unset_blacklist(css);1153 css = sp_css_attr_unset_blacklist(css);
11851154
1186 if (!(dynamic_cast<SPText *>(object) || dynamic_cast<SPTSpan *>(object) || dynamic_cast<SPTRef *>(object) || dynamic_cast<SPString *>(object))) {1155 if (!(dynamic_cast<SPText *>(object) || dynamic_cast<SPTSpan *>(object) || dynamic_cast<SPTRef *>(object) ||
1156 dynamic_cast<SPString *>(object))) {
1187 // do not copy text properties from non-text objects, it's confusing1157 // do not copy text properties from non-text objects, it's confusing
1188 css = sp_css_attr_unset_text(css);1158 css = sp_css_attr_unset_text(css);
1189 }1159 }
@@ -1229,16 +1199,15 @@
1229{1199{
1230 Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get();1200 Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get();
1231 if (cm->pastePathEffect(desktop)) {1201 if (cm->pastePathEffect(desktop)) {
1232 DocumentUndo::done(desktop->getDocument(), SP_VERB_EDIT_PASTE_LIVEPATHEFFECT,1202 DocumentUndo::done(desktop->getDocument(), SP_VERB_EDIT_PASTE_LIVEPATHEFFECT, _("Paste live path effect"));
1233 _("Paste live path effect"));
1234 }1203 }
1235}1204}
12361205
12371206
1238static void sp_selection_remove_livepatheffect_impl(SPItem *item)1207static void sp_selection_remove_livepatheffect_impl(SPItem *item)
1239{1208{
1240 if ( SPLPEItem *lpeitem = dynamic_cast<SPLPEItem*>(item) ) {1209 if (SPLPEItem *lpeitem = dynamic_cast<SPLPEItem *>(item)) {
1241 if ( lpeitem->hasPathEffect() ) {1210 if (lpeitem->hasPathEffect()) {
1242 lpeitem->removeAllPathEffects(false);1211 lpeitem->removeAllPathEffects(false);
1243 }1212 }
1244 }1213 }
@@ -1246,30 +1215,31 @@
12461215
1247void sp_selection_remove_livepatheffect(SPDesktop *desktop)1216void sp_selection_remove_livepatheffect(SPDesktop *desktop)
1248{1217{
1249 if (desktop == NULL) return;1218 if (desktop == NULL)
1219 return;
12501220
1251 Inkscape::Selection *selection = desktop->getSelection();1221 Inkscape::Selection *selection = desktop->getSelection();
12521222
1253 // check if something is selected1223 // check if something is selected
1254 if (selection->isEmpty()) {1224 if (selection->isEmpty()) {
1255 desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to remove live path effects from."));1225 desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE,
1226 _("Select <b>object(s)</b> to remove live path effects from."));
1256 return;1227 return;
1257 }1228 }
1258 std::vector<SPItem*> list=selection->itemList();1229 std::vector<SPItem *> list = selection->itemList();
1259 for ( std::vector<SPItem*>::const_iterator itemlist=list.begin();itemlist!=list.end();itemlist++) {1230 for (std::vector<SPItem *>::const_iterator itemlist = list.begin(); itemlist != list.end(); itemlist++) {
1260 SPItem *item = *itemlist;1231 SPItem *item = *itemlist;
12611232
1262 sp_selection_remove_livepatheffect_impl(item);1233 sp_selection_remove_livepatheffect_impl(item);
1263
1264 }1234 }
12651235
1266 DocumentUndo::done(desktop->getDocument(), SP_VERB_EDIT_REMOVE_LIVEPATHEFFECT,1236 DocumentUndo::done(desktop->getDocument(), SP_VERB_EDIT_REMOVE_LIVEPATHEFFECT, _("Remove live path effect"));
1267 _("Remove live path effect"));
1268}1237}
12691238
1270void sp_selection_remove_filter(SPDesktop *desktop)1239void sp_selection_remove_filter(SPDesktop *desktop)
1271{1240{
1272 if (desktop == NULL) return;1241 if (desktop == NULL)
1242 return;
12731243
1274 Inkscape::Selection *selection = desktop->getSelection();1244 Inkscape::Selection *selection = desktop->getSelection();
12751245
@@ -1284,8 +1254,7 @@
1284 sp_desktop_set_style(desktop, css);1254 sp_desktop_set_style(desktop, css);
1285 sp_repr_css_attr_unref(css);1255 sp_repr_css_attr_unref(css);
12861256
1287 DocumentUndo::done(desktop->getDocument(), SP_VERB_EDIT_REMOVE_FILTER,1257 DocumentUndo::done(desktop->getDocument(), SP_VERB_EDIT_REMOVE_FILTER, _("Remove filter"));
1288 _("Remove filter"));
1289}1258}
12901259
12911260
@@ -1293,8 +1262,7 @@
1293{1262{
1294 Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get();1263 Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get();
1295 if (cm->pasteSize(desktop, false, apply_x, apply_y)) {1264 if (cm->pasteSize(desktop, false, apply_x, apply_y)) {
1296 DocumentUndo::done(desktop->getDocument(), SP_VERB_EDIT_PASTE_SIZE,1265 DocumentUndo::done(desktop->getDocument(), SP_VERB_EDIT_PASTE_SIZE, _("Paste size"));
1297 _("Paste size"));
1298 }1266 }
1299}1267}
13001268
@@ -1302,8 +1270,7 @@
1302{1270{
1303 Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get();1271 Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get();
1304 if (cm->pasteSize(desktop, true, apply_x, apply_y)) {1272 if (cm->pasteSize(desktop, true, apply_x, apply_y)) {
1305 DocumentUndo::done(desktop->getDocument(), SP_VERB_EDIT_PASTE_SIZE_SEPARATELY,1273 DocumentUndo::done(desktop->getDocument(), SP_VERB_EDIT_PASTE_SIZE_SEPARATELY, _("Paste size separately"));
1306 _("Paste size separately"));
1307 }1274 }
1308}1275}
13091276
@@ -1311,16 +1278,15 @@
1311 * Ensures that the clones of objects are not modified when moving objects between layers.1278 * Ensures that the clones of objects are not modified when moving objects between layers.
1312 * Calls the same function as ungroup1279 * Calls the same function as ungroup
1313 */1280 */
1314void sp_selection_change_layer_maintain_clones(std::vector<SPItem*> const &items,SPObject *where)1281void sp_selection_change_layer_maintain_clones(std::vector<SPItem *> const &items, SPObject *where)
1315{1282{
1316 for (std::vector<SPItem*>::const_iterator i = items.begin(); i != items.end(); i++) {1283 for (std::vector<SPItem *>::const_iterator i = items.begin(); i != items.end(); i++) {
1317 SPItem *item = *i;1284 SPItem *item = *i;
1318 if (item) {1285 if (item) {
1319 SPItem *oldparent = dynamic_cast<SPItem *>(item->parent);1286 SPItem *oldparent = dynamic_cast<SPItem *>(item->parent);
1320 SPItem *newparent = dynamic_cast<SPItem *>(where);1287 SPItem *newparent = dynamic_cast<SPItem *>(where);
1321 sp_item_group_ungroup_handle_clones(item,1288 sp_item_group_ungroup_handle_clones(item,
1322 (oldparent->i2doc_affine())1289 (oldparent->i2doc_affine()) * ((newparent->i2doc_affine()).inverse()));
1323 *((newparent->i2doc_affine()).inverse()));
1324 }1290 }
1325 }1291 }
1326}1292}
@@ -1336,17 +1302,18 @@
1336 return;1302 return;
1337 }1303 }
13381304
1339 std::vector<SPItem*> items(selection->itemList());1305 std::vector<SPItem *> items(selection->itemList());
13401306
1341 bool no_more = false; // Set to true, if no more layers above1307 bool no_more = false; // Set to true, if no more layers above
1342 SPObject *next=Inkscape::next_layer(dt->currentRoot(), dt->currentLayer());1308 SPObject *next = Inkscape::next_layer(dt->currentRoot(), dt->currentLayer());
1343 if (next) {1309 if (next) {
1344 sp_selection_change_layer_maintain_clones(items,next);1310 sp_selection_change_layer_maintain_clones(items, next);
1345 std::vector<Inkscape::XML::Node*> temp_clip;1311 std::vector<Inkscape::XML::Node *> temp_clip;
1346 sp_selection_copy_impl(items, temp_clip, dt->doc()->getReprDoc());1312 sp_selection_copy_impl(items, temp_clip, dt->doc()->getReprDoc());
1347 sp_selection_delete_impl(items, false, false);1313 sp_selection_delete_impl(items, false, false);
1348 next=Inkscape::next_layer(dt->currentRoot(), dt->currentLayer()); // Fixes bug 1482973: crash while moving layers1314 next =
1349 std::vector<Inkscape::XML::Node*> copied;1315 Inkscape::next_layer(dt->currentRoot(), dt->currentLayer()); // Fixes bug 1482973: crash while moving layers
1316 std::vector<Inkscape::XML::Node *> copied;
1350 if (next) {1317 if (next) {
1351 copied = sp_selection_paste_impl(dt->getDocument(), next, temp_clip);1318 copied = sp_selection_paste_impl(dt->getDocument(), next, temp_clip);
1352 } else {1319 } else {
@@ -1354,10 +1321,10 @@
1354 no_more = true;1321 no_more = true;
1355 }1322 }
1356 selection->setReprList(copied);1323 selection->setReprList(copied);
1357 if (next) dt->setCurrentLayer(next);1324 if (next)
1358 if ( !suppressDone ) {1325 dt->setCurrentLayer(next);
1359 DocumentUndo::done(dt->getDocument(), SP_VERB_LAYER_MOVE_TO_NEXT,1326 if (!suppressDone) {
1360 _("Raise to next layer"));1327 DocumentUndo::done(dt->getDocument(), SP_VERB_LAYER_MOVE_TO_NEXT, _("Raise to next layer"));
1361 }1328 }
1362 } else {1329 } else {
1363 no_more = true;1330 no_more = true;
@@ -1366,7 +1333,6 @@
1366 if (no_more) {1333 if (no_more) {
1367 dt->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("No more layers above."));1334 dt->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("No more layers above."));
1368 }1335 }
1369
1370}1336}
13711337
1372void sp_selection_to_prev_layer(SPDesktop *dt, bool suppressDone)1338void sp_selection_to_prev_layer(SPDesktop *dt, bool suppressDone)
@@ -1379,28 +1345,30 @@
1379 return;1345 return;
1380 }1346 }
13811347
1382 const std::vector<SPItem*> items(selection->itemList());1348 const std::vector<SPItem *> items(selection->itemList());
13831349
1384 bool no_more = false; // Set to true, if no more layers below1350 bool no_more = false; // Set to true, if no more layers below
1385 SPObject *next=Inkscape::previous_layer(dt->currentRoot(), dt->currentLayer());1351 SPObject *next = Inkscape::previous_layer(dt->currentRoot(), dt->currentLayer());
1386 if (next) {1352 if (next) {
1387 sp_selection_change_layer_maintain_clones(items,next);1353 sp_selection_change_layer_maintain_clones(items, next);
1388 std::vector<Inkscape::XML::Node*> temp_clip;1354 std::vector<Inkscape::XML::Node *> temp_clip;
1389 sp_selection_copy_impl(items, temp_clip, dt->doc()->getReprDoc()); // we're in the same doc, so no need to copy defs1355 sp_selection_copy_impl(items, temp_clip,
1356 dt->doc()->getReprDoc()); // we're in the same doc, so no need to copy defs
1390 sp_selection_delete_impl(items, false, false);1357 sp_selection_delete_impl(items, false, false);
1391 next=Inkscape::previous_layer(dt->currentRoot(), dt->currentLayer()); // Fixes bug 1482973: crash while moving layers1358 next = Inkscape::previous_layer(dt->currentRoot(),
1392 std::vector<Inkscape::XML::Node*> copied;1359 dt->currentLayer()); // Fixes bug 1482973: crash while moving layers
1360 std::vector<Inkscape::XML::Node *> copied;
1393 if (next) {1361 if (next) {
1394 copied = sp_selection_paste_impl(dt->getDocument(), next, temp_clip);1362 copied = sp_selection_paste_impl(dt->getDocument(), next, temp_clip);
1395 } else {1363 } else {
1396 copied = sp_selection_paste_impl(dt->getDocument(), dt->currentLayer(), temp_clip);1364 copied = sp_selection_paste_impl(dt->getDocument(), dt->currentLayer(), temp_clip);
1397 no_more = true;1365 no_more = true;
1398 }1366 }
1399 selection->setReprList( copied);1367 selection->setReprList(copied);
1400 if (next) dt->setCurrentLayer(next);1368 if (next)
1401 if ( !suppressDone ) {1369 dt->setCurrentLayer(next);
1402 DocumentUndo::done(dt->getDocument(), SP_VERB_LAYER_MOVE_TO_PREV,1370 if (!suppressDone) {
1403 _("Lower to previous layer"));1371 DocumentUndo::done(dt->getDocument(), SP_VERB_LAYER_MOVE_TO_PREV, _("Lower to previous layer"));
1404 }1372 }
1405 } else {1373 } else {
1406 no_more = true;1374 no_more = true;
@@ -1421,34 +1389,34 @@
1421 return;1389 return;
1422 }1390 }
14231391
1424 std::vector<SPItem*> items(selection->itemList());1392 std::vector<SPItem *> items(selection->itemList());
14251393
1426 if (moveto) {1394 if (moveto) {
1427 sp_selection_change_layer_maintain_clones(items,moveto);1395 sp_selection_change_layer_maintain_clones(items, moveto);
1428 std::vector<Inkscape::XML::Node*> temp_clip;1396 std::vector<Inkscape::XML::Node *> temp_clip;
1429 sp_selection_copy_impl(items, temp_clip, dt->doc()->getReprDoc()); // we're in the same doc, so no need to copy defs1397 sp_selection_copy_impl(items, temp_clip,
1398 dt->doc()->getReprDoc()); // we're in the same doc, so no need to copy defs
1430 sp_selection_delete_impl(items, false, false);1399 sp_selection_delete_impl(items, false, false);
1431 std::vector<Inkscape::XML::Node*> copied = sp_selection_paste_impl(dt->getDocument(), moveto, temp_clip);1400 std::vector<Inkscape::XML::Node *> copied = sp_selection_paste_impl(dt->getDocument(), moveto, temp_clip);
1432 selection->setReprList(copied);1401 selection->setReprList(copied);
1433 if (!temp_clip.empty()) temp_clip.clear();1402 if (!temp_clip.empty())
1434 if (moveto) dt->setCurrentLayer(moveto);1403 temp_clip.clear();
1435 if ( !suppressDone ) {1404 if (moveto)
1436 DocumentUndo::done(dt->getDocument(), SP_VERB_LAYER_MOVE_TO,1405 dt->setCurrentLayer(moveto);
1437 _("Move selection to layer"));1406 if (!suppressDone) {
1407 DocumentUndo::done(dt->getDocument(), SP_VERB_LAYER_MOVE_TO, _("Move selection to layer"));
1438 }1408 }
1439 }1409 }
1440}1410}
14411411
1442static bool1412static bool selection_contains_original(SPItem *item, Inkscape::Selection *selection)
1443selection_contains_original(SPItem *item, Inkscape::Selection *selection)
1444{1413{
1445 bool contains_original = false;1414 bool contains_original = false;
14461415
1447 SPItem *item_use = item;1416 SPItem *item_use = item;
1448 SPItem *item_use_first = item;1417 SPItem *item_use_first = item;
1449 SPUse *use = dynamic_cast<SPUse *>(item_use);1418 SPUse *use = dynamic_cast<SPUse *>(item_use);
1450 while (use && item_use && !contains_original)1419 while (use && item_use && !contains_original) {
1451 {
1452 item_use = use->get_original();1420 item_use = use->get_original();
1453 use = dynamic_cast<SPUse *>(item_use);1421 use = dynamic_cast<SPUse *>(item_use);
1454 contains_original |= selection->includes(item_use);1422 contains_original |= selection->includes(item_use);
@@ -1467,12 +1435,11 @@
1467}1435}
14681436
14691437
1470static bool1438static bool selection_contains_both_clone_and_original(Inkscape::Selection *selection)
1471selection_contains_both_clone_and_original(Inkscape::Selection *selection)
1472{1439{
1473 bool clone_with_original = false;1440 bool clone_with_original = false;
1474 std::vector<SPItem*> items = selection->itemList();1441 std::vector<SPItem *> items = selection->itemList();
1475 for (std::vector<SPItem*>::const_iterator l=items.begin();l!=items.end() ;l++) {1442 for (std::vector<SPItem *>::const_iterator l = items.begin(); l != items.end(); l++) {
1476 SPItem *item = *l;1443 SPItem *item = *l;
1477 if (item) {1444 if (item) {
1478 clone_with_original |= selection_contains_original(item, selection);1445 clone_with_original |= selection_contains_original(item, selection);
@@ -1483,13 +1450,149 @@
1483 return clone_with_original;1450 return clone_with_original;
1484}1451}
14851452
1453/* This function is called by sp_selection_apply_affine.
1454It takes all elements in selection, looks for all clones (or linked offsets) that are also in the
1455selection (either directly selected or in a selected group)
1456
1457The matrix magic in it is designed so that any transformation (translation or other) is handled
1458with any selections in a coherent way.
1459
1460Note that if affine is a translation, then SPUse::compensate is involved in a subtle way and we
1461have to account for it.
1462
1463If you want to modify this function, please watch carefully for regressions, and take extra care
1464to have the right advertised transforms so that clones of clones behave well.
1465
1466There are 10 cases to test.
1467*/
1468static void prevent_clone_double_transform(Inkscape::Selection *selection, SPItem *parent, Geom::Affine affine,
1469 bool compensate)
1470{
1471 // "clones are unmoved when original is moved" preference
1472 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1473 int compensation = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED);
1474 bool prefs_unmoved = (compensation == SP_CLONE_COMPENSATION_UNMOVED);
1475 bool prefs_parallel = (compensation == SP_CLONE_COMPENSATION_PARALLEL);
1476
1477 // calculate the matrix we need to apply to the clone to cancel its induced transform from its original
1478 if (!dynamic_cast<SPItem *>(parent->parent))
1479 return;
1480 Geom::Affine parent2dt = dynamic_cast<SPItem *>(parent->parent)->i2dt_affine();
1481 Geom::Affine t = parent2dt * affine * parent2dt.inverse();
1482 Geom::Affine t_inv = t.inverse();
1483
1484 for (std::list<SPObject *>::const_iterator refd = parent->hrefList.begin(); refd != parent->hrefList.end();
1485 refd++) {
1486 SPItem *item = dynamic_cast<SPItem *>(*refd);
1487 if (!item || item->cloned)
1488 continue;
1489 bool transform_offset_with_source = false;
1490 bool transform_clone_with_original = false;
1491 bool transform_deep_offset_with_source = false;
1492 bool transform_deep_clone_with_original = false;
1493
1494 SPUse *useitem = dynamic_cast<SPUse *>(item);
1495 SPOffset *off = dynamic_cast<SPOffset *>(item);
1496 if (off && off->sourceHref && sp_offset_get_source(off) == parent) {
1497 // We transform a linked offset and (directly) its original
1498 transform_offset_with_source = selection->includes(off);
1499 transform_deep_offset_with_source = selection->includes_deeply(off);
1500 } else if (useitem && useitem->get_original() == parent) {
1501 // We are transforming a clone along with its original.
1502 transform_clone_with_original = selection->includes(useitem);
1503 transform_deep_clone_with_original = selection->includes_deeply(useitem);
1504 } else
1505 continue;
1506
1507 // restore item->transform field from the repr, in case it was changed by seltrans
1508 item->readAttr("transform");
1509
1510 if (transform_clone_with_original || transform_offset_with_source) {
1511 // case 1: the clone and the original are directly selected.
1512
1513 Geom::Affine result = t_inv * item->transform * t;
1514
1515 if (transform_clone_with_original && (prefs_parallel || prefs_unmoved) && affine.isTranslation()) {
1516 // 1.1: translation, clone
1517 // find out the clone move, same as in SPUse::move_compensate
1518 Geom::Affine parent = useitem->get_parent_transform();
1519 Geom::Affine clone_move = parent.inverse() * t * parent;
1520
1521 if (prefs_parallel) {
1522 Geom::Affine move = result * clone_move * t_inv;
1523 item->doWriteTransform(item->getRepr(), move, &move, compensate);
1524
1525 } else if (prefs_unmoved) {
1526 Geom::Affine move = result * clone_move;
1527 item->doWriteTransform(item->getRepr(), move, &t, compensate);
1528 }
1529
1530 } else if (transform_offset_with_source && (prefs_parallel || prefs_unmoved) && affine.isTranslation()) {
1531 // 1.2: translation, offset
1532 Geom::Affine parent = item->transform;
1533 Geom::Affine offset_move = parent.inverse() * t * parent;
1534
1535 if (prefs_parallel) {
1536 Geom::Affine move = result * offset_move * t_inv;
1537 item->doWriteTransform(item->getRepr(), move, &move, compensate);
1538
1539 } else if (prefs_unmoved) {
1540 Geom::Affine move = result * offset_move;
1541 item->doWriteTransform(item->getRepr(), move, &t, compensate);
1542 }
1543 } else { // 1.3: affine is no translation, just apply the result
1544 item->doWriteTransform(item->getRepr(), result, &t, compensate);
1545 }
1546 } else if (transform_deep_clone_with_original || transform_deep_offset_with_source) {
1547 // case 2: The original is selected, and the clone is somewhere in a selected group.
1548 if (transform_deep_clone_with_original && (prefs_parallel || prefs_unmoved) && affine.isTranslation()) {
1549 // 2.1: translation, clone
1550
1551 Geom::Affine parent = useitem->get_parent_transform();
1552 Geom::Affine clone_move = parent.inverse() * t * parent;
1553
1554 if (prefs_parallel) {
1555 Geom::Affine move = t_inv * item->transform * t_inv * clone_move;
1556 item->doWriteTransform(item->getRepr(), move, &move, compensate);
1557
1558 } else if (prefs_unmoved) {
1559 Geom::Affine move = t_inv * item->transform * clone_move;
1560 Geom::Affine move_a = Geom::Affine::identity();
1561 item->doWriteTransform(item->getRepr(), move, &move_a, compensate);
1562 }
1563 } else if (transform_deep_offset_with_source && (prefs_parallel || prefs_unmoved) &&
1564 affine.isTranslation()) {
1565 // 2.2: translation, offset
1566 Geom::Affine parent = item->transform;
1567 Geom::Affine offset_move = parent.inverse() * t * parent;
1568 Geom::Affine result = t_inv * item->transform * t_inv;
1569
1570 if (prefs_parallel) {
1571 Geom::Affine move = result * offset_move;
1572 item->doWriteTransform(item->getRepr(), move, &move, compensate);
1573
1574 } else if (prefs_unmoved) {
1575 Geom::Affine move = result * t * offset_move;
1576 Geom::Affine move_a = Geom::Affine::identity();
1577 item->doWriteTransform(item->getRepr(), move, &move_a, compensate);
1578 }
1579 } else { // 2.3: affine is no translation
1580 Geom::Affine move = parent2dt * affine.inverse() * parent2dt.inverse() * item->transform;
1581 item->doWriteTransform(item->getRepr(), move, &move, compensate);
1582 }
1583 }
1584 }
1585}
1586
1587
1486/** Apply matrix to the selection. \a set_i2d is normally true, which means objects are in the1588/** Apply matrix to the selection. \a set_i2d is normally true, which means objects are in the
1487original transform, synced with their reprs, and need to jump to the new transform in one go. A1589original transform, synced with their reprs, and need to jump to the new transform in one go. A
1488value of set_i2d==false is only used by seltrans when it's dragging objects live (not outlines); in1590value of set_i2d==false is only used by seltrans when it's dragging objects live (not outlines); in
1489that case, items are already in the new position, but the repr is in the old, and this function1591that case, items are already in the new position, but the repr is in the old, and this function
1490then simply updates the repr from item->transform.1592then simply updates the repr from item->transform.
1491 */1593 */
1492void sp_selection_apply_affine(Inkscape::Selection *selection, Geom::Affine const &affine, bool set_i2d, bool compensate, bool adjust_transf_center)1594void sp_selection_apply_affine(Inkscape::Selection *selection, Geom::Affine const &affine, bool set_i2d,
1595 bool compensate, bool adjust_transf_center)
1493{1596{
1494 if (selection->isEmpty())1597 if (selection->isEmpty())
1495 return;1598 return;
@@ -1500,13 +1603,13 @@
1500 Persp3D *transf_persp;1603 Persp3D *transf_persp;
1501 std::list<Persp3D *> plist = selection->perspList();1604 std::list<Persp3D *> plist = selection->perspList();
1502 for (std::list<Persp3D *>::iterator i = plist.begin(); i != plist.end(); ++i) {1605 for (std::list<Persp3D *>::iterator i = plist.begin(); i != plist.end(); ++i) {
1503 persp = (Persp3D *) (*i);1606 persp = (Persp3D *)(*i);
15041607
1505 if (!persp3d_has_all_boxes_in_selection (persp, selection)) {1608 if (!persp3d_has_all_boxes_in_selection(persp, selection)) {
1506 std::list<SPBox3D *> selboxes = selection->box3DList(persp);1609 std::list<SPBox3D *> selboxes = selection->box3DList(persp);
15071610
1508 // create a new perspective as a copy of the current one and link the selected boxes to it1611 // create a new perspective as a copy of the current one and link the selected boxes to it
1509 transf_persp = persp3d_create_xml_element (persp->document, persp->perspective_impl);1612 transf_persp = persp3d_create_xml_element(persp->document, persp->perspective_impl);
15101613
1511 for (std::list<SPBox3D *>::iterator b = selboxes.begin(); b != selboxes.end(); ++b)1614 for (std::list<SPBox3D *>::iterator b = selboxes.begin(); b != selboxes.end(); ++b)
1512 box3d_switch_perspectives(*b, persp, transf_persp);1615 box3d_switch_perspectives(*b, persp, transf_persp);
@@ -1516,38 +1619,49 @@
15161619
1517 persp3d_apply_affine_transformation(transf_persp, affine);1620 persp3d_apply_affine_transformation(transf_persp, affine);
1518 }1621 }
1519 std::vector<SPItem*> items = selection->itemList();1622 std::vector<SPItem *> items = selection->itemList();
1520 for (std::vector<SPItem*>::const_iterator l=items.begin();l!=items.end() ;l++) {1623 for (std::vector<SPItem *>::const_iterator l = items.begin(); l != items.end(); l++) {
1521 SPItem *item = *l;1624 SPItem *item = *l;
15221625
1523 if( dynamic_cast<SPRoot *>(item) ) {1626 if (dynamic_cast<SPRoot *>(item)) {
1524 // An SVG element cannot have a transform. We could change 'x' and 'y' in response1627 // An SVG element cannot have a transform. We could change 'x' and 'y' in response
1525 // to a translation... but leave that for another day.1628 // to a translation... but leave that for another day.
1526 selection->desktop()->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Cannot transform an embedded SVG."));1629 selection->desktop()->messageStack()->flash(Inkscape::WARNING_MESSAGE,
1630 _("Cannot transform an embedded SVG."));
1527 break;1631 break;
1528 }1632 }
15291633
1530 Geom::Point old_center(0,0);1634 Geom::Point old_center(0, 0);
1531 if (set_i2d && item->isCenterSet())1635 if (set_i2d && item->isCenterSet())
1532 old_center = item->getCenter();1636 old_center = item->getCenter();
15331637
1534#if 0 /* Re-enable this once persistent guides have a graphical indication.1638#if 0 /* Re-enable this once persistent guides have a graphical indication. \
1535 At the time of writing, this is the only place to re-enable. */1639 At the time of writing, this is the only place to re-enable. */
1536 sp_item_update_cns(*item, selection->desktop());1640 sp_item_update_cns(*item, selection->desktop());
1537#endif1641#endif
15381642
1539 // we're moving both a clone and its original or any ancestor in clone chain?1643 // everyting is taken care of in prevent_clone_double_transform for the two first cases,
1540 bool transform_clone_with_original = selection_contains_original(item, selection);1644 // *after* the transformation is applied to the original.
15411645
1542 // ...both a text-on-path and its path?1646 // Tests if we're moving both a clone and its original...
1543 bool transform_textpath_with_path = ((dynamic_cast<SPText *>(item) && item->firstChild() && dynamic_cast<SPTextPath *>(item->firstChild()))1647 if (selection_contains_original(item, selection))
1544 && selection->includes( sp_textpath_get_path_item(dynamic_cast<SPTextPath *>(item->firstChild())) ));1648 continue;
15451649
1546 // ...both a flowtext and its frame?1650 // ...both an offset and its source...
1547 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)1651 if ((dynamic_cast<SPOffset *>(item) && dynamic_cast<SPOffset *>(item)->sourceHref) &&
15481652 selection->includes(sp_offset_get_source(dynamic_cast<SPOffset *>(item))))
1549 // ...both an offset and its source?1653 continue;
1550 bool transform_offset_with_source = (dynamic_cast<SPOffset *>(item) && dynamic_cast<SPOffset *>(item)->sourceHref) && selection->includes( sp_offset_get_source(dynamic_cast<SPOffset *>(item)) );1654
1655 // ...both a text-on-path and its path...
1656 bool transform_textpath_with_path =
1657 ((dynamic_cast<SPText *>(item) && item->firstChild() && dynamic_cast<SPTextPath *>(item->firstChild())) &&
1658 selection->includes(sp_textpath_get_path_item(dynamic_cast<SPTextPath *>(item->firstChild()))));
1659
1660 // ...both a flowtext and its frame...
1661 bool transform_flowtext_with_frame = (dynamic_cast<SPFlowtext *>(item) &&
1662 selection->includes(dynamic_cast<SPFlowtext *>(item)->get_frame(
1663 NULL))); // (only the first frame is checked so far)
1664
15511665
1552 // If we're moving a connector, we want to detach it1666 // If we're moving a connector, we want to detach it
1553 // from shapes that aren't part of the selection, but1667 // from shapes that aren't part of the selection, but
@@ -1555,7 +1669,7 @@
1555 if (Inkscape::UI::Tools::cc_item_is_connector(item)) {1669 if (Inkscape::UI::Tools::cc_item_is_connector(item)) {
1556 SPPath *path = dynamic_cast<SPPath *>(item);1670 SPPath *path = dynamic_cast<SPPath *>(item);
1557 if (path) {1671 if (path) {
1558 SPItem *attItem[2] = {0, 0};1672 SPItem *attItem[2] = { 0, 0 };
1559 path->connEndPair.getAttachedItems(attItem);1673 path->connEndPair.getAttachedItems(attItem);
1560 for (int n = 0; n < 2; ++n) {1674 for (int n = 0; n < 2; ++n) {
1561 if (!selection->includes(attItem[n])) {1675 if (!selection->includes(attItem[n])) {
@@ -1567,12 +1681,6 @@
1567 }1681 }
1568 }1682 }
15691683
1570 // "clones are unmoved when original is moved" preference
1571 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1572 int compensation = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED);
1573 bool prefs_unmoved = (compensation == SP_CLONE_COMPENSATION_UNMOVED);
1574 bool prefs_parallel = (compensation == SP_CLONE_COMPENSATION_PARALLEL);
1575
1576 /* If this is a clone and it's selected along with its original, do not move it;1684 /* If this is a clone and it's selected along with its original, do not move it;
1577 * it will feel the transform of its original and respond to it itself.1685 * it will feel the transform of its original and respond to it itself.
1578 * Without this, a clone is doubly transformed, very unintuitive.1686 * Without this, a clone is doubly transformed, very unintuitive.
@@ -1582,86 +1690,20 @@
1582 * Same for linked offset if we are also moving its source: do not move it. */1690 * Same for linked offset if we are also moving its source: do not move it. */
1583 if (transform_textpath_with_path) {1691 if (transform_textpath_with_path) {
1584 // Restore item->transform field from the repr, in case it was changed by seltrans.1692 // Restore item->transform field from the repr, in case it was changed by seltrans.
1585 item->readAttr( "transform" );1693 item->readAttr("transform");
1586 } else if (transform_flowtext_with_frame) {1694 } else if (transform_flowtext_with_frame) {
1587 // apply the inverse of the region's transform to the <use> so that the flow remains1695 // apply the inverse of the region's transform to the <use> so that the flow remains
1588 // the same (even though the output itself gets transformed)1696 // the same (even though the output itself gets transformed)
1589 for ( SPObject *region = item->firstChild() ; region ; region = region->getNext() ) {1697 for (SPObject *region = item->firstChild(); region; region = region->getNext()) {
1590 if (dynamic_cast<SPFlowregion *>(region) || dynamic_cast<SPFlowregionExclude *>(region)) {1698 if (dynamic_cast<SPFlowregion *>(region) || dynamic_cast<SPFlowregionExclude *>(region)) {
1591 for ( SPObject *item = region->firstChild() ; item ; item = item->getNext() ) {1699 for (SPObject *item = region->firstChild(); item; item = item->getNext()) {
1592 SPUse *use = dynamic_cast<SPUse *>(item);1700 SPUse *use = dynamic_cast<SPUse *>(item);
1593 if ( use ) {1701 if (use) {
1594 use->doWriteTransform(use->getRepr(), use->transform.inverse(), NULL, compensate);1702 use->doWriteTransform(use->getRepr(), use->transform.inverse(), NULL, compensate);
1595 }1703 }
1596 }1704 }
1597 }1705 }
1598 }1706 }
1599 } else if (transform_clone_with_original || transform_offset_with_source) {
1600 // We are transforming a clone along with its original. The below matrix juggling is
1601 // necessary to ensure that they transform as a whole, i.e. the clone's induced
1602 // transform and its move compensation are both cancelled out.
1603
1604 // restore item->transform field from the repr, in case it was changed by seltrans
1605 item->readAttr( "transform" );
1606
1607 // calculate the matrix we need to apply to the clone to cancel its induced transform from its original
1608 Geom::Affine parent2dt;
1609 {
1610 SPItem *parentItem = dynamic_cast<SPItem *>(item->parent);
1611 if (parentItem) {
1612 parent2dt = parentItem->i2dt_affine();
1613 } else {
1614 g_assert_not_reached();
1615 }
1616 }
1617 Geom::Affine t = parent2dt * affine * parent2dt.inverse();
1618 Geom::Affine t_inv = t.inverse();
1619 Geom::Affine result = t_inv * item->transform * t;
1620
1621 if (transform_clone_with_original && (prefs_parallel || prefs_unmoved) && affine.isTranslation()) {
1622 // we need to cancel out the move compensation, too
1623
1624 // find out the clone move, same as in sp_use_move_compensate
1625 Geom::Affine parent;
1626 {
1627 SPUse *use = dynamic_cast<SPUse *>(item);
1628 if (use) {
1629 parent = use->get_parent_transform();
1630 } else {
1631 g_assert_not_reached();
1632 }
1633 }
1634 Geom::Affine clone_move = parent.inverse() * t * parent;
1635
1636 if (prefs_parallel) {
1637 Geom::Affine move = result * clone_move * t_inv;
1638 item->doWriteTransform(item->getRepr(), move, &move, compensate);
1639
1640 } else if (prefs_unmoved) {
1641 //if (dynamic_cast<SPUse *>(sp_use_get_original(dynamic_cast<SPUse *>(item))))
1642 // clone_move = Geom::identity();
1643 Geom::Affine move = result * clone_move;
1644 item->doWriteTransform(item->getRepr(), move, &t, compensate);
1645 }
1646
1647 } else if (transform_offset_with_source && (prefs_parallel || prefs_unmoved) && affine.isTranslation()){
1648 Geom::Affine parent = item->transform;
1649 Geom::Affine offset_move = parent.inverse() * t * parent;
1650
1651 if (prefs_parallel) {
1652 Geom::Affine move = result * offset_move * t_inv;
1653 item->doWriteTransform(item->getRepr(), move, &move, compensate);
1654
1655 } else if (prefs_unmoved) {
1656 Geom::Affine move = result * offset_move;
1657 item->doWriteTransform(item->getRepr(), move, &t, compensate);
1658 }
1659
1660 } else {
1661 // just apply the result
1662 item->doWriteTransform(item->getRepr(), result, &t, compensate);
1663 }
1664
1665 } else {1707 } else {
1666 if (set_i2d) {1708 if (set_i2d) {
1667 item->set_i2d_affine(item->i2dt_affine() * (Geom::Affine)affine);1709 item->set_i2d_affine(item->i2dt_affine() * (Geom::Affine)affine);
@@ -1669,7 +1711,11 @@
1669 item->doWriteTransform(item->getRepr(), item->transform, NULL, compensate);1711 item->doWriteTransform(item->getRepr(), item->transform, NULL, compensate);
1670 }1712 }
16711713
1672 if (adjust_transf_center) { // The transformation center should not be touched in case of pasting or importing, which is allowed by this if clause1714 // taking care of clones and linked offsets
1715 prevent_clone_double_transform(selection, item, affine, compensate);
1716
1717 if (adjust_transf_center) { // The transformation center should not be touched in case of pasting or importing,
1718 // which is allowed by this if clause
1673 // if we're moving the actual object, not just updating the repr, we can transform the1719 // if we're moving the actual object, not just updating the repr, we can transform the
1674 // center by the same matrix (only necessary for non-translations)1720 // center by the same matrix (only necessary for non-translations)
1675 if (set_i2d && item->isCenterSet() && !(affine.isTranslation() || affine.isIdentity())) {1721 if (set_i2d && item->isCenterSet() && !(affine.isTranslation() || affine.isIdentity())) {
@@ -1687,35 +1733,31 @@
16871733
1688 Inkscape::Selection *selection = desktop->getSelection();1734 Inkscape::Selection *selection = desktop->getSelection();
16891735
1690 std::vector<Inkscape::XML::Node*> items = selection->reprList();1736 std::vector<Inkscape::XML::Node *> items = selection->reprList();
1691 for (std::vector<Inkscape::XML::Node*>::const_iterator l=items.begin();l!=items.end() ;l++) {1737 for (std::vector<Inkscape::XML::Node *>::const_iterator l = items.begin(); l != items.end(); l++) {
1692 (*l)->setAttribute("transform", NULL, false);1738 (*l)->setAttribute("transform", NULL, false);
1693 }1739 }
16941740
1695 DocumentUndo::done(desktop->getDocument(), SP_VERB_OBJECT_FLATTEN,1741 DocumentUndo::done(desktop->getDocument(), SP_VERB_OBJECT_FLATTEN, _("Remove transform"));
1696 _("Remove transform"));
1697}1742}
16981743
1699void1744void sp_selection_scale_absolute(Inkscape::Selection *selection, double const x0, double const x1, double const y0,
1700sp_selection_scale_absolute(Inkscape::Selection *selection,1745 double const y1)
1701 double const x0, double const x1,
1702 double const y0, double const y1)
1703{1746{
1704 if (selection->isEmpty())1747 if (selection->isEmpty())
1705 return;1748 return;
17061749
1707 Geom::OptRect bbox = selection->visualBounds();1750 Geom::OptRect bbox = selection->visualBounds();
1708 if ( !bbox ) {1751 if (!bbox) {
1709 return;1752 return;
1710 }1753 }
17111754
1712 Geom::Translate const p2o(-bbox->min());1755 Geom::Translate const p2o(-bbox->min());
17131756
1714 Geom::Scale const newSize(x1 - x0,1757 Geom::Scale const newSize(x1 - x0, y1 - y0);
1715 y1 - y0);1758 Geom::Scale const scale(newSize * Geom::Scale(bbox->dimensions()).inverse());
1716 Geom::Scale const scale( newSize * Geom::Scale(bbox->dimensions()).inverse() );
1717 Geom::Translate const o2n(x0, y0);1759 Geom::Translate const o2n(x0, y0);
1718 Geom::Affine const final( p2o * scale * o2n );1760 Geom::Affine const final(p2o * scale * o2n);
17191761
1720 sp_selection_apply_affine(selection, final);1762 sp_selection_apply_affine(selection, final);
1721}1763}
@@ -1728,42 +1770,38 @@
17281770
1729 Geom::OptRect bbox = selection->visualBounds();1771 Geom::OptRect bbox = selection->visualBounds();
17301772
1731 if ( !bbox ) {1773 if (!bbox) {
1732 return;1774 return;
1733 }1775 }
17341776
1735 // FIXME: ARBITRARY LIMIT: don't try to scale above 1 Mpx, it won't display properly and will crash sooner or later anyway1777 // FIXME: ARBITRARY LIMIT: don't try to scale above 1 Mpx, it won't display properly and will crash sooner or later
1736 if ( bbox->dimensions()[Geom::X] * scale[Geom::X] > 1e6 ||1778 // anyway
1737 bbox->dimensions()[Geom::Y] * scale[Geom::Y] > 1e6 )1779 if (bbox->dimensions()[Geom::X] * scale[Geom::X] > 1e6 || bbox->dimensions()[Geom::Y] * scale[Geom::Y] > 1e6) {
1738 {
1739 return;1780 return;
1740 }1781 }
17411782
1742 Geom::Translate const n2d(-align);1783 Geom::Translate const n2d(-align);
1743 Geom::Translate const d2n(align);1784 Geom::Translate const d2n(align);
1744 Geom::Affine const final( n2d * scale * d2n );1785 Geom::Affine const final(n2d * scale * d2n);
1745 sp_selection_apply_affine(selection, final);1786 sp_selection_apply_affine(selection, final);
1746}1787}
17471788
1748void1789void sp_selection_rotate_relative(Inkscape::Selection *selection, Geom::Point const &center,
1749sp_selection_rotate_relative(Inkscape::Selection *selection, Geom::Point const &center, gdouble const angle_degrees)1790 gdouble const angle_degrees)
1750{1791{
1751 Geom::Translate const d2n(center);1792 Geom::Translate const d2n(center);
1752 Geom::Translate const n2d(-center);1793 Geom::Translate const n2d(-center);
1753 Geom::Rotate const rotate(Geom::Rotate::from_degrees(angle_degrees));1794 Geom::Rotate const rotate(Geom::Rotate::from_degrees(angle_degrees));
1754 Geom::Affine const final( Geom::Affine(n2d) * rotate * d2n );1795 Geom::Affine const final(Geom::Affine(n2d) * rotate * d2n);
1755 sp_selection_apply_affine(selection, final);1796 sp_selection_apply_affine(selection, final);
1756}1797}
17571798
1758void1799void sp_selection_skew_relative(Inkscape::Selection *selection, Geom::Point const &align, double dx, double dy)
1759sp_selection_skew_relative(Inkscape::Selection *selection, Geom::Point const &align, double dx, double dy)
1760{1800{
1761 Geom::Translate const d2n(align);1801 Geom::Translate const d2n(align);
1762 Geom::Translate const n2d(-align);1802 Geom::Translate const n2d(-align);
1763 Geom::Affine const skew(1, dy,1803 Geom::Affine const skew(1, dy, dx, 1, 0, 0);
1764 dx, 1,1804 Geom::Affine const final(n2d * skew * d2n);
1765 0, 0);
1766 Geom::Affine const final( n2d * skew * d2n );
1767 sp_selection_apply_affine(selection, final);1805 sp_selection_apply_affine(selection, final);
1768}1806}
17691807
@@ -1787,9 +1825,9 @@
1787 if (selection->isEmpty())1825 if (selection->isEmpty())
1788 return;1826 return;
17891827
1790 std::vector<SPItem*> items = selection->itemList();1828 std::vector<SPItem *> items = selection->itemList();
1791 Geom::Rotate const rot_90(Geom::Point(0, ccw ? 1 : -1)); // pos. or neg. rotation, depending on the value of ccw1829 Geom::Rotate const rot_90(Geom::Point(0, ccw ? 1 : -1)); // pos. or neg. rotation, depending on the value of ccw
1792 for (std::vector<SPItem*>::const_iterator l=items.begin();l!=items.end() ;l++) {1830 for (std::vector<SPItem *>::const_iterator l = items.begin(); l != items.end(); l++) {
1793 SPItem *item = *l;1831 SPItem *item = *l;
1794 if (item) {1832 if (item) {
1795 sp_item_rotate_rel(item, rot_90);1833 sp_item_rotate_rel(item, rot_90);
@@ -1798,13 +1836,11 @@
1798 }1836 }
1799 }1837 }
18001838
1801 DocumentUndo::done(desktop->getDocument(),1839 DocumentUndo::done(desktop->getDocument(), ccw ? SP_VERB_OBJECT_ROTATE_90_CCW : SP_VERB_OBJECT_ROTATE_90_CW,
1802 ccw ? SP_VERB_OBJECT_ROTATE_90_CCW : SP_VERB_OBJECT_ROTATE_90_CW,
1803 ccw ? _("Rotate 90\xc2\xb0 CCW") : _("Rotate 90\xc2\xb0 CW"));1840 ccw ? _("Rotate 90\xc2\xb0 CCW") : _("Rotate 90\xc2\xb0 CW"));
1804}1841}
18051842
1806void1843void sp_selection_rotate(Inkscape::Selection *selection, gdouble const angle_degrees)
1807sp_selection_rotate(Inkscape::Selection *selection, gdouble const angle_degrees)
1808{1844{
1809 if (selection->isEmpty())1845 if (selection->isEmpty())
1810 return;1846 return;
@@ -1817,11 +1853,8 @@
1817 sp_selection_rotate_relative(selection, *center, angle_degrees);1853 sp_selection_rotate_relative(selection, *center, angle_degrees);
18181854
1819 DocumentUndo::maybeDone(selection->desktop()->getDocument(),1855 DocumentUndo::maybeDone(selection->desktop()->getDocument(),
1820 ( ( angle_degrees > 0 )1856 ((angle_degrees > 0) ? "selector:rotate:ccw" : "selector:rotate:cw"),
1821 ? "selector:rotate:ccw"1857 SP_VERB_CONTEXT_SELECT, _("Rotate"));
1822 : "selector:rotate:cw" ),
1823 SP_VERB_CONTEXT_SELECT,
1824 _("Rotate"));
1825}1858}
18261859
1827/*1860/*
@@ -1846,42 +1879,39 @@
1846 bool onlyvisible = prefs->getBool("/options/kbselection/onlyvisible", true);1879 bool onlyvisible = prefs->getBool("/options/kbselection/onlyvisible", true);
1847 bool onlysensitive = prefs->getBool("/options/kbselection/onlysensitive", true);1880 bool onlysensitive = prefs->getBool("/options/kbselection/onlysensitive", true);
1848 bool ingroups = TRUE;1881 bool ingroups = TRUE;
1849 std::vector<SPItem*> x,y;1882 std::vector<SPItem *> x, y;
1850 std::vector<SPItem*> all_list = get_all_items(x, desktop->currentRoot(), desktop, onlyvisible, onlysensitive, ingroups, y);1883 std::vector<SPItem *> all_list =
1851 std::vector<SPItem*> all_matches;1884 get_all_items(x, desktop->currentRoot(), desktop, onlyvisible, onlysensitive, ingroups, y);
1885 std::vector<SPItem *> all_matches;
18521886
1853 Inkscape::Selection *selection = desktop->getSelection();1887 Inkscape::Selection *selection = desktop->getSelection();
1854 std::vector<SPItem*> items = selection->itemList();1888 std::vector<SPItem *> items = selection->itemList();
18551889
1856 std::vector<SPItem*> tmp;1890 std::vector<SPItem *> tmp;
1857 for (std::vector<SPItem*>::const_iterator iter=all_list.begin();iter!=all_list.end();iter++) {1891 for (std::vector<SPItem *>::const_iterator iter = all_list.begin(); iter != all_list.end(); iter++) {
1858 if(!SP_IS_GROUP(*iter)){1892 if (!SP_IS_GROUP(*iter)) {
1859 tmp.push_back(*iter);1893 tmp.push_back(*iter);
1860 }1894 }
1861 }1895 }
1862 all_list=tmp;1896 all_list = tmp;
18631897
1864 for (std::vector<SPItem*>::const_iterator sel_iter=items.begin();sel_iter!=items.end();sel_iter++) {1898 for (std::vector<SPItem *>::const_iterator sel_iter = items.begin(); sel_iter != items.end(); sel_iter++) {
1865 SPItem *sel = *sel_iter;1899 SPItem *sel = *sel_iter;
1866 std::vector<SPItem*> matches = all_list;1900 std::vector<SPItem *> matches = all_list;
1867 if (fill && stroke && style) {1901 if (fill && stroke && style) {
1868 matches = sp_get_same_style(sel, matches);1902 matches = sp_get_same_style(sel, matches);
1869 }1903 } else if (fill) {
1870 else if (fill) {
1871 matches = sp_get_same_style(sel, matches, SP_FILL_COLOR);1904 matches = sp_get_same_style(sel, matches, SP_FILL_COLOR);
1872 }1905 } else if (stroke) {
1873 else if (stroke) {
1874 matches = sp_get_same_style(sel, matches, SP_STROKE_COLOR);1906 matches = sp_get_same_style(sel, matches, SP_STROKE_COLOR);
1875 }1907 } else if (style) {
1876 else if (style) {1908 matches = sp_get_same_style(sel, matches, SP_STROKE_STYLE_ALL);
1877 matches = sp_get_same_style(sel, matches,SP_STROKE_STYLE_ALL);1909 }
1878 }1910 all_matches.insert(all_matches.end(), matches.begin(), matches.end());
1879 all_matches.insert(all_matches.end(), matches.begin(),matches.end());
1880 }1911 }
18811912
1882 selection->clear();1913 selection->clear();
1883 selection->setList(all_matches);1914 selection->setList(all_matches);
1884
1885}1915}
18861916
18871917
@@ -1902,14 +1932,15 @@
1902 bool onlyvisible = prefs->getBool("/options/kbselection/onlyvisible", true);1932 bool onlyvisible = prefs->getBool("/options/kbselection/onlyvisible", true);
1903 bool onlysensitive = prefs->getBool("/options/kbselection/onlysensitive", true);1933 bool onlysensitive = prefs->getBool("/options/kbselection/onlysensitive", true);
1904 bool ingroups = TRUE;1934 bool ingroups = TRUE;
1905 std::vector<SPItem*> x,y;1935 std::vector<SPItem *> x, y;
1906 std::vector<SPItem*> all_list = get_all_items(x, desktop->currentRoot(), desktop, onlyvisible, onlysensitive, ingroups, y);1936 std::vector<SPItem *> all_list =
1907 std::vector<SPItem*> matches = all_list;1937 get_all_items(x, desktop->currentRoot(), desktop, onlyvisible, onlysensitive, ingroups, y);
1938 std::vector<SPItem *> matches = all_list;
19081939
1909 Inkscape::Selection *selection = desktop->getSelection();1940 Inkscape::Selection *selection = desktop->getSelection();
19101941
1911 std::vector<SPItem*> items=selection->itemList();1942 std::vector<SPItem *> items = selection->itemList();
1912 for (std::vector<SPItem*>::const_iterator sel_iter=items.begin();sel_iter!=items.end();sel_iter++) {1943 for (std::vector<SPItem *>::const_iterator sel_iter = items.begin(); sel_iter != items.end(); sel_iter++) {
1913 SPItem *sel = *sel_iter;1944 SPItem *sel = *sel_iter;
1914 if (sel) {1945 if (sel) {
1915 matches = sp_get_same_object_type(sel, matches);1946 matches = sp_get_same_object_type(sel, matches);
@@ -1920,7 +1951,6 @@
19201951
1921 selection->clear();1952 selection->clear();
1922 selection->setList(matches);1953 selection->setList(matches);
1923
1924}1954}
19251955
19261956
@@ -1929,14 +1959,15 @@
1929 * Find all items in src list that have the same fill or stroke style as sel1959 * Find all items in src list that have the same fill or stroke style as sel
1930 * Return the list of matching items1960 * Return the list of matching items
1931 */1961 */
1932std::vector<SPItem*> sp_get_same_fill_or_stroke_color(SPItem *sel, std::vector<SPItem*> &src, SPSelectStrokeStyleType type)1962std::vector<SPItem *> sp_get_same_fill_or_stroke_color(SPItem *sel, std::vector<SPItem *> &src,
1963 SPSelectStrokeStyleType type)
1933{1964{
1934 std::vector<SPItem*> matches ;1965 std::vector<SPItem *> matches;
1935 gboolean match = false;1966 gboolean match = false;
19361967
1937 SPIPaint *sel_paint = (type == SP_FILL_COLOR) ? &(sel->style->fill) : &(sel->style->stroke);1968 SPIPaint *sel_paint = (type == SP_FILL_COLOR) ? &(sel->style->fill) : &(sel->style->stroke);
19381969
1939 for (std::vector<SPItem*>::const_reverse_iterator i=src.rbegin();i!=src.rend();i++) {1970 for (std::vector<SPItem *>::const_reverse_iterator i = src.rbegin(); i != src.rend(); i++) {
1940 SPItem *iter = *i;1971 SPItem *iter = *i;
1941 if (iter) {1972 if (iter) {
1942 SPIPaint *iter_paint = (type == SP_FILL_COLOR) ? &(iter->style->fill) : &(iter->style->stroke);1973 SPIPaint *iter_paint = (type == SP_FILL_COLOR) ? &(iter->style->fill) : &(iter->style->stroke);
@@ -1952,10 +1983,11 @@
1952 (type == SP_FILL_COLOR) ? iter->style->getFillPaintServer() : iter->style->getStrokePaintServer();1983 (type == SP_FILL_COLOR) ? iter->style->getFillPaintServer() : iter->style->getStrokePaintServer();
19531984
1954 if ((dynamic_cast<SPLinearGradient *>(sel_server) || dynamic_cast<SPRadialGradient *>(sel_server) ||1985 if ((dynamic_cast<SPLinearGradient *>(sel_server) || dynamic_cast<SPRadialGradient *>(sel_server) ||
1955 (dynamic_cast<SPGradient *>(sel_server) && dynamic_cast<SPGradient *>(sel_server)->getVector()->isSwatch()))1986 (dynamic_cast<SPGradient *>(sel_server) &&
1956 &&1987 dynamic_cast<SPGradient *>(sel_server)->getVector()->isSwatch())) &&
1957 (dynamic_cast<SPLinearGradient *>(iter_server) || dynamic_cast<SPRadialGradient *>(iter_server) ||1988 (dynamic_cast<SPLinearGradient *>(iter_server) || dynamic_cast<SPRadialGradient *>(iter_server) ||
1958 (dynamic_cast<SPGradient *>(iter_server) && dynamic_cast<SPGradient *>(iter_server)->getVector()->isSwatch()))) {1989 (dynamic_cast<SPGradient *>(iter_server) &&
1990 dynamic_cast<SPGradient *>(iter_server)->getVector()->isSwatch()))) {
1959 SPGradient *sel_vector = dynamic_cast<SPGradient *>(sel_server)->getVector();1991 SPGradient *sel_vector = dynamic_cast<SPGradient *>(sel_server)->getVector();
1960 SPGradient *iter_vector = dynamic_cast<SPGradient *>(iter_server)->getVector();1992 SPGradient *iter_vector = dynamic_cast<SPGradient *>(iter_server)->getVector();
1961 if (sel_vector == iter_vector) {1993 if (sel_vector == iter_vector) {
@@ -1986,16 +2018,16 @@
1986 return matches;2018 return matches;
1987}2019}
19882020
1989static bool item_type_match (SPItem *i, SPItem *j)2021static bool item_type_match(SPItem *i, SPItem *j)
1990{2022{
1991 if ( dynamic_cast<SPRect *>(i)) {2023 if (dynamic_cast<SPRect *>(i)) {
1992 return ( dynamic_cast<SPRect *>(j) );2024 return (dynamic_cast<SPRect *>(j));
19932025
1994 } else if (dynamic_cast<SPGenericEllipse *>(i)) {2026 } else if (dynamic_cast<SPGenericEllipse *>(i)) {
1995 return (dynamic_cast<SPGenericEllipse *>(j));2027 return (dynamic_cast<SPGenericEllipse *>(j));
19962028
1997 } else if (dynamic_cast<SPStar *>(i) || dynamic_cast<SPPolygon *>(i)) {2029 } else if (dynamic_cast<SPStar *>(i) || dynamic_cast<SPPolygon *>(i)) {
1998 return (dynamic_cast<SPStar *>(j) || dynamic_cast<SPPolygon *>(j)) ;2030 return (dynamic_cast<SPStar *>(j) || dynamic_cast<SPPolygon *>(j));
19992031
2000 } else if (dynamic_cast<SPSpiral *>(i)) {2032 } else if (dynamic_cast<SPSpiral *>(i)) {
2001 return (dynamic_cast<SPSpiral *>(j));2033 return (dynamic_cast<SPSpiral *>(j));
@@ -2003,21 +2035,22 @@
2003 } else if (dynamic_cast<SPPath *>(i) || dynamic_cast<SPLine *>(i) || dynamic_cast<SPPolyLine *>(i)) {2035 } else if (dynamic_cast<SPPath *>(i) || dynamic_cast<SPLine *>(i) || dynamic_cast<SPPolyLine *>(i)) {
2004 return (dynamic_cast<SPPath *>(j) || dynamic_cast<SPLine *>(j) || dynamic_cast<SPPolyLine *>(j));2036 return (dynamic_cast<SPPath *>(j) || dynamic_cast<SPLine *>(j) || dynamic_cast<SPPolyLine *>(j));
20052037
2006 } else if (dynamic_cast<SPText *>(i) || dynamic_cast<SPFlowtext *>(i) || dynamic_cast<SPTSpan *>(i) || dynamic_cast<SPTRef *>(i) || dynamic_cast<SPString *>(i)) {2038 } else if (dynamic_cast<SPText *>(i) || dynamic_cast<SPFlowtext *>(i) || dynamic_cast<SPTSpan *>(i) ||
2007 return (dynamic_cast<SPText *>(j) || dynamic_cast<SPFlowtext *>(j) || dynamic_cast<SPTSpan *>(j) || dynamic_cast<SPTRef *>(j) || dynamic_cast<SPString *>(j));2039 dynamic_cast<SPTRef *>(i) || dynamic_cast<SPString *>(i)) {
2040 return (dynamic_cast<SPText *>(j) || dynamic_cast<SPFlowtext *>(j) || dynamic_cast<SPTSpan *>(j) ||
2041 dynamic_cast<SPTRef *>(j) || dynamic_cast<SPString *>(j));
20082042
2009 } else if (dynamic_cast<SPUse *>(i)) {2043 } else if (dynamic_cast<SPUse *>(i)) {
2010 return (dynamic_cast<SPUse *>(j)) ;2044 return (dynamic_cast<SPUse *>(j));
20112045
2012 } else if (dynamic_cast<SPImage *>(i)) {2046 } else if (dynamic_cast<SPImage *>(i)) {
2013 return (dynamic_cast<SPImage *>(j));2047 return (dynamic_cast<SPImage *>(j));
20142048
2015 } else if (dynamic_cast<SPOffset *>(i) && dynamic_cast<SPOffset *>(i)->sourceHref) { // Linked offset2049 } else if (dynamic_cast<SPOffset *>(i) && dynamic_cast<SPOffset *>(i)->sourceHref) { // Linked offset
2016 return (dynamic_cast<SPOffset *>(j) && dynamic_cast<SPOffset *>(j)->sourceHref);2050 return (dynamic_cast<SPOffset *>(j) && dynamic_cast<SPOffset *>(j)->sourceHref);
20172051
2018 } else if (dynamic_cast<SPOffset *>(i) && !dynamic_cast<SPOffset *>(i)->sourceHref) { // Dynamic offset2052 } else if (dynamic_cast<SPOffset *>(i) && !dynamic_cast<SPOffset *>(i)->sourceHref) { // Dynamic offset
2019 return (dynamic_cast<SPOffset *>(j) && !dynamic_cast<SPOffset *>(j)->sourceHref);2053 return (dynamic_cast<SPOffset *>(j) && !dynamic_cast<SPOffset *>(j)->sourceHref);
2020
2021 }2054 }
20222055
2023 return false;2056 return false;
@@ -2027,11 +2060,11 @@
2027 * Find all items in src list that have the same object type as sel by type2060 * Find all items in src list that have the same object type as sel by type
2028 * Return the list of matching items2061 * Return the list of matching items
2029 */2062 */
2030std::vector<SPItem*> sp_get_same_object_type(SPItem *sel, std::vector<SPItem*> &src)2063std::vector<SPItem *> sp_get_same_object_type(SPItem *sel, std::vector<SPItem *> &src)
2031{2064{
2032 std::vector<SPItem*> matches;2065 std::vector<SPItem *> matches;
20332066
2034 for (std::vector<SPItem*>::const_reverse_iterator i=src.rbegin();i!=src.rend();i++) {2067 for (std::vector<SPItem *>::const_reverse_iterator i = src.rbegin(); i != src.rend(); i++) {
2035 SPItem *item = *i;2068 SPItem *item = *i;
2036 if (item && item_type_match(sel, item) && !item->cloned) {2069 if (item && item_type_match(sel, item) && !item->cloned) {
2037 matches.push_back(item);2070 matches.push_back(item);
@@ -2046,9 +2079,9 @@
2046 * Find all items in src list that have the same stroke style as sel by type2079 * Find all items in src list that have the same stroke style as sel by type
2047 * Return the list of matching items2080 * Return the list of matching items
2048 */2081 */
2049std::vector<SPItem*> sp_get_same_style(SPItem *sel, std::vector<SPItem*> &src, SPSelectStrokeStyleType type)2082std::vector<SPItem *> sp_get_same_style(SPItem *sel, std::vector<SPItem *> &src, SPSelectStrokeStyleType type)
2050{2083{
2051 std::vector<SPItem*> matches;2084 std::vector<SPItem *> matches;
2052 bool match = false;2085 bool match = false;
20532086
2054 SPStyle *sel_style = sel->style;2087 SPStyle *sel_style = sel->style;
@@ -2064,28 +2097,28 @@
2064 * Stroke width needs to handle transformations, so call this function2097 * Stroke width needs to handle transformations, so call this function
2065 * to get the transformed stroke width2098 * to get the transformed stroke width
2066 */2099 */
2067 std::vector<SPItem*> objects;2100 std::vector<SPItem *> objects;
2068 SPStyle *sel_style_for_width = NULL;2101 SPStyle *sel_style_for_width = NULL;
2069 if (type == SP_STROKE_STYLE_WIDTH || type == SP_STROKE_STYLE_ALL || type==SP_STYLE_ALL ) {2102 if (type == SP_STROKE_STYLE_WIDTH || type == SP_STROKE_STYLE_ALL || type == SP_STYLE_ALL) {
2070 objects.push_back(sel);2103 objects.push_back(sel);
2071 sel_style_for_width = new SPStyle(SP_ACTIVE_DOCUMENT);2104 sel_style_for_width = new SPStyle(SP_ACTIVE_DOCUMENT);
2072 objects_query_strokewidth (objects, sel_style_for_width);2105 objects_query_strokewidth(objects, sel_style_for_width);
2073 }2106 }
2074 bool match_g;2107 bool match_g;
2075 for (std::vector<SPItem*>::const_iterator i=src.begin();i!=src.end();i++) {2108 for (std::vector<SPItem *>::const_iterator i = src.begin(); i != src.end(); i++) {
2076 SPItem *iter = *i;2109 SPItem *iter = *i;
2077 if (iter) {2110 if (iter) {
2078 match_g=true;2111 match_g = true;
2079 SPStyle *iter_style = iter->style;2112 SPStyle *iter_style = iter->style;
2080 match = true;2113 match = true;
20812114
2082 if (type == SP_STROKE_STYLE_WIDTH|| type == SP_STROKE_STYLE_ALL|| type==SP_STYLE_ALL) {2115 if (type == SP_STROKE_STYLE_WIDTH || type == SP_STROKE_STYLE_ALL || type == SP_STYLE_ALL) {
2083 match = (sel_style->stroke_width.set == iter_style->stroke_width.set);2116 match = (sel_style->stroke_width.set == iter_style->stroke_width.set);
2084 if (sel_style->stroke_width.set && iter_style->stroke_width.set) {2117 if (sel_style->stroke_width.set && iter_style->stroke_width.set) {
2085 std::vector<SPItem*> objects;2118 std::vector<SPItem *> objects;
2086 objects.insert(objects.begin(),iter);2119 objects.insert(objects.begin(), iter);
2087 SPStyle tmp_style(SP_ACTIVE_DOCUMENT);2120 SPStyle tmp_style(SP_ACTIVE_DOCUMENT);
2088 objects_query_strokewidth (objects, &tmp_style);2121 objects_query_strokewidth(objects, &tmp_style);
20892122
2090 if (sel_style_for_width) {2123 if (sel_style_for_width) {
2091 match = (sel_style_for_width->stroke_width.computed == tmp_style.stroke_width.computed);2124 match = (sel_style_for_width->stroke_width.computed == tmp_style.stroke_width.computed);
@@ -2093,16 +2126,16 @@
2093 }2126 }
2094 }2127 }
2095 match_g = match_g && match;2128 match_g = match_g && match;
2096 if (type == SP_STROKE_STYLE_DASHES|| type == SP_STROKE_STYLE_ALL || type==SP_STYLE_ALL) {2129 if (type == SP_STROKE_STYLE_DASHES || type == SP_STROKE_STYLE_ALL || type == SP_STYLE_ALL) {
2097 match = (sel_style->stroke_dasharray.set == iter_style->stroke_dasharray.set);2130 match = (sel_style->stroke_dasharray.set == iter_style->stroke_dasharray.set);
2098 if (sel_style->stroke_dasharray.set && iter_style->stroke_dasharray.set) {2131 if (sel_style->stroke_dasharray.set && iter_style->stroke_dasharray.set) {
2099 match = (sel_style->stroke_dasharray.values == iter_style->stroke_dasharray.values);2132 match = (sel_style->stroke_dasharray.values == iter_style->stroke_dasharray.values);
2100 }2133 }
2101 }2134 }
2102 match_g = match_g && match;2135 match_g = match_g && match;
2103 if (type == SP_STROKE_STYLE_MARKERS|| type == SP_STROKE_STYLE_ALL|| type==SP_STYLE_ALL) {2136 if (type == SP_STROKE_STYLE_MARKERS || type == SP_STROKE_STYLE_ALL || type == SP_STYLE_ALL) {
2104 match = true;2137 match = true;
2105 int len = sizeof(sel_style->marker)/sizeof(SPIString);2138 int len = sizeof(sel_style->marker) / sizeof(SPIString);
2106 for (int i = 0; i < len; i++) {2139 for (int i = 0; i < len; i++) {
2107 match = (sel_style->marker_ptrs[i]->set == iter_style->marker_ptrs[i]->set);2140 match = (sel_style->marker_ptrs[i]->set == iter_style->marker_ptrs[i]->set);
2108 if (sel_style->marker_ptrs[i]->set && iter_style->marker_ptrs[i]->set &&2141 if (sel_style->marker_ptrs[i]->set && iter_style->marker_ptrs[i]->set &&
@@ -2112,24 +2145,25 @@
2112 }2145 }
2113 }2146 }
2114 }2147 }
2115 match_g = match_g && match;2148 match_g = match_g && match;
2116 if (match_g) {2149 if (match_g) {
2117 while (iter->cloned) iter=dynamic_cast<SPItem *>(iter->parent);2150 while (iter->cloned)
2118 matches.insert(matches.begin(),iter);2151 iter = dynamic_cast<SPItem *>(iter->parent);
2152 matches.insert(matches.begin(), iter);
2119 }2153 }
2120 } else {2154 } else {
2121 g_assert_not_reached();2155 g_assert_not_reached();
2122 }2156 }
2123 }2157 }
21242158
2125 if( sel_style_for_width != NULL ) delete sel_style_for_width;2159 if (sel_style_for_width != NULL)
2160 delete sel_style_for_width;
2126 return matches;2161 return matches;
2127}2162}
21282163
2129// helper function:2164// helper function:
2130static2165static Geom::Point cornerFarthestFrom(Geom::Rect const &r, Geom::Point const &p)
2131Geom::Point2166{
2132cornerFarthestFrom(Geom::Rect const &r, Geom::Point const &p){
2133 Geom::Point m = r.midpoint();2167 Geom::Point m = r.midpoint();
2134 unsigned i = 0;2168 unsigned i = 0;
2135 if (p[X] < m[X]) {2169 if (p[X] < m[X]) {
@@ -2142,10 +2176,10 @@
2142}2176}
21432177
2144/**2178/**
2145\param angle the angle in "angular pixels", i.e. how many visible pixels must move the outermost point of the rotated object2179\param angle the angle in "angular pixels", i.e. how many visible pixels must move the outermost point of the rotated
2180object
2146*/2181*/
2147void2182void sp_selection_rotate_screen(Inkscape::Selection *selection, gdouble angle)
2148sp_selection_rotate_screen(Inkscape::Selection *selection, gdouble angle)
2149{2183{
2150 if (selection->isEmpty())2184 if (selection->isEmpty())
2151 return;2185 return;
@@ -2153,7 +2187,7 @@
2153 Geom::OptRect bbox = selection->visualBounds();2187 Geom::OptRect bbox = selection->visualBounds();
2154 boost::optional<Geom::Point> center = selection->center();2188 boost::optional<Geom::Point> center = selection->center();
21552189
2156 if ( !bbox || !center ) {2190 if (!bbox || !center) {
2157 return;2191 return;
2158 }2192 }
21592193
@@ -2166,15 +2200,11 @@
2166 sp_selection_rotate_relative(selection, *center, zangle);2200 sp_selection_rotate_relative(selection, *center, zangle);
21672201
2168 DocumentUndo::maybeDone(selection->desktop()->getDocument(),2202 DocumentUndo::maybeDone(selection->desktop()->getDocument(),
2169 ( (angle > 0)2203 ((angle > 0) ? "selector:rotate:ccw" : "selector:rotate:cw"), SP_VERB_CONTEXT_SELECT,
2170 ? "selector:rotate:ccw"
2171 : "selector:rotate:cw" ),
2172 SP_VERB_CONTEXT_SELECT,
2173 _("Rotate by pixels"));2204 _("Rotate by pixels"));
2174}2205}
21752206
2176void2207void sp_selection_scale(Inkscape::Selection *selection, gdouble grow)
2177sp_selection_scale(Inkscape::Selection *selection, gdouble grow)
2178{2208{
2179 if (selection->isEmpty())2209 if (selection->isEmpty())
2180 return;2210 return;
@@ -2188,7 +2218,7 @@
21882218
2189 // you can't scale "do nizhe pola" (below zero)2219 // you can't scale "do nizhe pola" (below zero)
2190 double const max_len = bbox->maxExtent();2220 double const max_len = bbox->maxExtent();
2191 if ( max_len + grow <= 1e-3 ) {2221 if (max_len + grow <= 1e-3) {
2192 return;2222 return;
2193 }2223 }
21942224
@@ -2196,22 +2226,16 @@
2196 sp_selection_scale_relative(selection, center, Geom::Scale(times, times));2226 sp_selection_scale_relative(selection, center, Geom::Scale(times, times));
21972227
2198 DocumentUndo::maybeDone(selection->desktop()->getDocument(),2228 DocumentUndo::maybeDone(selection->desktop()->getDocument(),
2199 ( (grow > 0)2229 ((grow > 0) ? "selector:scale:larger" : "selector:scale:smaller"), SP_VERB_CONTEXT_SELECT,
2200 ? "selector:scale:larger"
2201 : "selector:scale:smaller" ),
2202 SP_VERB_CONTEXT_SELECT,
2203 _("Scale"));2230 _("Scale"));
2204}2231}
22052232
2206void2233void sp_selection_scale_screen(Inkscape::Selection *selection, gdouble grow_pixels)
2207sp_selection_scale_screen(Inkscape::Selection *selection, gdouble grow_pixels)
2208{2234{
2209 sp_selection_scale(selection,2235 sp_selection_scale(selection, grow_pixels / selection->desktop()->current_zoom());
2210 grow_pixels / selection->desktop()->current_zoom());
2211}2236}
22122237
2213void2238void sp_selection_scale_times(Inkscape::Selection *selection, gdouble times)
2214sp_selection_scale_times(Inkscape::Selection *selection, gdouble times)
2215{2239{
2216 if (selection->isEmpty())2240 if (selection->isEmpty())
2217 return;2241 return;
@@ -2224,12 +2248,10 @@
22242248
2225 Geom::Point const center(sel_bbox->midpoint());2249 Geom::Point const center(sel_bbox->midpoint());
2226 sp_selection_scale_relative(selection, center, Geom::Scale(times, times));2250 sp_selection_scale_relative(selection, center, Geom::Scale(times, times));
2227 DocumentUndo::done(selection->desktop()->getDocument(), SP_VERB_CONTEXT_SELECT,2251 DocumentUndo::done(selection->desktop()->getDocument(), SP_VERB_CONTEXT_SELECT, _("Scale by whole factor"));
2228 _("Scale by whole factor"));
2229}2252}
22302253
2231void2254void sp_selection_move(Inkscape::Selection *selection, gdouble dx, gdouble dy)
2232sp_selection_move(Inkscape::Selection *selection, gdouble dx, gdouble dy)
2233{2255{
2234 if (selection->isEmpty()) {2256 if (selection->isEmpty()) {
2235 return;2257 return;
@@ -2239,19 +2261,15 @@
22392261
2240 SPDocument *doc = selection->layers()->getDocument();2262 SPDocument *doc = selection->layers()->getDocument();
2241 if (dx == 0) {2263 if (dx == 0) {
2242 DocumentUndo::maybeDone(doc, "selector:move:vertical", SP_VERB_CONTEXT_SELECT,2264 DocumentUndo::maybeDone(doc, "selector:move:vertical", SP_VERB_CONTEXT_SELECT, _("Move vertically"));
2243 _("Move vertically"));
2244 } else if (dy == 0) {2265 } else if (dy == 0) {
2245 DocumentUndo::maybeDone(doc, "selector:move:horizontal", SP_VERB_CONTEXT_SELECT,2266 DocumentUndo::maybeDone(doc, "selector:move:horizontal", SP_VERB_CONTEXT_SELECT, _("Move horizontally"));
2246 _("Move horizontally"));
2247 } else {2267 } else {
2248 DocumentUndo::done(doc, SP_VERB_CONTEXT_SELECT,2268 DocumentUndo::done(doc, SP_VERB_CONTEXT_SELECT, _("Move"));
2249 _("Move"));
2250 }2269 }
2251}2270}
22522271
2253void2272void sp_selection_move_screen(Inkscape::Selection *selection, gdouble dx, gdouble dy)
2254sp_selection_move_screen(Inkscape::Selection *selection, gdouble dx, gdouble dy)
2255{2273{
2256 if (selection->isEmpty() || !selection->desktop()) {2274 if (selection->isEmpty() || !selection->desktop()) {
2257 return;2275 return;
@@ -2265,14 +2283,12 @@
22652283
2266 SPDocument *doc = selection->layers()->getDocument();2284 SPDocument *doc = selection->layers()->getDocument();
2267 if (dx == 0) {2285 if (dx == 0) {
2268 DocumentUndo::maybeDone(doc, "selector:move:vertical", SP_VERB_CONTEXT_SELECT,2286 DocumentUndo::maybeDone(doc, "selector:move:vertical", SP_VERB_CONTEXT_SELECT, _("Move vertically by pixels"));
2269 _("Move vertically by pixels"));
2270 } else if (dy == 0) {2287 } else if (dy == 0) {
2271 DocumentUndo::maybeDone(doc, "selector:move:horizontal", SP_VERB_CONTEXT_SELECT,2288 DocumentUndo::maybeDone(doc, "selector:move:horizontal", SP_VERB_CONTEXT_SELECT,
2272 _("Move horizontally by pixels"));2289 _("Move horizontally by pixels"));
2273 } else {2290 } else {
2274 DocumentUndo::done(doc, SP_VERB_CONTEXT_SELECT,2291 DocumentUndo::done(doc, SP_VERB_CONTEXT_SELECT, _("Move"));
2275 _("Move"));
2276 }2292 }
2277}2293}
22782294
@@ -2292,25 +2308,18 @@
2292typedef struct ListReverse {2308typedef struct ListReverse {
2293 typedef GSList *Iterator;2309 typedef GSList *Iterator;
22942310
2295 static Iterator children(SPObject *o) {2311 static Iterator children(SPObject *o) { return make_list(o->firstChild(), NULL); }
2296 return make_list(o->firstChild(), NULL);2312 static Iterator siblings_after(SPObject *o) { return make_list(o->parent->firstChild(), o); }
2297 }2313 static void dispose(Iterator i) { g_slist_free(i); }
2298 static Iterator siblings_after(SPObject *o) {
2299 return make_list(o->parent->firstChild(), o);
2300 }
2301 static void dispose(Iterator i) {
2302 g_slist_free(i);
2303 }
23042314
2305 static SPObject *object(Iterator i) {2315 static SPObject *object(Iterator i) { return reinterpret_cast<SPObject *>(i->data); }
2306 return reinterpret_cast<SPObject *>(i->data);
2307 }
2308 static Iterator next(Iterator i) { return i->next; }2316 static Iterator next(Iterator i) { return i->next; }
23092317
2310private:2318 private:
2311 static GSList *make_list(SPObject *object, SPObject *limit) {2319 static GSList *make_list(SPObject *object, SPObject *limit)
2320 {
2312 GSList *list = NULL;2321 GSList *list = NULL;
2313 while ( object != limit ) {2322 while (object != limit) {
2314 if (!object) { // TODO check if this happens in practice2323 if (!object) { // TODO check if this happens in practice
2315 g_warning("Unexpected list overrun");2324 g_warning("Unexpected list overrun");
2316 break;2325 break;
@@ -2325,16 +2334,16 @@
23252334
23262335
2327template <typename D>2336template <typename D>
2328SPItem *next_item(SPDesktop *desktop, GSList *path, SPObject *root,2337SPItem *next_item(SPDesktop *desktop, GSList *path, SPObject *root, bool only_in_viewport,
2329 bool only_in_viewport, PrefsSelectionContext inlayer, bool onlyvisible, bool onlysensitive)2338 PrefsSelectionContext inlayer, bool onlyvisible, bool onlysensitive)
2330{2339{
2331 typename D::Iterator children;2340 typename D::Iterator children;
2332 typename D::Iterator iter;2341 typename D::Iterator iter;
23332342
2334 SPItem *found=NULL;2343 SPItem *found = NULL;
23352344
2336 if (path) {2345 if (path) {
2337 SPObject *object=reinterpret_cast<SPObject *>(path->data);2346 SPObject *object = reinterpret_cast<SPObject *>(path->data);
2338 g_assert(object->parent == root);2347 g_assert(object->parent == root);
2339 if (desktop->isLayer(object)) {2348 if (desktop->isLayer(object)) {
2340 found = next_item<D>(desktop, path->next, object, only_in_viewport, inlayer, onlyvisible, onlysensitive);2349 found = next_item<D>(desktop, path->next, object, only_in_viewport, inlayer, onlyvisible, onlysensitive);
@@ -2344,20 +2353,17 @@
2344 iter = children = D::children(root);2353 iter = children = D::children(root);
2345 }2354 }
23462355
2347 while ( iter && !found ) {2356 while (iter && !found) {
2348 SPObject *object=D::object(iter);2357 SPObject *object = D::object(iter);
2349 if (desktop->isLayer(object)) {2358 if (desktop->isLayer(object)) {
2350 if (PREFS_SELECTION_LAYER != inlayer) { // recurse into sublayers2359 if (PREFS_SELECTION_LAYER != inlayer) { // recurse into sublayers
2351 found = next_item<D>(desktop, NULL, object, only_in_viewport, inlayer, onlyvisible, onlysensitive);2360 found = next_item<D>(desktop, NULL, object, only_in_viewport, inlayer, onlyvisible, onlysensitive);
2352 }2361 }
2353 } else {2362 } else {
2354 SPItem *item = dynamic_cast<SPItem *>(object);2363 SPItem *item = dynamic_cast<SPItem *>(object);
2355 if ( item &&2364 if (item && (!only_in_viewport || desktop->isWithinViewport(item)) &&
2356 ( !only_in_viewport || desktop->isWithinViewport(item) ) &&2365 (!onlyvisible || !desktop->itemIsHidden(item)) && (!onlysensitive || !item->isLocked()) &&
2357 ( !onlyvisible || !desktop->itemIsHidden(item)) &&2366 !desktop->isLayer(item)) {
2358 ( !onlysensitive || !item->isLocked()) &&
2359 !desktop->isLayer(item) )
2360 {
2361 found = item;2367 found = item;
2362 }2368 }
2363 }2369 }
@@ -2371,22 +2377,20 @@
23712377
23722378
2373template <typename D>2379template <typename D>
2374SPItem *next_item_from_list(SPDesktop *desktop, std::vector<SPItem*> const items,2380SPItem *next_item_from_list(SPDesktop *desktop, std::vector<SPItem *> const items, SPObject *root,
2375 SPObject *root, bool only_in_viewport, PrefsSelectionContext inlayer, bool onlyvisible, bool onlysensitive)2381 bool only_in_viewport, PrefsSelectionContext inlayer, bool onlyvisible, bool onlysensitive)
2376{2382{
2377 SPObject *current=root;2383 SPObject *current = root;
2378 for(std::vector<SPItem*>::const_iterator i = items.begin();i!=items.end();i++) {2384 for (std::vector<SPItem *>::const_iterator i = items.begin(); i != items.end(); i++) {
2379 SPItem *item = *i;2385 SPItem *item = *i;
2380 if ( root->isAncestorOf(item) &&2386 if (root->isAncestorOf(item) && (!only_in_viewport || desktop->isWithinViewport(item))) {
2381 ( !only_in_viewport || desktop->isWithinViewport(item) ) )
2382 {
2383 current = item;2387 current = item;
2384 break;2388 break;
2385 }2389 }
2386 }2390 }
23872391
2388 GSList *path=NULL;2392 GSList *path = NULL;
2389 while ( current != root ) {2393 while (current != root) {
2390 path = g_slist_prepend(path, current);2394 path = g_slist_prepend(path, current);
2391 current = current->parent;2395 current = current->parent;
2392 }2396 }
@@ -2403,14 +2407,14 @@
2403 return next;2407 return next;
2404}2408}
24052409
2406void2410void sp_selection_item_next(SPDesktop *desktop)
2407sp_selection_item_next(SPDesktop *desktop)
2408{2411{
2409 g_return_if_fail(desktop != NULL);2412 g_return_if_fail(desktop != NULL);
2410 Inkscape::Selection *selection = desktop->getSelection();2413 Inkscape::Selection *selection = desktop->getSelection();
24112414
2412 Inkscape::Preferences *prefs = Inkscape::Preferences::get();2415 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
2413 PrefsSelectionContext inlayer = (PrefsSelectionContext)prefs->getInt("/options/kbselection/inlayer", PREFS_SELECTION_LAYER);2416 PrefsSelectionContext inlayer =
2417 (PrefsSelectionContext)prefs->getInt("/options/kbselection/inlayer", PREFS_SELECTION_LAYER);
2414 bool onlyvisible = prefs->getBool("/options/kbselection/onlyvisible", true);2418 bool onlyvisible = prefs->getBool("/options/kbselection/onlyvisible", true);
2415 bool onlysensitive = prefs->getBool("/options/kbselection/onlysensitive", true);2419 bool onlysensitive = prefs->getBool("/options/kbselection/onlysensitive", true);
24162420
@@ -2421,18 +2425,18 @@
2421 root = desktop->currentRoot();2425 root = desktop->currentRoot();
2422 }2426 }
24232427
2424 SPItem *item=next_item_from_list<Forward>(desktop, selection->itemList(), root, SP_CYCLING == SP_CYCLE_VISIBLE, inlayer, onlyvisible, onlysensitive);2428 SPItem *item = next_item_from_list<Forward>(desktop, selection->itemList(), root, SP_CYCLING == SP_CYCLE_VISIBLE,
2429 inlayer, onlyvisible, onlysensitive);
24252430
2426 if (item) {2431 if (item) {
2427 selection->set(item, PREFS_SELECTION_LAYER_RECURSIVE == inlayer);2432 selection->set(item, PREFS_SELECTION_LAYER_RECURSIVE == inlayer);
2428 if ( SP_CYCLING == SP_CYCLE_FOCUS ) {2433 if (SP_CYCLING == SP_CYCLE_FOCUS) {
2429 scroll_to_show_item(desktop, item);2434 scroll_to_show_item(desktop, item);
2430 }2435 }
2431 }2436 }
2432}2437}
24332438
2434void2439void sp_selection_item_prev(SPDesktop *desktop)
2435sp_selection_item_prev(SPDesktop *desktop)
2436{2440{
2437 SPDocument *document = desktop->getDocument();2441 SPDocument *document = desktop->getDocument();
2438 g_return_if_fail(document != NULL);2442 g_return_if_fail(document != NULL);
@@ -2440,7 +2444,8 @@
2440 Inkscape::Selection *selection = desktop->getSelection();2444 Inkscape::Selection *selection = desktop->getSelection();
24412445
2442 Inkscape::Preferences *prefs = Inkscape::Preferences::get();2446 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
2443 PrefsSelectionContext inlayer = (PrefsSelectionContext) prefs->getInt("/options/kbselection/inlayer", PREFS_SELECTION_LAYER);2447 PrefsSelectionContext inlayer =
2448 (PrefsSelectionContext)prefs->getInt("/options/kbselection/inlayer", PREFS_SELECTION_LAYER);
2444 bool onlyvisible = prefs->getBool("/options/kbselection/onlyvisible", true);2449 bool onlyvisible = prefs->getBool("/options/kbselection/onlyvisible", true);
2445 bool onlysensitive = prefs->getBool("/options/kbselection/onlysensitive", true);2450 bool onlysensitive = prefs->getBool("/options/kbselection/onlysensitive", true);
24462451
@@ -2451,24 +2456,26 @@
2451 root = desktop->currentRoot();2456 root = desktop->currentRoot();
2452 }2457 }
24532458
2454 SPItem *item=next_item_from_list<ListReverse>(desktop, selection->itemList(), root, SP_CYCLING == SP_CYCLE_VISIBLE, inlayer, onlyvisible, onlysensitive);2459 SPItem *item = next_item_from_list<ListReverse>(
2460 desktop, selection->itemList(), root, SP_CYCLING == SP_CYCLE_VISIBLE, inlayer, onlyvisible, onlysensitive);
24552461
2456 if (item) {2462 if (item) {
2457 selection->set(item, PREFS_SELECTION_LAYER_RECURSIVE == inlayer);2463 selection->set(item, PREFS_SELECTION_LAYER_RECURSIVE == inlayer);
2458 if ( SP_CYCLING == SP_CYCLE_FOCUS ) {2464 if (SP_CYCLING == SP_CYCLE_FOCUS) {
2459 scroll_to_show_item(desktop, item);2465 scroll_to_show_item(desktop, item);
2460 }2466 }
2461 }2467 }
2462}2468}
24632469
2464void sp_selection_next_patheffect_param(SPDesktop * dt)2470void sp_selection_next_patheffect_param(SPDesktop *dt)
2465{2471{
2466 if (!dt) return;2472 if (!dt)
2473 return;
24672474
2468 Inkscape::Selection *selection = dt->getSelection();2475 Inkscape::Selection *selection = dt->getSelection();
2469 if ( selection && !selection->isEmpty() ) {2476 if (selection && !selection->isEmpty()) {
2470 SPItem *item = selection->singleItem();2477 SPItem *item = selection->singleItem();
2471 if ( SPLPEItem *lpeitem = dynamic_cast<SPLPEItem*>(item) ) {2478 if (SPLPEItem *lpeitem = dynamic_cast<SPLPEItem *>(item)) {
2472 if (lpeitem->hasPathEffect()) {2479 if (lpeitem->hasPathEffect()) {
2473 lpeitem->editNextParamOncanvas(dt);2480 lpeitem->editNextParamOncanvas(dt);
2474 } else {2481 } else {
@@ -2528,8 +2535,6 @@
25282535
25292536
25302537
2531
2532
2533/**2538/**
2534 * If \a item is not entirely visible then adjust visible area to centre on the centre on of2539 * If \a item is not entirely visible then adjust visible area to centre on the centre on of
2535 * \a item.2540 * \a item.
@@ -2539,14 +2544,14 @@
2539 Geom::Rect dbox = desktop->get_display_area();2544 Geom::Rect dbox = desktop->get_display_area();
2540 Geom::OptRect sbox = item->desktopVisualBounds();2545 Geom::OptRect sbox = item->desktopVisualBounds();
25412546
2542 if ( sbox && dbox.contains(*sbox) == false ) {2547 if (sbox && dbox.contains(*sbox) == false) {
2543 Geom::Point const s_dt = sbox->midpoint();2548 Geom::Point const s_dt = sbox->midpoint();
2544 Geom::Point const s_w = desktop->d2w(s_dt);2549 Geom::Point const s_w = desktop->d2w(s_dt);
2545 Geom::Point const d_dt = dbox.midpoint();2550 Geom::Point const d_dt = dbox.midpoint();
2546 Geom::Point const d_w = desktop->d2w(d_dt);2551 Geom::Point const d_w = desktop->d2w(d_dt);
2547 Geom::Point const moved_w( d_w - s_w );2552 Geom::Point const moved_w(d_w - s_w);
2548 gint const dx = (gint) moved_w[X];2553 gint const dx = (gint)moved_w[X];
2549 gint const dy = (gint) moved_w[Y];2554 gint const dy = (gint)moved_w[Y];
2550 desktop->scroll_world(dx, dy);2555 desktop->scroll_world(dx, dy);
2551 }2556 }
2552}2557}
@@ -2568,17 +2573,17 @@
2568 return;2573 return;
2569 }2574 }
25702575
2571 std::vector<Inkscape::XML::Node*> reprs (selection->reprList());2576 std::vector<Inkscape::XML::Node *> reprs(selection->reprList());
25722577
2573 selection->clear();2578 selection->clear();
25742579
2575 // sorting items from different parents sorts each parent's subset without possibly mixing them, just what we need2580 // sorting items from different parents sorts each parent's subset without possibly mixing them, just what we need
2576 sort(reprs.begin(),reprs.end(),sp_repr_compare_position_bool);2581 sort(reprs.begin(), reprs.end(), sp_repr_compare_position_bool);
25772582
2578 std::vector<Inkscape::XML::Node*> newsel;2583 std::vector<Inkscape::XML::Node *> newsel;
25792584
2580 for(std::vector<Inkscape::XML::Node*>::const_iterator i=reprs.begin();i!=reprs.end();i++){2585 for (std::vector<Inkscape::XML::Node *>::const_iterator i = reprs.begin(); i != reprs.end(); i++) {
2581 Inkscape::XML::Node *sel_repr = *i;2586 Inkscape::XML::Node *sel_repr = *i;
2582 Inkscape::XML::Node *parent = sel_repr->parent();2587 Inkscape::XML::Node *parent = sel_repr->parent();
25832588
2584 Inkscape::XML::Node *clone = xml_doc->createElement("svg:use");2589 Inkscape::XML::Node *clone = xml_doc->createElement("svg:use");
@@ -2598,14 +2603,12 @@
2598 Inkscape::GC::release(clone);2603 Inkscape::GC::release(clone);
2599 }2604 }
26002605
2601 DocumentUndo::done(desktop->getDocument(), SP_VERB_EDIT_CLONE,2606 DocumentUndo::done(desktop->getDocument(), SP_VERB_EDIT_CLONE, C_("Action", "Clone"));
2602 C_("Action", "Clone"));
26032607
2604 selection->setReprList(newsel);2608 selection->setReprList(newsel);
2605}2609}
26062610
2607void2611void sp_selection_relink(SPDesktop *desktop)
2608sp_selection_relink(SPDesktop *desktop)
2609{2612{
2610 if (!desktop)2613 if (!desktop)
2611 return;2614 return;
@@ -2620,15 +2623,16 @@
2620 Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get();2623 Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get();
2621 const gchar *newid = cm->getFirstObjectID();2624 const gchar *newid = cm->getFirstObjectID();
2622 if (!newid) {2625 if (!newid) {
2623 desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Copy an <b>object</b> to clipboard to relink clones to."));2626 desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE,
2627 _("Copy an <b>object</b> to clipboard to relink clones to."));
2624 return;2628 return;
2625 }2629 }
2626 gchar *newref = g_strdup_printf("#%s", newid);2630 gchar *newref = g_strdup_printf("#%s", newid);
26272631
2628 // Get a copy of current selection.2632 // Get a copy of current selection.
2629 bool relinked = false;2633 bool relinked = false;
2630 std::vector<SPItem*> items=selection->itemList();2634 std::vector<SPItem *> items = selection->itemList();
2631 for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){2635 for (std::vector<SPItem *>::const_iterator i = items.begin(); i != items.end(); i++) {
2632 SPItem *item = *i;2636 SPItem *item = *i;
26332637
2634 if (dynamic_cast<SPUse *>(item)) {2638 if (dynamic_cast<SPUse *>(item)) {
@@ -2643,14 +2647,12 @@
2643 if (!relinked) {2647 if (!relinked) {
2644 desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("<b>No clones to relink</b> in the selection."));2648 desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("<b>No clones to relink</b> in the selection."));
2645 } else {2649 } else {
2646 DocumentUndo::done(desktop->getDocument(), SP_VERB_EDIT_UNLINK_CLONE,2650 DocumentUndo::done(desktop->getDocument(), SP_VERB_EDIT_UNLINK_CLONE, _("Relink clone"));
2647 _("Relink clone"));
2648 }2651 }
2649}2652}
26502653
26512654
2652void2655void sp_selection_unlink(SPDesktop *desktop)
2653sp_selection_unlink(SPDesktop *desktop)
2654{2656{
2655 if (!desktop)2657 if (!desktop)
2656 return;2658 return;
@@ -2663,10 +2665,10 @@
2663 }2665 }
26642666
2665 // Get a copy of current selection.2667 // Get a copy of current selection.
2666 std::vector<SPItem*> new_select;2668 std::vector<SPItem *> new_select;
2667 bool unlinked = false;2669 bool unlinked = false;
2668 std::vector<SPItem*> items=selection->itemList();2670 std::vector<SPItem *> items = selection->itemList();
2669 for (std::vector<SPItem*>::const_reverse_iterator i=items.rbegin();i!=items.rend();i++){2671 for (std::vector<SPItem *>::const_reverse_iterator i = items.rbegin(); i != items.rend(); i++) {
2670 SPItem *item = *i;2672 SPItem *item = *i;
26712673
2672 if (dynamic_cast<SPText *>(item)) {2674 if (dynamic_cast<SPText *>(item)) {
@@ -2714,12 +2716,10 @@
2714 desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("<b>No clones to unlink</b> in the selection."));2716 desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("<b>No clones to unlink</b> in the selection."));
2715 }2717 }
27162718
2717 DocumentUndo::done(desktop->getDocument(), SP_VERB_EDIT_UNLINK_CLONE,2719 DocumentUndo::done(desktop->getDocument(), SP_VERB_EDIT_UNLINK_CLONE, _("Unlink clone"));
2718 _("Unlink clone"));
2719}2720}
27202721
2721void2722void sp_select_clone_original(SPDesktop *desktop)
2722sp_select_clone_original(SPDesktop *desktop)
2723{2723{
2724 if (desktop == NULL)2724 if (desktop == NULL)
2725 return;2725 return;
@@ -2728,11 +2728,13 @@
27282728
2729 SPItem *item = selection->singleItem();2729 SPItem *item = selection->singleItem();
27302730
2731 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.");2731 gchar const *error =
2732 _("Select a <b>clone</b> to go to its original. Select a <b>linked offset</b> to go to its source. Select a "
2733 "<b>text on path</b> to go to the path. Select a <b>flowed text</b> to go to its frame.");
27322734
2733 // Check if other than two objects are selected2735 // Check if other than two objects are selected
27342736
2735 std::vector<SPItem*> items=selection->itemList();2737 std::vector<SPItem *> items = selection->itemList();
2736 if (items.size() != 1 || !item) {2738 if (items.size() != 1 || !item) {
2737 desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, error);2739 desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, error);
2738 return;2740 return;
@@ -2759,10 +2761,12 @@
2759 SPLPEItem *lpeItem = dynamic_cast<SPLPEItem *>(item);2761 SPLPEItem *lpeItem = dynamic_cast<SPLPEItem *>(item);
2760 if (lpeItem) {2762 if (lpeItem) {
2761 // check if the applied LPE is Clone original, if so, go to the refered path2763 // check if the applied LPE is Clone original, if so, go to the refered path
2762 Inkscape::LivePathEffect::Effect* lpe = lpeItem->getPathEffectOfType(Inkscape::LivePathEffect::CLONE_ORIGINAL);2764 Inkscape::LivePathEffect::Effect *lpe =
2765 lpeItem->getPathEffectOfType(Inkscape::LivePathEffect::CLONE_ORIGINAL);
2763 if (lpe) {2766 if (lpe) {
2764 Inkscape::LivePathEffect::Parameter *lpeparam = lpe->getParameter("linkedpath");2767 Inkscape::LivePathEffect::Parameter *lpeparam = lpe->getParameter("linkedpath");
2765 if (Inkscape::LivePathEffect::OriginalPathParam *pathparam = dynamic_cast<Inkscape::LivePathEffect::OriginalPathParam *>(lpeparam)) {2768 if (Inkscape::LivePathEffect::OriginalPathParam *pathparam =
2769 dynamic_cast<Inkscape::LivePathEffect::OriginalPathParam *>(lpeparam)) {
2766 original = pathparam->getObject();2770 original = pathparam->getObject();
2767 }2771 }
2768 }2772 }
@@ -2778,13 +2782,17 @@
2778 }2782 }
27792783
2780 if (!original) {2784 if (!original) {
2781 desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("<b>Cannot find</b> the object to select (orphaned clone, offset, textpath, flowed text?)"));2785 desktop->messageStack()->flash(
2786 Inkscape::ERROR_MESSAGE,
2787 _("<b>Cannot find</b> the object to select (orphaned clone, offset, textpath, flowed text?)"));
2782 return;2788 return;
2783 }2789 }
27842790
2785 for (SPObject *o = original; o && !dynamic_cast<SPRoot *>(o); o = o->parent) {2791 for (SPObject *o = original; o && !dynamic_cast<SPRoot *>(o); o = o->parent) {
2786 if (dynamic_cast<SPDefs *>(o)) {2792 if (dynamic_cast<SPDefs *>(o)) {
2787 desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("The object you're trying to select is <b>not visible</b> (it is in &lt;defs&gt;)"));2793 desktop->messageStack()->flash(
2794 Inkscape::ERROR_MESSAGE,
2795 _("The object you're trying to select is <b>not visible</b> (it is in &lt;defs&gt;)"));
2788 return;2796 return;
2789 }2797 }
2790 }2798 }
@@ -2795,14 +2803,15 @@
2795 if (highlight) {2803 if (highlight) {
2796 Geom::OptRect a = item->desktopVisualBounds();2804 Geom::OptRect a = item->desktopVisualBounds();
2797 Geom::OptRect b = original->desktopVisualBounds();2805 Geom::OptRect b = original->desktopVisualBounds();
2798 if ( a && b ) {2806 if (a && b) {
2799 // draw a flashing line between the objects2807 // draw a flashing line between the objects
2800 SPCurve *curve = new SPCurve();2808 SPCurve *curve = new SPCurve();
2801 curve->moveto(a->midpoint());2809 curve->moveto(a->midpoint());
2802 curve->lineto(b->midpoint());2810 curve->lineto(b->midpoint());
28032811
2804 SPCanvasItem * canvasitem = sp_canvas_bpath_new(desktop->getTempGroup(), curve);2812 SPCanvasItem *canvasitem = sp_canvas_bpath_new(desktop->getTempGroup(), curve);
2805 sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(canvasitem), 0x0000ddff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT, 5, 3);2813 sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(canvasitem), 0x0000ddff, 1.0, SP_STROKE_LINEJOIN_MITER,
2814 SP_STROKE_LINECAP_BUTT, 5, 3);
2806 sp_canvas_item_show(canvasitem);2815 sp_canvas_item_show(canvasitem);
2807 curve->unref();2816 curve->unref();
2808 desktop->add_temporary_canvasitem(canvasitem, 1000);2817 desktop->add_temporary_canvasitem(canvasitem, 1000);
@@ -2829,9 +2838,9 @@
2829 Inkscape::Selection *selection = desktop->getSelection();2838 Inkscape::Selection *selection = desktop->getSelection();
28302839
2831 Inkscape::SVGOStringStream os;2840 Inkscape::SVGOStringStream os;
2832 SPObject * firstItem = NULL;2841 SPObject *firstItem = NULL;
2833 std::vector<SPItem*> items=selection->itemList();2842 std::vector<SPItem *> items = selection->itemList();
2834 for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){2843 for (std::vector<SPItem *>::const_iterator i = items.begin(); i != items.end(); i++) {
2835 if (SP_IS_SHAPE(*i) || SP_IS_TEXT(*i)) {2844 if (SP_IS_SHAPE(*i) || SP_IS_TEXT(*i)) {
2836 if (firstItem) {2845 if (firstItem) {
2837 os << "|";2846 os << "|";
@@ -2850,7 +2859,8 @@
2850 {2859 {
2851 lpe_repr->setAttribute("effect", "fill_between_many");2860 lpe_repr->setAttribute("effect", "fill_between_many");
2852 lpe_repr->setAttribute("linkedpaths", os.str());2861 lpe_repr->setAttribute("linkedpaths", os.str());
2853 desktop->doc()->getDefs()->getRepr()->addChild(lpe_repr, NULL); // adds to <defs> and assigns the 'id' attribute2862 desktop->doc()->getDefs()->getRepr()->addChild(lpe_repr,
2863 NULL); // adds to <defs> and assigns the 'id' attribute
2854 }2864 }
2855 std::string lpe_id_href = std::string("#") + lpe_repr->attribute("id");2865 std::string lpe_id_href = std::string("#") + lpe_repr->attribute("id");
2856 Inkscape::GC::release(lpe_repr);2866 Inkscape::GC::release(lpe_repr);
@@ -2899,25 +2909,25 @@
2899 doc->ensureUpToDate();2909 doc->ensureUpToDate();
2900 Geom::OptRect r = selection->visualBounds();2910 Geom::OptRect r = selection->visualBounds();
2901 boost::optional<Geom::Point> c = selection->center();2911 boost::optional<Geom::Point> c = selection->center();
2902 if ( !r || !c ) {2912 if (!r || !c) {
2903 return;2913 return;
2904 }2914 }
29052915
2906 // FIXME: Inverted Y coodinate2916 // FIXME: Inverted Y coodinate
2907 Geom::Point doc_height( 0, doc->getHeight().value("px"));2917 Geom::Point doc_height(0, doc->getHeight().value("px"));
29082918
2909 // calculate the transform to be applied to objects to move them to 0,02919 // calculate the transform to be applied to objects to move them to 0,0
2910 Geom::Point corner( r->min()[Geom::X], r->max()[Geom::Y] ); // FIXME: Inverted Y coodinate 2920 Geom::Point corner(r->min()[Geom::X], r->max()[Geom::Y]); // FIXME: Inverted Y coodinate
2911 Geom::Point move_p = doc_height - corner;2921 Geom::Point move_p = doc_height - corner;
2912 move_p[Geom::Y] = -move_p[Geom::Y];2922 move_p[Geom::Y] = -move_p[Geom::Y];
2913 Geom::Affine move = Geom::Affine(Geom::Translate(move_p));2923 Geom::Affine move = Geom::Affine(Geom::Translate(move_p));
29142924
2915 Geom::Point center( *c - corner ); // As defined by rotation center2925 Geom::Point center(*c - corner); // As defined by rotation center
2916 center[Geom::Y] = -center[Geom::Y];2926 center[Geom::Y] = -center[Geom::Y];
29172927
2918 std::vector<SPItem*> items(selection->itemList());2928 std::vector<SPItem *> items(selection->itemList());
29192929
2920 //items = g_slist_sort(items, (GCompareFunc) sp_object_compare_position); // Why needed?2930 // items = g_slist_sort(items, (GCompareFunc) sp_object_compare_position); // Why needed?
29212931
2922 // bottommost object, after sorting2932 // bottommost object, after sorting
2923 SPObject *parent = items[0]->parent;2933 SPObject *parent = items[0]->parent;
@@ -2933,8 +2943,8 @@
2933 }2943 }
29342944
2935 // Create a list of duplicates, to be pasted inside marker element.2945 // Create a list of duplicates, to be pasted inside marker element.
2936 std::vector<Inkscape::XML::Node*> repr_copies;2946 std::vector<Inkscape::XML::Node *> repr_copies;
2937 for (std::vector<SPItem*>::const_reverse_iterator i=items.rbegin();i!=items.rend();i++){2947 for (std::vector<SPItem *>::const_reverse_iterator i = items.rbegin(); i != items.rend(); i++) {
2938 Inkscape::XML::Node *dup = (*i)->getRepr()->duplicate(xml_doc);2948 Inkscape::XML::Node *dup = (*i)->getRepr()->duplicate(xml_doc);
2939 repr_copies.push_back(dup);2949 repr_copies.push_back(dup);
2940 }2950 }
@@ -2944,7 +2954,7 @@
2944 if (apply) {2954 if (apply) {
2945 // Delete objects so that their clones don't get alerted;2955 // Delete objects so that their clones don't get alerted;
2946 // the objects will be restored inside the marker element.2956 // the objects will be restored inside the marker element.
2947 for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){2957 for (std::vector<SPItem *>::const_iterator i = items.begin(); i != items.end(); i++) {
2948 SPObject *item = *i;2958 SPObject *item = *i;
2949 item->deleteObject(false);2959 item->deleteObject(false);
2950 }2960 }
@@ -2965,15 +2975,15 @@
29652975
29662976
29672977
2968 DocumentUndo::done(doc, SP_VERB_EDIT_SELECTION_2_MARKER,2978 DocumentUndo::done(doc, SP_VERB_EDIT_SELECTION_2_MARKER, _("Objects to marker"));
2969 _("Objects to marker"));
2970}2979}
29712980
2972static void sp_selection_to_guides_recursive(SPItem *item, bool wholegroups) {2981static void sp_selection_to_guides_recursive(SPItem *item, bool wholegroups)
2982{
2973 SPGroup *group = dynamic_cast<SPGroup *>(item);2983 SPGroup *group = dynamic_cast<SPGroup *>(item);
2974 if (group && !dynamic_cast<SPBox3D *>(item) && !wholegroups) {2984 if (group && !dynamic_cast<SPBox3D *>(item) && !wholegroups) {
2975 std::vector<SPItem*> items=sp_item_group_item_list(group);2985 std::vector<SPItem *> items = sp_item_group_item_list(group);
2976 for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){2986 for (std::vector<SPItem *>::const_iterator i = items.begin(); i != items.end(); i++) {
2977 sp_selection_to_guides_recursive(*i, wholegroups);2987 sp_selection_to_guides_recursive(*i, wholegroups);
2978 }2988 }
2979 } else {2989 } else {
@@ -2989,7 +2999,7 @@
2989 SPDocument *doc = desktop->getDocument();2999 SPDocument *doc = desktop->getDocument();
2990 Inkscape::Selection *selection = desktop->getSelection();3000 Inkscape::Selection *selection = desktop->getSelection();
2991 // we need to copy the list because it gets reset when objects are deleted3001 // we need to copy the list because it gets reset when objects are deleted
2992 std::vector<SPItem*> items(selection->itemList());3002 std::vector<SPItem *> items(selection->itemList());
29933003
2994 if (items.empty()) {3004 if (items.empty()) {
2995 desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to convert to guides."));3005 desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to convert to guides."));
@@ -3004,7 +3014,7 @@
3004 // and its entry in the selection list is invalid (crash).3014 // and its entry in the selection list is invalid (crash).
3005 // Therefore: first convert all, then delete all.3015 // Therefore: first convert all, then delete all.
30063016
3007 for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){3017 for (std::vector<SPItem *>::const_iterator i = items.begin(); i != items.end(); i++) {
3008 sp_selection_to_guides_recursive(*i, wholegroups);3018 sp_selection_to_guides_recursive(*i, wholegroups);
3009 }3019 }
30103020
@@ -3018,7 +3028,7 @@
30183028
3019/*3029/*
3020 * Convert objects to <symbol>. How that happens depends on what is selected:3030 * Convert objects to <symbol>. How that happens depends on what is selected:
3021 * 3031 *
3022 * 1) A random selection of objects will be embedded into a single <symbol> element.3032 * 1) A random selection of objects will be embedded into a single <symbol> element.
3023 *3033 *
3024 * 2) Except, a single <g> will have its content directly embedded into a <symbol>; the 'id' and3034 * 2) Except, a single <g> will have its content directly embedded into a <symbol>; the 'id' and
@@ -3036,7 +3046,7 @@
3036 * For SVG2, set 'refX' 'refY' to object center (with compensating shift in <use>3046 * For SVG2, set 'refX' 'refY' to object center (with compensating shift in <use>
3037 * transformation).3047 * transformation).
3038 */3048 */
3039void sp_selection_symbol(SPDesktop *desktop, bool /*apply*/ )3049void sp_selection_symbol(SPDesktop *desktop, bool /*apply*/)
3040{3050{
3041 if (desktop == NULL) {3051 if (desktop == NULL) {
3042 return;3052 return;
@@ -3049,13 +3059,13 @@
30493059
3050 // Check if something is selected.3060 // Check if something is selected.
3051 if (selection->isEmpty()) {3061 if (selection->isEmpty()) {
3052 desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>objects</b> to convert to symbol."));3062 desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>objects</b> to convert to symbol."));
3053 return;3063 return;
3054 }3064 }
30553065
3056 doc->ensureUpToDate();3066 doc->ensureUpToDate();
30573067
3058 std::vector<SPObject*> items(selection->list());3068 std::vector<SPObject *> items(selection->list());
30593069
3060 // Keep track of parent, this is where <use> will be inserted.3070 // Keep track of parent, this is where <use> will be inserted.
3061 Inkscape::XML::Node *the_first_repr = items[0]->getRepr();3071 Inkscape::XML::Node *the_first_repr = items[0]->getRepr();
@@ -3065,16 +3075,16 @@
3065 bool single_group = false;3075 bool single_group = false;
3066 SPGroup *the_group = NULL;3076 SPGroup *the_group = NULL;
3067 Geom::Affine transform;3077 Geom::Affine transform;
3068 if( items.size() == 1 ) {3078 if (items.size() == 1) {
3069 SPObject *object = items[0];3079 SPObject *object = items[0];
3070 the_group = dynamic_cast<SPGroup *>(object);3080 the_group = dynamic_cast<SPGroup *>(object);
3071 if ( the_group ) {3081 if (the_group) {
3072 single_group = true;3082 single_group = true;
30733083
3074 if( !sp_svg_transform_read( object->getAttribute("transform"), &transform ))3084 if (!sp_svg_transform_read(object->getAttribute("transform"), &transform))
3075 transform = Geom::identity();3085 transform = Geom::identity();
30763086
3077 if( transform.isTranslation() ) {3087 if (transform.isTranslation()) {
30783088
3079 // Create new list from group children.3089 // Create new list from group children.
3080 items = object->childList(false);3090 items = object->childList(false);
@@ -3083,7 +3093,8 @@
3083 // without disturbing clones.3093 // without disturbing clones.
3084 // See ActorAlign::on_button_click() in src/ui/dialog/align-and-distribute.cpp3094 // See ActorAlign::on_button_click() in src/ui/dialog/align-and-distribute.cpp
3085 Inkscape::Preferences *prefs = Inkscape::Preferences::get();3095 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3086 int saved_compensation = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED);3096 int saved_compensation =
3097 prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED);
3087 prefs->setInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED);3098 prefs->setInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED);
30883099
3089 // Remove transform on group, updating clones.3100 // Remove transform on group, updating clones.
@@ -3101,11 +3112,11 @@
3101 defsrepr->appendChild(symbol_repr);3112 defsrepr->appendChild(symbol_repr);
31023113
3103 // For a single group, copy relevant attributes.3114 // For a single group, copy relevant attributes.
3104 if( single_group ) {3115 if (single_group) {
31053116
3106 symbol_repr->setAttribute("style", the_group->getAttribute("style"));3117 symbol_repr->setAttribute("style", the_group->getAttribute("style"));
3107 symbol_repr->setAttribute("class", the_group->getAttribute("class"));3118 symbol_repr->setAttribute("class", the_group->getAttribute("class"));
3108 symbol_repr->setAttribute("id", the_group->getAttribute("id") );3119 symbol_repr->setAttribute("id", the_group->getAttribute("id"));
31093120
3110 // This should eventually be replaced by 'refX' and 'refY' once SVG WG approves it.3121 // This should eventually be replaced by 'refX' and 'refY' once SVG WG approves it.
3111 // It is done here for round-tripping3122 // It is done here for round-tripping
@@ -3118,30 +3129,29 @@
3118 Glib::ustring id = symbol_repr->attribute("id");3129 Glib::ustring id = symbol_repr->attribute("id");
3119 id += "_transform";3130 id += "_transform";
3120 the_group->setAttribute("id", id);3131 the_group->setAttribute("id", id);
3121
3122 }3132 }
31233133
3124 // Move selected items to new <symbol>3134 // Move selected items to new <symbol>
3125 for (std::vector<SPObject*>::const_iterator i=items.begin();i!=items.end();i++){3135 for (std::vector<SPObject *>::const_iterator i = items.begin(); i != items.end(); i++) {
3126 Inkscape::XML::Node *repr = (*i)->getRepr();3136 Inkscape::XML::Node *repr = (*i)->getRepr();
3127 repr->parent()->removeChild(repr);3137 repr->parent()->removeChild(repr);
3128 symbol_repr->addChild(repr,NULL);3138 symbol_repr->addChild(repr, NULL);
3129 }3139 }
31303140
3131 if( single_group && transform.isTranslation() ) {3141 if (single_group && transform.isTranslation()) {
3132 the_group->deleteObject(true);3142 the_group->deleteObject(true);
3133 }3143 }
31343144
3135 // Create <use> pointing to new symbol (to replace the moved objects).3145 // Create <use> pointing to new symbol (to replace the moved objects).
3136 Inkscape::XML::Node *clone = xml_doc->createElement("svg:use");3146 Inkscape::XML::Node *clone = xml_doc->createElement("svg:use");
31373147
3138 clone->setAttribute("xlink:href", Glib::ustring("#")+symbol_repr->attribute("id"), false);3148 clone->setAttribute("xlink:href", Glib::ustring("#") + symbol_repr->attribute("id"), false);
31393149
3140 the_parent_repr->appendChild(clone);3150 the_parent_repr->appendChild(clone);
31413151
3142 if( single_group && transform.isTranslation() ) {3152 if (single_group && transform.isTranslation()) {
3143 if( !transform.isIdentity() )3153 if (!transform.isIdentity())
3144 clone->setAttribute("transform", sp_svg_transform_write( transform ));3154 clone->setAttribute("transform", sp_svg_transform_write(transform));
3145 }3155 }
31463156
3147 // Change selection to new <use> element.3157 // Change selection to new <use> element.
@@ -3173,12 +3183,13 @@
3173 return;3183 return;
3174 }3184 }
31753185
3176 SPObject* symbol = selection->single();3186 SPObject *symbol = selection->single();
3177 3187
3178 // Make sure we have only one object in selection.3188 // Make sure we have only one object in selection.
3179 // Require that we really have a <symbol>.3189 // Require that we really have a <symbol>.
3180 if( symbol == NULL || !dynamic_cast<SPSymbol *>( symbol )) {3190 if (symbol == NULL || !dynamic_cast<SPSymbol *>(symbol)) {
3181 desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select only one <b>symbol</b> in Symbol dialog to convert to group."));3191 desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE,
3192 _("Select only one <b>symbol</b> in Symbol dialog to convert to group."));
3182 return;3193 return;
3183 }3194 }
31843195
@@ -3189,36 +3200,33 @@
3189 desktop->currentLayer()->getRepr()->appendChild(group);3200 desktop->currentLayer()->getRepr()->appendChild(group);
31903201
3191 // Move all children of symbol to group3202 // Move all children of symbol to group
3192 std::vector<SPObject*> children = symbol->childList(false);3203 std::vector<SPObject *> children = symbol->childList(false);
31933204
3194 // Converting a group to a symbol inserts a group for non-translational transform.3205 // Converting a group to a symbol inserts a group for non-translational transform.
3195 // In converting a symbol back to a group we strip out the inserted group (or any other3206 // In converting a symbol back to a group we strip out the inserted group (or any other
3196 // group that only adds a transform to the symbol content).3207 // group that only adds a transform to the symbol content).
3197 if( children.size() == 1 ) {3208 if (children.size() == 1) {
3198 SPObject *object = children[0];3209 SPObject *object = children[0];
3199 if ( dynamic_cast<SPGroup *>( object ) ) {3210 if (dynamic_cast<SPGroup *>(object)) {
3200 if( object->getAttribute("style") == NULL ||3211 if (object->getAttribute("style") == NULL || object->getAttribute("class") == NULL) {
3201 object->getAttribute("class") == NULL ) {
32023212
3203 group->setAttribute("transform", object->getAttribute("transform"));3213 group->setAttribute("transform", object->getAttribute("transform"));
3204 children = object->childList(false);3214 children = object->childList(false);
3205 }3215 }
3206 }3216 }
3207 }3217 }
3208 3218
3209 for (std::vector<SPObject*>::const_reverse_iterator i=children.rbegin();i!=children.rend();i++){3219 for (std::vector<SPObject *>::const_reverse_iterator i = children.rbegin(); i != children.rend(); i++) {
3210 Inkscape::XML::Node *repr = (*i)->getRepr();3220 Inkscape::XML::Node *repr = (*i)->getRepr();
3211 repr->parent()->removeChild(repr);3221 repr->parent()->removeChild(repr);
3212 group->addChild(repr,NULL);3222 group->addChild(repr, NULL);
3213 }3223 }
32143224
3215 // Copy relevant attributes3225 // Copy relevant attributes
3216 group->setAttribute("style", symbol->getAttribute("style"));3226 group->setAttribute("style", symbol->getAttribute("style"));
3217 group->setAttribute("class", symbol->getAttribute("class"));3227 group->setAttribute("class", symbol->getAttribute("class"));
3218 group->setAttribute("inkscape:transform-center-x",3228 group->setAttribute("inkscape:transform-center-x", symbol->getAttribute("inkscape:transform-center-x"));
3219 symbol->getAttribute("inkscape:transform-center-x"));3229 group->setAttribute("inkscape:transform-center-y", symbol->getAttribute("inkscape:transform-center-y"));
3220 group->setAttribute("inkscape:transform-center-y",
3221 symbol->getAttribute("inkscape:transform-center-y"));
32223230
32233231
3224 // Need to delete <symbol>; all <use> elements that referenced <symbol> should3232 // Need to delete <symbol>; all <use> elements that referenced <symbol> should
@@ -3237,8 +3245,7 @@
3237 DocumentUndo::done(doc, SP_VERB_EDIT_UNSYMBOL, _("Group from symbol"));3245 DocumentUndo::done(doc, SP_VERB_EDIT_UNSYMBOL, _("Group from symbol"));
3238}3246}
32393247
3240void3248void sp_selection_tile(SPDesktop *desktop, bool apply)
3241sp_selection_tile(SPDesktop *desktop, bool apply)
3242{3249{
3243 // sp_selection_to_marker has similar code3250 // sp_selection_to_marker has similar code
3244 if (desktop == NULL) {3251 if (desktop == NULL) {
@@ -3258,22 +3265,23 @@
32583265
3259 doc->ensureUpToDate();3266 doc->ensureUpToDate();
3260 Geom::OptRect r = selection->visualBounds();3267 Geom::OptRect r = selection->visualBounds();
3261 if ( !r ) {3268 if (!r) {
3262 return;3269 return;
3263 }3270 }
32643271
3265 // calculate the transform to be applied to objects to move them to 0,03272 // calculate the transform to be applied to objects to move them to 0,0
3266 Geom::Point move_p = Geom::Point(0, doc->getHeight().value("px")) - (r->min() + Geom::Point(0, r->dimensions()[Geom::Y]));3273 Geom::Point move_p =
3274 Geom::Point(0, doc->getHeight().value("px")) - (r->min() + Geom::Point(0, r->dimensions()[Geom::Y]));
3267 move_p[Geom::Y] = -move_p[Geom::Y];3275 move_p[Geom::Y] = -move_p[Geom::Y];
3268 Geom::Affine move = Geom::Affine(Geom::Translate(move_p));3276 Geom::Affine move = Geom::Affine(Geom::Translate(move_p));
32693277
3270 std::vector<SPItem*> items (selection->itemList());3278 std::vector<SPItem *> items(selection->itemList());
32713279
3272 sort(items.begin(),items.end(),sp_object_compare_position_bool);3280 sort(items.begin(), items.end(), sp_object_compare_position_bool);
32733281
3274 // bottommost object, after sorting3282 // bottommost object, after sorting
3275 SPObject *parent = items[0]->parent;3283 SPObject *parent = items[0]->parent;
3276 3284
32773285
3278 Geom::Affine parent_transform;3286 Geom::Affine parent_transform;
3279 {3287 {
@@ -3289,8 +3297,8 @@
3289 gint pos = items[0]->getRepr()->position();3297 gint pos = items[0]->getRepr()->position();
32903298
3291 // create a list of duplicates3299 // create a list of duplicates
3292 std::vector<Inkscape::XML::Node*> repr_copies;3300 std::vector<Inkscape::XML::Node *> repr_copies;
3293 for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){3301 for (std::vector<SPItem *>::const_iterator i = items.begin(); i != items.end(); i++) {
3294 Inkscape::XML::Node *dup = (*i)->getRepr()->duplicate(xml_doc);3302 Inkscape::XML::Node *dup = (*i)->getRepr()->duplicate(xml_doc);
3295 repr_copies.push_back(dup);3303 repr_copies.push_back(dup);
3296 }3304 }
@@ -3299,7 +3307,7 @@
32993307
3300 if (apply) {3308 if (apply) {
3301 // delete objects so that their clones don't get alerted; this object will be restored shortly3309 // delete objects so that their clones don't get alerted; this object will be restored shortly
3302 for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){3310 for (std::vector<SPItem *>::const_iterator i = items.begin(); i != items.end(); i++) {
3303 SPObject *item = *i;3311 SPObject *item = *i;
3304 item->deleteObject(false);3312 item->deleteObject(false);
3305 }3313 }
@@ -3312,11 +3320,11 @@
3312 int saved_compensation = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED);3320 int saved_compensation = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED);
3313 prefs->setInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED);3321 prefs->setInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED);
33143322
3315 gchar const *pat_id = SPPattern::produce(repr_copies, bbox, doc,3323 gchar const *pat_id = SPPattern::produce(
3316 ( Geom::Affine(Geom::Translate(desktop->dt2doc(Geom::Point(r->min()[Geom::X],3324 repr_copies, bbox, doc,
3317 r->max()[Geom::Y]))))3325 (Geom::Affine(Geom::Translate(desktop->dt2doc(Geom::Point(r->min()[Geom::X], r->max()[Geom::Y])))) *
3318 * parent_transform.inverse() ),3326 parent_transform.inverse()),
3319 parent_transform * move);3327 parent_transform * move);
33203328
3321 // restore compensation setting3329 // restore compensation setting
3322 prefs->setInt("/options/clonecompensation/value", saved_compensation);3330 prefs->setInt("/options/clonecompensation/value", saved_compensation);
@@ -3347,8 +3355,7 @@
3347 }3355 }
33483356
33493357
3350 DocumentUndo::done(doc, SP_VERB_EDIT_TILE,3358 DocumentUndo::done(doc, SP_VERB_EDIT_TILE, _("Objects to pattern"));
3351 _("Objects to pattern"));
3352}3359}
33533360
3354void sp_selection_untile(SPDesktop *desktop)3361void sp_selection_untile(SPDesktop *desktop)
@@ -3364,16 +3371,17 @@
33643371
3365 // check if something is selected3372 // check if something is selected
3366 if (selection->isEmpty()) {3373 if (selection->isEmpty()) {
3367 desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select an <b>object with pattern fill</b> to extract objects from."));3374 desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE,
3375 _("Select an <b>object with pattern fill</b> to extract objects from."));
3368 return;3376 return;
3369 }3377 }
33703378
3371 std::vector<SPItem*> new_select;3379 std::vector<SPItem *> new_select;
33723380
3373 bool did = false;3381 bool did = false;
33743382
3375 std::vector<SPItem*> items(selection->itemList());3383 std::vector<SPItem *> items(selection->itemList());
3376 for (std::vector<SPItem*>::const_reverse_iterator i=items.rbegin();i!=items.rend();i++){3384 for (std::vector<SPItem *>::const_reverse_iterator i = items.rbegin(); i != items.rend(); i++) {
3377 SPItem *item = *i;3385 SPItem *item = *i;
33783386
3379 SPStyle *style = item->style;3387 SPStyle *style = item->style;
@@ -3395,19 +3403,19 @@
3395 Geom::Affine pat_transform = basePat->getTransform();3403 Geom::Affine pat_transform = basePat->getTransform();
3396 pat_transform *= item->transform;3404 pat_transform *= item->transform;
33973405
3398 for (SPObject *child = pattern->firstChild() ; child != NULL; child = child->next ) {3406 for (SPObject *child = pattern->firstChild(); child != NULL; child = child->next) {
3399 if (dynamic_cast<SPItem *>(child)) {3407 if (dynamic_cast<SPItem *>(child)) {
3400 Inkscape::XML::Node *copy = child->getRepr()->duplicate(xml_doc);3408 Inkscape::XML::Node *copy = child->getRepr()->duplicate(xml_doc);
3401 SPItem *i = dynamic_cast<SPItem *>(desktop->currentLayer()->appendChildRepr(copy));3409 SPItem *i = dynamic_cast<SPItem *>(desktop->currentLayer()->appendChildRepr(copy));
34023410
3403 // FIXME: relink clones to the new canvas objects3411 // FIXME: relink clones to the new canvas objects
3404 // use SPObject::setid when mental finishes it to steal ids of3412 // use SPObject::setid when mental finishes it to steal ids of
34053413
3406 // this is needed to make sure the new item has curve (simply requestDisplayUpdate does not work)3414 // this is needed to make sure the new item has curve (simply requestDisplayUpdate does not work)
3407 doc->ensureUpToDate();3415 doc->ensureUpToDate();
34083416
3409 if (i) {3417 if (i) {
3410 Geom::Affine transform( i->transform * pat_transform );3418 Geom::Affine transform(i->transform * pat_transform);
3411 i->doWriteTransform(i->getRepr(), transform);3419 i->doWriteTransform(i->getRepr(), transform);
34123420
3413 new_select.push_back(i);3421 new_select.push_back(i);
@@ -3425,8 +3433,7 @@
3425 if (!did) {3433 if (!did) {
3426 desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("<b>No pattern fills</b> in the selection."));3434 desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("<b>No pattern fills</b> in the selection."));
3427 } else {3435 } else {
3428 DocumentUndo::done(desktop->getDocument(), SP_VERB_EDIT_UNTILE,3436 DocumentUndo::done(desktop->getDocument(), SP_VERB_EDIT_UNTILE, _("Pattern to objects"));
3429 _("Pattern to objects"));
3430 selection->setList(new_select);3437 selection->setList(new_select);
3431 }3438 }
3432}3439}
@@ -3437,22 +3444,22 @@
3437 return;3444 return;
3438 }3445 }
34393446
3440 std::vector<Inkscape::XML::Node*> const reprlst = selection->reprList();3447 std::vector<Inkscape::XML::Node *> const reprlst = selection->reprList();
3441 bool filename_search = TRUE;3448 bool filename_search = TRUE;
3442 bool xdpi_search = TRUE;3449 bool xdpi_search = TRUE;
3443 bool ydpi_search = TRUE;3450 bool ydpi_search = TRUE;
34443451
3445 for (std::vector<Inkscape::XML::Node*>::const_iterator i=reprlst.begin();filename_search&&xdpi_search&&ydpi_search&&i!=reprlst.end();i++){3452 for (std::vector<Inkscape::XML::Node *>::const_iterator i = reprlst.begin();
3453 filename_search && xdpi_search && ydpi_search && i != reprlst.end(); i++) {
3446 gchar const *dpi_string;3454 gchar const *dpi_string;
3447 Inkscape::XML::Node *repr = *i;3455 Inkscape::XML::Node *repr = *i;
34483456
3449 if (filename_search) {3457 if (filename_search) {
3450 const gchar* tmp = repr->attribute("inkscape:export-filename");3458 const gchar *tmp = repr->attribute("inkscape:export-filename");
3451 if (tmp){3459 if (tmp) {
3452 filename = tmp;3460 filename = tmp;
3453 filename_search = FALSE;3461 filename_search = FALSE;
3454 }3462 } else {
3455 else{
3456 filename.clear();3463 filename.clear();
3457 }3464 }
3458 }3465 }
@@ -3477,15 +3484,12 @@
34773484
3478void sp_document_get_export_hints(SPDocument *doc, Glib::ustring &filename, float *xdpi, float *ydpi)3485void sp_document_get_export_hints(SPDocument *doc, Glib::ustring &filename, float *xdpi, float *ydpi)
3479{3486{
3480 Inkscape::XML::Node * repr = doc->getReprRoot();3487 Inkscape::XML::Node *repr = doc->getReprRoot();
34813488
3482 const gchar* tmp = repr->attribute("inkscape:export-filename");3489 const gchar *tmp = repr->attribute("inkscape:export-filename");
3483 if(tmp)3490 if (tmp) {
3484 {
3485 filename = tmp;3491 filename = tmp;
3486 }3492 } else {
3487 else
3488 {
3489 filename.clear();3493 filename.clear();
3490 }3494 }
3491 gchar const *dpi_string = repr->attribute("inkscape:export-xdpi");3495 gchar const *dpi_string = repr->attribute("inkscape:export-xdpi");
@@ -3530,30 +3534,28 @@
3530 }3534 }
35313535
3532 // List of the items to show; all others will be hidden3536 // List of the items to show; all others will be hidden
3533 std::vector<SPItem*> items(selection->itemList());3537 std::vector<SPItem *> items(selection->itemList());
35343538
3535 // Sort items so that the topmost comes last3539 // Sort items so that the topmost comes last
3536 sort(items.begin(),items.end(),sp_item_repr_compare_position_bool);3540 sort(items.begin(), items.end(), sp_item_repr_compare_position_bool);
35373541
3538 // Generate a random value from the current time (you may create bitmap from the same object(s)3542 // Generate a random value from the current time (you may create bitmap from the same object(s)
3539 // multiple times, and this is done so that they don't clash)3543 // multiple times, and this is done so that they don't clash)
3540 GTimeVal cu;3544 GTimeVal cu;
3541 g_get_current_time(&cu);3545 g_get_current_time(&cu);
3542 guint current = (int) (cu.tv_sec * 1000000 + cu.tv_usec) % 1024;3546 guint current = (int)(cu.tv_sec * 1000000 + cu.tv_usec) % 1024;
35433547
3544 // Create the filename.3548 // Create the filename.
3545 gchar *const basename = g_strdup_printf("%s-%s-%u.png",3549 gchar *const basename =
3546 document->getName(),3550 g_strdup_printf("%s-%s-%u.png", document->getName(), items[0]->getRepr()->attribute("id"), current);
3547 items[0]->getRepr()->attribute("id"),
3548 current);
3549 // Imagemagick is known not to handle spaces in filenames, so we replace anything but letters,3551 // Imagemagick is known not to handle spaces in filenames, so we replace anything but letters,
3550 // digits, and a few other chars, with "_"3552 // digits, and a few other chars, with "_"
3551 g_strcanon(basename, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.=+~$#@^&!?", '_');3553 g_strcanon(basename, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.=+~$#@^&!?", '_');
35523554
3553 // Build the complete path by adding document base dir, if set, otherwise home dir3555 // Build the complete path by adding document base dir, if set, otherwise home dir
3554 gchar *directory = NULL;3556 gchar *directory = NULL;
3555 if ( document->getURI() ) {3557 if (document->getURI()) {
3556 directory = g_path_get_dirname( document->getURI() );3558 directory = g_path_get_dirname(document->getURI());
3557 }3559 }
3558 if (directory == NULL) {3560 if (directory == NULL) {
3559 directory = INKSCAPE.homedir_path(NULL);3561 directory = INKSCAPE.homedir_path(NULL);
@@ -3561,7 +3563,7 @@
3561 gchar *filepath = g_build_filename(directory, basename, NULL);3563 gchar *filepath = g_build_filename(directory, basename, NULL);
3562 g_free(directory);3564 g_free(directory);
35633565
3564 //g_print("%s\n", filepath);3566 // g_print("%s\n", filepath);
35653567
3566 // Remember parent and z-order of the topmost one3568 // Remember parent and z-order of the topmost one
3567 gint pos = items.back()->getRepr()->position();3569 gint pos = items.back()->getRepr()->position();
@@ -3599,8 +3601,8 @@
3599 }3601 }
36003602
3601 // The width and height of the bitmap in pixels3603 // The width and height of the bitmap in pixels
3602 unsigned width = (unsigned) floor(bbox->width() * Inkscape::Util::Quantity::convert(res, "px", "in"));3604 unsigned width = (unsigned)floor(bbox->width() * Inkscape::Util::Quantity::convert(res, "px", "in"));
3603 unsigned height =(unsigned) floor(bbox->height() * Inkscape::Util::Quantity::convert(res, "px", "in"));3605 unsigned height = (unsigned)floor(bbox->height() * Inkscape::Util::Quantity::convert(res, "px", "in"));
36043606
3605 // Find out if we have to run an external filter3607 // Find out if we have to run an external filter
3606 gchar const *run = NULL;3608 gchar const *run = NULL;
@@ -3642,19 +3644,16 @@
3642 double shift_y = bbox->max()[Geom::Y];3644 double shift_y = bbox->max()[Geom::Y];
3643 if (res == Inkscape::Util::Quantity::convert(1, "in", "px")) { // for default 96 dpi, snap it to pixel grid3645 if (res == Inkscape::Util::Quantity::convert(1, "in", "px")) { // for default 96 dpi, snap it to pixel grid
3644 shift_x = round(shift_x);3646 shift_x = round(shift_x);
3645 shift_y = -round(-shift_y); // this gets correct rounding despite coordinate inversion, remove the negations when the inversion is gone3647 shift_y = -round(-shift_y); // this gets correct rounding despite coordinate inversion, remove the negations
3648 // when the inversion is gone
3646 }3649 }
3647 t = Geom::Scale(1, -1) * Geom::Translate(shift_x, shift_y) * eek.inverse(); /// @fixme hardcoded doc2dt transform?3650 t = Geom::Scale(1, -1) * Geom::Translate(shift_x, shift_y) * eek.inverse(); /// @fixme hardcoded doc2dt transform?
36483651
3649 // TODO: avoid roundtrip via file3652 // TODO: avoid roundtrip via file
3650 // Do the export3653 // Do the export
3651 sp_export_png_file(document, filepath,3654 sp_export_png_file(document, filepath, bbox->min()[Geom::X], bbox->min()[Geom::Y], bbox->max()[Geom::X],
3652 bbox->min()[Geom::X], bbox->min()[Geom::Y],3655 bbox->max()[Geom::Y], width, height, res, res, (guint32)0xffffff00, NULL, NULL,
3653 bbox->max()[Geom::X], bbox->max()[Geom::Y],3656 true, /*bool force_overwrite,*/
3654 width, height, res, res,
3655 (guint32) 0xffffff00,
3656 NULL, NULL,
3657 true, /*bool force_overwrite,*/
3658 items);3657 items);
36593658
3660 // Run filter, if any3659 // Run filter, if any
@@ -3662,7 +3661,7 @@
3662 g_print("Running external filter: %s\n", run);3661 g_print("Running external filter: %s\n", run);
3663 int result = system(run);3662 int result = system(run);
36643663
3665 if(result == -1)3664 if (result == -1)
3666 g_warning("Could not run external filter: %s\n", run);3665 g_warning("Could not run external filter: %s\n", run);
3667 }3666 }
36683667
@@ -3671,7 +3670,7 @@
3671 if (pb) {3670 if (pb) {
3672 // Create the repr for the image3671 // Create the repr for the image
3673 // TODO: avoid unnecessary roundtrip between data URI and decoded pixbuf3672 // TODO: avoid unnecessary roundtrip between data URI and decoded pixbuf
3674 Inkscape::XML::Node * repr = xml_doc->createElement("svg:image");3673 Inkscape::XML::Node *repr = xml_doc->createElement("svg:image");
3675 sp_embed_image(repr, pb);3674 sp_embed_image(repr, pb);
3676 if (res == Inkscape::Util::Quantity::convert(1, "in", "px")) { // for default 96 dpi, snap it to pixel grid3675 if (res == Inkscape::Util::Quantity::convert(1, "in", "px")) { // for default 96 dpi, snap it to pixel grid
3677 sp_repr_set_svg_double(repr, "width", width);3676 sp_repr_set_svg_double(repr, "width", width);
@@ -3682,7 +3681,7 @@
3682 }3681 }
36833682
3684 // Write transform3683 // Write transform
3685 gchar *c=sp_svg_transform_write(t);3684 gchar *c = sp_svg_transform_write(t);
3686 repr->setAttribute("transform", c);3685 repr->setAttribute("transform", c);
3687 g_free(c);3686 g_free(c);
36883687
@@ -3701,8 +3700,7 @@
3701 g_object_unref(pb);3700 g_object_unref(pb);
37023701
3703 // Complete undoable transaction3702 // Complete undoable transaction
3704 DocumentUndo::done(document, SP_VERB_SELECTION_CREATE_BITMAP,3703 DocumentUndo::done(document, SP_VERB_SELECTION_CREATE_BITMAP, _("Create bitmap"));
3705 _("Create bitmap"));
3706 }3704 }
37073705
3708 desktop->clearWaitingCursor();3706 desktop->clearWaitingCursor();
@@ -3722,18 +3720,19 @@
3722 if (desktop == NULL) {3720 if (desktop == NULL) {
3723 return;3721 return;
3724 }3722 }
3725 SPDocument* doc = desktop->getDocument();3723 SPDocument *doc = desktop->getDocument();
3726 Inkscape::XML::Document *xml_doc = doc->getReprDoc();3724 Inkscape::XML::Document *xml_doc = doc->getReprDoc();
37273725
3728 Inkscape::Selection *selection = desktop->getSelection();3726 Inkscape::Selection *selection = desktop->getSelection();
3729 if (selection->isEmpty()) {3727 if (selection->isEmpty()) {
3730 desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to create clippath or mask from."));3728 desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE,
3729 _("Select <b>object(s)</b> to create clippath or mask from."));
3731 return;3730 return;
3732 }3731 }
3733 3732
3734 std::vector<Inkscape::XML::Node*> p(selection->reprList());3733 std::vector<Inkscape::XML::Node *> p(selection->reprList());
3735 3734
3736 sort(p.begin(),p.end(),sp_repr_compare_position_bool);3735 sort(p.begin(), p.end(), sp_repr_compare_position_bool);
37373736
3738 selection->clear();3737 selection->clear();
37393738
@@ -3742,21 +3741,23 @@
37423741
3743 Inkscape::XML::Node *inner = xml_doc->createElement("svg:g");3742 Inkscape::XML::Node *inner = xml_doc->createElement("svg:g");
3744 inner->setAttribute("inkscape:label", "Clip");3743 inner->setAttribute("inkscape:label", "Clip");
3745 3744
3746 for(std::vector<Inkscape::XML::Node*>::const_iterator i=p.begin();i!=p.end();i++){3745 for (std::vector<Inkscape::XML::Node *>::const_iterator i = p.begin(); i != p.end(); i++) {
3747 Inkscape::XML::Node *current = *i;3746 Inkscape::XML::Node *current = *i;
37483747
3749 if (current->parent() == topmost_parent) {3748 if (current->parent() == topmost_parent) {
3750 Inkscape::XML::Node *spnew = current->duplicate(xml_doc);3749 Inkscape::XML::Node *spnew = current->duplicate(xml_doc);
3751 sp_repr_unparent(current);3750 sp_repr_unparent(current);
3752 inner->appendChild(spnew);3751 inner->appendChild(spnew);
3753 Inkscape::GC::release(spnew);3752 Inkscape::GC::release(spnew);
3754 topmost --; // only reduce count for those items deleted from topmost_parent3753 topmost--; // only reduce count for those items deleted from topmost_parent
3755 } else { // move it to topmost_parent first3754 } else { // move it to topmost_parent first
3756 std::vector<Inkscape::XML::Node*> temp_clip;3755 std::vector<Inkscape::XML::Node *> temp_clip;
37573756
3758 // At this point, current may already have no item, due to its being a clone whose original is already moved away3757 // At this point, current may already have no item, due to its being a clone whose original is already moved
3759 // So we copy it artificially calculating the transform from its repr->attr("transform") and the parent transform3758 // away
3759 // So we copy it artificially calculating the transform from its repr->attr("transform") and the parent
3760 // transform
3760 gchar const *t_str = current->attribute("transform");3761 gchar const *t_str = current->attribute("transform");
3761 Geom::Affine item_t(Geom::identity());3762 Geom::Affine item_t(Geom::identity());
3762 if (t_str)3763 if (t_str)
@@ -3773,7 +3774,8 @@
3773 sp_repr_unparent(current);3774 sp_repr_unparent(current);
37743775
3775 // paste into topmost_parent (temporarily)3776 // paste into topmost_parent (temporarily)
3776 std::vector<Inkscape::XML::Node*> copied = sp_selection_paste_impl(doc, doc->getObjectByRepr(topmost_parent), temp_clip);3777 std::vector<Inkscape::XML::Node *> copied =
3778 sp_selection_paste_impl(doc, doc->getObjectByRepr(topmost_parent), temp_clip);
3777 if (!copied.empty()) { // if success,3779 if (!copied.empty()) { // if success,
3778 // take pasted object (now in topmost_parent)3780 // take pasted object (now in topmost_parent)
3779 Inkscape::XML::Node *in_topmost = copied.back();3781 Inkscape::XML::Node *in_topmost = copied.back();
@@ -3787,12 +3789,12 @@
3787 }3789 }
3788 }3790 }
3789 }3791 }
3790 3792
3791 Inkscape::XML::Node *outer = xml_doc->createElement("svg:g");3793 Inkscape::XML::Node *outer = xml_doc->createElement("svg:g");
3792 outer->appendChild(inner);3794 outer->appendChild(inner);
3793 topmost_parent->appendChild(outer);3795 topmost_parent->appendChild(outer);
3794 outer->setPosition(topmost + 1);3796 outer->setPosition(topmost + 1);
3795 3797
3796 Inkscape::XML::Node *clone = xml_doc->createElement("svg:use");3798 Inkscape::XML::Node *clone = xml_doc->createElement("svg:use");
3797 clone->setAttribute("x", "0", false);3799 clone->setAttribute("x", "0", false);
3798 clone->setAttribute("y", "0", false);3800 clone->setAttribute("y", "0", false);
@@ -3802,16 +3804,16 @@
3802 clone->setAttribute("inkscape:transform-center-y", inner->attribute("inkscape:transform-center-y"), false);3804 clone->setAttribute("inkscape:transform-center-y", inner->attribute("inkscape:transform-center-y"), false);
38033805
3804 const Geom::Affine maskTransform(Geom::Affine::identity());3806 const Geom::Affine maskTransform(Geom::Affine::identity());
3805 std::vector<Inkscape::XML::Node*> templist;3807 std::vector<Inkscape::XML::Node *> templist;
3806 templist.push_back(clone);3808 templist.push_back(clone);
3807 // add the new clone to the top of the original's parent3809 // add the new clone to the top of the original's parent
3808 gchar const *mask_id = SPClipPath::create(templist, doc, &maskTransform);3810 gchar const *mask_id = SPClipPath::create(templist, doc, &maskTransform);
3809 3811
3810 3812
3811 outer->setAttribute("clip-path", g_strdup_printf("url(#%s)", mask_id));3813 outer->setAttribute("clip-path", g_strdup_printf("url(#%s)", mask_id));
38123814
3813 Inkscape::GC::release(clone);3815 Inkscape::GC::release(clone);
3814 3816
3815 selection->set(outer);3817 selection->set(outer);
3816 DocumentUndo::done(doc, SP_VERB_OBJECT_SET_CLIPPATH, _("Create Clip Group"));3818 DocumentUndo::done(doc, SP_VERB_OBJECT_SET_CLIPPATH, _("Create Clip Group"));
3817}3819}
@@ -3838,11 +3840,13 @@
38383840
3839 // check if something is selected3841 // check if something is selected
3840 bool is_empty = selection->isEmpty();3842 bool is_empty = selection->isEmpty();
3841 if ( apply_to_layer && is_empty) {3843 if (apply_to_layer && is_empty) {
3842 desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to create clippath or mask from."));3844 desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE,
3845 _("Select <b>object(s)</b> to create clippath or mask from."));
3843 return;3846 return;
3844 } else if (!apply_to_layer && ( is_empty || selection->itemList().size()==1 )) {3847 } else if (!apply_to_layer && (is_empty || selection->itemList().size() == 1)) {
3845 desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select mask object and <b>object(s)</b> to apply clippath or mask to."));3848 desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE,
3849 _("Select mask object and <b>object(s)</b> to apply clippath or mask to."));
3846 return;3850 return;
3847 }3851 }
38483852
@@ -3856,18 +3860,18 @@
38563860
3857 doc->ensureUpToDate();3861 doc->ensureUpToDate();
38583862
3859 std::vector<SPItem*> items(selection->itemList());3863 std::vector<SPItem *> items(selection->itemList());
38603864
3861 sort(items.begin(),items.end(),sp_object_compare_position_bool);3865 sort(items.begin(), items.end(), sp_object_compare_position_bool);
38623866
3863 // See lp bug #5420043867 // See lp bug #542004
3864 selection->clear();3868 selection->clear();
38653869
3866 // create a list of duplicates3870 // create a list of duplicates
3867 std::vector<Inkscape::XML::Node*> mask_items;3871 std::vector<Inkscape::XML::Node *> mask_items;
3868 std::vector<SPItem*> apply_to_items;3872 std::vector<SPItem *> apply_to_items;
3869 std::vector<SPItem*> items_to_delete;3873 std::vector<SPItem *> items_to_delete;
3870 std::vector<SPItem*> items_to_select;3874 std::vector<SPItem *> items_to_select;
38713875
3872 Inkscape::Preferences *prefs = Inkscape::Preferences::get();3876 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3873 bool topmost = prefs->getBool("/options/maskobject/topmost", true);3877 bool topmost = prefs->getBool("/options/maskobject/topmost", true);
@@ -3879,12 +3883,11 @@
3879 apply_to_items.push_back(SP_ITEM(desktop->currentLayer()));3883 apply_to_items.push_back(SP_ITEM(desktop->currentLayer()));
3880 }3884 }
38813885
3882 for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++) {3886 for (std::vector<SPItem *>::const_iterator i = items.begin(); i != items.end(); i++) {
3883 if((!topmost && !apply_to_layer && *i == items.front())3887 if ((!topmost && !apply_to_layer && *i == items.front()) ||
3884 || (topmost && !apply_to_layer && *i == items.back())3888 (topmost && !apply_to_layer && *i == items.back()) || apply_to_layer) {
3885 || apply_to_layer){
38863889
3887 Geom::Affine oldtr=(*i)->transform;3890 Geom::Affine oldtr = (*i)->transform;
3888 (*i)->doWriteTransform((*i)->getRepr(), (*i)->i2doc_affine());3891 (*i)->doWriteTransform((*i)->getRepr(), (*i)->i2doc_affine());
3889 Inkscape::XML::Node *dup = (*i)->getRepr()->duplicate(xml_doc);3892 Inkscape::XML::Node *dup = (*i)->getRepr()->duplicate(xml_doc);
3890 (*i)->doWriteTransform((*i)->getRepr(), oldtr);3893 (*i)->doWriteTransform((*i)->getRepr(), oldtr);
@@ -3892,12 +3895,11 @@
38923895
3893 if (remove_original) {3896 if (remove_original) {
3894 items_to_delete.push_back(*i);3897 items_to_delete.push_back(*i);
3895 }3898 } else {
3896 else {
3897 items_to_select.push_back(*i);3899 items_to_select.push_back(*i);
3898 }3900 }
3899 continue;3901 continue;
3900 }else{3902 } else {
3901 apply_to_items.push_back(*i);3903 apply_to_items.push_back(*i);
3902 items_to_select.push_back(*i);3904 items_to_select.push_back(*i);
3903 }3905 }
@@ -3913,9 +3915,9 @@
3913 // make a note we should ungroup this when unsetting mask3915 // make a note we should ungroup this when unsetting mask
3914 group->setAttribute("inkscape:groupmode", "maskhelper");3916 group->setAttribute("inkscape:groupmode", "maskhelper");
39153917
3916 std::vector<Inkscape::XML::Node*> reprs_to_group;3918 std::vector<Inkscape::XML::Node *> reprs_to_group;
3917 for (std::vector<SPItem*>::const_iterator i = apply_to_items.begin(); i != apply_to_items.end(); i++) {3919 for (std::vector<SPItem *>::const_iterator i = apply_to_items.begin(); i != apply_to_items.end(); i++) {
3918 reprs_to_group.push_back(static_cast<SPObject*>(*i)->getRepr());3920 reprs_to_group.push_back(static_cast<SPObject *>(*i)->getRepr());
3919 }3921 }
3920 items_to_select.clear();3922 items_to_select.clear();
39213923
@@ -3923,9 +3925,9 @@
39233925
3924 // apply clip/mask only to newly created group3926 // apply clip/mask only to newly created group
3925 apply_to_items.clear();3927 apply_to_items.clear();
3926 apply_to_items.push_back(dynamic_cast<SPItem*>(doc->getObjectByRepr(group)));3928 apply_to_items.push_back(dynamic_cast<SPItem *>(doc->getObjectByRepr(group)));
39273929
3928 items_to_select.push_back((SPItem*)(doc->getObjectByRepr(group)));3930 items_to_select.push_back((SPItem *)(doc->getObjectByRepr(group)));
39293931
3930 Inkscape::GC::release(group);3932 Inkscape::GC::release(group);
3931 }3933 }
@@ -3935,13 +3937,13 @@
39353937
39363938
3937 gchar const *attributeName = apply_clip_path ? "clip-path" : "mask";3939 gchar const *attributeName = apply_clip_path ? "clip-path" : "mask";
3938 for (std::vector<SPItem*>::const_reverse_iterator i = apply_to_items.rbegin(); i != apply_to_items.rend(); i++) {3940 for (std::vector<SPItem *>::const_reverse_iterator i = apply_to_items.rbegin(); i != apply_to_items.rend(); i++) {
3939 SPItem *item = reinterpret_cast<SPItem *>(*i);3941 SPItem *item = reinterpret_cast<SPItem *>(*i);
3940 // inverted object transform should be applied to a mask object,3942 // inverted object transform should be applied to a mask object,
3941 // as mask is calculated in user space (after applying transform)3943 // as mask is calculated in user space (after applying transform)
3942 std::vector<Inkscape::XML::Node*> mask_items_dup;3944 std::vector<Inkscape::XML::Node *> mask_items_dup;
3943 for(std::vector<Inkscape::XML::Node*>::const_iterator it=mask_items.begin();it!=mask_items.end();it++)3945 for (std::vector<Inkscape::XML::Node *>::const_iterator it = mask_items.begin(); it != mask_items.end(); it++)
3944 mask_items_dup.push_back((*it)->duplicate(xml_doc));3946 mask_items_dup.push_back((*it)->duplicate(xml_doc));
3945 Inkscape::XML::Node *current = SP_OBJECT(*i)->getRepr();3947 Inkscape::XML::Node *current = SP_OBJECT(*i)->getRepr();
3946 // Node to apply mask to3948 // Node to apply mask to
3947 Inkscape::XML::Node *apply_mask_to = current;3949 Inkscape::XML::Node *apply_mask_to = current;
@@ -3962,7 +3964,7 @@
3962 // Apply clip/mask to group instead3964 // Apply clip/mask to group instead
3963 apply_mask_to = group;3965 apply_mask_to = group;
39643966
3965 items_to_select.push_back(item = (SPItem*)(doc->getObjectByRepr(group)));3967 items_to_select.push_back(item = (SPItem *)(doc->getObjectByRepr(group)));
3966 Inkscape::GC::release(spnew);3968 Inkscape::GC::release(spnew);
3967 Inkscape::GC::release(group);3969 Inkscape::GC::release(group);
3968 }3970 }
@@ -3977,11 +3979,10 @@
3977 }3979 }
39783980
3979 apply_mask_to->setAttribute(attributeName, Glib::ustring("url(#") + mask_id + ')');3981 apply_mask_to->setAttribute(attributeName, Glib::ustring("url(#") + mask_id + ')');
3980
3981 }3982 }
39823983
3983 for (std::vector<SPItem*>::const_iterator i = items_to_delete.begin(); i != items_to_delete.end(); i++) {3984 for (std::vector<SPItem *>::const_iterator i = items_to_delete.begin(); i != items_to_delete.end(); i++) {
3984 SPObject *item = reinterpret_cast<SPObject*>(*i);3985 SPObject *item = reinterpret_cast<SPObject *>(*i);
3985 item->deleteObject(false);3986 item->deleteObject(false);
3986 items_to_select.erase(remove(items_to_select.begin(), items_to_select.end(), item), items_to_select.end());3987 items_to_select.erase(remove(items_to_select.begin(), items_to_select.end(), item), items_to_select.end());
3987 }3988 }
@@ -3995,7 +3996,8 @@
3995 }3996 }
3996}3997}
39973998
3998void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) {3999void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path)
4000{
3999 if (desktop == NULL) {4001 if (desktop == NULL) {
4000 return;4002 return;
4001 }4003 }
@@ -4006,7 +4008,8 @@
40064008
4007 // check if something is selected4009 // check if something is selected
4008 if (selection->isEmpty()) {4010 if (selection->isEmpty()) {
4009 desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>object(s)</b> to remove clippath or mask from."));4011 desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE,
4012 _("Select <b>object(s)</b> to remove clippath or mask from."));
4010 return;4013 return;
4011 }4014 }
40124015
@@ -4016,18 +4019,18 @@
4016 doc->ensureUpToDate();4019 doc->ensureUpToDate();
40174020
4018 gchar const *attributeName = apply_clip_path ? "clip-path" : "mask";4021 gchar const *attributeName = apply_clip_path ? "clip-path" : "mask";
4019 std::map<SPObject*,SPItem*> referenced_objects;4022 std::map<SPObject *, SPItem *> referenced_objects;
40204023
4021 std::vector<SPItem*> items(selection->itemList());4024 std::vector<SPItem *> items(selection->itemList());
4022 selection->clear();4025 selection->clear();
40234026
4024 GSList *items_to_ungroup = NULL;4027 GSList *items_to_ungroup = NULL;
4025 std::vector<SPItem*> items_to_select(items);4028 std::vector<SPItem *> items_to_select(items);
40264029
40274030
4028 // SPObject* refers to a group containing the clipped path or mask itself,4031 // SPObject* refers to a group containing the clipped path or mask itself,
4029 // whereas SPItem* refers to the item being clipped or masked4032 // whereas SPItem* refers to the item being clipped or masked
4030 for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){4033 for (std::vector<SPItem *>::const_iterator i = items.begin(); i != items.end(); i++) {
4031 if (remove_original) {4034 if (remove_original) {
4032 // remember referenced mask/clippath, so orphaned masks can be moved back to document4035 // remember referenced mask/clippath, so orphaned masks can be moved back to document
4033 SPItem *item = *i;4036 SPItem *item = *i;
@@ -4049,26 +4052,25 @@
40494052
4050 SPGroup *group = dynamic_cast<SPGroup *>(*i);4053 SPGroup *group = dynamic_cast<SPGroup *>(*i);
4051 if (ungroup_masked && group) {4054 if (ungroup_masked && group) {
4052 // if we had previously enclosed masked object in group,4055 // if we had previously enclosed masked object in group,
4053 // add it to list so we can ungroup it later4056 // add it to list so we can ungroup it later
40544057
4055 // ungroup only groups we created when setting clip/mask4058 // ungroup only groups we created when setting clip/mask
4056 if (group->layerMode() == SPGroup::MASK_HELPER) {4059 if (group->layerMode() == SPGroup::MASK_HELPER) {
4057 items_to_ungroup = g_slist_prepend(items_to_ungroup, group);4060 items_to_ungroup = g_slist_prepend(items_to_ungroup, group);
4058 }4061 }
4059
4060 }4062 }
4061 }4063 }
40624064
4063 // restore mask objects into a document4065 // restore mask objects into a document
4064 for ( std::map<SPObject*,SPItem*>::iterator it = referenced_objects.begin() ; it != referenced_objects.end() ; ++it) {4066 for (std::map<SPObject *, SPItem *>::iterator it = referenced_objects.begin(); it != referenced_objects.end();
4067 ++it) {
4065 SPObject *obj = (*it).first; // Group containing the clipped paths or masks4068 SPObject *obj = (*it).first; // Group containing the clipped paths or masks
4066 GSList *items_to_move = NULL;4069 GSList *items_to_move = NULL;
4067 for ( SPObject *child = obj->firstChild() ; child; child = child->getNext() ) {4070 for (SPObject *child = obj->firstChild(); child; child = child->getNext()) {
4068 // Collect all clipped paths and masks within a single group4071 // Collect all clipped paths and masks within a single group
4069 Inkscape::XML::Node *copy = child->getRepr()->duplicate(xml_doc);4072 Inkscape::XML::Node *copy = child->getRepr()->duplicate(xml_doc);
4070 if(copy->attribute("inkscape:original-d") && copy->attribute("inkscape:path-effect"))4073 if (copy->attribute("inkscape:original-d") && copy->attribute("inkscape:path-effect")) {
4071 {
4072 copy->setAttribute("d", copy->attribute("inkscape:original-d"));4074 copy->setAttribute("d", copy->attribute("inkscape:original-d"));
4073 }4075 }
4074 items_to_move = g_slist_prepend(items_to_move, copy);4076 items_to_move = g_slist_prepend(items_to_move, copy);
@@ -4104,13 +4106,13 @@
4104 }4106 }
41054107
4106 // ungroup marked groups added when setting mask4108 // ungroup marked groups added when setting mask
4107 for (GSList *i = items_to_ungroup ; NULL != i ; i = i->next) {4109 for (GSList *i = items_to_ungroup; NULL != i; i = i->next) {
4108 SPGroup *group = dynamic_cast<SPGroup *>(static_cast<SPObject *>(i->data));4110 SPGroup *group = dynamic_cast<SPGroup *>(static_cast<SPObject *>(i->data));
4109 if (group) {4111 if (group) {
4110 items_to_select.erase(remove(items_to_select.begin(), items_to_select.end(), group), items_to_select.end());4112 items_to_select.erase(remove(items_to_select.begin(), items_to_select.end(), group), items_to_select.end());
4111 std::vector<SPItem*> children;4113 std::vector<SPItem *> children;
4112 sp_item_group_ungroup(group, children, false);4114 sp_item_group_ungroup(group, children, false);
4113 items_to_select.insert(items_to_select.end(),children.rbegin(),children.rend());4115 items_to_select.insert(items_to_select.end(), children.rbegin(), children.rend());
4114 } else {4116 } else {
4115 g_assert_not_reached();4117 g_assert_not_reached();
4116 }4118 }
@@ -4133,8 +4135,7 @@
4133 * "fit-margin-..." attributes. See SPDocument::fitToRect.4135 * "fit-margin-..." attributes. See SPDocument::fitToRect.
4134 * \return true if an undoable change should be recorded.4136 * \return true if an undoable change should be recorded.
4135 */4137 */
4136bool4138bool fit_canvas_to_selection(SPDesktop *desktop, bool with_margins)
4137fit_canvas_to_selection(SPDesktop *desktop, bool with_margins)
4138{4139{
4139 g_return_val_if_fail(desktop != NULL, false);4140 g_return_val_if_fail(desktop != NULL, false);
4140 SPDocument *doc = desktop->getDocument();4141 SPDocument *doc = desktop->getDocument();
@@ -4158,12 +4159,10 @@
4158/**4159/**
4159 * Fit canvas to the bounding box of the selection, as an undoable action.4160 * Fit canvas to the bounding box of the selection, as an undoable action.
4160 */4161 */
4161void4162void verb_fit_canvas_to_selection(SPDesktop *const desktop)
4162verb_fit_canvas_to_selection(SPDesktop *const desktop)
4163{4163{
4164 if (fit_canvas_to_selection(desktop)) {4164 if (fit_canvas_to_selection(desktop)) {
4165 DocumentUndo::done(desktop->getDocument(), SP_VERB_FIT_CANVAS_TO_SELECTION,4165 DocumentUndo::done(desktop->getDocument(), SP_VERB_FIT_CANVAS_TO_SELECTION, _("Fit Page to Selection"));
4166 _("Fit Page to Selection"));
4167 }4166 }
4168}4167}
41694168
@@ -4171,8 +4170,7 @@
4171 * \param with_margins margins defined in the xml under <sodipodi:namedview>4170 * \param with_margins margins defined in the xml under <sodipodi:namedview>
4172 * "fit-margin-..." attributes. See SPDocument::fitToRect.4171 * "fit-margin-..." attributes. See SPDocument::fitToRect.
4173 */4172 */
4174bool4173bool fit_canvas_to_drawing(SPDocument *doc, bool with_margins)
4175fit_canvas_to_drawing(SPDocument *doc, bool with_margins)
4176{4174{
4177 g_return_val_if_fail(doc != NULL, false);4175 g_return_val_if_fail(doc != NULL, false);
41784176
@@ -4187,12 +4185,10 @@
4187 }4185 }
4188}4186}
41894187
4190void4188void verb_fit_canvas_to_drawing(SPDesktop *desktop)
4191verb_fit_canvas_to_drawing(SPDesktop *desktop)
4192{4189{
4193 if (fit_canvas_to_drawing(desktop->getDocument())) {4190 if (fit_canvas_to_drawing(desktop->getDocument())) {
4194 DocumentUndo::done(desktop->getDocument(), SP_VERB_FIT_CANVAS_TO_DRAWING,4191 DocumentUndo::done(desktop->getDocument(), SP_VERB_FIT_CANVAS_TO_DRAWING, _("Fit Page to Drawing"));
4195 _("Fit Page to Drawing"));
4196 }4192 }
4197}4193}
41984194
@@ -4201,23 +4197,24 @@
4201 * "fit-margin-..." attributes. See SPDocument::fitToRect and4197 * "fit-margin-..." attributes. See SPDocument::fitToRect and
4202 * ui/dialog/page-sizer.4198 * ui/dialog/page-sizer.
4203 */4199 */
4204void fit_canvas_to_selection_or_drawing(SPDesktop *desktop) {4200void fit_canvas_to_selection_or_drawing(SPDesktop *desktop)
4201{
4205 g_return_if_fail(desktop != NULL);4202 g_return_if_fail(desktop != NULL);
4206 SPDocument *doc = desktop->getDocument();4203 SPDocument *doc = desktop->getDocument();
42074204
4208 g_return_if_fail(doc != NULL);4205 g_return_if_fail(doc != NULL);
4209 g_return_if_fail(desktop->selection != NULL);4206 g_return_if_fail(desktop->selection != NULL);
42104207
4211 bool const changed = ( desktop->selection->isEmpty()4208 bool const changed =
4212 ? fit_canvas_to_drawing(doc, true)4209 (desktop->selection->isEmpty() ? fit_canvas_to_drawing(doc, true) : fit_canvas_to_selection(desktop, true));
4213 : fit_canvas_to_selection(desktop, true) );
4214 if (changed) {4210 if (changed) {
4215 DocumentUndo::done(desktop->getDocument(), SP_VERB_FIT_CANVAS_TO_SELECTION_OR_DRAWING,4211 DocumentUndo::done(desktop->getDocument(), SP_VERB_FIT_CANVAS_TO_SELECTION_OR_DRAWING,
4216 _("Fit Page to Selection or Drawing"));4212 _("Fit Page to Selection or Drawing"));
4217 }4213 }
4218};4214};
42194215
4220static void itemtree_map(void (*f)(SPItem *, SPDesktop *), SPObject *root, SPDesktop *desktop) {4216static void itemtree_map(void (*f)(SPItem *, SPDesktop *), SPObject *root, SPDesktop *desktop)
4217{
4221 // don't operate on layers4218 // don't operate on layers
4222 {4219 {
4223 SPItem *item = dynamic_cast<SPItem *>(root);4220 SPItem *item = dynamic_cast<SPItem *>(root);
@@ -4225,8 +4222,8 @@
4225 f(item, desktop);4222 f(item, desktop);
4226 }4223 }
4227 }4224 }
4228 for ( SPObject::SiblingIterator iter = root->firstChild() ; iter ; ++iter ) {4225 for (SPObject::SiblingIterator iter = root->firstChild(); iter; ++iter) {
4229 //don't recurse into locked layers4226 // don't recurse into locked layers
4230 SPItem *item = dynamic_cast<SPItem *>(&*iter);4227 SPItem *item = dynamic_cast<SPItem *>(&*iter);
4231 if (!(item && desktop->isLayer(item) && item->isLocked())) {4228 if (!(item && desktop->isLayer(item) && item->isLocked())) {
4232 itemtree_map(f, iter, desktop);4229 itemtree_map(f, iter, desktop);
@@ -4234,20 +4231,24 @@
4234 }4231 }
4235}4232}
42364233
4237static void unlock(SPItem *item, SPDesktop */*desktop*/) {4234static void unlock(SPItem *item, SPDesktop * /*desktop*/)
4235{
4238 if (item->isLocked()) {4236 if (item->isLocked()) {
4239 item->setLocked(FALSE);4237 item->setLocked(FALSE);
4240 }4238 }
4241}4239}
42424240
4243static void unhide(SPItem *item, SPDesktop *desktop) {4241static void unhide(SPItem *item, SPDesktop *desktop)
4242{
4244 if (desktop->itemIsHidden(item)) {4243 if (desktop->itemIsHidden(item)) {
4245 item->setExplicitlyHidden(FALSE);4244 item->setExplicitlyHidden(FALSE);
4246 }4245 }
4247}4246}
42484247
4249static void process_all(void (*f)(SPItem *, SPDesktop *), SPDesktop *dt, bool layer_only) {4248static void process_all(void (*f)(SPItem *, SPDesktop *), SPDesktop *dt, bool layer_only)
4250 if (!dt) return;4249{
4250 if (!dt)
4251 return;
42514252
4252 SPObject *root;4253 SPObject *root;
4253 if (layer_only) {4254 if (layer_only) {
@@ -4259,21 +4260,13 @@
4259 itemtree_map(f, root, dt);4260 itemtree_map(f, root, dt);
4260}4261}
42614262
4262void unlock_all(SPDesktop *dt) {4263void unlock_all(SPDesktop *dt) { process_all(&unlock, dt, true); }
4263 process_all(&unlock, dt, true);4264
4264}4265void unlock_all_in_all_layers(SPDesktop *dt) { process_all(&unlock, dt, false); }
42654266
4266void unlock_all_in_all_layers(SPDesktop *dt) {4267void unhide_all(SPDesktop *dt) { process_all(&unhide, dt, true); }
4267 process_all(&unlock, dt, false);4268
4268}4269void unhide_all_in_all_layers(SPDesktop *dt) { process_all(&unhide, dt, false); }
4269
4270void unhide_all(SPDesktop *dt) {
4271 process_all(&unhide, dt, true);
4272}
4273
4274void unhide_all_in_all_layers(SPDesktop *dt) {
4275 process_all(&unhide, dt, false);
4276}
42774270
42784271
4279/*4272/*
42804273
=== modified file 'src/selection.cpp'
--- src/selection.cpp 2015-05-12 22:12:43 +0000
+++ src/selection.cpp 2015-09-02 11:21:15 +0000
@@ -30,6 +30,7 @@
3030
31#include "sp-shape.h"31#include "sp-shape.h"
32#include "sp-path.h"32#include "sp-path.h"
33#include "sp-root.h"
33#include "sp-item-group.h"34#include "sp-item-group.h"
34#include "box3d.h"35#include "box3d.h"
35#include "box3d.h"36#include "box3d.h"
@@ -151,6 +152,12 @@
151 return ( _objs_set.find(obj)!=_objs_set.end() );152 return ( _objs_set.find(obj)!=_objs_set.end() );
152}153}
153154
155bool Selection::includes_deeply(SPObject *obj) const{
156 if(!obj || dynamic_cast<SPRoot*>(obj)){return false;}
157 return (includes(obj) || includes_deeply(obj->parent));
158}
159
160
154void Selection::add(SPObject *obj, bool persist_selection_context/* = false */) {161void Selection::add(SPObject *obj, bool persist_selection_context/* = false */) {
155 g_return_if_fail(obj != NULL);162 g_return_if_fail(obj != NULL);
156 g_return_if_fail(SP_IS_OBJECT(obj));163 g_return_if_fail(SP_IS_OBJECT(obj));
157164
=== modified file 'src/selection.h'
--- src/selection.h 2015-04-29 22:29:17 +0000
+++ src/selection.h 2015-09-02 11:21:15 +0000
@@ -209,6 +209,16 @@
209 }209 }
210210
211 /**211 /**
212 * Returns true if the given item is descendant of a selected item.
213 */
214 bool includes_deeply(SPObject *obj) const;
215 bool includes_deeply(XML::Node *repr) const {
216 return includes_deeply(_objectForXMLNode(repr));
217 }
218
219
220
221 /**
212 * Returns a single selected object.222 * Returns a single selected object.
213 *223 *
214 * @return NULL unless exactly one object is selected224 * @return NULL unless exactly one object is selected