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