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 &>
171 {
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();
313 }
314 inline void Handle::setRelativePos(Geom::Point const &p) {
315 setPosition(_parent->position() + p);
316 }
317 inline double Handle::length() {
318 return relativePos().length();
319 }
321 // definitions for node iterator
322 template <typename N>
323 NodeIterator<N>::operator bool() const {
324 return _node && static_cast<ListNode*>(_node->list) != _node;
325 }
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;
332 }
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;
339 }
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 };
352 }
353 }
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 :