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 <sigc++/sigc++.h>
23 #include "libnr/nr-rect.h"
24 #include "libnr/nr-convex-hull.h"
25 #include "forward.h"
26 #include "gc-managed.h"
27 #include "gc-finalized.h"
28 #include "gc-anchored.h"
29 #include "gc-soft-ptr.h"
30 #include "util/list.h"
32 class SPItem;
34 namespace Inkscape {
35 namespace XML {
36 class Node;
37 }
38 }
40 namespace Inkscape {
42 /**
43 * @brief The set of selected SPObjects for a given desktop.
44 *
45 * This class represents the set of selected SPItems for a given
46 * SPDesktop.
47 *
48 * An SPObject and its parent cannot be simultaneously selected;
49 * selecting an SPObjects has the side-effect of unselecting any of
50 * its children which might have been selected.
51 *
52 * This is a per-desktop object that keeps the list of selected objects
53 * at the given desktop. Both SPItem and SPRepr lists can be retrieved
54 * from the selection. Many actions operate on the selection, so it is
55 * widely used throughout the code.
56 * It also implements its own asynchronous notification signals that
57 * UI elements can listen to.
58 */
59 class Selection : public Inkscape::GC::Managed<>,
60 public Inkscape::GC::Finalized,
61 public Inkscape::GC::Anchored
62 {
63 public:
64 /**
65 * Constructs an selection object, bound to a particular
66 * SPDesktop
67 *
68 * @param desktop the desktop in question
69 */
70 Selection(SPDesktop *desktop);
71 ~Selection();
73 /**
74 * @brief Returns the desktop the seoection is bound to
75 *
76 * @return the desktop the selection is bound to
77 */
78 SPDesktop *desktop() { return _desktop; }
80 /**
81 * @brief Returns active layer for selection (currentLayer or its parent)
82 *
83 * @return layer item the selection is bound to
84 */
85 SPObject *activeContext();
87 /**
88 * @brief Add an SPObject to the set of selected objects
89 *
90 * @param obj the SPObject to add
91 */
92 void add(SPObject *obj, bool persist_selection_context = false);
94 /**
95 * @brief Add an XML node's SPObject to the set of selected objects
96 *
97 * @param the xml node of the item to add
98 */
99 void add(XML::Node *repr) { add(_objectForXMLNode(repr)); }
101 /**
102 * @brief Set the selection to a single specific object
103 *
104 * @param obj the object to select
105 */
106 void set(SPObject *obj, bool persist_selection_context = false);
108 /**
109 * @brief Set the selection to an XML node's SPObject
110 *
111 * @param repr the xml node of the item to select
112 */
113 void set(XML::Node *repr) { set(_objectForXMLNode(repr)); }
115 /**
116 * @brief Removes an item from the set of selected objects
117 *
118 * It is ok to call this method for an unselected item.
119 *
120 * @param item the item to unselect
121 */
122 void remove(SPObject *obj);
124 /**
125 * @brief Removes an item if selected, adds otherwise
126 *
127 * @param item the item to unselect
128 */
129 void toggle(SPObject *obj);
131 /**
132 * @brief Removes an item from the set of selected objects
133 *
134 * It is ok to call this method for an unselected item.
135 *
136 * @param repr the xml node of the item to remove
137 */
138 void remove(XML::Node *repr) { remove(_objectForXMLNode(repr)); }
140 /**
141 * @brief Selects exactly the specified objects
142 *
143 * @param objs the objects to select
144 */
145 void setList(GSList const *objs);
147 /**
148 * @brief Adds the specified objects to selection, without deselecting first
149 *
150 * @param objs the objects to select
151 */
152 void addList(GSList const *objs);
154 /**
155 * @brief Clears the selection and selects the specified objects
156 *
157 * @param repr a list of xml nodes for the items to select
158 */
159 void setReprList(GSList const *reprs);
161 /** \brief Add items from an STL iterator range to the selection
162 * \param from the begin iterator
163 * \param to the end iterator
164 */
165 template <typename InputIterator>
166 void add(InputIterator from, InputIterator to) {
167 _invalidateCachedLists();
168 while ( from != to ) {
169 _add(*from);
170 ++from;
171 }
172 _emitChanged();
173 }
175 /**
176 * @brief Unselects all selected objects.
177 */
178 void clear();
180 /**
181 * @brief Returns true if no items are selected
182 */
183 bool isEmpty() const { return _objs == NULL; }
185 /**
186 * @brief Returns true if the given object is selected
187 */
188 bool includes(SPObject *obj) const;
190 /**
191 * @brief Returns true if the given item is selected
192 */
193 bool includes(XML::Node *repr) const {
194 return includes(_objectForXMLNode(repr));
195 }
197 /**
198 * @brief Returns a single selected object
199 *
200 * @return NULL unless exactly one object is selected
201 */
202 SPObject *single();
204 /**
205 * @brief Returns a single selected item
206 *
207 * @return NULL unless exactly one object is selected
208 */
209 SPItem *singleItem();
211 /**
212 * @brief Returns a single selected object's xml node
213 *
214 * @return NULL unless exactly one object is selected
215 */
216 XML::Node *singleRepr();
218 /** @brief Returns the list of selected objects */
219 GSList const *list();
220 /** @brief Returns the list of selected SPItems */
221 GSList const *itemList();
222 /** @brief Returns a list of the xml nodes of all selected objects */
223 /// \todo only returns reprs of SPItems currently; need a separate
224 /// method for that
225 GSList const *reprList();
227 /** @brief Returns the number of layers in which there are selected objects */
228 guint numberOfLayers();
230 /** @brief Returns the number of parents to which the selected objects belong */
231 guint numberOfParents();
233 /** @brief Returns the bounding rectangle of the selection */
234 NRRect *bounds(NRRect *dest) const;
235 /** @brief Returns the bounding rectangle of the selection */
236 ::NR::Rect bounds() const;
238 /**
239 * @brief Returns the bounding rectangle of the selection
240 *
241 * \todo how is this different from bounds()?
242 */
243 NRRect *boundsInDocument(NRRect *dest) const;
245 /**
246 * @brief Returns the bounding rectangle of the selection
247 *
248 * \todo how is this different from bounds()?
249 */
250 ::NR::Rect boundsInDocument() const;
252 /**
253 * @brief Returns the rotation/skew center of the selection
254 */
255 ::NR::Point center() const;
257 /**
258 * @brief Gets the selection's snap points.
259 * @return Selection's snap points
260 */
261 std::vector<NR::Point> getSnapPoints() const;
263 /**
264 * @brief Gets the snap points of a selection that form a convex hull.
265 * @return Selection's convex hull points
266 */
267 std::vector<NR::Point> getSnapPointsConvexHull() const;
269 /**
270 * @return A vector containing the top-left and bottom-right
271 * corners of each selected object's bounding box.
272 */
273 std::vector<NR::Point> getBBoxPoints() const;
275 /**
276 * @return A vector containing the 2 (top-left and bottom-right)
277 * corners of the selection bounding box.
278 */
279 std::vector<NR::Point> getBBoxPointsOuter() const;
281 /**
282 * @brief Connects a slot to be notified of selection changes
283 *
284 * This method connects the given slot such that it will
285 * be called upon any change in the set of selected objects.
286 *
287 * @param slot the slot to connect
288 *
289 * @return the resulting connection
290 */
291 sigc::connection connectChanged(sigc::slot<void, Selection *> const &slot) {
292 return _changed_signal.connect(slot);
293 }
295 /**
296 * @brief Connects a slot to be notified of selected
297 * object modifications
298 *
299 * This method connects the given slot such that it will
300 * receive notifications whenever any selected item is
301 * modified.
302 *
303 * @param slot the slot to connect
304 *
305 * @return the resulting connection
306 *
307 */
308 sigc::connection connectModified(sigc::slot<void, Selection *, guint> const &slot)
309 {
310 return _modified_signal.connect(slot);
311 }
313 private:
314 /** @brief no copy */
315 Selection(Selection const &);
316 /** @brief no assign */
317 void operator=(Selection const &);
319 /** @brief Issues modification notification signals */
320 static gboolean _emit_modified(Selection *selection);
321 /** @brief Schedules an item modification signal to be sent */
322 void _schedule_modified(SPObject *obj, guint flags);
324 /** @brief Issues modified selection signal */
325 void _emitModified(guint flags);
326 /** @brief Issues changed selection signal */
327 void _emitChanged(bool persist_selection_context = false);
329 void _invalidateCachedLists();
331 /** @brief unselect all descendants of the given item */
332 void _removeObjectDescendants(SPObject *obj);
333 /** @brief unselect all ancestors of the given item */
334 void _removeObjectAncestors(SPObject *obj);
335 /** @brief clears the selection (without issuing a notification) */
336 void _clear();
337 /** @brief adds an object (without issuing a notification) */
338 void _add(SPObject *obj);
339 /** @brief removes an object (without issuing a notification) */
340 void _remove(SPObject *obj);
341 /** @brief returns the SPObject corresponding to an xml node (if any) */
342 SPObject *_objectForXMLNode(XML::Node *repr) const;
343 /** @brief Releases an active layer object that is being removed */
344 void _releaseContext(SPObject *obj);
346 mutable GSList *_objs;
347 mutable GSList *_reprs;
348 mutable GSList *_items;
350 GC::soft_ptr<SPDesktop> _desktop;
351 SPObject* _selection_context;
352 guint _flags;
353 guint _idle;
355 std::map<SPObject *, sigc::connection> _modified_connections;
356 std::map<SPObject *, sigc::connection> _release_connections;
357 sigc::connection _context_release_connection;
359 sigc::signal<void, Selection *> _changed_signal;
360 sigc::signal<void, Selection *, guint> _modified_signal;
361 };
363 }
365 #endif
366 /*
367 Local Variables:
368 mode:c++
369 c-file-style:"stroustrup"
370 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
371 indent-tabs-mode:nil
372 fill-column:99
373 End:
374 */
375 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :