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 &>
200 {
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();
345 }
346 inline void Handle::setRelativePos(Geom::Point const &p) {
347 setPosition(_parent->position() + p);
348 }
349 inline double Handle::length() {
350 return relativePos().length();
351 }
353 // definitions for node iterator
354 template <typename N>
355 NodeIterator<N>::operator bool() const {
356 return _node && static_cast<ListNode*>(_node->list) != _node;
357 }
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;
364 }
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;
371 }
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 };
384 }
385 }
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 :