Code

Merge from fe-moved
[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 <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 };
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 :