Code

Node tool: fix snapping of node rotation center
[inkscape.git] / src / ui / tool / node.h
index d822d854f100971a1eda0d697e527bf54a9d7e17..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>
@@ -65,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 {
@@ -95,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;
@@ -132,22 +139,28 @@ 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);
@@ -155,6 +168,7 @@ private:
     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);
 
@@ -173,24 +187,28 @@ private:
 
 /// Iterator for editable nodes
 /** Use this class for all operations that require some knowledge about the node's
- * neighbors. It works like a bidirectional iterator.
+ * neighbors. It is a bidirectional iterator.
  *
  * Because paths can be cyclic, node iterators have two different ways to
- * increment and decrement them. Nodes can be iterated over either in the
- * sequence order, which always has a beginning and an end, or in the path order,
- * which can be cyclic (moving to the next node never yields the end iterator).
+ * 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 if the path is cyclic;
- * - <code>i.prev()</code> returns the previous node with wrap-around if the path is cyclic.
+ * - <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 a node iterator is invalid
- * (is an end iterator) without having access to the iterator's container.
+ * 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>
@@ -206,11 +224,11 @@ 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; }
@@ -221,15 +239,24 @@ public:
     /// @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> {
@@ -242,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();
@@ -296,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); }
@@ -326,9 +348,8 @@ public:
     typedef std::list< boost::shared_ptr<NodeList> > list_type;
 
     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;
@@ -349,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
 
 /*
@@ -395,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 :