1 #ifndef SEEN_INKSCAPE_SELECTION_H
2 #define SEEN_INKSCAPE_SELECTION_H
4 /** \file
5 * Inkscape::Selection: per-desktop selection container
6 *
7 * Authors:
8 * Lauris Kaplinski <lauris@kaplinski.com>
9 * MenTaLguY <mental@rydia.net>
10 * bulia byak <buliabyak@users.sf.net>
11 *
12 * Copyright (C) 2004-2005 MenTaLguY
13 * Copyright (C) 1999-2002 Lauris Kaplinski
14 * Copyright (C) 2001-2002 Ximian, Inc.
15 *
16 * Released under GNU GPL, read the file 'COPYING' for more information
17 */
19 #include <vector>
20 #include <map>
21 #include <list>
22 #include <sigc++/sigc++.h>
24 //#include "libnr/nr-rect.h"
25 #include "libnr/nr-convex-hull.h"
26 #include "forward.h"
27 #include "gc-managed.h"
28 #include "gc-finalized.h"
29 #include "gc-anchored.h"
30 #include "gc-soft-ptr.h"
31 #include "util/list.h"
32 #include "sp-item.h"
33 #include "snapped-point.h"
35 class SPItem;
36 class SPBox3D;
37 class Persp3D;
39 namespace Inkscape {
40 namespace XML {
41 class Node;
42 }
43 }
45 namespace Inkscape {
47 /**
48 * @brief The set of selected SPObjects for a given desktop.
49 *
50 * This class represents the set of selected SPItems for a given
51 * SPDesktop.
52 *
53 * An SPObject and its parent cannot be simultaneously selected;
54 * selecting an SPObjects has the side-effect of unselecting any of
55 * its children which might have been selected.
56 *
57 * This is a per-desktop object that keeps the list of selected objects
58 * at the given desktop. Both SPItem and SPRepr lists can be retrieved
59 * from the selection. Many actions operate on the selection, so it is
60 * widely used throughout the code.
61 * It also implements its own asynchronous notification signals that
62 * UI elements can listen to.
63 */
64 class Selection : public Inkscape::GC::Managed<>,
65 public Inkscape::GC::Finalized,
66 public Inkscape::GC::Anchored
67 {
68 public:
69 /**
70 * Constructs an selection object, bound to a particular
71 * SPDesktop
72 *
73 * @param desktop the desktop in question
74 */
75 Selection(SPDesktop *desktop);
76 ~Selection();
78 /**
79 * @brief Returns the desktop the selection is bound to
80 *
81 * @return the desktop the selection is bound to
82 */
83 SPDesktop *desktop() { return _desktop; }
85 /**
86 * @brief Returns active layer for selection (currentLayer or its parent)
87 *
88 * @return layer item the selection is bound to
89 */
90 SPObject *activeContext();
92 /**
93 * @brief Add an SPObject to the set of selected objects
94 *
95 * @param obj the SPObject to add
96 */
97 void add(SPObject *obj, bool persist_selection_context = false);
99 /**
100 * @brief Add an XML node's SPObject to the set of selected objects
101 *
102 * @param the xml node of the item to add
103 */
104 void add(XML::Node *repr) { add(_objectForXMLNode(repr)); }
106 /**
107 * @brief Set the selection to a single specific object
108 *
109 * @param obj the object to select
110 */
111 void set(SPObject *obj, bool persist_selection_context = false);
113 /**
114 * @brief Set the selection to an XML node's SPObject
115 *
116 * @param repr the xml node of the item to select
117 */
118 void set(XML::Node *repr) { set(_objectForXMLNode(repr)); }
120 /**
121 * @brief Removes an item from the set of selected objects
122 *
123 * It is ok to call this method for an unselected item.
124 *
125 * @param item the item to unselect
126 */
127 void remove(SPObject *obj);
129 /**
130 * @brief Removes an item if selected, adds otherwise
131 *
132 * @param item the item to unselect
133 */
134 void toggle(SPObject *obj);
136 /**
137 * @brief Removes an item from the set of selected objects
138 *
139 * It is ok to call this method for an unselected item.
140 *
141 * @param repr the xml node of the item to remove
142 */
143 void remove(XML::Node *repr) { remove(_objectForXMLNode(repr)); }
145 /**
146 * @brief Selects exactly the specified objects
147 *
148 * @param objs the objects to select
149 */
150 void setList(GSList const *objs);
152 /**
153 * @brief Adds the specified objects to selection, without deselecting first
154 *
155 * @param objs the objects to select
156 */
157 void addList(GSList const *objs);
159 /**
160 * @brief Clears the selection and selects the specified objects
161 *
162 * @param repr a list of xml nodes for the items to select
163 */
164 void setReprList(GSList const *reprs);
166 /** \brief Add items from an STL iterator range to the selection
167 * \param from the begin iterator
168 * \param to the end iterator
169 */
170 template <typename InputIterator>
171 void add(InputIterator from, InputIterator to) {
172 _invalidateCachedLists();
173 while ( from != to ) {
174 _add(*from);
175 ++from;
176 }
177 _emitChanged();
178 }
180 /**
181 * @brief Unselects all selected objects.
182 */
183 void clear();
185 /**
186 * @brief Returns true if no items are selected
187 */
188 bool isEmpty() const { return _objs == NULL; }
190 /**
191 * @brief Returns true if the given object is selected
192 */
193 bool includes(SPObject *obj) const;
195 /**
196 * @brief Returns true if the given item is selected
197 */
198 bool includes(XML::Node *repr) const {
199 return includes(_objectForXMLNode(repr));
200 }
202 /**
203 * @brief Returns a single selected object
204 *
205 * @return NULL unless exactly one object is selected
206 */
207 SPObject *single();
209 /**
210 * @brief Returns a single selected item
211 *
212 * @return NULL unless exactly one object is selected
213 */
214 SPItem *singleItem();
216 /**
217 * @brief Returns a single selected object's xml node
218 *
219 * @return NULL unless exactly one object is selected
220 */
221 XML::Node *singleRepr();
223 /** @brief Returns the list of selected objects */
224 GSList const *list();
225 /** @brief Returns the list of selected SPItems */
226 GSList const *itemList();
227 /** @brief Returns a list of the xml nodes of all selected objects */
228 /// \todo only returns reprs of SPItems currently; need a separate
229 /// method for that
230 GSList const *reprList();
232 /** @brief Returns a list of all perspectives which have a 3D box in the current selection
233 (these may also be nested in groups) */
234 std::list<Persp3D *> const perspList();
236 /** @brief Returns a list of all 3D boxes in the current selection which are associated to @c
237 persp. If @c pers is @c NULL, return all selected boxes.
238 */
239 std::list<SPBox3D *> const box3DList(Persp3D *persp = NULL);
241 /** @brief Returns the number of layers in which there are selected objects */
242 guint numberOfLayers();
244 /** @brief Returns the number of parents to which the selected objects belong */
245 guint numberOfParents();
247 /** @brief Returns the bounding rectangle of the selection */
248 NRRect *bounds(NRRect *dest, SPItem::BBoxType type = SPItem::APPROXIMATE_BBOX) const;
249 /** @brief Returns the bounding rectangle of the selection */
250 Geom::OptRect bounds(SPItem::BBoxType type = SPItem::APPROXIMATE_BBOX) const;
252 /**
253 * @brief Returns the bounding rectangle of the selection
254 *
255 * Gives the coordinates in internal format, does not match onscreen guides.
256 * (0,0 is the upper left corner, not the lower left corner)
257 */
258 NRRect *boundsInDocument(NRRect *dest, SPItem::BBoxType type = SPItem::APPROXIMATE_BBOX) const;
260 /**
261 * @brief Returns the bounding rectangle of the selection
262 *
263 * Gives the coordinates in internal format, does not match onscreen guides.
264 * (0,0 is the upper left corner, not the lower left corner)
265 */
266 Geom::OptRect boundsInDocument(SPItem::BBoxType type = SPItem::APPROXIMATE_BBOX) const;
268 /**
269 * @brief Returns the rotation/skew center of the selection
270 */
271 boost::optional<Geom::Point> center() const;
273 /**
274 * @brief Gets the selection's snap points.
275 * @return Selection's snap points
276 */
277 std::vector<Inkscape::SnapCandidatePoint> getSnapPoints(SnapPreferences const *snapprefs) const;
279 /**
280 * @brief Gets the snap points of a selection that form a convex hull.
281 * @return Selection's convex hull points
282 */
283 std::vector<Inkscape::SnapCandidatePoint> getSnapPointsConvexHull(SnapPreferences const *snapprefs) const;
285 /**
286 * @brief Connects a slot to be notified of selection changes
287 *
288 * This method connects the given slot such that it will
289 * be called upon any change in the set of selected objects.
290 *
291 * @param slot the slot to connect
292 *
293 * @return the resulting connection
294 */
295 sigc::connection connectChanged(sigc::slot<void, Selection *> const &slot) {
296 return _changed_signal.connect(slot);
297 }
299 /**
300 * @brief Connects a slot to be notified of selected
301 * object modifications
302 *
303 * This method connects the given slot such that it will
304 * receive notifications whenever any selected item is
305 * modified.
306 *
307 * @param slot the slot to connect
308 *
309 * @return the resulting connection
310 *
311 */
312 sigc::connection connectModified(sigc::slot<void, Selection *, guint> const &slot)
313 {
314 return _modified_signal.connect(slot);
315 }
317 private:
318 /** @brief no copy */
319 Selection(Selection const &);
320 /** @brief no assign */
321 void operator=(Selection const &);
323 /** @brief Issues modification notification signals */
324 static gboolean _emit_modified(Selection *selection);
325 /** @brief Schedules an item modification signal to be sent */
326 void _schedule_modified(SPObject *obj, guint flags);
328 /** @brief Issues modified selection signal */
329 void _emitModified(guint flags);
330 /** @brief Issues changed selection signal */
331 void _emitChanged(bool persist_selection_context = false);
333 void _invalidateCachedLists();
335 /** @brief unselect all descendants of the given item */
336 void _removeObjectDescendants(SPObject *obj);
337 /** @brief unselect all ancestors of the given item */
338 void _removeObjectAncestors(SPObject *obj);
339 /** @brief clears the selection (without issuing a notification) */
340 void _clear();
341 /** @brief adds an object (without issuing a notification) */
342 void _add(SPObject *obj);
343 /** @brief removes an object (without issuing a notification) */
344 void _remove(SPObject *obj);
345 /** @brief returns the SPObject corresponding to an xml node (if any) */
346 SPObject *_objectForXMLNode(XML::Node *repr) const;
347 /** @brief Releases an active layer object that is being removed */
348 void _releaseContext(SPObject *obj);
350 mutable GSList *_objs;
351 mutable GSList *_reprs;
352 mutable GSList *_items;
354 void add_box_perspective(SPBox3D *box);
355 void add_3D_boxes_recursively(SPObject *obj);
356 void remove_box_perspective(SPBox3D *box);
357 void remove_3D_boxes_recursively(SPObject *obj);
359 std::list<SPBox3D *> _3dboxes;
361 GC::soft_ptr<SPDesktop> _desktop;
362 SPObject* _selection_context;
363 guint _flags;
364 guint _idle;
366 std::map<SPObject *, sigc::connection> _modified_connections;
367 std::map<SPObject *, sigc::connection> _release_connections;
368 sigc::connection _context_release_connection;
370 sigc::signal<void, Selection *> _changed_signal;
371 sigc::signal<void, Selection *, guint> _modified_signal;
372 };
374 }
376 #endif
377 /*
378 Local Variables:
379 mode:c++
380 c-file-style:"stroustrup"
381 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
382 indent-tabs-mode:nil
383 fill-column:99
384 End:
385 */
386 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :