Code

34de82c7ce7df69d7c3dbe0776edb73df2d3580b
[inkscape.git] / src / selection.h
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 selection 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::Maybe<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::Maybe<NR::Rect> boundsInDocument() const;
252     /**
253      * @brief Returns the rotation/skew center of the selection
254      */
255     NR::Maybe<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      * @brief Connects a slot to be notified of selection changes
271      *
272      * This method connects the given slot such that it will
273      * be called upon any change in the set of selected objects.
274      *
275      * @param slot the slot to connect
276      *
277      * @return the resulting connection
278      */
279     sigc::connection connectChanged(sigc::slot<void, Selection *> const &slot) {
280         return _changed_signal.connect(slot);
281     }
283     /**
284      * @brief Connects a slot to be notified of selected 
285      *        object modifications 
286      *
287      * This method connects the given slot such that it will
288      * receive notifications whenever any selected item is
289      * modified.
290      *
291      * @param slot the slot to connect
292      *
293      * @return the resulting connection
294      *
295      */
296     sigc::connection connectModified(sigc::slot<void, Selection *, guint> const &slot)
297     {
298         return _modified_signal.connect(slot);
299     }
301 private:
302     /** @brief no copy */
303     Selection(Selection const &);
304     /** @brief no assign */
305     void operator=(Selection const &);
307     /** @brief Issues modification notification signals */
308     static gboolean _emit_modified(Selection *selection);
309     /** @brief Schedules an item modification signal to be sent */
310     void _schedule_modified(SPObject *obj, guint flags);
312     /** @brief Issues modified selection signal */
313     void _emitModified(guint flags);
314     /** @brief Issues changed selection signal */
315     void _emitChanged(bool persist_selection_context = false);
317     void _invalidateCachedLists();
319     /** @brief unselect all descendants of the given item */
320     void _removeObjectDescendants(SPObject *obj);
321     /** @brief unselect all ancestors of the given item */
322     void _removeObjectAncestors(SPObject *obj);
323     /** @brief clears the selection (without issuing a notification) */
324     void _clear();
325     /** @brief adds an object (without issuing a notification) */
326     void _add(SPObject *obj);
327     /** @brief removes an object (without issuing a notification) */
328     void _remove(SPObject *obj);
329     /** @brief returns the SPObject corresponding to an xml node (if any) */
330     SPObject *_objectForXMLNode(XML::Node *repr) const;
331     /** @brief Releases an active layer object that is being removed */
332     void _releaseContext(SPObject *obj);
334     mutable GSList *_objs;
335     mutable GSList *_reprs;
336     mutable GSList *_items;
338     GC::soft_ptr<SPDesktop> _desktop;
339     SPObject* _selection_context;
340     guint _flags;
341     guint _idle;
343     std::map<SPObject *, sigc::connection> _modified_connections;
344     std::map<SPObject *, sigc::connection> _release_connections;
345     sigc::connection _context_release_connection;
347     sigc::signal<void, Selection *> _changed_signal;
348     sigc::signal<void, Selection *, guint> _modified_signal;
349 };
353 #endif
354 /*
355   Local Variables:
356   mode:c++
357   c-file-style:"stroustrup"
358   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
359   indent-tabs-mode:nil
360   fill-column:99
361   End:
362 */
363 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :