Code

a85877d5ca996345e572b41de689f88a8de04480
[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 template <typename N>
175 class NodeIterator
176     : public boost::bidirectional_iterator_helper<NodeIterator<N>, N, std::ptrdiff_t,
177         N *, N &>
179 public:
180     typedef NodeIterator self;
181     NodeIterator()
182         : _node(0)
183     {}
184     // default copy, default assign
186     self &operator++() {
187         _node = _node->next;
188         return *this;
189     }
190     self &operator--() {
191         _node = _node->prev;
192         return *this;
193     }
194     bool operator==(self const &other) const { return _node == other._node; }
195     N &operator*() const { return *static_cast<N*>(_node); }
196     inline operator bool() const; // define after NodeList
197     N *get_pointer() const { return static_cast<N*>(_node); }
198     N *ptr() const { return static_cast<N*>(_node); }
200     self next() const;
201     self prev() const;
202 private:
203     NodeIterator(ListNode const *n)
204         : _node(const_cast<ListNode*>(n))
205     {}
206     ListNode *_node;
207     friend class NodeList;
208     friend class std::tr1::hash<self>;
209 };
211 class NodeList : ListNode, boost::noncopyable, public boost::enable_shared_from_this<NodeList> {
212 public:
213     typedef std::size_t size_type;
214     typedef Node &reference;
215     typedef Node const &const_reference;
216     typedef Node *pointer;
217     typedef Node const *const_pointer;
218     typedef Node value_type;
219     typedef NodeIterator<value_type> iterator;
220     typedef NodeIterator<value_type const> const_iterator;
221     typedef std::reverse_iterator<iterator> reverse_iterator;
222     typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
224     // TODO Lame. Make this private and make SubpathList a factory
225     NodeList(SubpathList &_list);
226     ~NodeList();
228     // iterators
229     iterator begin() { return iterator(next); }
230     iterator end() { return iterator(this); }
231     const_iterator begin() const { return const_iterator(next); }
232     const_iterator end() const { return const_iterator(this); }
233     reverse_iterator rbegin() { return reverse_iterator(end()); }
234     reverse_iterator rend() { return reverse_iterator(begin()); }
235     const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
236     const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
238     // size
239     bool empty();
240     size_type size();
242     // extra node-specific methods
243     bool closed();
244     bool degenerate();
245     void setClosed(bool c) { _closed = c; }
246     iterator before(double t, double *fracpart = NULL);
247     const_iterator before(double t, double *fracpart = NULL) const {
248         return const_iterator(before(t, fracpart)._node);
249     }
251     // list operations
252     iterator insert(iterator pos, Node *x);
253     template <class InputIterator>
254     void insert(iterator pos, InputIterator first, InputIterator last) {
255         for (; first != last; ++first) insert(pos, *first);
256     }
257     void splice(iterator pos, NodeList &list);
258     void splice(iterator pos, NodeList &list, iterator i);
259     void splice(iterator pos, NodeList &list, iterator first, iterator last);
260     void reverse();
261     void shift(int n);
262     void push_front(Node *x) { insert(begin(), x); }
263     void pop_front() { erase(begin()); }
264     void push_back(Node *x) { insert(end(), x); }
265     void pop_back() { erase(--end()); }
266     void clear();
267     iterator erase(iterator pos);
268     iterator erase(iterator first, iterator last) {
269         NodeList::iterator ret = first;
270         while (first != last) ret = erase(first++);
271         return ret;
272     }
274     // member access - undefined results when the list is empty
275     Node &front() { return *static_cast<Node*>(next); }
276     Node &back() { return *static_cast<Node*>(prev); }
278     // HACK remove this subpath from its path. This will be removed later.
279     void kill();
281     static iterator get_iterator(Node *n) { return iterator(n); }
282     static const_iterator get_iterator(Node const *n) { return const_iterator(n); }
283     static NodeList &get(Node *n);
284     static NodeList &get(iterator const &i);
285 private:
286     // no copy or assign
287     NodeList(NodeList const &);
288     void operator=(NodeList const &);
290     SubpathList &_list;
291     bool _closed;
293     friend class Node;
294     friend class Handle; // required to access handle and handle line groups
295     friend class NodeIterator<Node>;
296     friend class NodeIterator<Node const>;
297 };
299 /** List of node lists. Represents an editable path. */
300 class SubpathList : public std::list< boost::shared_ptr<NodeList> > {
301 public:
302     typedef std::list< boost::shared_ptr<NodeList> > list_type;
304     SubpathList(PathManipulator &pm) : _path_manipulator(pm) {}
306     sigc::signal<void, Node *> signal_insert_node;
307     sigc::signal<void, Node *> signal_remove_node;
308 private:
309     list_type _nodelists;
310     PathManipulator &_path_manipulator;
311     friend class NodeList;
312     friend class Node;
313     friend class Handle;
314 };
318 // define inline Handle funcs after definition of Node
319 inline Geom::Point Handle::relativePos() {
320     return position() - _parent->position();
322 inline void Handle::setRelativePos(Geom::Point const &p) {
323     setPosition(_parent->position() + p);
325 inline double Handle::length() {
326     return relativePos().length();
329 // definitions for node iterator
330 template <typename N>
331 NodeIterator<N>::operator bool() const {
332     return _node && static_cast<ListNode*>(_node->list) != _node;
334 template <typename N>
335 NodeIterator<N> NodeIterator<N>::next() const {
336     NodeIterator<N> ret(*this);
337     ++ret;
338     if (!ret && _node->list->closed()) ++ret;
339     return ret;
341 template <typename N>
342 NodeIterator<N> NodeIterator<N>::prev() const {
343     NodeIterator<N> ret(*this);
344     --ret;
345     if (!ret && _node->list->closed()) --ret;
346     return ret;
349 } // namespace UI
350 } // namespace Inkscape
352 namespace std {
353 namespace tr1 {
354 template <typename N>
355 struct hash< Inkscape::UI::NodeIterator<N> > : public unary_function<Inkscape::UI::NodeIterator<N>, size_t> {
356     size_t operator()(Inkscape::UI::NodeIterator<N> const &ni) const {
357         return reinterpret_cast<size_t>(ni._node);
358     }
359 };
363 #endif
365 /*
366   Local Variables:
367   mode:c++
368   c-file-style:"stroustrup"
369   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
370   indent-tabs-mode:nil
371   fill-column:99
372   End:
373 */
374 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :