summaryrefslogtreecommitdiffstats
path: root/src/ui/tool/node.h
diff options
context:
space:
mode:
authorKrzysztof Kosi??ski <tweenk.pl@gmail.com>2009-11-29 15:33:18 +0000
committerKrzysztof Kosiński <tweenk.pl@gmail.com>2009-11-29 15:33:18 +0000
commit31bb8269c26a781036448ed8f8cd93cc84fb2118 (patch)
treec714ce9b38e9b75680b61e7e0992aa2ab40e2584 /src/ui/tool/node.h
parentDeprecation warning fix on xcf export (diff)
downloadinkscape-31bb8269c26a781036448ed8f8cd93cc84fb2118.tar.gz
inkscape-31bb8269c26a781036448ed8f8cd93cc84fb2118.zip
First GSoC node tool commit to Bazaar
(bzr r8846.1.1)
Diffstat (limited to 'src/ui/tool/node.h')
-rw-r--r--src/ui/tool/node.h366
1 files changed, 366 insertions, 0 deletions
diff --git a/src/ui/tool/node.h b/src/ui/tool/node.h
new file mode 100644
index 000000000..9a36642eb
--- /dev/null
+++ b/src/ui/tool/node.h
@@ -0,0 +1,366 @@
+/** @file
+ * Editable node and associated data structures.
+ */
+/* Authors:
+ * Krzysztof Kosiński <tweenk.pl@gmail.com>
+ *
+ * Copyright (C) 2009 Authors
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_UI_TOOL_NODE_H
+#define SEEN_UI_TOOL_NODE_H
+
+#include <iterator>
+#include <iosfwd>
+#include <stdexcept>
+#include <tr1/functional>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/optional.hpp>
+#include <boost/operators.hpp>
+#include "ui/tool/selectable-control-point.h"
+#include "ui/tool/node-types.h"
+
+
+namespace Inkscape {
+namespace UI {
+template <typename> class NodeIterator;
+}
+}
+
+namespace std {
+namespace tr1 {
+template <typename N> struct hash< Inkscape::UI::NodeIterator<N> >;
+}
+}
+
+namespace Inkscape {
+namespace UI {
+
+class PathManipulator;
+
+class Node;
+class Handle;
+class NodeList;
+class SubpathList;
+template <typename> class NodeIterator;
+
+std::ostream &operator<<(std::ostream &, NodeType);
+
+/*
+template <typename T>
+struct ListMember {
+ T *next;
+ T *prev;
+};
+struct SubpathMember : public ListMember<NodeListMember> {
+ Subpath *list;
+};
+struct SubpathListMember : public ListMember<SubpathListMember> {
+ SubpathList *list;
+};
+*/
+
+struct ListNode {
+ ListNode *next;
+ ListNode *prev;
+ NodeList *list;
+};
+
+struct NodeSharedData {
+ SPDesktop *desktop;
+ ControlPointSelection *selection;
+ SPCanvasGroup *node_group;
+ SPCanvasGroup *handle_group;
+ SPCanvasGroup *handle_line_group;
+};
+
+class Handle : public ControlPoint {
+public:
+ virtual ~Handle();
+ inline Geom::Point relativePos();
+ inline double length();
+ bool isDegenerate() { return _degenerate; }
+
+ virtual void setVisible(bool);
+ virtual void move(Geom::Point const &p);
+
+ virtual void setPosition(Geom::Point const &p);
+ inline void setRelativePos(Geom::Point const &p);
+ void setLength(double len);
+ void retract();
+ void setDirection(Geom::Point const &from, Geom::Point const &to);
+ void setDirection(Geom::Point const &dir);
+ Node *parent() { return _parent; }
+
+ static char const *handle_type_to_localized_string(NodeType type);
+ sigc::signal<void> signal_update;
+protected:
+ Handle(NodeSharedData const &data, Geom::Point const &initial_pos, Node *parent);
+ virtual Glib::ustring _getTip(unsigned state);
+ virtual Glib::ustring _getDragTip(GdkEventMotion *event);
+ virtual bool _hasDragTips() { return true; }
+private:
+ void _grabbedHandler();
+ void _draggedHandler(Geom::Point &, GdkEventMotion *);
+ void _ungrabbedHandler();
+ Node *_parent; // the handle's lifetime does not extend beyond that of the parent node,
+ // so a naked pointer is OK and allows setting it during Node's construction
+ SPCanvasItem *_handle_line;
+ bool _degenerate; // this is used often internally so it makes sense to cache this
+
+ static double _saved_length;
+ static bool _drag_out;
+ friend class Node;
+};
+
+class Node : ListNode, public SelectableControlPoint {
+public:
+ Node(NodeSharedData const &data, Geom::Point const &pos);
+ virtual void move(Geom::Point const &p);
+ virtual void transform(Geom::Matrix const &m);
+ virtual Geom::Rect bounds();
+
+ NodeType type() { return _type; }
+ void setType(NodeType type, bool update_handles = true);
+ void showHandles(bool v);
+ void pickBestType(); // automatically determine the type from handle positions
+ bool isDegenerate() { return _front.isDegenerate() && _back.isDegenerate(); }
+ bool isEndNode();
+ Handle *front() { return &_front; }
+ Handle *back() { return &_back; }
+ static NodeType parse_nodetype(char x);
+ NodeList *list() { return static_cast<ListNode*>(this)->list; }
+ void sink();
+
+ static char const *node_type_to_localized_string(NodeType type);
+protected:
+ virtual void _setState(State state);
+ virtual Glib::ustring _getTip(unsigned state);
+ virtual Glib::ustring _getDragTip(GdkEventMotion *event);
+ virtual bool _hasDragTips() { return true; }
+private:
+ Node(Node const &);
+ bool _grabbedHandler(GdkEventMotion *);
+ void _draggedHandler(Geom::Point &, GdkEventMotion *);
+ void _fixNeighbors(Geom::Point const &old_pos, Geom::Point const &new_pos);
+ void _updateAutoHandles();
+ Node *_next();
+ Node *_prev();
+ static SPCtrlShapeType _node_type_to_shape(NodeType type);
+ static bool _is_line_segment(Node *first, Node *second);
+
+ // Handles are always present, but are not visible if they coincide with the node
+ // (are degenerate). A segment that has both handles degenerate is always treated
+ // as a line segment
+ Handle _front; ///< Node handle in the backward direction of the path
+ Handle _back; ///< Node handle in the forward direction of the path
+ NodeType _type; ///< Type of node - cusp, smooth...
+ bool _handles_shown;
+ friend class Handle;
+ friend class NodeList;
+ friend class NodeIterator<Node>;
+ friend class NodeIterator<Node const>;
+};
+
+template <typename N>
+class NodeIterator
+ : public boost::bidirectional_iterator_helper<NodeIterator<N>, N, std::ptrdiff_t,
+ N *, N &>
+{
+public:
+ typedef NodeIterator self;
+ NodeIterator()
+ : _node(0)
+ {}
+ // default copy, default assign
+
+ self &operator++() {
+ _node = _node->next;
+ return *this;
+ }
+ self &operator--() {
+ _node = _node->prev;
+ return *this;
+ }
+ bool operator==(self const &other) const { return _node == other._node; }
+ N &operator*() const { return *static_cast<N*>(_node); }
+ inline operator bool() const; // define after NodeList
+ N *get_pointer() const { return static_cast<N*>(_node); }
+ N *ptr() const { return static_cast<N*>(_node); }
+
+ self next() const;
+ self prev() const;
+private:
+ NodeIterator(ListNode const *n)
+ : _node(const_cast<ListNode*>(n))
+ {}
+ ListNode *_node;
+ friend class NodeList;
+ friend class std::tr1::hash<self>;
+};
+
+class NodeList : ListNode, boost::noncopyable, public boost::enable_shared_from_this<NodeList> {
+public:
+ typedef std::size_t size_type;
+ typedef Node &reference;
+ typedef Node const &const_reference;
+ typedef Node *pointer;
+ typedef Node const *const_pointer;
+ typedef Node value_type;
+ typedef NodeIterator<value_type> iterator;
+ typedef NodeIterator<value_type const> const_iterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+ // TODO Lame. Make this private and make SubpathList a factory
+ NodeList(SubpathList &_list);
+ ~NodeList();
+
+ // iterators
+ iterator begin() { return iterator(next); }
+ iterator end() { return iterator(this); }
+ const_iterator begin() const { return const_iterator(next); }
+ const_iterator end() const { return const_iterator(this); }
+ reverse_iterator rbegin() { return reverse_iterator(end()); }
+ reverse_iterator rend() { return reverse_iterator(begin()); }
+ const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
+ const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
+
+ // size
+ bool empty();
+ size_type size();
+
+ // extra node-specific methods
+ bool closed();
+ bool degenerate();
+ void setClosed(bool c) { _closed = c; }
+ iterator before(double t, double *fracpart = NULL);
+ const_iterator before(double t, double *fracpart = NULL) const {
+ return const_iterator(before(t, fracpart)._node);
+ }
+
+ // list operations
+ iterator insert(iterator pos, Node *x);
+ template <class InputIterator>
+ void insert(iterator pos, InputIterator first, InputIterator last) {
+ for (; first != last; ++first) insert(pos, *first);
+ }
+ void splice(iterator pos, NodeList &list);
+ void splice(iterator pos, NodeList &list, iterator i);
+ void splice(iterator pos, NodeList &list, iterator first, iterator last);
+ void reverse();
+ void shift(int n);
+ void push_front(Node *x) { insert(begin(), x); }
+ void pop_front() { erase(begin()); }
+ void push_back(Node *x) { insert(end(), x); }
+ void pop_back() { erase(--end()); }
+ void clear();
+ iterator erase(iterator pos);
+ iterator erase(iterator first, iterator last) {
+ NodeList::iterator ret = first;
+ while (first != last) ret = erase(first++);
+ return ret;
+ }
+
+ // member access - undefined results when the list is empty
+ Node &front() { return *static_cast<Node*>(next); }
+ Node &back() { return *static_cast<Node*>(prev); }
+
+ // HACK remove this subpath from its path. This will be removed later.
+ void kill();
+
+ static iterator get_iterator(Node *n) { return iterator(n); }
+ static const_iterator get_iterator(Node const *n) { return const_iterator(n); }
+ static NodeList &get(Node *n);
+ static NodeList &get(iterator const &i);
+private:
+ // no copy or assign
+ NodeList(NodeList const &);
+ void operator=(NodeList const &);
+
+ SubpathList &_list;
+ bool _closed;
+
+ friend class Node;
+ friend class Handle; // required to access handle and handle line groups
+ friend class NodeIterator<Node>;
+ friend class NodeIterator<Node const>;
+};
+
+/** List of node lists. Represents an editable path. */
+class SubpathList : public std::list< boost::shared_ptr<NodeList> > {
+public:
+ typedef std::list< boost::shared_ptr<NodeList> > list_type;
+
+ SubpathList() {}
+
+ sigc::signal<void, Node *> signal_insert_node;
+ sigc::signal<void, Node *> signal_remove_node;
+private:
+ list_type _nodelists;
+ friend class NodeList;
+ friend class Node;
+ friend class Handle;
+};
+
+
+
+// define inline Handle funcs after definition of Node
+inline Geom::Point Handle::relativePos() {
+ return position() - _parent->position();
+}
+inline void Handle::setRelativePos(Geom::Point const &p) {
+ setPosition(_parent->position() + p);
+}
+inline double Handle::length() {
+ return relativePos().length();
+}
+
+// definitions for node iterator
+template <typename N>
+NodeIterator<N>::operator bool() const {
+ return _node && static_cast<ListNode*>(_node->list) != _node;
+}
+template <typename N>
+NodeIterator<N> NodeIterator<N>::next() const {
+ NodeIterator<N> ret(*this);
+ ++ret;
+ if (!ret && _node->list->closed()) ++ret;
+ return ret;
+}
+template <typename N>
+NodeIterator<N> NodeIterator<N>::prev() const {
+ NodeIterator<N> ret(*this);
+ --ret;
+ if (!ret && _node->list->closed()) --ret;
+ return ret;
+}
+
+} // namespace UI
+} // namespace Inkscape
+
+namespace std {
+namespace tr1 {
+template <typename N>
+struct hash< Inkscape::UI::NodeIterator<N> > : public unary_function<Inkscape::UI::NodeIterator<N>, size_t> {
+ size_t operator()(Inkscape::UI::NodeIterator<N> const &ni) const {
+ return reinterpret_cast<size_t>(ni._node);
+ }
+};
+}
+}
+
+#endif
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :