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 &>
173 {
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();
316 }
317 inline void Handle::setRelativePos(Geom::Point const &p) {
318 setPosition(_parent->position() + p);
319 }
320 inline double Handle::length() {
321 return relativePos().length();
322 }
324 // definitions for node iterator
325 template <typename N>
326 NodeIterator<N>::operator bool() const {
327 return _node && static_cast<ListNode*>(_node->list) != _node;
328 }
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;
335 }
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;
342 }
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 };
355 }
356 }
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 :