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"
34 class SPItem;
35 class SPBox3D;
36 class Persp3D;
38 namespace Inkscape {
39 namespace XML {
40 class Node;
41 }
42 }
44 namespace Inkscape {
46 /**
47 * @brief The set of selected SPObjects for a given desktop.
48 *
49 * This class represents the set of selected SPItems for a given
50 * SPDesktop.
51 *
52 * An SPObject and its parent cannot be simultaneously selected;
53 * selecting an SPObjects has the side-effect of unselecting any of
54 * its children which might have been selected.
55 *
56 * This is a per-desktop object that keeps the list of selected objects
57 * at the given desktop. Both SPItem and SPRepr lists can be retrieved
58 * from the selection. Many actions operate on the selection, so it is
59 * widely used throughout the code.
60 * It also implements its own asynchronous notification signals that
61 * UI elements can listen to.
62 */
63 class Selection : public Inkscape::GC::Managed<>,
64 public Inkscape::GC::Finalized,
65 public Inkscape::GC::Anchored
66 {
67 public:
68 /**
69 * Constructs an selection object, bound to a particular
70 * SPDesktop
71 *
72 * @param desktop the desktop in question
73 */
74 Selection(SPDesktop *desktop);
75 ~Selection();
77 /**
78 * @brief Returns the desktop the selection is bound to
79 *
80 * @return the desktop the selection is bound to
81 */
82 SPDesktop *desktop() { return _desktop; }
84 /**
85 * @brief Returns active layer for selection (currentLayer or its parent)
86 *
87 * @return layer item the selection is bound to
88 */
89 SPObject *activeContext();
91 /**
92 * @brief Add an SPObject to the set of selected objects
93 *
94 * @param obj the SPObject to add
95 */
96 void add(SPObject *obj, bool persist_selection_context = false);
98 /**
99 * @brief Add an XML node's SPObject to the set of selected objects
100 *
101 * @param the xml node of the item to add
102 */
103 void add(XML::Node *repr) { add(_objectForXMLNode(repr)); }
105 /**
106 * @brief Set the selection to a single specific object
107 *
108 * @param obj the object to select
109 */
110 void set(SPObject *obj, bool persist_selection_context = false);
112 /**
113 * @brief Set the selection to an XML node's SPObject
114 *
115 * @param repr the xml node of the item to select
116 */
117 void set(XML::Node *repr) { set(_objectForXMLNode(repr)); }
119 /**
120 * @brief Removes an item from the set of selected objects
121 *
122 * It is ok to call this method for an unselected item.
123 *
124 * @param item the item to unselect
125 */
126 void remove(SPObject *obj);
128 /**
129 * @brief Removes an item if selected, adds otherwise
130 *
131 * @param item the item to unselect
132 */
133 void toggle(SPObject *obj);
135 /**
136 * @brief Removes an item from the set of selected objects
137 *
138 * It is ok to call this method for an unselected item.
139 *
140 * @param repr the xml node of the item to remove
141 */
142 void remove(XML::Node *repr) { remove(_objectForXMLNode(repr)); }
144 /**
145 * @brief Selects exactly the specified objects
146 *
147 * @param objs the objects to select
148 */
149 void setList(GSList const *objs);
151 /**
152 * @brief Adds the specified objects to selection, without deselecting first
153 *
154 * @param objs the objects to select
155 */
156 void addList(GSList const *objs);
158 /**
159 * @brief Clears the selection and selects the specified objects
160 *
161 * @param repr a list of xml nodes for the items to select
162 */
163 void setReprList(GSList const *reprs);
165 /** \brief Add items from an STL iterator range to the selection
166 * \param from the begin iterator
167 * \param to the end iterator
168 */
169 template <typename InputIterator>
170 void add(InputIterator from, InputIterator to) {
171 _invalidateCachedLists();
172 while ( from != to ) {
173 _add(*from);
174 ++from;
175 }
176 _emitChanged();
177 }
179 /**
180 * @brief Unselects all selected objects.
181 */
182 void clear();
184 /**
185 * @brief Returns true if no items are selected
186 */
187 bool isEmpty() const { return _objs == NULL; }
189 /**
190 * @brief Returns true if the given object is selected
191 */
192 bool includes(SPObject *obj) const;
194 /**
195 * @brief Returns true if the given item is selected
196 */
197 bool includes(XML::Node *repr) const {
198 return includes(_objectForXMLNode(repr));
199 }
201 /**
202 * @brief Returns a single selected object
203 *
204 * @return NULL unless exactly one object is selected
205 */
206 SPObject *single();
208 /**
209 * @brief Returns a single selected item
210 *
211 * @return NULL unless exactly one object is selected
212 */
213 SPItem *singleItem();
215 /**
216 * @brief Returns a single selected object's xml node
217 *
218 * @return NULL unless exactly one object is selected
219 */
220 XML::Node *singleRepr();
222 /** @brief Returns the list of selected objects */
223 GSList const *list();
224 /** @brief Returns the list of selected SPItems */
225 GSList const *itemList();
226 /** @brief Returns a list of the xml nodes of all selected objects */
227 /// \todo only returns reprs of SPItems currently; need a separate
228 /// method for that
229 GSList const *reprList();
231 /* list of all perspectives which have a 3D box in the current selection
232 (these may also be nested in groups) */
233 std::list<Persp3D *> const perspList();
235 std::list<SPBox3D *> const box3DList();
237 /** @brief Returns the number of layers in which there are selected objects */
238 guint numberOfLayers();
240 /** @brief Returns the number of parents to which the selected objects belong */
241 guint numberOfParents();
243 /** @brief Returns the bounding rectangle of the selection */
244 NRRect *bounds(NRRect *dest, SPItem::BBoxType type = SPItem::APPROXIMATE_BBOX) const;
245 /** @brief Returns the bounding rectangle of the selection */
246 Geom::OptRect bounds(SPItem::BBoxType type = SPItem::APPROXIMATE_BBOX) const;
248 /**
249 * @brief Returns the bounding rectangle of the selection
250 *
251 * \todo how is this different from bounds()?
252 */
253 NRRect *boundsInDocument(NRRect *dest, SPItem::BBoxType type = SPItem::APPROXIMATE_BBOX) const;
255 /**
256 * @brief Returns the bounding rectangle of the selection
257 *
258 * \todo how is this different from bounds()?
259 */
260 Geom::OptRect boundsInDocument(SPItem::BBoxType type = SPItem::APPROXIMATE_BBOX) const;
262 /**
263 * @brief Returns the rotation/skew center of the selection
264 */
265 boost::optional<Geom::Point> center() const;
267 /**
268 * @brief Gets the selection's snap points.
269 * @return Selection's snap points
270 */
271 std::vector<Geom::Point> getSnapPoints(SnapPreferences const *snapprefs) const;
273 /**
274 * @brief Gets the snap points of a selection that form a convex hull.
275 * @return Selection's convex hull points
276 */
277 std::vector<Geom::Point> getSnapPointsConvexHull(SnapPreferences const *snapprefs) const;
279 /**
280 * @brief Connects a slot to be notified of selection changes
281 *
282 * This method connects the given slot such that it will
283 * be called upon any change in the set of selected objects.
284 *
285 * @param slot the slot to connect
286 *
287 * @return the resulting connection
288 */
289 sigc::connection connectChanged(sigc::slot<void, Selection *> const &slot) {
290 return _changed_signal.connect(slot);
291 }
293 /**
294 * @brief Connects a slot to be notified of selected
295 * object modifications
296 *
297 * This method connects the given slot such that it will
298 * receive notifications whenever any selected item is
299 * modified.
300 *
301 * @param slot the slot to connect
302 *
303 * @return the resulting connection
304 *
305 */
306 sigc::connection connectModified(sigc::slot<void, Selection *, guint> const &slot)
307 {
308 return _modified_signal.connect(slot);
309 }
311 private:
312 /** @brief no copy */
313 Selection(Selection const &);
314 /** @brief no assign */
315 void operator=(Selection const &);
317 /** @brief Issues modification notification signals */
318 static gboolean _emit_modified(Selection *selection);
319 /** @brief Schedules an item modification signal to be sent */
320 void _schedule_modified(SPObject *obj, guint flags);
322 /** @brief Issues modified selection signal */
323 void _emitModified(guint flags);
324 /** @brief Issues changed selection signal */
325 void _emitChanged(bool persist_selection_context = false);
327 void _invalidateCachedLists();
329 /** @brief unselect all descendants of the given item */
330 void _removeObjectDescendants(SPObject *obj);
331 /** @brief unselect all ancestors of the given item */
332 void _removeObjectAncestors(SPObject *obj);
333 /** @brief clears the selection (without issuing a notification) */
334 void _clear();
335 /** @brief adds an object (without issuing a notification) */
336 void _add(SPObject *obj);
337 /** @brief removes an object (without issuing a notification) */
338 void _remove(SPObject *obj);
339 /** @brief returns the SPObject corresponding to an xml node (if any) */
340 SPObject *_objectForXMLNode(XML::Node *repr) const;
341 /** @brief Releases an active layer object that is being removed */
342 void _releaseContext(SPObject *obj);
344 mutable GSList *_objs;
345 mutable GSList *_reprs;
346 mutable GSList *_items;
348 void add_box_perspective(SPBox3D *box);
349 void add_3D_boxes_recursively(SPObject *obj);
350 void remove_box_perspective(SPBox3D *box);
351 void remove_3D_boxes_recursively(SPObject *obj);
353 std::map<Persp3D *, unsigned int> _persps;
354 std::list<SPBox3D *> _3dboxes;
356 GC::soft_ptr<SPDesktop> _desktop;
357 SPObject* _selection_context;
358 guint _flags;
359 guint _idle;
361 std::map<SPObject *, sigc::connection> _modified_connections;
362 std::map<SPObject *, sigc::connection> _release_connections;
363 sigc::connection _context_release_connection;
365 sigc::signal<void, Selection *> _changed_signal;
366 sigc::signal<void, Selection *, guint> _modified_signal;
367 };
369 }
371 #endif
372 /*
373 Local Variables:
374 mode:c++
375 c-file-style:"stroustrup"
376 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
377 indent-tabs-mode:nil
378 fill-column:99
379 End:
380 */
381 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :