Code

Fix four minor node tool regressions:
[inkscape.git] / src / ui / tool / node.cpp
index 886ddd1bed248543aa29b60ee9cab7f6748a4e9e..12d04dd2b74541e3e4b804c73e600000f4ae16a2 100644 (file)
@@ -270,14 +270,14 @@ void Handle::dragged(Geom::Point &new_pos, GdkEventMotion *event)
                 _parent->position() - node_away->position());
             Inkscape::SnappedPoint p;
             p = sm.constrainedSnap(Inkscape::SnapCandidatePoint(new_pos, SNAPSOURCE_NODE_HANDLE), cl);
-            if (p.getSnapped()) {
-                p.getPoint(new_pos);
-            }
+            new_pos = p.getPoint();
         } else {
             sm.freeSnapReturnByRef(new_pos, SNAPSOURCE_NODE_HANDLE);
         }
+        sm.unSetup();
     }
 
+
     // with Shift, if the node is cusp, rotate the other handle as well
     if (_parent->type() == NODE_CUSP && !_drag_out) {
         if (held_shift(*event)) {
@@ -568,11 +568,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 +576,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 +728,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 +739,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);
 }
 
@@ -944,7 +961,15 @@ void Node::dragged(Geom::Point &new_pos, GdkEventMotion *event)
 {
     // For a note on how snapping is implemented in Inkscape, see snap.h.
     SnapManager &sm = _desktop->namedview->snap_manager;
-    bool snap = sm.someSnapperMightSnap();
+    // even if we won't really snap, we might still call the one of the
+    // constrainedSnap() methods to enforce the constraints, so we need
+    // to setup the snapmanager anyway; this is also required for someSnapperMightSnap()
+    sm.setup(_desktop);
+
+    // do not snap when Shift is pressed
+    bool snap = !held_shift(*event) && sm.someSnapperMightSnap();
+
+    Inkscape::SnappedPoint sp;
     std::vector<Inkscape::SnapCandidatePoint> unselected;
     if (snap) {
         /* setup
@@ -964,17 +989,23 @@ void Node::dragged(Geom::Point &new_pos, GdkEventMotion *event)
                 unselected.push_back(p);
             }
         }
-        sm.setupIgnoreSelection(_desktop, false, &unselected);
+        sm.unSetup();
+        sm.setupIgnoreSelection(_desktop, true, &unselected);
     }
 
     if (held_control(*event)) {
         Geom::Point origin = _last_drag_origin();
-        Inkscape::SnappedPoint fp, bp;
+        std::vector<Inkscape::Snapper::SnapConstraint> constraints;
         if (held_alt(*event)) {
             // with Ctrl+Alt, constrain to handle lines
-            // project the new position onto a handle line that is closer
-            boost::optional<Geom::Point> front_point, back_point;
-            boost::optional<Inkscape::Snapper::SnapConstraint> line_front, line_back;
+            // project the new position onto a handle line that is closer;
+            // also snap to perpendiculars of handle lines
+
+            Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+            int snaps = prefs->getIntLimited("/options/rotationsnapsperpi/value", 12, 1, 1000);
+            double min_angle = M_PI / snaps;
+
+            boost::optional<Geom::Point> front_point, back_point, fperp_point, bperp_point;
             if (_front.isDegenerate()) {
                 if (_is_line_segment(this, _next()))
                     front_point = _next()->position() - origin;
@@ -987,74 +1018,44 @@ void Node::dragged(Geom::Point &new_pos, GdkEventMotion *event)
             } else {
                 back_point = _back.relativePos();
             }
-            if (front_point)
-                line_front = Inkscape::Snapper::SnapConstraint(origin, *front_point);
-            if (back_point)
-                line_back = Inkscape::Snapper::SnapConstraint(origin, *back_point);
-
-            // TODO: combine the snap and non-snap branches by modifying snap.h / snap.cpp
-            if (snap) {
-                if (line_front) {
-                    fp = sm.constrainedSnap(Inkscape::SnapCandidatePoint(new_pos,
-                        _snapSourceType()), *line_front);
-                }
-                if (line_back) {
-                    bp = sm.constrainedSnap(Inkscape::SnapCandidatePoint(new_pos,
-                        _snapSourceType()), *line_back);
-                }
+            if (front_point) {
+                constraints.push_back(Inkscape::Snapper::SnapConstraint(origin, *front_point));
+                fperp_point = Geom::rot90(*front_point);
             }
-            if (fp.getSnapped() || bp.getSnapped()) {
-                if (fp.isOtherSnapBetter(bp, false)) {
-                    fp = bp;
-                }
-                fp.getPoint(new_pos);
-                _desktop->snapindicator->set_new_snaptarget(fp);
-            } else {
-                boost::optional<Geom::Point> pos;
-                if (line_front) {
-                    pos = line_front->projection(new_pos);
-                }
-                if (line_back) {
-                    Geom::Point pos2 = line_back->projection(new_pos);
-                    if (!pos || (pos && Geom::distance(new_pos, *pos) > Geom::distance(new_pos, pos2)))
-                        pos = pos2;
-                }
-                if (pos) {
-                    new_pos = *pos;
-                } else {
-                    new_pos = origin;
-                }
+            if (back_point) {
+                constraints.push_back(Inkscape::Snapper::SnapConstraint(origin, *back_point));
+                bperp_point = Geom::rot90(*back_point);
             }
-        } else {
-            // with Ctrl, constrain to axes
-            // TODO combine the two branches
-            if (snap) {
-                Inkscape::Snapper::SnapConstraint line_x(origin, Geom::Point(1, 0));
-                Inkscape::Snapper::SnapConstraint line_y(origin, Geom::Point(0, 1));
-                fp = sm.constrainedSnap(Inkscape::SnapCandidatePoint(new_pos, _snapSourceType()), line_x);
-                bp = sm.constrainedSnap(Inkscape::SnapCandidatePoint(new_pos, _snapSourceType()), line_y);
+            // perpendiculars only snap when they are further than snap increment away
+            // from the second handle constraint
+            if (fperp_point && (!back_point ||
+                (fabs(Geom::angle_between(*fperp_point, *back_point)) > min_angle &&
+                 fabs(Geom::angle_between(*fperp_point, *back_point)) < M_PI - min_angle)))
+            {
+                constraints.push_back(Inkscape::Snapper::SnapConstraint(origin, *fperp_point));
             }
-            if (fp.getSnapped() || bp.getSnapped()) {
-                if (fp.isOtherSnapBetter(bp, false)) {
-                    fp = bp;
-                }
-                fp.getPoint(new_pos);
-                _desktop->snapindicator->set_new_snaptarget(fp);
-            } else {
-                Geom::Point origin = _last_drag_origin();
-                Geom::Point delta = new_pos - origin;
-                Geom::Dim2 d = (fabs(delta[Geom::X]) < fabs(delta[Geom::Y])) ? Geom::X : Geom::Y;
-                new_pos[d] = origin[d];
+            if (bperp_point && (!front_point ||
+                (fabs(Geom::angle_between(*bperp_point, *front_point)) > min_angle &&
+                 fabs(Geom::angle_between(*bperp_point, *front_point)) < M_PI - min_angle)))
+            {
+                constraints.push_back(Inkscape::Snapper::SnapConstraint(origin, *bperp_point));
             }
+
+            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, held_shift(*event));
         }
+        new_pos = sp.getPoint();
     } else if (snap) {
-        Inkscape::SnappedPoint p = sm.freeSnap(Inkscape::SnapCandidatePoint(new_pos, _snapSourceType()));
-        if (p.getSnapped()) {
-            p.getPoint(new_pos);
-            _desktop->snapindicator->set_new_snaptarget(p);
-        }
+        sp = sm.freeSnap(Inkscape::SnapCandidatePoint(new_pos, _snapSourceType()));
+        new_pos = sp.getPoint();
     }
 
+    sm.unSetup();
+
     SelectableControlPoint::dragged(new_pos, event);
 }
 
@@ -1402,4 +1403,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 :