Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
object-set.h
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Multiindex container for selection
4 *
5 * Authors:
6 * Adrian Boguszewski
7 * Marc Jeanmougin
8 *
9 * Copyright (C) 2016 Adrian Boguszewski
10 *
11 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
12 */
13
14#ifndef INKSCAPE_PROTOTYPE_OBJECTSET_H
15#define INKSCAPE_PROTOTYPE_OBJECTSET_H
16
17#include <unordered_map>
18#include <vector>
19
20#include <boost/multi_index_container.hpp>
21#include <boost/multi_index/identity.hpp>
22#include <boost/multi_index/sequenced_index.hpp>
23#include <boost/multi_index/hashed_index.hpp>
24#include <boost/multi_index/random_access_index.hpp>
25#include <boost/range/adaptor/filtered.hpp>
26#include <boost/range/adaptor/transformed.hpp>
27#include <boost/range/sub_range.hpp>
28#include <boost/range/any_range.hpp>
29#include <boost/type_traits.hpp>
30#include <boost/utility/enable_if.hpp>
31
32#include <sigc++/connection.h>
33
34#include "sp-object.h"
35#include "sp-item.h"
36#include "sp-item-group.h"
37#include "livarot/LivarotDefs.h"
38
45enum class SiblingState {
46 SIBLING_NONE, // no relation to item
47 SIBLING_CLONE_ORIGINAL, // moving both a clone and its original or any ancestor
48 SIBLING_OFFSET_SOURCE, // moving both an offset and its source
49 SIBLING_TEXT_PATH, // moving both a text-on-path and its path
50 SIBLING_TEXT_FLOW_FRAME, // moving both a flowtext and its frame
51 SIBLING_TEXT_SHAPE_INSIDE, // moving object containing sub object
52};
53
54class SPDocument;
55class SPDesktop;
56
57class SPBox3D;
58class Persp3D;
59
60namespace Inkscape {
61
62namespace XML {
63class Node;
64}
65
66struct hashed{};
68
69namespace {
70
71inline constexpr auto object_to_node = [] (SPObject *obj) {
72 return obj->getRepr();
73};
74
75}
76
77typedef boost::multi_index_container<
78 SPObject*,
79 boost::multi_index::indexed_by<
80 boost::multi_index::sequenced<>,
81 boost::multi_index::random_access<
82 boost::multi_index::tag<random_access>>,
83 boost::multi_index::hashed_unique<
84 boost::multi_index::tag<hashed>,
85 boost::multi_index::identity<SPObject*>>
87
88typedef boost::any_range<
89 SPObject*,
90 boost::random_access_traversal_tag,
91 SPObject* const&,
92 std::ptrdiff_t> SPObjectRange;
93
94class ObjectSet {
95public:
97 using SPItemRange = decltype(MultiIndexContainer().get<random_access>() | boost::adaptors::filtered(is<SPItem>) | boost::adaptors::transformed(cast_unsafe<SPItem>));
98 using SPGroupRange = decltype(MultiIndexContainer().get<random_access>() | boost::adaptors::filtered(is<SPGroup>) | boost::adaptors::transformed(cast_unsafe<SPGroup>));
99 using XMLNodeRange = decltype(MultiIndexContainer().get<random_access>() | boost::adaptors::filtered(is<SPItem>) | boost::adaptors::transformed(object_to_node));
100
102 ObjectSet(SPDocument* doc): _desktop(nullptr), _document(doc) {};
103 ObjectSet(): _desktop(nullptr), _document(nullptr) {}; // Used in spray-tool.h.
104 virtual ~ObjectSet();
105
106 ObjectSet(ObjectSet const &) = delete;
107 ObjectSet &operator=(ObjectSet const &) = delete;
108
110 _document = doc;
111 }
112
113
120 bool add(SPObject *object, bool nosignal = false);
121
127 void add(XML::Node *repr);
128
133 template <typename InputIterator>
134 void add(InputIterator from, InputIterator to) {
135 for(auto it = from; it != to; ++it) {
136 _add(*it);
137 }
138 _emitChanged();
139 }
140
150 bool remove(SPObject* object);
151
155 bool includes(SPObject *object, bool anyAncestor = false);
156 bool includes(Inkscape::XML::Node *node, bool anyAncestor = false);
157
162
168 void set(SPObject *object, bool persist_selection_context = false);
169 void set(XML::Node *repr);
173 void clear();
174
178 int size();
179
183 bool isEmpty();
184
190 void toggle(SPObject *obj);
191
197 SPObject *single();
198
205
209 SPItem *firstItem() const;
210
214 SPItem *lastItem() const;
215
220
225
228
232 | boost::adaptors::filtered(is<SPItem>)
233 | boost::adaptors::transformed(cast_unsafe<SPItem>));
234 };
235
236 std::vector<SPItem*> items_vector() {
237 auto i = items();
238 return {i.begin(), i.end()};
239 }
240
244 | boost::adaptors::filtered(is<SPGroup>)
245 | boost::adaptors::transformed(cast_unsafe<SPGroup>));
246 }
247
251 | boost::adaptors::filtered(is<SPItem>)
252 | boost::adaptors::transformed(object_to_node));
253 }
254
261
265 XML::Node *topRepr() const;
266
272 template <class T>
273 typename boost::enable_if<boost::is_base_of<SPObject, T>, void>::type
274 setList(const std::vector<T*> &objs) {
275 _clear();
276 addList(objs);
277 }
278
286 void setReprList(std::vector<XML::Node*> const &list);
287
292 void enforceIds();
293
299 template <class T>
300 typename boost::enable_if<boost::is_base_of<SPObject, T>, void>::type
301 addList(const std::vector<T*> &objs) {
302 for (auto obj: objs) {
303 if (!includes(obj)) {
304 add(obj, true);
305 }
306 }
307 _emitChanged();
308 }
309
315 template <class T>
316 typename boost::enable_if<boost::is_base_of<SPObject, T>, void>::type
317 removeList(const std::vector<T*> &objs) {
318 for (auto obj: objs) {
319 remove(obj);
320 }
321 _emitChanged();
322 }
323
329
335
336 /* Returns the bounding rectangle of the selectionin document coordinates.*/
338
344
348 std::optional<Geom::Point> center() const;
349
352 std::list<Persp3D *> const perspList();
353
358 std::list<SPBox3D *> const box3DList(Persp3D *persp = nullptr);
359
366
373
374 //item groups operations
375 //in selection-chemistry.cpp
376 void deleteItems(bool skip_undo = false);
377 void duplicate(bool suppressDone = false, bool duplicateLayer = false);
378 void clone(bool skip_undo = false);
379
385 bool unlink(const bool skip_undo = false, const bool silent = false);
391 bool unlinkRecursive(const bool skip_undo = false, const bool force = false, const bool silent = false);
392 void removeLPESRecursive(bool keep_paths);
393 void relink();
394 void cloneOriginal();
395 void cloneOriginalPathLPE(bool allow_transforms = false, bool sync = false, bool skip_undo = false);
396 Inkscape::XML::Node* group(bool is_anchor = false);
397 void popFromGroup();
398 void ungroup(bool skip_undo = false);
399 void ungroup_all(bool skip_undo = false);
400
401 //z-order management
402 //in selection-chemistry.cpp
403 void stackUp(bool skip_undo = false);
404 void raise(bool skip_undo = false);
405 void raiseToTop(bool skip_undo = false);
406 void stackDown(bool skip_undo = false);
407 void lower(bool skip_undo = false);
408 void lowerToBottom(bool skip_undo = false);
409 void toNextLayer(bool skip_undo = false);
410 void toPrevLayer(bool skip_undo = false);
411 void toLayer(SPObject *layer);
412 void toLayer(SPObject *layer, Inkscape::XML::Node *after);
413
414 //clipboard management
415 //in selection-chemistry.cpp
416 void copy();
417 void cut();
418 void pasteStyle();
419 void pasteSize(bool apply_x, bool apply_y);
420 void pasteSizeSeparately(bool apply_x, bool apply_y);
421 void pastePathEffect();
422
423 //path operations
424 //in path-chemistry.cpp
425 void combine(bool skip_undo = false, bool silent = false);
426 void breakApart(bool skip_undo = false, bool overlapping = true, bool silent = false);
427 void toCurves(bool skip_undo = false, bool clonesjustunlink = false);
428 void toLPEItems();
429 void pathReverse();
430
431 // path operations
432 // in path/path-object-set.cpp
433 bool strokesToPaths(bool legacy = false, bool skip_undo = false);
434 bool simplifyPaths(bool skip_undo = false);
435
436 // Boolean operations
437 void pathUnion (bool skip_undo = false, bool silent = false);
438 void pathIntersect(bool skip_undo = false, bool silent = false);
439 void pathDiff (bool skip_undo = false, bool silent = false);
440 void pathSymDiff (bool skip_undo = false, bool silent = false);
441 void pathCut (bool skip_undo = false, bool silent = false);
442 void pathSlice (bool skip_undo = false, bool silent = false);
443
444 // Other path operations
445 // in selection-chemistry.cpp
446 void toMarker(bool apply = true);
447 void toGuides();
448 void toSymbol();
449 void unSymbol();
450 void tile(bool apply = true); //"Object to Pattern"
451 void untile();
452 void createBitmapCopy();
453 void setMask(bool apply_clip_path, bool apply_to_layer, bool remove_original);
454 void editMask(bool clip);
455 void unsetMask(const bool apply_clip_path, const bool delete_helper_group, bool remove_original);
456 void setClipGroup();
457 void chameleonFill();
458
459 // moves
460 // in selection-chemistry.cpp
461 void removeLPE();
462 void removeFilter();
463 void reapplyAffine();
464 void clearLastAffine();
465 void applyAffine(Geom::Affine const &affine, bool set_i2d=true,bool compensate=true, bool adjust_transf_center=true);
467 void removeTransform();
468 void setScaleAbsolute(double, double, double, double);
469 void scaleRelative(const Geom::Point&, const Geom::Scale&);
470 void rotateRelative(const Geom::Point&, double);
471 void skewRelative(const Geom::Point&, double, double);
472 void moveRelative(const Geom::Point &move, bool compensate = true);
473 void moveRelative(double dx, double dy);
474 void move(double dx, double dy);
475 void moveScreen(double dx, double dy);
476 void move(double dx, double dy, bool rotated);
477 void move(double dx, double dy, bool rotated, bool screen);
478 void moveScreen(double dx, double dy, bool rotated);
479
480 // various
481 bool fitCanvas(bool with_margins, bool skip_undo = false);
482 void swapFillStroke();
483 void fillBetweenMany();
484
487 void clearSiblingStates();
488
489protected:
490 virtual void _connectSignals(SPObject* object) {};
491 virtual void _releaseSignals(SPObject* object) {};
492 virtual void _emitChanged(bool persist_selection_context = false);
493 void _add(SPObject* object);
494 void _clear();
495 void _remove(SPObject* object);
496 bool _anyAncestorIsInSet(SPObject *object);
498 void _removeAncestorsFromSet(SPObject *object);
499 SPItem *_sizeistItem(bool sml, CompareSize compare);
501 virtual void _add3DBoxesRecursively(SPObject *obj);
502 virtual void _remove3DBoxesRecursively(SPObject *obj);
503
505 SPDesktop * _desktop = nullptr;
507 std::list<SPBox3D *> _3dboxes;
508 std::unordered_map<SPObject*, sigc::connection> _releaseConnections;
509
510private:
511 void _pathBoolOp(BooleanOp bop, char const *icon_name, char const *description, bool skip_undo, bool silent);
512 void _pathBoolOp(BooleanOp bop);
513
514 void _disconnect(SPObject* object);
515 std::map<SPObject *, SiblingState> _sibling_state;
516
518};
519
523
524} // namespace Inkscape
525
526#endif // INKSCAPE_PROTOTYPE_OBJECTSET_H
527
528/*
529 Local Variables:
530 mode:c++
531 c-file-style:"stroustrup"
532 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
533 indent-tabs-mode:nil
534 fill-column:99
535 End:
536*/
537// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
TODO: insert short description here.
BooleanOp
Definition LivarotDefs.h:77
Geom::IntRect bounds
Definition canvas.cpp:182
3x3 matrix representing an affine transformation.
Definition affine.h:70
Axis-aligned rectangle that can be empty.
Definition rect.h:203
Two-dimensional point that doubles as a vector.
Definition point.h:66
Scaling from the origin.
Definition transforms.h:150
void enforceIds()
Assign IDs to selected objects that don't have an ID attribute Checks if the object's id attribute is...
SPItem * smallestItem(CompareSize compare)
Returns the smallest item from this selection.
void moveScreen(double dx, double dy)
SPObject * includesAncestor(SPObject *object)
Returns ancestor if the given object has ancestor selected.
void pasteSize(bool apply_x, bool apply_y)
void _remove(SPObject *object)
SPGroupRange groups()
Returns a range of selected groups.
Definition object-set.h:242
Inkscape::XML::Node * group(bool is_anchor=false)
void stackDown(bool skip_undo=false)
void pasteSizeSeparately(bool apply_x, bool apply_y)
SPItem * lastItem() const
Returns the last selected item, returns nullptr if no items selected.
SPDesktop * desktop()
Returns the desktop the selection is bound to.
Definition object-set.h:365
void toNextLayer(bool skip_undo=false)
bool remove(SPObject *object)
Removes an item from the set of selected objects.
bool unlink(const bool skip_undo=false, const bool silent=false)
Unlink all directly selected clones.
void breakApart(bool skip_undo=false, bool overlapping=true, bool silent=false)
void move(double dx, double dy)
SPItemRange items()
Returns a range of selected SPItems.
Definition object-set.h:230
void pathUnion(bool skip_undo=false, bool silent=false)
void removeLPESRecursive(bool keep_paths)
void _disconnect(SPObject *object)
void unsetMask(const bool apply_clip_path, const bool delete_helper_group, bool remove_original)
Geom::OptRect preferredBounds() const
Returns either the visual or geometric bounding rectangle of the selection, based on the preferences ...
void cloneOriginalPathLPE(bool allow_transforms=false, bool sync=false, bool skip_undo=false)
This applies the Fill Between Many LPE, and has it refer to the selection.
void rotateRelative(const Geom::Point &, double)
virtual void _remove3DBoxesRecursively(SPObject *obj)
void pathCut(bool skip_undo=false, bool silent=false)
bool add(SPObject *object, bool nosignal=false)
Add an SPObject to the set of selected objects.
boost::enable_if< boost::is_base_of< SPObject, T >, void >::type setList(const std::vector< T * > &objs)
Selects exactly the specified objects.
Definition object-set.h:274
XMLNodeRange xmlNodes()
Returns a range of the xml nodes of all selected objects.
Definition object-set.h:249
void raiseToTop(bool skip_undo=false)
void stackUp(bool skip_undo=false)
void setReprList(std::vector< XML::Node * > const &list)
Selects the objects with the same IDs as those in list.
void applyAffine(Geom::Affine const &affine, bool set_i2d=true, bool compensate=true, bool adjust_transf_center=true)
Apply matrix to the selection.
SPItem * largestItem(CompareSize compare)
Returns the largest item from this selection.
void add(InputIterator from, InputIterator to)
Add items from an STL iterator range to the selection.
Definition object-set.h:134
bool strokesToPaths(bool legacy=false, bool skip_undo=false)
Geom::OptRect documentPreferredBounds() const
Returns either the visual or geometric bounding rectangle of selection in document coordinates based ...
void pathDiff(bool skip_undo=false, bool silent=false)
std::list< SPBox3D * > _3dboxes
Definition object-set.h:507
SPDocument * _document
Definition object-set.h:506
void moveRelative(const Geom::Point &move, bool compensate=true)
Geom::Affine _last_affine
Definition object-set.h:517
void duplicate(bool suppressDone=false, bool duplicateLayer=false)
SPItem * _sizeistItem(bool sml, CompareSize compare)
void setDocument(SPDocument *doc)
Definition object-set.h:109
void pathIntersect(bool skip_undo=false, bool silent=false)
void toMarker(bool apply=true)
std::unordered_map< SPObject *, sigc::connection > _releaseConnections
Definition object-set.h:508
void pathSymDiff(bool skip_undo=false, bool silent=false)
void toPrevLayer(bool skip_undo=false)
void reapplyAffine()
Reapply the same transform again.
std::optional< Geom::Point > center() const
Returns the rotation/skew center of the selection.
void _add(SPObject *object)
Geom::OptRect strokedBounds() const
void clear()
Unselects all selected objects.
virtual void _emitChanged(bool persist_selection_context=false)
std::list< SPBox3D * > const box3DList(Persp3D *persp=nullptr)
Returns a list of all 3D boxes in the current selection which are associated to persp.
Geom::OptRect geometricBounds() const
virtual void _add3DBoxesRecursively(SPObject *obj)
decltype(MultiIndexContainer().get< random_access >()|boost::adaptors::filtered(is< SPItem >)|boost::adaptors::transformed(cast_unsafe< SPItem >)) SPItemRange
Definition object-set.h:97
virtual void _releaseSignals(SPObject *object)
Definition object-set.h:491
ObjectSet & operator=(ObjectSet const &)=delete
void ungroup_all(bool skip_undo=false)
Keep ungrouping until there are no more groups.
boost::enable_if< boost::is_base_of< SPObject, T >, void >::type addList(const std::vector< T * > &objs)
Adds the specified objects to selection, without deselecting first.
Definition object-set.h:301
void deleteItems(bool skip_undo=false)
SPObject * single()
Returns a single selected object.
decltype(MultiIndexContainer().get< random_access >()|boost::adaptors::filtered(is< SPGroup >)|boost::adaptors::transformed(cast_unsafe< SPGroup >)) SPGroupRange
Definition object-set.h:98
void ungroup(bool skip_undo=false)
void skewRelative(const Geom::Point &, double, double)
void toLPEItems()
Converts the selected items to LPEItems if they are not already so; e.g.
bool isEmpty()
Returns true if no items are selected.
void tile(bool apply=true)
std::map< SPObject *, SiblingState > _sibling_state
Definition object-set.h:515
Geom::OptRect documentBounds(SPItem::BBoxType type) const
int size()
Returns size of the selection.
SPDesktop * _desktop
Definition object-set.h:505
void scaleRelative(const Geom::Point &, const Geom::Scale &)
SPDocument * document()
Returns the document the selection is bound to.
Definition object-set.h:372
void _removeAncestorsFromSet(SPObject *object)
void raise(bool skip_undo=false)
bool _anyAncestorIsInSet(SPObject *object)
SPItem * firstItem() const
Returns the first selected item, returns nullptr if no items selected.
void toCurves(bool skip_undo=false, bool clonesjustunlink=false)
void combine(bool skip_undo=false, bool silent=false)
void lowerToBottom(bool skip_undo=false)
void lower(bool skip_undo=false)
void toggle(SPObject *obj)
Removes an item if selected, adds otherwise.
void _removeDescendantsFromSet(SPObject *object)
bool includes(SPObject *object, bool anyAncestor=false)
Returns true if the given object is selected.
SPItem * singleItem()
Returns a single selected item.
void setScaleAbsolute(double, double, double, double)
bool unlinkRecursive(const bool skip_undo=false, const bool force=false, const bool silent=false)
Recursively unlink any clones present in the current selection, including clones which are used to cl...
ObjectSet(SPDocument *doc)
Definition object-set.h:102
SPObjectRange objects()
Returns the list of selected objects.
void insertSiblingState(SPObject *object, SiblingState state)
decltype(MultiIndexContainer().get< random_access >()|boost::adaptors::filtered(is< SPItem >)|boost::adaptors::transformed(object_to_node)) XMLNodeRange
Definition object-set.h:99
virtual void _connectSignals(SPObject *object)
Definition object-set.h:490
void clone(bool skip_undo=false)
void toLayer(SPObject *layer)
Move selection to group moveto, after the last child of moveto (if it has any children).
void setMask(bool apply_clip_path, bool apply_to_layer, bool remove_original)
Creates a mask or clipPath from selection.
XML::Node * singleRepr()
Returns a single selected object's xml node.
bool simplifyPaths(bool skip_undo=false)
std::vector< SPItem * > items_vector()
Definition object-set.h:236
bool fitCanvas(bool with_margins, bool skip_undo=false)
XML::Node * topRepr() const
The top-most item, or NULL if the selection is empty.
MultiIndexContainer _container
Definition object-set.h:504
void _pathBoolOp(BooleanOp bop, char const *icon_name, char const *description, bool skip_undo, bool silent)
Geom::OptRect visualBounds() const
void pathSlice(bool skip_undo=false, bool silent=false)
boost::enable_if< boost::is_base_of< SPObject, T >, void >::type removeList(const std::vector< T * > &objs)
Remove the specified objects from selection.
Definition object-set.h:317
SPObject * _getMutualAncestor(SPObject *object)
std::list< Persp3D * > const perspList()
Returns a list of all perspectives which have a 3D box in the current selection.
ObjectSet(ObjectSet const &)=delete
void fillBetweenMany()
Creates a linked fill between all the objects in the current selection using the "Fill Between Many" ...
SiblingState getSiblingState(SPItem *item)
Associates the given SPItem with a SiblingState enum Needed for handling special cases while transfor...
Interface for refcounted XML nodes.
Definition node.h:80
To do: update description of desktop.
Definition desktop.h:149
Typed SVG document implementation.
Definition document.h:101
Base class for visual SVG elements.
Definition sp-item.h:109
SPObject is an abstract base class of all of the document nodes at the SVG document level.
Definition sp-object.h:160
SPItem * item
Inkscape::XML::Node * node
Helper class to stream background task notifications as a series of messages.
boost::multi_index_container< SPObject *, boost::multi_index::indexed_by< boost::multi_index::sequenced<>, boost::multi_index::random_access< boost::multi_index::tag< random_access > >, boost::multi_index::hashed_unique< boost::multi_index::tag< hashed >, boost::multi_index::identity< SPObject * > > > > MultiIndexContainer
Definition object-set.h:86
ObjectSet::SPGroupRange SPGroupRange
Definition object-set.h:521
ObjectSet::XMLNodeRange XMLNodeRange
Definition object-set.h:522
ObjectSet::SPItemRange SPItemRange
Definition object-set.h:520
boost::any_range< SPObject *, boost::random_access_traversal_tag, SPObject *const &, std::ptrdiff_t > SPObjectRange
Definition object-set.h:92
static T clip(T const &v, T const &a, T const &b)
SiblingState
SiblingState enums are used to associate the current state while grabbing objects.
Definition object-set.h:45
@ SIBLING_CLONE_ORIGINAL
@ SIBLING_TEXT_SHAPE_INSIDE
@ SIBLING_TEXT_FLOW_FRAME
GLsync sync
Some things pertinent to all visible shapes: SPItem, SPItemView, SPItemCtx.