0194f5053176936f7ee0ef62543cb02fa32d2403
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 <glib.h>
15 #include <iterator>
16 #include <iosfwd>
17 #include <stdexcept>
18 #include <tr1/functional>
19 #include <boost/utility.hpp>
20 #include <boost/shared_ptr.hpp>
21 #include <boost/optional.hpp>
22 #include <boost/operators.hpp>
23 #include "snapped-point.h"
24 #include "ui/tool/selectable-control-point.h"
25 #include "ui/tool/node-types.h"
28 namespace Inkscape {
29 namespace UI {
30 template <typename> class NodeIterator;
31 }
32 }
34 namespace std {
35 namespace tr1 {
36 template <typename N> struct hash< Inkscape::UI::NodeIterator<N> >;
37 }
38 }
40 namespace Inkscape {
41 namespace UI {
43 class PathManipulator;
44 class MultiPathManipulator;
46 class Node;
47 class Handle;
48 class NodeList;
49 class SubpathList;
50 template <typename> class NodeIterator;
52 std::ostream &operator<<(std::ostream &, NodeType);
54 /*
55 template <typename T>
56 struct ListMember {
57 T *next;
58 T *prev;
59 };
60 struct SubpathMember : public ListMember<NodeListMember> {
61 Subpath *list;
62 };
63 struct SubpathListMember : public ListMember<SubpathListMember> {
64 SubpathList *list;
65 };
66 */
68 struct ListNode {
69 ListNode *ln_next;
70 ListNode *ln_prev;
71 NodeList *ln_list;
72 };
74 struct NodeSharedData {
75 SPDesktop *desktop;
76 ControlPointSelection *selection;
77 SPCanvasGroup *node_group;
78 SPCanvasGroup *handle_group;
79 SPCanvasGroup *handle_line_group;
80 };
82 class Handle : public ControlPoint {
83 public:
84 virtual ~Handle();
85 inline Geom::Point relativePos();
86 inline double length();
87 bool isDegenerate() { return _degenerate; }
89 virtual void setVisible(bool);
90 virtual void move(Geom::Point const &p);
92 virtual void setPosition(Geom::Point const &p);
93 inline void setRelativePos(Geom::Point const &p);
94 void setLength(double len);
95 void retract();
96 void setDirection(Geom::Point const &from, Geom::Point const &to);
97 void setDirection(Geom::Point const &dir);
98 Node *parent() { return _parent; }
99 Handle *other();
101 static char const *handle_type_to_localized_string(NodeType type);
102 protected:
103 Handle(NodeSharedData const &data, Geom::Point const &initial_pos, Node *parent);
105 virtual void dragged(Geom::Point &, GdkEventMotion *);
106 virtual bool grabbed(GdkEventMotion *);
107 virtual void ungrabbed(GdkEventButton *);
108 virtual bool clicked(GdkEventButton *);
110 virtual Glib::ustring _getTip(unsigned state);
111 virtual Glib::ustring _getDragTip(GdkEventMotion *event);
112 virtual bool _hasDragTips() { return true; }
113 private:
114 inline PathManipulator &_pm();
115 Node *_parent; // the handle's lifetime does not extend beyond that of the parent node,
116 // so a naked pointer is OK and allows setting it during Node's construction
117 SPCanvasItem *_handle_line;
118 bool _degenerate; // this is used often internally so it makes sense to cache this
120 static Geom::Point _saved_other_pos;
121 static double _saved_length;
122 static bool _drag_out;
123 friend class Node;
124 };
126 class Node : ListNode, public SelectableControlPoint {
127 public:
128 Node(NodeSharedData const &data, Geom::Point const &pos);
129 virtual void move(Geom::Point const &p);
130 virtual void transform(Geom::Matrix const &m);
131 virtual Geom::Rect bounds();
133 NodeType type() { return _type; }
134 void setType(NodeType type, bool update_handles = true);
135 void showHandles(bool v);
136 void pickBestType(); // automatically determine the type from handle positions
137 bool isDegenerate() { return _front.isDegenerate() && _back.isDegenerate(); }
138 bool isEndNode();
139 Handle *front() { return &_front; }
140 Handle *back() { return &_back; }
141 Handle *handleToward(Node *to);
142 Node *nodeToward(Handle *h);
143 Handle *handleAwayFrom(Node *to);
144 Node *nodeAwayFrom(Handle *h);
145 NodeList &nodeList() { return *(static_cast<ListNode*>(this)->ln_list); }
146 void sink();
148 static NodeType parse_nodetype(char x);
149 static char const *node_type_to_localized_string(NodeType type);
150 // temporarily public
151 virtual bool _eventHandler(GdkEvent *event);
152 protected:
153 virtual void dragged(Geom::Point &, GdkEventMotion *);
154 virtual bool grabbed(GdkEventMotion *);
155 virtual bool clicked(GdkEventButton *);
157 virtual void _setState(State state);
158 virtual Glib::ustring _getTip(unsigned state);
159 virtual Glib::ustring _getDragTip(GdkEventMotion *event);
160 virtual bool _hasDragTips() { return true; }
161 private:
162 Node(Node const &);
163 void _fixNeighbors(Geom::Point const &old_pos, Geom::Point const &new_pos);
164 void _updateAutoHandles();
165 void _linearGrow(int dir);
166 Node *_next();
167 Node *_prev();
168 Inkscape::SnapSourceType _snapSourceType();
169 Inkscape::SnapTargetType _snapTargetType();
170 inline PathManipulator &_pm();
171 static SPCtrlShapeType _node_type_to_shape(NodeType type);
172 static bool _is_line_segment(Node *first, Node *second);
174 // Handles are always present, but are not visible if they coincide with the node
175 // (are degenerate). A segment that has both handles degenerate is always treated
176 // as a line segment
177 Handle _front; ///< Node handle in the backward direction of the path
178 Handle _back; ///< Node handle in the forward direction of the path
179 NodeType _type; ///< Type of node - cusp, smooth...
180 bool _handles_shown;
181 friend class Handle;
182 friend class NodeList;
183 friend class NodeIterator<Node>;
184 friend class NodeIterator<Node const>;
185 };
187 /// Iterator for editable nodes
188 /** Use this class for all operations that require some knowledge about the node's
189 * neighbors. It is a bidirectional iterator.
190 *
191 * Because paths can be cyclic, node iterators have two different ways to
192 * increment and decrement them. When using ++/--, the end iterator will eventually
193 * be returned. Whent using advance()/retreat(), the end iterator will only be returned
194 * when the path is open. If it's closed, calling advance() will cycle indefinitely.
195 * This is particularly useful for cases where the adjacency of nodes is more important
196 * than their sequence order.
197 *
198 * When @a i is a node iterator, then:
199 * - <code>++i</code> moves the iterator to the next node in sequence order;
200 * - <code>--i</code> moves the iterator to the previous node in sequence order;
201 * - <code>i.next()</code> returns the next node with wrap-around;
202 * - <code>i.prev()</code> returns the previous node with wrap-around;
203 * - <code>i.advance()</code> moves the iterator to the next node with wrap-around;
204 * - <code>i.retreat()</code> moves the iterator to the previous node with wrap-around.
205 *
206 * next() and prev() do not change their iterator. They can return the end iterator
207 * if the path is open.
208 *
209 * Unlike most other iterators, you can check whether you've reached the end of the list
210 * without having access to the iterator's container.
211 * Simply use <code>if (i) { ...</code>
212 * */
213 template <typename N>
214 class NodeIterator
215 : public boost::bidirectional_iterator_helper<NodeIterator<N>, N, std::ptrdiff_t,
216 N *, N &>
217 {
218 public:
219 typedef NodeIterator self;
220 NodeIterator()
221 : _node(0)
222 {}
223 // default copy, default assign
225 self &operator++() {
226 _node = _node->ln_next;
227 return *this;
228 }
229 self &operator--() {
230 _node = _node->ln_prev;
231 return *this;
232 }
233 bool operator==(self const &other) const { return _node == other._node; }
234 N &operator*() const { return *static_cast<N*>(_node); }
235 inline operator bool() const; // define after NodeList
236 /// Get a pointer to the underlying node. Equivalent to <code>&*i</code>.
237 N *get_pointer() const { return static_cast<N*>(_node); }
238 /// @see get_pointer()
239 N *ptr() const { return static_cast<N*>(_node); }
241 self next() const {
242 self r(*this);
243 r.advance();
244 return r;
245 }
246 self prev() const {
247 self r(*this);
248 r.retreat();
249 return r;
250 }
251 self &advance();
252 self &retreat();
253 private:
254 NodeIterator(ListNode const *n)
255 : _node(const_cast<ListNode*>(n))
256 {}
257 ListNode *_node;
258 friend class NodeList;
259 };
261 class NodeList : ListNode, boost::noncopyable, public boost::enable_shared_from_this<NodeList> {
262 public:
263 typedef std::size_t size_type;
264 typedef Node &reference;
265 typedef Node const &const_reference;
266 typedef Node *pointer;
267 typedef Node const *const_pointer;
268 typedef Node value_type;
269 typedef NodeIterator<value_type> iterator;
270 typedef NodeIterator<value_type const> const_iterator;
272 // TODO Lame. Make this private and make SubpathList a factory
273 NodeList(SubpathList &_list);
274 ~NodeList();
276 // iterators
277 iterator begin() { return iterator(ln_next); }
278 iterator end() { return iterator(this); }
279 const_iterator begin() const { return const_iterator(ln_next); }
280 const_iterator end() const { return const_iterator(this); }
282 // size
283 bool empty();
284 size_type size();
286 // extra node-specific methods
287 bool closed();
288 bool degenerate();
289 void setClosed(bool c) { _closed = c; }
290 iterator before(double t, double *fracpart = NULL);
291 const_iterator before(double t, double *fracpart = NULL) const {
292 return const_iterator(before(t, fracpart)._node);
293 }
295 // list operations
296 iterator insert(iterator pos, Node *x);
297 template <class InputIterator>
298 void insert(iterator pos, InputIterator first, InputIterator last) {
299 for (; first != last; ++first) insert(pos, *first);
300 }
301 void splice(iterator pos, NodeList &list);
302 void splice(iterator pos, NodeList &list, iterator i);
303 void splice(iterator pos, NodeList &list, iterator first, iterator last);
304 void reverse();
305 void shift(int n);
306 void push_front(Node *x) { insert(begin(), x); }
307 void pop_front() { erase(begin()); }
308 void push_back(Node *x) { insert(end(), x); }
309 void pop_back() { erase(--end()); }
310 void clear();
311 iterator erase(iterator pos);
312 iterator erase(iterator first, iterator last) {
313 NodeList::iterator ret = first;
314 while (first != last) ret = erase(first++);
315 return ret;
316 }
318 // member access - undefined results when the list is empty
319 Node &front() { return *static_cast<Node*>(ln_next); }
320 Node &back() { return *static_cast<Node*>(ln_prev); }
322 // HACK remove this subpath from its path. This will be removed later.
323 void kill();
324 SubpathList &subpathList() { return _list; }
326 static iterator get_iterator(Node *n) { return iterator(n); }
327 static const_iterator get_iterator(Node const *n) { return const_iterator(n); }
328 static NodeList &get(Node *n);
329 static NodeList &get(iterator const &i);
330 private:
331 // no copy or assign
332 NodeList(NodeList const &);
333 void operator=(NodeList const &);
335 SubpathList &_list;
336 bool _closed;
338 friend class Node;
339 friend class Handle; // required to access handle and handle line groups
340 friend class NodeIterator<Node>;
341 friend class NodeIterator<Node const>;
342 };
344 /** List of node lists. Represents an editable path. */
345 class SubpathList : public std::list< boost::shared_ptr<NodeList> > {
346 public:
347 typedef std::list< boost::shared_ptr<NodeList> > list_type;
349 SubpathList(PathManipulator &pm) : _path_manipulator(pm) {}
350 PathManipulator &pm() { return _path_manipulator; }
352 private:
353 list_type _nodelists;
354 PathManipulator &_path_manipulator;
355 friend class NodeList;
356 friend class Node;
357 friend class Handle;
358 };
362 // define inline Handle funcs after definition of Node
363 inline Geom::Point Handle::relativePos() {
364 return position() - _parent->position();
365 }
366 inline void Handle::setRelativePos(Geom::Point const &p) {
367 setPosition(_parent->position() + p);
368 }
369 inline double Handle::length() {
370 return relativePos().length();
371 }
372 inline PathManipulator &Handle::_pm() {
373 return _parent->_pm();
374 }
375 inline PathManipulator &Node::_pm() {
376 return nodeList().subpathList().pm();
377 }
379 // definitions for node iterator
380 template <typename N>
381 NodeIterator<N>::operator bool() const {
382 return _node && static_cast<ListNode*>(_node->ln_list) != _node;
383 }
384 template <typename N>
385 NodeIterator<N> &NodeIterator<N>::advance() {
386 ++(*this);
387 if (G_UNLIKELY(!*this) && _node->ln_list->closed()) ++(*this);
388 return *this;
389 }
390 template <typename N>
391 NodeIterator<N> &NodeIterator<N>::retreat() {
392 --(*this);
393 if (G_UNLIKELY(!*this) && _node->ln_list->closed()) --(*this);
394 return *this;
395 }
397 } // namespace UI
398 } // namespace Inkscape
400 #endif
402 /*
403 Local Variables:
404 mode:c++
405 c-file-style:"stroustrup"
406 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
407 indent-tabs-mode:nil
408 fill-column:99
409 End:
410 */
411 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :