Code

First GSoC node tool commit to Bazaar
[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;
43 class Node;
44 class Handle;
45 class NodeList;
46 class SubpathList;
47 template <typename> class NodeIterator;
49 std::ostream &operator<<(std::ostream &, NodeType);
51 /*
52 template <typename T>
53 struct ListMember {
54     T *next;
55     T *prev;
56 };
57 struct SubpathMember : public ListMember<NodeListMember> {
58     Subpath *list;
59 };
60 struct SubpathListMember : public ListMember<SubpathListMember> {
61     SubpathList *list;
62 };
63 */
65 struct ListNode {
66     ListNode *next;
67     ListNode *prev;
68     NodeList *list;
69 };
71 struct NodeSharedData {
72     SPDesktop *desktop;
73     ControlPointSelection *selection;
74     SPCanvasGroup *node_group;
75     SPCanvasGroup *handle_group;
76     SPCanvasGroup *handle_line_group;
77 };
79 class Handle : public ControlPoint {
80 public:
81     virtual ~Handle();
82     inline Geom::Point relativePos();
83     inline double length();
84     bool isDegenerate() { return _degenerate; }
86     virtual void setVisible(bool);
87     virtual void move(Geom::Point const &p);
89     virtual void setPosition(Geom::Point const &p);
90     inline void setRelativePos(Geom::Point const &p);
91     void setLength(double len);
92     void retract();
93     void setDirection(Geom::Point const &from, Geom::Point const &to);
94     void setDirection(Geom::Point const &dir);
95     Node *parent() { return _parent; }
97     static char const *handle_type_to_localized_string(NodeType type);
98     sigc::signal<void> signal_update;
99 protected:
100     Handle(NodeSharedData const &data, Geom::Point const &initial_pos, Node *parent);
101     virtual Glib::ustring _getTip(unsigned state);
102     virtual Glib::ustring _getDragTip(GdkEventMotion *event);
103     virtual bool _hasDragTips() { return true; }
104 private:
105     void _grabbedHandler();
106     void _draggedHandler(Geom::Point &, GdkEventMotion *);
107     void _ungrabbedHandler();
108     Node *_parent; // the handle's lifetime does not extend beyond that of the parent node,
109     // so a naked pointer is OK and allows setting it during Node's construction
110     SPCanvasItem *_handle_line;
111     bool _degenerate; // this is used often internally so it makes sense to cache this
113     static double _saved_length;
114     static bool _drag_out;
115     friend class Node;
116 };
118 class Node : ListNode, public SelectableControlPoint {
119 public:
120     Node(NodeSharedData const &data, Geom::Point const &pos);
121     virtual void move(Geom::Point const &p);
122     virtual void transform(Geom::Matrix const &m);
123     virtual Geom::Rect bounds();
125     NodeType type() { return _type; }
126     void setType(NodeType type, bool update_handles = true);
127     void showHandles(bool v);
128     void pickBestType(); // automatically determine the type from handle positions
129     bool isDegenerate() { return _front.isDegenerate() && _back.isDegenerate(); }
130     bool isEndNode();
131     Handle *front() { return &_front; }
132     Handle *back()  { return &_back;  }
133     static NodeType parse_nodetype(char x);
134     NodeList *list() { return static_cast<ListNode*>(this)->list; }
135     void sink();
137     static char const *node_type_to_localized_string(NodeType type);
138 protected:
139     virtual void _setState(State state);
140     virtual Glib::ustring _getTip(unsigned state);
141     virtual Glib::ustring _getDragTip(GdkEventMotion *event);
142     virtual bool _hasDragTips() { return true; }
143 private:
144     Node(Node const &);
145     bool _grabbedHandler(GdkEventMotion *);
146     void _draggedHandler(Geom::Point &, GdkEventMotion *);
147     void _fixNeighbors(Geom::Point const &old_pos, Geom::Point const &new_pos);
148     void _updateAutoHandles();
149     Node *_next();
150     Node *_prev();
151     static SPCtrlShapeType _node_type_to_shape(NodeType type);
152     static bool _is_line_segment(Node *first, Node *second);
154     // Handles are always present, but are not visible if they coincide with the node
155     // (are degenerate). A segment that has both handles degenerate is always treated
156     // as a line segment
157     Handle _front; ///< Node handle in the backward direction of the path
158     Handle _back; ///< Node handle in the forward direction of the path
159     NodeType _type; ///< Type of node - cusp, smooth...
160     bool _handles_shown;
161     friend class Handle;
162     friend class NodeList;
163     friend class NodeIterator<Node>;
164     friend class NodeIterator<Node const>;
165 };
167 template <typename N>
168 class NodeIterator
169     : public boost::bidirectional_iterator_helper<NodeIterator<N>, N, std::ptrdiff_t,
170         N *, N &>
172 public:
173     typedef NodeIterator self;
174     NodeIterator()
175         : _node(0)
176     {}
177     // default copy, default assign
179     self &operator++() {
180         _node = _node->next;
181         return *this;
182     }
183     self &operator--() {
184         _node = _node->prev;
185         return *this;
186     }
187     bool operator==(self const &other) const { return _node == other._node; }
188     N &operator*() const { return *static_cast<N*>(_node); }
189     inline operator bool() const; // define after NodeList
190     N *get_pointer() const { return static_cast<N*>(_node); }
191     N *ptr() const { return static_cast<N*>(_node); }
193     self next() const;
194     self prev() const;
195 private:
196     NodeIterator(ListNode const *n)
197         : _node(const_cast<ListNode*>(n))
198     {}
199     ListNode *_node;
200     friend class NodeList;
201     friend class std::tr1::hash<self>;
202 };
204 class NodeList : ListNode, boost::noncopyable, public boost::enable_shared_from_this<NodeList> {
205 public:
206     typedef std::size_t size_type;
207     typedef Node &reference;
208     typedef Node const &const_reference;
209     typedef Node *pointer;
210     typedef Node const *const_pointer;
211     typedef Node value_type;
212     typedef NodeIterator<value_type> iterator;
213     typedef NodeIterator<value_type const> const_iterator;
214     typedef std::reverse_iterator<iterator> reverse_iterator;
215     typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
217     // TODO Lame. Make this private and make SubpathList a factory
218     NodeList(SubpathList &_list);
219     ~NodeList();
221     // iterators
222     iterator begin() { return iterator(next); }
223     iterator end() { return iterator(this); }
224     const_iterator begin() const { return const_iterator(next); }
225     const_iterator end() const { return const_iterator(this); }
226     reverse_iterator rbegin() { return reverse_iterator(end()); }
227     reverse_iterator rend() { return reverse_iterator(begin()); }
228     const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
229     const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
231     // size
232     bool empty();
233     size_type size();
235     // extra node-specific methods
236     bool closed();
237     bool degenerate();
238     void setClosed(bool c) { _closed = c; }
239     iterator before(double t, double *fracpart = NULL);
240     const_iterator before(double t, double *fracpart = NULL) const {
241         return const_iterator(before(t, fracpart)._node);
242     }
244     // list operations
245     iterator insert(iterator pos, Node *x);
246     template <class InputIterator>
247     void insert(iterator pos, InputIterator first, InputIterator last) {
248         for (; first != last; ++first) insert(pos, *first);
249     }
250     void splice(iterator pos, NodeList &list);
251     void splice(iterator pos, NodeList &list, iterator i);
252     void splice(iterator pos, NodeList &list, iterator first, iterator last);
253     void reverse();
254     void shift(int n);
255     void push_front(Node *x) { insert(begin(), x); }
256     void pop_front() { erase(begin()); }
257     void push_back(Node *x) { insert(end(), x); }
258     void pop_back() { erase(--end()); }
259     void clear();
260     iterator erase(iterator pos);
261     iterator erase(iterator first, iterator last) {
262         NodeList::iterator ret = first;
263         while (first != last) ret = erase(first++);
264         return ret;
265     }
267     // member access - undefined results when the list is empty
268     Node &front() { return *static_cast<Node*>(next); }
269     Node &back() { return *static_cast<Node*>(prev); }
271     // HACK remove this subpath from its path. This will be removed later.
272     void kill();
274     static iterator get_iterator(Node *n) { return iterator(n); }
275     static const_iterator get_iterator(Node const *n) { return const_iterator(n); }
276     static NodeList &get(Node *n);
277     static NodeList &get(iterator const &i);
278 private:
279     // no copy or assign
280     NodeList(NodeList const &);
281     void operator=(NodeList const &);
283     SubpathList &_list;
284     bool _closed;
286     friend class Node;
287     friend class Handle; // required to access handle and handle line groups
288     friend class NodeIterator<Node>;
289     friend class NodeIterator<Node const>;
290 };
292 /** List of node lists. Represents an editable path. */
293 class SubpathList : public std::list< boost::shared_ptr<NodeList> > {
294 public:
295     typedef std::list< boost::shared_ptr<NodeList> > list_type;
297     SubpathList() {}
299     sigc::signal<void, Node *> signal_insert_node;
300     sigc::signal<void, Node *> signal_remove_node;
301 private:
302     list_type _nodelists;
303     friend class NodeList;
304     friend class Node;
305     friend class Handle;
306 };
310 // define inline Handle funcs after definition of Node
311 inline Geom::Point Handle::relativePos() {
312     return position() - _parent->position();
314 inline void Handle::setRelativePos(Geom::Point const &p) {
315     setPosition(_parent->position() + p);
317 inline double Handle::length() {
318     return relativePos().length();
321 // definitions for node iterator
322 template <typename N>
323 NodeIterator<N>::operator bool() const {
324     return _node && static_cast<ListNode*>(_node->list) != _node;
326 template <typename N>
327 NodeIterator<N> NodeIterator<N>::next() const {
328     NodeIterator<N> ret(*this);
329     ++ret;
330     if (!ret && _node->list->closed()) ++ret;
331     return ret;
333 template <typename N>
334 NodeIterator<N> NodeIterator<N>::prev() const {
335     NodeIterator<N> ret(*this);
336     --ret;
337     if (!ret && _node->list->closed()) --ret;
338     return ret;
341 } // namespace UI
342 } // namespace Inkscape
344 namespace std {
345 namespace tr1 {
346 template <typename N>
347 struct hash< Inkscape::UI::NodeIterator<N> > : public unary_function<Inkscape::UI::NodeIterator<N>, size_t> {
348     size_t operator()(Inkscape::UI::NodeIterator<N> const &ni) const {
349         return reinterpret_cast<size_t>(ni._node);
350     }
351 };
355 #endif
357 /*
358   Local Variables:
359   mode:c++
360   c-file-style:"stroustrup"
361   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
362   indent-tabs-mode:nil
363   fill-column:99
364   End:
365 */
366 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :