Code

Node tool: fix handle retraction with non-cusp nodes
[inkscape.git] / src / ui / tool / node.cpp
index 575a2f59ee93c750b7f110ba27a9397e065c223b..1ea994bb98dc58a8bded0f036837c36f52688bd0 100644 (file)
@@ -113,12 +113,29 @@ void Handle::move(Geom::Point const &new_pos)
     Handle *towards_second = node_towards ? node_towards->handleToward(_parent) : NULL;
 
     if (Geom::are_near(new_pos, _parent->position())) {
-        // The handle becomes degenerate. If the segment between it and the node
+        // The handle becomes degenerate.
+        // Adjust node type as necessary.
+        if (other->isDegenerate()) {
+            // If both handles become degenerate, convert to parent cusp node
+            _parent->setType(NODE_CUSP, false);
+        } else {
+            // Only 1 handle becomes degenerate
+            switch (_parent->type()) {
+            case NODE_AUTO:
+            case NODE_SYMMETRIC:
+                _parent->setType(NODE_SMOOTH, false);
+                break;
+            default:
+                // do nothing for other node types
+                break;
+            }
+        }
+        // If the segment between the handle and the node
         // in its direction becomes linear and there are smooth nodes
         // at its ends, make their handles colinear with the segment
-        if (towards && towards->isDegenerate()) {
+        if (towards && towards_second->isDegenerate()) {
             if (node_towards->type() == NODE_SMOOTH) {
-                towards_second->setDirection(*_parent, *node_towards);
+                towards->setDirection(*_parent, *node_towards);
             }
             if (_parent->type() == NODE_SMOOTH) {
                 other->setDirection(*node_towards, *_parent);
@@ -160,6 +177,7 @@ void Handle::move(Geom::Point const &new_pos)
 
 void Handle::setPosition(Geom::Point const &p)
 {
+    Geom::Point old_pos = position();
     ControlPoint::setPosition(p);
     sp_ctrlline_set_coords(SP_CTRLLINE(_handle_line), _parent->position(), position());
 
@@ -167,15 +185,12 @@ void Handle::setPosition(Geom::Point const &p)
     if (Geom::are_near(position(), _parent->position()))
         _degenerate = true;
     else _degenerate = false;
+
     if (_parent->_handles_shown && _parent->visible() && !_degenerate) {
         setVisible(true);
     } else {
         setVisible(false);
     }
-    // If both handles become degenerate, convert to parent cusp node
-    if (_parent->isDegenerate()) {
-        _parent->setType(NODE_CUSP, false);
-    }
 }
 
 void Handle::setLength(double len)
@@ -187,7 +202,7 @@ void Handle::setLength(double len)
 
 void Handle::retract()
 {
-    setPosition(_parent->position());
+    move(_parent->position());
 }
 
 void Handle::setDirection(Geom::Point const &from, Geom::Point const &to)
@@ -568,11 +583,7 @@ void Node::setType(NodeType type, bool update_handles)
     if (update_handles) {
         switch (type) {
         case NODE_CUSP:
-            // if the existing type is also NODE_CUSP, retract handles
-            if (_type == NODE_CUSP) {
-                _front.retract();
-                _back.retract();
-            }
+            // nothing to do
             break;
         case NODE_AUTO:
             // auto handles make no sense for endnodes
@@ -580,13 +591,15 @@ void Node::setType(NodeType type, bool update_handles)
             _updateAutoHandles();
             break;
         case NODE_SMOOTH: {
+            // ignore attempts to make smooth endnodes.
+            if (isEndNode()) return;
             // rotate handles to be colinear
             // for degenerate nodes set positions like auto handles
             bool prev_line = _is_line_segment(_prev(), this);
             bool next_line = _is_line_segment(this, _next());
             if (_type == NODE_SMOOTH) {
-                // for a node that is already smooth and has a degenerate handle,
-                // drag out the second handle to 1/3 the length of the linear segment
+                // For a node that is already smooth and has a degenerate handle,
+                // drag out the second handle without changing the direction of the first one.
                 if (_front.isDegenerate()) {
                     double dist = Geom::distance(_next()->position(), position());
                     _front.setRelativePos(Geom::unit_vector(-_back.relativePos()) * dist / 3);
@@ -730,8 +743,7 @@ NodeType Node::parse_nodetype(char x)
 /** Customized event handler to catch scroll events needed for selection grow/shrink. */
 bool Node::_eventHandler(GdkEvent *event)
 {
-    static NodeList::iterator origin;
-    static int dir;
+    int dir = 0;
 
     switch (event->type)
     {
@@ -742,14 +754,34 @@ bool Node::_eventHandler(GdkEvent *event)
             dir = -1;
         } else break;
         if (held_control(event->scroll)) {
-            _selection.spatialGrow(this, dir);
+            _linearGrow(dir);
         } else {
+            _selection.spatialGrow(this, dir);
+        }
+        return true;
+    case GDK_KEY_PRESS:
+        switch (shortcut_key(event->key))
+        {
+        case GDK_Page_Up:
+            dir = 1;
+            break;
+        case GDK_Page_Down:
+            dir = -1;
+            break;
+        default: goto bail_out;
+        }
+
+        if (held_control(event->key)) {
             _linearGrow(dir);
+        } else {
+            _selection.spatialGrow(this, dir);
         }
         return true;
     default:
         break;
     }
+    
+    bail_out:
     return ControlPoint::_eventHandler(event);
 }
 
@@ -948,7 +980,9 @@ void Node::dragged(Geom::Point &new_pos, GdkEventMotion *event)
     // constrainedSnap() methods to enforce the constraints, so we need
     // to setup the snapmanager anyway; this is also required for someSnapperMightSnap()
     sm.setup(_desktop);
-    bool snap = sm.someSnapperMightSnap();
+
+    // do not snap when Shift is pressed
+    bool snap = !held_shift(*event) && sm.someSnapperMightSnap();
 
     Inkscape::SnappedPoint sp;
     std::vector<Inkscape::SnapCandidatePoint> unselected;
@@ -970,6 +1004,7 @@ void Node::dragged(Geom::Point &new_pos, GdkEventMotion *event)
                 unselected.push_back(p);
             }
         }
+        sm.unSetup();
         sm.setupIgnoreSelection(_desktop, true, &unselected);
     }
 
@@ -1021,12 +1056,12 @@ void Node::dragged(Geom::Point &new_pos, GdkEventMotion *event)
                 constraints.push_back(Inkscape::Snapper::SnapConstraint(origin, *bperp_point));
             }
 
-            sp = sm.multipleConstrainedSnaps(Inkscape::SnapCandidatePoint(new_pos, _snapSourceType()), constraints);
+            sp = sm.multipleConstrainedSnaps(Inkscape::SnapCandidatePoint(new_pos, _snapSourceType()), constraints, held_shift(*event));
         } else {
             // with Ctrl, constrain to axes
             constraints.push_back(Inkscape::Snapper::SnapConstraint(origin, Geom::Point(1, 0)));
             constraints.push_back(Inkscape::Snapper::SnapConstraint(origin, Geom::Point(0, 1)));
-            sp = sm.multipleConstrainedSnaps(Inkscape::SnapCandidatePoint(new_pos, _snapSourceType()), constraints);
+            sp = sm.multipleConstrainedSnaps(Inkscape::SnapCandidatePoint(new_pos, _snapSourceType()), constraints, held_shift(*event));
         }
         new_pos = sp.getPoint();
     } else if (snap) {
@@ -1383,4 +1418,4 @@ NodeList &NodeList::get(iterator const &i) {
   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 :