1 // SPDX-License-Identifier: GPL-2.0-or-later
2 #ifndef SEEN_INKSCAPE_SELECTION_H
3 #define SEEN_INKSCAPE_SELECTION_H
4 /*
5  * Authors:
6  *   Lauris Kaplinski <lauris@kaplinski.com>
7  *   MenTaLguY <mental@rydia.net>
8  *   bulia byak <buliabyak@users.sf.net>
9  *   Adrian Boguszewski
10  *
11  * Copyright (C) 2016 Adrian Boguszewski
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 v2+, read the file 'COPYING' for more information.
17  */
18 
19 #include <vector>
20 #include <map>
21 #include <cstddef>
22 #include <sigc++/sigc++.h>
23 
24 #include "inkgc/gc-managed.h"
25 #include "gc-finalized.h"
26 #include "gc-anchored.h"
27 #include "object/object-set.h"
28 
29 
30 namespace Inkscape {
31 class LayerModel;
32 namespace XML {
33 class Node;
34 }
35 }
36 
37 namespace Inkscape {
38 
39 /**
40  * The set of selected SPObjects for a given document and layer model.
41  *
42  * This class represents the set of selected SPItems for a given
43  * document (referenced in LayerModel).
44  *
45  * An SPObject and its parent cannot be simultaneously selected;
46  * selecting an SPObjects has the side-effect of unselecting any of
47  * its children which might have been selected.
48  *
49  * This is a per-desktop object that keeps the list of selected objects
50  * at the given desktop. Both SPItem and SPRepr lists can be retrieved
51  * from the selection. Many actions operate on the selection, so it is
52  * widely used throughout the code.
53  * It also implements its own asynchronous notification signals that
54  * UI elements can listen to.
55  */
56 class Selection : public Inkscape::GC::Managed<>,
57                   public Inkscape::GC::Finalized,
58                   public Inkscape::GC::Anchored,
59                   public ObjectSet
60 {
61 friend class ObjectSet;
62 public:
63     /**
64      * Constructs an selection object, bound to a particular
65      * layer model
66      *
67      * @param layers the layer model (for the SPDesktop, if GUI)
68      * @param desktop the desktop associated with the layer model, or NULL if in console mode
69      */
70     Selection(LayerModel *layers, SPDesktop *desktop);
71     ~Selection() override;
72 
73     /** no copy. */
74     Selection(Selection const &) = delete;
75     /** no assign. */
76     void operator=(Selection const &) = delete;
77 
78     /**
79      * Returns the layer model the selection is bound to (works in console or GUI mode)
80      *
81      * @return the layer model the selection is bound to, which is the same as the desktop
82      * layer model for GUI mode
83      */
layers()84     LayerModel *layers() { return _layers; }
85 
86     /**
87      * Returns active layer for selection (currentLayer or its parent).
88      *
89      * @return layer item the selection is bound to
90      */
91     SPObject *activeContext();
92 
93     using ObjectSet::add;
94 
95     /**
96      * Add an XML node's SPObject to the set of selected objects.
97      *
98      * @param the xml node of the item to add
99      */
add(XML::Node * repr)100     void add(XML::Node *repr) {
101         add(_objectForXMLNode(repr));
102     }
103 
104      using ObjectSet::set;
105 
106     /**
107      * Set the selection to an XML node's SPObject.
108      *
109      * @param repr the xml node of the item to select
110      */
set(XML::Node * repr)111     void set(XML::Node *repr) {
112         set(_objectForXMLNode(repr));
113     }
114 
115     using ObjectSet::remove;
116 
117     /**
118      * Removes an item from the set of selected objects.
119      *
120      * It is ok to call this method for an unselected item.
121      *
122      * @param repr the xml node of the item to remove
123      */
remove(XML::Node * repr)124     void remove(XML::Node *repr) {
125         remove(_objectForXMLNode(repr));
126     }
127 
128     using ObjectSet::includes;
129 
130     /**
131      * Returns true if the given item is selected.
132      */
includes(XML::Node * repr)133     bool includes(XML::Node *repr) {
134         return includes(_objectForXMLNode(repr));
135     }
136 
137     /** Returns the number of layers in which there are selected objects. */
138     size_t numberOfLayers();
139 
140     /** Returns the number of parents to which the selected objects belong. */
141     size_t numberOfParents();
142 
143     /**
144      * Compute the list of points in the selection that are to be considered for snapping from.
145      *
146      * @return Selection's snap points
147      */
148     std::vector<Inkscape::SnapCandidatePoint> getSnapPoints(SnapPreferences const *snapprefs) const;
149 
150     /**
151      * Connects a slot to be notified of selection changes.
152      *
153      * This method connects the given slot such that it will
154      * be called upon any change in the set of selected objects.
155      *
156      * @param slot the slot to connect
157      *
158      * @return the resulting connection
159      */
emitModified()160     void emitModified(){ _emitModified(this->_flags); };
connectChanged(sigc::slot<void,Selection * > const & slot)161     sigc::connection connectChanged(sigc::slot<void, Selection *> const &slot) {
162         return _changed_signal.connect(slot);
163     }
connectChangedFirst(sigc::slot<void,Selection * > const & slot)164     sigc::connection connectChangedFirst(sigc::slot<void, Selection *> const &slot)
165     {
166         return _changed_signal.slots().insert(_changed_signal.slots().begin(), slot);
167     }
168 
169     /**
170      * Connects a slot to be notified of selected object modifications.
171      *
172      * This method connects the given slot such that it will
173      * receive notifications whenever any selected item is
174      * modified.
175      *
176      * @param slot the slot to connect
177      *
178      * @return the resulting connection
179      *
180      */
connectModified(sigc::slot<void,Selection *,unsigned int> const & slot)181     sigc::connection connectModified(sigc::slot<void, Selection *, unsigned int> const &slot)
182     {
183         return _modified_signal.connect(slot);
184     }
connectModifiedFirst(sigc::slot<void,Selection *,unsigned int> const & slot)185     sigc::connection connectModifiedFirst(sigc::slot<void, Selection *, unsigned int> const &slot)
186     {
187         return _modified_signal.slots().insert(_modified_signal.slots().begin(), slot);
188     }
189 
190     /**
191      * Set a backup of current selection and store it also to be command line readable by extension system
192      */
193     void setBackup();
194     /**
195      * Clear backup of current selection
196      */
197     void emptyBackup();
198     /**
199      * Restore a selection from a existing backup
200      */
201     void restoreBackup();
202     /**
203      * Here store a paramlist when set backup
204      */
205     std::list<std::string> params;
206 
207 protected:
208     void _connectSignals(SPObject* object) override;
209     void _releaseSignals(SPObject* object) override;
210 
211 private:
212     /** Issues modification notification signals. */
213     static int _emit_modified(Selection *selection);
214     /** Schedules an item modification signal to be sent. */
215     void _schedule_modified(SPObject *obj, unsigned int flags);
216 
217     /** Issues modified selection signal. */
218     void _emitModified(unsigned int flags);
219     /** Issues changed selection signal. */
220     void _emitChanged(bool persist_selection_context = false) override;
221     /** returns the SPObject corresponding to an xml node (if any). */
222     SPObject *_objectForXMLNode(XML::Node *repr) const;
223     /** Releases an active layer object that is being removed. */
224     void _releaseContext(SPObject *obj);
225 
226     LayerModel *_layers;
227     SPObject* _selection_context;
228     unsigned int _flags;
229     unsigned int _idle;
230     std::vector<std::pair<std::string, std::pair<int, int> > > _seldata;
231     std::vector<std::string> _selected_ids;
232     std::map<SPObject *, sigc::connection> _modified_connections;
233     sigc::connection _context_release_connection;
234 
235     sigc::signal<void, Selection *> _changed_signal;
236     sigc::signal<void, Selection *, unsigned int> _modified_signal;
237 };
238 
239 }
240 
241 #endif
242 /*
243   Local Variables:
244   mode:c++
245   c-file-style:"stroustrup"
246   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
247   indent-tabs-mode:nil
248   fill-column:99
249   End:
250 */
251 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
252