Code

Merge GSoC 2009 node tool rewrite
[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 "snapped-point.h"
23 #include "ui/tool/selectable-control-point.h"
24 #include "ui/tool/node-types.h"
27 namespace Inkscape {
28 namespace UI {
29 template <typename> class NodeIterator;
30 }
31 }
33 namespace std {
34 namespace tr1 {
35 template <typename N> struct hash< Inkscape::UI::NodeIterator<N> >;
36 }
37 }
39 namespace Inkscape {
40 namespace UI {
42 class PathManipulator;
43 class MultiPathManipulator;
45 class Node;
46 class Handle;
47 class NodeList;
48 class SubpathList;
49 template <typename> class NodeIterator;
51 std::ostream &operator<<(std::ostream &, NodeType);
53 /*
54 template <typename T>
55 struct ListMember {
56     T *next;
57     T *prev;
58 };
59 struct SubpathMember : public ListMember<NodeListMember> {
60     Subpath *list;
61 };
62 struct SubpathListMember : public ListMember<SubpathListMember> {
63     SubpathList *list;
64 };
65 */
67 struct ListNode {
68     ListNode *next;
69     ListNode *prev;
70     NodeList *list;
71 };
73 struct NodeSharedData {
74     SPDesktop *desktop;
75     ControlPointSelection *selection;
76     SPCanvasGroup *node_group;
77     SPCanvasGroup *handle_group;
78     SPCanvasGroup *handle_line_group;
79 };
81 class Handle : public ControlPoint {
82 public:
83     virtual ~Handle();
84     inline Geom::Point relativePos();
85     inline double length();
86     bool isDegenerate() { return _degenerate; }
88     virtual void setVisible(bool);
89     virtual void move(Geom::Point const &p);
91     virtual void setPosition(Geom::Point const &p);
92     inline void setRelativePos(Geom::Point const &p);
93     void setLength(double len);
94     void retract();
95     void setDirection(Geom::Point const &from, Geom::Point const &to);
96     void setDirection(Geom::Point const &dir);
97     Node *parent() { return _parent; }
99     static char const *handle_type_to_localized_string(NodeType type);
100     sigc::signal<void> signal_update;
101 protected:
102     Handle(NodeSharedData const &data, Geom::Point const &initial_pos, Node *parent);
103     virtual Glib::ustring _getTip(unsigned state);
104     virtual Glib::ustring _getDragTip(GdkEventMotion *event);
105     virtual bool _hasDragTips() { return true; }
106 private:
107     void _grabbedHandler();
108     void _draggedHandler(Geom::Point &, GdkEventMotion *);
109     void _ungrabbedHandler();
110     Node *_parent; // the handle's lifetime does not extend beyond that of the parent node,
111     // so a naked pointer is OK and allows setting it during Node's construction
112     SPCanvasItem *_handle_line;
113     bool _degenerate; // this is used often internally so it makes sense to cache this
115     static double _saved_length;
116     static bool _drag_out;
117     friend class Node;
118 };
120 class Node : ListNode, public SelectableControlPoint {
121 public:
122     Node(NodeSharedData const &data, Geom::Point const &pos);
123     virtual void move(Geom::Point const &p);
124     virtual void transform(Geom::Matrix const &m);
125     virtual Geom::Rect bounds();
127     NodeType type() { return _type; }
128     void setType(NodeType type, bool update_handles = true);
129     void showHandles(bool v);
130     void pickBestType(); // automatically determine the type from handle positions
131     bool isDegenerate() { return _front.isDegenerate() && _back.isDegenerate(); }
132     bool isEndNode();
133     Handle *front() { return &_front; }
134     Handle *back()  { return &_back;  }
135     static NodeType parse_nodetype(char x);
136     NodeList *list() { return static_cast<ListNode*>(this)->list; }
137     void sink();
139     static char const *node_type_to_localized_string(NodeType type);
140     // temporarily public
141     virtual bool _eventHandler(GdkEvent *event);
142 protected:
143     virtual void _setState(State state);
144     virtual Glib::ustring _getTip(unsigned state);
145     virtual Glib::ustring _getDragTip(GdkEventMotion *event);
146     virtual bool _hasDragTips() { return true; }
147 private:
148     Node(Node const &);
149     bool _grabbedHandler(GdkEventMotion *);
150     void _draggedHandler(Geom::Point &, GdkEventMotion *);
151     void _fixNeighbors(Geom::Point const &old_pos, Geom::Point const &new_pos);
152     void _updateAutoHandles();
153     void _linearGrow(int dir);
154     Node *_next();
155     Node *_prev();
156     Inkscape::SnapSourceType _snapSourceType();
157     Inkscape::SnapTargetType _snapTargetType();
158     static SPCtrlShapeType _node_type_to_shape(NodeType type);
159     static bool _is_line_segment(Node *first, Node *second);
161     // Handles are always present, but are not visible if they coincide with the node
162     // (are degenerate). A segment that has both handles degenerate is always treated
163     // as a line segment
164     Handle _front; ///< Node handle in the backward direction of the path
165     Handle _back; ///< Node handle in the forward direction of the path
166     NodeType _type; ///< Type of node - cusp, smooth...
167     bool _handles_shown;
168     friend class Handle;
169     friend class NodeList;
170     friend class NodeIterator<Node>;
171     friend class NodeIterator<Node const>;
172 };
174 /// Iterator for editable nodes
175 /** Use this class for all operations that require some knowledge about the node's
176  * neighbors. It works like a bidirectional iterator.
177  *
178  * Because paths can be cyclic, node iterators have two different ways to
179  * increment and decrement them. Nodes can be iterated over either in the
180  * sequence order, which always has a beginning and an end, or in the path order,
181  * which can be cyclic (moving to the next node never yields the end iterator).
182  *
183  * When @a i is a node iterator, then:
184  * - <code>++i</code> moves the iterator to the next node in sequence order;
185  * - <code>--i</code> moves the iterator to the previous node in sequence order;
186  * - <code>i.next()</code> returns the next node with wrap-around if the path is cyclic;
187  * - <code>i.prev()</code> returns the previous node with wrap-around if the path is cyclic.
188  *
189  * next() and prev() do not change their iterator. They can return the end iterator
190  * if the path is open.
191  *
192  * Unlike most other iterators, you can check whether a node iterator is invalid
193  * (is an end iterator) without having access to the iterator's container.
194  * Simply use <code>if (i) { ...</code>
195  * */
196 template <typename N>
197 class NodeIterator
198     : public boost::bidirectional_iterator_helper<NodeIterator<N>, N, std::ptrdiff_t,
199         N *, N &>
201 public:
202     typedef NodeIterator self;
203     NodeIterator()
204         : _node(0)
205     {}
206     // default copy, default assign
208     self &operator++() {
209         _node = _node->next;
210         return *this;
211     }
212     self &operator--() {
213         _node = _node->prev;
214         return *this;
215     }
216     bool operator==(self const &other) const { return _node == other._node; }
217     N &operator*() const { return *static_cast<N*>(_node); }
218     inline operator bool() const; // define after NodeList
219     /// Get a pointer to the underlying node. Equivalent to <code>&*i</code>.
220     N *get_pointer() const { return static_cast<N*>(_node); }
221     /// @see get_pointer()
222     N *ptr() const { return static_cast<N*>(_node); }
224     self next() const;
225     self prev() const;
226 private:
227     NodeIterator(ListNode const *n)
228         : _node(const_cast<ListNode*>(n))
229     {}
230     ListNode *_node;
231     friend class NodeList;
232     friend class std::tr1::hash<self>;
233 };
235 class NodeList : ListNode, boost::noncopyable, public boost::enable_shared_from_this<NodeList> {
236 public:
237     typedef std::size_t size_type;
238     typedef Node &reference;
239     typedef Node const &const_reference;
240     typedef Node *pointer;
241     typedef Node const *const_pointer;
242     typedef Node value_type;
243     typedef NodeIterator<value_type> iterator;
244     typedef NodeIterator<value_type const> const_iterator;
245     typedef std::reverse_iterator<iterator> reverse_iterator;
246     typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
248     // TODO Lame. Make this private and make SubpathList a factory
249     NodeList(SubpathList &_list);
250     ~NodeList();
252     // iterators
253     iterator begin() { return iterator(next); }
254     iterator end() { return iterator(this); }
255     const_iterator begin() const { return const_iterator(next); }
256     const_iterator end() const { return const_iterator(this); }
257     reverse_iterator rbegin() { return reverse_iterator(end()); }
258     reverse_iterator rend() { return reverse_iterator(begin()); }
259     const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
260     const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
262     // size
263     bool empty();
264     size_type size();
266     // extra node-specific methods
267     bool closed();
268     bool degenerate();
269     void setClosed(bool c) { _closed = c; }
270     iterator before(double t, double *fracpart = NULL);
271     const_iterator before(double t, double *fracpart = NULL) const {
272         return const_iterator(before(t, fracpart)._node);
273     }
275     // list operations
276     iterator insert(iterator pos, Node *x);
277     template <class InputIterator>
278     void insert(iterator pos, InputIterator first, InputIterator last) {
279         for (; first != last; ++first) insert(pos, *first);
280     }
281     void splice(iterator pos, NodeList &list);
282     void splice(iterator pos, NodeList &list, iterator i);
283     void splice(iterator pos, NodeList &list, iterator first, iterator last);
284     void reverse();
285     void shift(int n);
286     void push_front(Node *x) { insert(begin(), x); }
287     void pop_front() { erase(begin()); }
288     void push_back(Node *x) { insert(end(), x); }
289     void pop_back() { erase(--end()); }
290     void clear();
291     iterator erase(iterator pos);
292     iterator erase(iterator first, iterator last) {
293         NodeList::iterator ret = first;
294         while (first != last) ret = erase(first++);
295         return ret;
296     }
298     // member access - undefined results when the list is empty
299     Node &front() { return *static_cast<Node*>(next); }
300     Node &back() { return *static_cast<Node*>(prev); }
302     // HACK remove this subpath from its path. This will be removed later.
303     void kill();
305     static iterator get_iterator(Node *n) { return iterator(n); }
306     static const_iterator get_iterator(Node const *n) { return const_iterator(n); }
307     static NodeList &get(Node *n);
308     static NodeList &get(iterator const &i);
309 private:
310     // no copy or assign
311     NodeList(NodeList const &);
312     void operator=(NodeList const &);
314     SubpathList &_list;
315     bool _closed;
317     friend class Node;
318     friend class Handle; // required to access handle and handle line groups
319     friend class NodeIterator<Node>;
320     friend class NodeIterator<Node const>;
321 };
323 /** List of node lists. Represents an editable path. */
324 class SubpathList : public std::list< boost::shared_ptr<NodeList> > {
325 public:
326     typedef std::list< boost::shared_ptr<NodeList> > list_type;
328     SubpathList(PathManipulator &pm) : _path_manipulator(pm) {}
330     sigc::signal<void, Node *> signal_insert_node;
331     sigc::signal<void, Node *> signal_remove_node;
332 private:
333     list_type _nodelists;
334     PathManipulator &_path_manipulator;
335     friend class NodeList;
336     friend class Node;
337     friend class Handle;
338 };
342 // define inline Handle funcs after definition of Node
343 inline Geom::Point Handle::relativePos() {
344     return position() - _parent->position();
346 inline void Handle::setRelativePos(Geom::Point const &p) {
347     setPosition(_parent->position() + p);
349 inline double Handle::length() {
350     return relativePos().length();
353 // definitions for node iterator
354 template <typename N>
355 NodeIterator<N>::operator bool() const {
356     return _node && static_cast<ListNode*>(_node->list) != _node;
358 template <typename N>
359 NodeIterator<N> NodeIterator<N>::next() const {
360     NodeIterator<N> ret(*this);
361     ++ret;
362     if (!ret && _node->list->closed()) ++ret;
363     return ret;
365 template <typename N>
366 NodeIterator<N> NodeIterator<N>::prev() const {
367     NodeIterator<N> ret(*this);
368     --ret;
369     if (!ret && _node->list->closed()) --ret;
370     return ret;
373 } // namespace UI
374 } // namespace Inkscape
376 namespace std {
377 namespace tr1 {
378 template <typename N>
379 struct hash< Inkscape::UI::NodeIterator<N> > : public unary_function<Inkscape::UI::NodeIterator<N>, size_t> {
380     size_t operator()(Inkscape::UI::NodeIterator<N> const &ni) const {
381         return reinterpret_cast<size_t>(ni._node);
382     }
383 };
387 #endif
389 /*
390   Local Variables:
391   mode:c++
392   c-file-style:"stroustrup"
393   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
394   indent-tabs-mode:nil
395   fill-column:99
396   End:
397 */
398 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :