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