Code

Implement selection spatial grow
[inkscape.git] / src / ui / tool / node.h
1 /** @file
2  * Editable node and associated data structures.
3  */
4 /* Authors:
5  *   Krzysztof KosiƄski <tweenk.pl@gmail.com>
6  *
7  * Copyright (C) 2009 Authors
8  * Released under GNU GPL, read the file 'COPYING' for more information
9  */
11 #ifndef SEEN_UI_TOOL_NODE_H
12 #define SEEN_UI_TOOL_NODE_H
14 #include <iterator>
15 #include <iosfwd>
16 #include <stdexcept>
17 #include <tr1/functional>
18 #include <boost/utility.hpp>
19 #include <boost/shared_ptr.hpp>
20 #include <boost/optional.hpp>
21 #include <boost/operators.hpp>
22 #include "ui/tool/selectable-control-point.h"
23 #include "ui/tool/node-types.h"
26 namespace Inkscape {
27 namespace UI {
28 template <typename> class NodeIterator;
29 }
30 }
32 namespace std {
33 namespace tr1 {
34 template <typename N> struct hash< Inkscape::UI::NodeIterator<N> >;
35 }
36 }
38 namespace Inkscape {
39 namespace UI {
41 class PathManipulator;
42 class MultiPathManipulator;
44 class Node;
45 class Handle;
46 class NodeList;
47 class SubpathList;
48 template <typename> class NodeIterator;
50 std::ostream &operator<<(std::ostream &, NodeType);
52 /*
53 template <typename T>
54 struct ListMember {
55     T *next;
56     T *prev;
57 };
58 struct SubpathMember : public ListMember<NodeListMember> {
59     Subpath *list;
60 };
61 struct SubpathListMember : public ListMember<SubpathListMember> {
62     SubpathList *list;
63 };
64 */
66 struct ListNode {
67     ListNode *next;
68     ListNode *prev;
69     NodeList *list;
70 };
72 struct NodeSharedData {
73     SPDesktop *desktop;
74     ControlPointSelection *selection;
75     SPCanvasGroup *node_group;
76     SPCanvasGroup *handle_group;
77     SPCanvasGroup *handle_line_group;
78 };
80 class Handle : public ControlPoint {
81 public:
82     virtual ~Handle();
83     inline Geom::Point relativePos();
84     inline double length();
85     bool isDegenerate() { return _degenerate; }
87     virtual void setVisible(bool);
88     virtual void move(Geom::Point const &p);
90     virtual void setPosition(Geom::Point const &p);
91     inline void setRelativePos(Geom::Point const &p);
92     void setLength(double len);
93     void retract();
94     void setDirection(Geom::Point const &from, Geom::Point const &to);
95     void setDirection(Geom::Point const &dir);
96     Node *parent() { return _parent; }
98     static char const *handle_type_to_localized_string(NodeType type);
99     sigc::signal<void> signal_update;
100 protected:
101     Handle(NodeSharedData const &data, Geom::Point const &initial_pos, Node *parent);
102     virtual Glib::ustring _getTip(unsigned state);
103     virtual Glib::ustring _getDragTip(GdkEventMotion *event);
104     virtual bool _hasDragTips() { return true; }
105 private:
106     void _grabbedHandler();
107     void _draggedHandler(Geom::Point &, GdkEventMotion *);
108     void _ungrabbedHandler();
109     Node *_parent; // the handle's lifetime does not extend beyond that of the parent node,
110     // so a naked pointer is OK and allows setting it during Node's construction
111     SPCanvasItem *_handle_line;
112     bool _degenerate; // this is used often internally so it makes sense to cache this
114     static double _saved_length;
115     static bool _drag_out;
116     friend class Node;
117 };
119 class Node : ListNode, public SelectableControlPoint {
120 public:
121     Node(NodeSharedData const &data, Geom::Point const &pos);
122     virtual void move(Geom::Point const &p);
123     virtual void transform(Geom::Matrix const &m);
124     virtual Geom::Rect bounds();
126     NodeType type() { return _type; }
127     void setType(NodeType type, bool update_handles = true);
128     void showHandles(bool v);
129     void pickBestType(); // automatically determine the type from handle positions
130     bool isDegenerate() { return _front.isDegenerate() && _back.isDegenerate(); }
131     bool isEndNode();
132     Handle *front() { return &_front; }
133     Handle *back()  { return &_back;  }
134     static NodeType parse_nodetype(char x);
135     NodeList *list() { return static_cast<ListNode*>(this)->list; }
136     void sink();
138     static char const *node_type_to_localized_string(NodeType type);
139 protected:
140     virtual bool _eventHandler(GdkEvent *event);
141     virtual void _setState(State state);
142     virtual Glib::ustring _getTip(unsigned state);
143     virtual Glib::ustring _getDragTip(GdkEventMotion *event);
144     virtual bool _hasDragTips() { return true; }
145 private:
146     Node(Node const &);
147     bool _grabbedHandler(GdkEventMotion *);
148     void _draggedHandler(Geom::Point &, GdkEventMotion *);
149     void _fixNeighbors(Geom::Point const &old_pos, Geom::Point const &new_pos);
150     void _updateAutoHandles();
151     Node *_next();
152     Node *_prev();
153     static SPCtrlShapeType _node_type_to_shape(NodeType type);
154     static bool _is_line_segment(Node *first, Node *second);
156     // Handles are always present, but are not visible if they coincide with the node
157     // (are degenerate). A segment that has both handles degenerate is always treated
158     // as a line segment
159     Handle _front; ///< Node handle in the backward direction of the path
160     Handle _back; ///< Node handle in the forward direction of the path
161     NodeType _type; ///< Type of node - cusp, smooth...
162     bool _handles_shown;
163     friend class Handle;
164     friend class NodeList;
165     friend class NodeIterator<Node>;
166     friend class NodeIterator<Node const>;
167 };
169 template <typename N>
170 class NodeIterator
171     : public boost::bidirectional_iterator_helper<NodeIterator<N>, N, std::ptrdiff_t,
172         N *, N &>
174 public:
175     typedef NodeIterator self;
176     NodeIterator()
177         : _node(0)
178     {}
179     // default copy, default assign
181     self &operator++() {
182         _node = _node->next;
183         return *this;
184     }
185     self &operator--() {
186         _node = _node->prev;
187         return *this;
188     }
189     bool operator==(self const &other) const { return _node == other._node; }
190     N &operator*() const { return *static_cast<N*>(_node); }
191     inline operator bool() const; // define after NodeList
192     N *get_pointer() const { return static_cast<N*>(_node); }
193     N *ptr() const { return static_cast<N*>(_node); }
195     self next() const;
196     self prev() const;
197 private:
198     NodeIterator(ListNode const *n)
199         : _node(const_cast<ListNode*>(n))
200     {}
201     ListNode *_node;
202     friend class NodeList;
203     friend class std::tr1::hash<self>;
204 };
206 class NodeList : ListNode, boost::noncopyable, public boost::enable_shared_from_this<NodeList> {
207 public:
208     typedef std::size_t size_type;
209     typedef Node &reference;
210     typedef Node const &const_reference;
211     typedef Node *pointer;
212     typedef Node const *const_pointer;
213     typedef Node value_type;
214     typedef NodeIterator<value_type> iterator;
215     typedef NodeIterator<value_type const> const_iterator;
216     typedef std::reverse_iterator<iterator> reverse_iterator;
217     typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
219     // TODO Lame. Make this private and make SubpathList a factory
220     NodeList(SubpathList &_list);
221     ~NodeList();
223     // iterators
224     iterator begin() { return iterator(next); }
225     iterator end() { return iterator(this); }
226     const_iterator begin() const { return const_iterator(next); }
227     const_iterator end() const { return const_iterator(this); }
228     reverse_iterator rbegin() { return reverse_iterator(end()); }
229     reverse_iterator rend() { return reverse_iterator(begin()); }
230     const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
231     const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
233     // size
234     bool empty();
235     size_type size();
237     // extra node-specific methods
238     bool closed();
239     bool degenerate();
240     void setClosed(bool c) { _closed = c; }
241     iterator before(double t, double *fracpart = NULL);
242     const_iterator before(double t, double *fracpart = NULL) const {
243         return const_iterator(before(t, fracpart)._node);
244     }
246     // list operations
247     iterator insert(iterator pos, Node *x);
248     template <class InputIterator>
249     void insert(iterator pos, InputIterator first, InputIterator last) {
250         for (; first != last; ++first) insert(pos, *first);
251     }
252     void splice(iterator pos, NodeList &list);
253     void splice(iterator pos, NodeList &list, iterator i);
254     void splice(iterator pos, NodeList &list, iterator first, iterator last);
255     void reverse();
256     void shift(int n);
257     void push_front(Node *x) { insert(begin(), x); }
258     void pop_front() { erase(begin()); }
259     void push_back(Node *x) { insert(end(), x); }
260     void pop_back() { erase(--end()); }
261     void clear();
262     iterator erase(iterator pos);
263     iterator erase(iterator first, iterator last) {
264         NodeList::iterator ret = first;
265         while (first != last) ret = erase(first++);
266         return ret;
267     }
269     // member access - undefined results when the list is empty
270     Node &front() { return *static_cast<Node*>(next); }
271     Node &back() { return *static_cast<Node*>(prev); }
273     // HACK remove this subpath from its path. This will be removed later.
274     void kill();
276     static iterator get_iterator(Node *n) { return iterator(n); }
277     static const_iterator get_iterator(Node const *n) { return const_iterator(n); }
278     static NodeList &get(Node *n);
279     static NodeList &get(iterator const &i);
280 private:
281     // no copy or assign
282     NodeList(NodeList const &);
283     void operator=(NodeList const &);
285     SubpathList &_list;
286     bool _closed;
288     friend class Node;
289     friend class Handle; // required to access handle and handle line groups
290     friend class NodeIterator<Node>;
291     friend class NodeIterator<Node const>;
292 };
294 /** List of node lists. Represents an editable path. */
295 class SubpathList : public std::list< boost::shared_ptr<NodeList> > {
296 public:
297     typedef std::list< boost::shared_ptr<NodeList> > list_type;
299     SubpathList(PathManipulator &pm) : _path_manipulator(pm) {}
301     sigc::signal<void, Node *> signal_insert_node;
302     sigc::signal<void, Node *> signal_remove_node;
303 private:
304     list_type _nodelists;
305     PathManipulator &_path_manipulator;
306     friend class NodeList;
307     friend class Node;
308     friend class Handle;
309 };
313 // define inline Handle funcs after definition of Node
314 inline Geom::Point Handle::relativePos() {
315     return position() - _parent->position();
317 inline void Handle::setRelativePos(Geom::Point const &p) {
318     setPosition(_parent->position() + p);
320 inline double Handle::length() {
321     return relativePos().length();
324 // definitions for node iterator
325 template <typename N>
326 NodeIterator<N>::operator bool() const {
327     return _node && static_cast<ListNode*>(_node->list) != _node;
329 template <typename N>
330 NodeIterator<N> NodeIterator<N>::next() const {
331     NodeIterator<N> ret(*this);
332     ++ret;
333     if (!ret && _node->list->closed()) ++ret;
334     return ret;
336 template <typename N>
337 NodeIterator<N> NodeIterator<N>::prev() const {
338     NodeIterator<N> ret(*this);
339     --ret;
340     if (!ret && _node->list->closed()) --ret;
341     return ret;
344 } // namespace UI
345 } // namespace Inkscape
347 namespace std {
348 namespace tr1 {
349 template <typename N>
350 struct hash< Inkscape::UI::NodeIterator<N> > : public unary_function<Inkscape::UI::NodeIterator<N>, size_t> {
351     size_t operator()(Inkscape::UI::NodeIterator<N> const &ni) const {
352         return reinterpret_cast<size_t>(ni._node);
353     }
354 };
358 #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 :