Code

Node tool: fix snapping of node rotation center
[inkscape.git] / src / ui / tool / node.h
index 9a36642eb64cbadfbbe8059be4efc2ad568d55ae..b5d4d88f2045c424edfa7882ba427386434cd1fa 100644 (file)
@@ -11,6 +11,7 @@
 #ifndef SEEN_UI_TOOL_NODE_H
 #define SEEN_UI_TOOL_NODE_H
 
+#include <glib.h>
 #include <iterator>
 #include <iosfwd>
 #include <stdexcept>
@@ -19,6 +20,7 @@
 #include <boost/shared_ptr.hpp>
 #include <boost/optional.hpp>
 #include <boost/operators.hpp>
+#include "snapped-point.h"
 #include "ui/tool/selectable-control-point.h"
 #include "ui/tool/node-types.h"
 
@@ -39,6 +41,7 @@ namespace Inkscape {
 namespace UI {
 
 class PathManipulator;
+class MultiPathManipulator;
 
 class Node;
 class Handle;
@@ -63,9 +66,9 @@ struct SubpathListMember : public ListMember<SubpathListMember> {
 */
 
 struct ListNode {
-    ListNode *next;
-    ListNode *prev;
-    NodeList *list;
+    ListNode *ln_next;
+    ListNode *ln_prev;
+    NodeList *ln_list;
 };
 
 struct NodeSharedData {
@@ -93,23 +96,29 @@ public:
     void setDirection(Geom::Point const &from, Geom::Point const &to);
     void setDirection(Geom::Point const &dir);
     Node *parent() { return _parent; }
+    Handle *other();
 
     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 bool _eventHandler(GdkEvent *event);
+    virtual void dragged(Geom::Point &, GdkEventMotion *);
+    virtual bool grabbed(GdkEventMotion *);
+    virtual void ungrabbed(GdkEventButton *);
+    virtual bool clicked(GdkEventButton *);
+
     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();
+    inline PathManipulator &_pm();
     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 Geom::Point _saved_other_pos;
     static double _saved_length;
     static bool _drag_out;
     friend class Node;
@@ -130,24 +139,36 @@ public:
     bool isEndNode();
     Handle *front() { return &_front; }
     Handle *back()  { return &_back;  }
-    static NodeType parse_nodetype(char x);
-    NodeList *list() { return static_cast<ListNode*>(this)->list; }
+    Handle *handleToward(Node *to);
+    Node *nodeToward(Handle *h);
+    Handle *handleAwayFrom(Node *to);
+    Node *nodeAwayFrom(Handle *h);
+    NodeList &nodeList() { return *(static_cast<ListNode*>(this)->ln_list); }
     void sink();
 
+    static NodeType parse_nodetype(char x);
     static char const *node_type_to_localized_string(NodeType type);
+    // temporarily public
+    virtual bool _eventHandler(GdkEvent *event);
 protected:
+    virtual void dragged(Geom::Point &, GdkEventMotion *);
+    virtual bool grabbed(GdkEventMotion *);
+    virtual bool clicked(GdkEventButton *);
+
     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();
+    void _linearGrow(int dir);
     Node *_next();
     Node *_prev();
+    Inkscape::SnapSourceType _snapSourceType();
+    Inkscape::SnapTargetType _snapTargetType();
+    inline PathManipulator &_pm();
     static SPCtrlShapeType _node_type_to_shape(NodeType type);
     static bool _is_line_segment(Node *first, Node *second);
 
@@ -164,6 +185,32 @@ private:
     friend class NodeIterator<Node const>;
 };
 
+/// Iterator for editable nodes
+/** Use this class for all operations that require some knowledge about the node's
+ * neighbors. It is a bidirectional iterator.
+ *
+ * Because paths can be cyclic, node iterators have two different ways to
+ * increment and decrement them. When using ++/--, the end iterator will eventually
+ * be returned. Whent using advance()/retreat(), the end iterator will only be returned
+ * when the path is open. If it's closed, calling advance() will cycle indefinitely.
+ * This is particularly useful for cases where the adjacency of nodes is more important
+ * than their sequence order.
+ *
+ * When @a i is a node iterator, then:
+ * - <code>++i</code> moves the iterator to the next node in sequence order;
+ * - <code>--i</code> moves the iterator to the previous node in sequence order;
+ * - <code>i.next()</code> returns the next node with wrap-around;
+ * - <code>i.prev()</code> returns the previous node with wrap-around;
+ * - <code>i.advance()</code> moves the iterator to the next node with wrap-around;
+ * - <code>i.retreat()</code> moves the iterator to the previous node with wrap-around.
+ *
+ * next() and prev() do not change their iterator. They can return the end iterator
+ * if the path is open.
+ *
+ * Unlike most other iterators, you can check whether you've reached the end of the list
+ * without having access to the iterator's container.
+ * Simply use <code>if (i) { ...</code>
+ * */
 template <typename N>
 class NodeIterator
     : public boost::bidirectional_iterator_helper<NodeIterator<N>, N, std::ptrdiff_t,
@@ -177,28 +224,39 @@ public:
     // default copy, default assign
 
     self &operator++() {
-        _node = _node->next;
+        _node = _node->ln_next;
         return *this;
     }
     self &operator--() {
-        _node = _node->prev;
+        _node = _node->ln_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
+    /// Get a pointer to the underlying node. Equivalent to <code>&*i</code>.
     N *get_pointer() const { return static_cast<N*>(_node); }
+    /// @see get_pointer()
     N *ptr() const { return static_cast<N*>(_node); }
 
-    self next() const;
-    self prev() const;
+    self next() const {
+        self r(*this);
+        r.advance();
+        return r;
+    }
+    self prev() const {
+        self r(*this);
+        r.retreat();
+        return r;
+    }
+    self &advance();
+    self &retreat();
 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> {
@@ -211,22 +269,16 @@ public:
     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 begin() { return iterator(ln_next); }
     iterator end() { return iterator(this); }
-    const_iterator begin() const { return const_iterator(next); }
+    const_iterator begin() const { return const_iterator(ln_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();
@@ -265,11 +317,12 @@ public:
     }
 
     // member access - undefined results when the list is empty
-    Node &front() { return *static_cast<Node*>(next); }
-    Node &back() { return *static_cast<Node*>(prev); }
+    Node &front() { return *static_cast<Node*>(ln_next); }
+    Node &back() { return *static_cast<Node*>(ln_prev); }
 
     // HACK remove this subpath from its path. This will be removed later.
     void kill();
+    SubpathList &subpathList() { return _list; }
 
     static iterator get_iterator(Node *n) { return iterator(n); }
     static const_iterator get_iterator(Node const *n) { return const_iterator(n); }
@@ -294,12 +347,12 @@ class SubpathList : public std::list< boost::shared_ptr<NodeList> > {
 public:
     typedef std::list< boost::shared_ptr<NodeList> > list_type;
 
-    SubpathList() {}
+    SubpathList(PathManipulator &pm) : _path_manipulator(pm) {}
+    PathManipulator &pm() { return _path_manipulator; }
 
-    sigc::signal<void, Node *> signal_insert_node;
-    sigc::signal<void, Node *> signal_remove_node;
 private:
     list_type _nodelists;
+    PathManipulator &_path_manipulator;
     friend class NodeList;
     friend class Node;
     friend class Handle;
@@ -317,41 +370,34 @@ inline void Handle::setRelativePos(Geom::Point const &p) {
 inline double Handle::length() {
     return relativePos().length();
 }
+inline PathManipulator &Handle::_pm() {
+    return _parent->_pm();
+}
+inline PathManipulator &Node::_pm() {
+    return nodeList().subpathList().pm();
+}
 
 // definitions for node iterator
 template <typename N>
 NodeIterator<N>::operator bool() const {
-    return _node && static_cast<ListNode*>(_node->list) != _node;
+    return _node && static_cast<ListNode*>(_node->ln_list) != _node;
 }
 template <typename N>
-NodeIterator<N> NodeIterator<N>::next() const {
-    NodeIterator<N> ret(*this);
-    ++ret;
-    if (!ret && _node->list->closed()) ++ret;
-    return ret;
+NodeIterator<N> &NodeIterator<N>::advance() {
+    ++(*this);
+    if (G_UNLIKELY(!*this) && _node->ln_list->closed()) ++(*this);
+    return *this;
 }
 template <typename N>
-NodeIterator<N> NodeIterator<N>::prev() const {
-    NodeIterator<N> ret(*this);
-    --ret;
-    if (!ret && _node->list->closed()) --ret;
-    return ret;
+NodeIterator<N> &NodeIterator<N>::retreat() {
+    --(*this);
+    if (G_UNLIKELY(!*this) && _node->ln_list->closed()) --(*this);
+    return *this;
 }
 
 } // 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
 
 /*
@@ -363,4 +409,4 @@ struct hash< Inkscape::UI::NodeIterator<N> > : public unary_function<Inkscape::U
   fill-column:99
   End:
 */
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :