--- orig/src/ui/tool/node.cpp 2018-07-11 05:49:21.700392332 -0700 +++ patch1/src/ui/tool/node.cpp 2018-07-15 15:00:19.449497508 -0700 @@ -158,9 +158,8 @@ 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 the segment between the handle and the node in its direction becomes linear, + // and there are smooth nodes at its ends, make their handles collinear with the segment. if (towards && towards_second->isDegenerate()) { if (node_towards->type() == NODE_SMOOTH) { towards->setDirection(*_parent, *node_towards); @@ -171,7 +170,7 @@ } setPosition(new_pos); - //move the handler and its opposite the same proportion + // move the handle and its opposite the same proportion if(_pm()._isBSpline()){ setPosition(_pm()._bsplineHandleReposition(this, false)); bspline_weight = _pm()._bsplineHandlePosition(this, false); @@ -189,7 +188,7 @@ / Geom::L2sq(direction)) * direction; setRelativePos(new_delta); - //move the handler and its opposite the same proportion + // move the handle and its opposite the same proportion if(_pm()._isBSpline()){ setPosition(_pm()._bsplineHandleReposition(this, false)); bspline_weight = _pm()._bsplineHandlePosition(this, false); @@ -204,8 +203,8 @@ _parent->setType(NODE_SMOOTH, false); // fall through - auto nodes degrade into smooth nodes case NODE_SMOOTH: { - /* for smooth nodes, we need to rotate the other handle so that it's colinear - * with the dragged one while conserving length. */ + // for smooth nodes, we need to rotate the opposite handle + // so that it's collinear with the dragged one, while conserving length. other->setDirection(new_pos, *_parent); } break; case NODE_SYMMETRIC: @@ -216,7 +215,7 @@ } setPosition(new_pos); - // moves the handler and its opposite the same proportion + // move the handle and its opposite the same proportion if(_pm()._isBSpline()){ setPosition(_pm()._bsplineHandleReposition(this, false)); bspline_weight = _pm()._bsplineHandlePosition(this, false); @@ -280,37 +279,75 @@ switch (event->type) { case GDK_KEY_PRESS: + switch (shortcut_key(event->key)) { case GDK_KEY_s: case GDK_KEY_S: + + /* if Shift+S is pressed while hovering over a cusp node handle, + hold the handle in place; otherwise, process normally. + this handle is guaranteed not to be degenerate. */ + if (held_only_shift(event->key) && _parent->_type == NODE_CUSP) { - // when Shift+S is pressed when hovering over a handle belonging to a cusp node, - // hold this handle in place; otherwise process normally - // this handle is guaranteed not to be degenerate - other()->move(_parent->position() - (position() - _parent->position())); + + // make opposite handle collinear, + // but preserve length, unless degenerate + if (other()->isDegenerate()) + other()->setRelativePos(-relativePos()); + else + other()->setDirection(-relativePos()); _parent->setType(NODE_SMOOTH, false); - _parent->_pm().update(); // magic triple combo to add undo event - _parent->_pm().writeXML(); + + // update display + _parent->_pm().update(); + + // update undo history _parent->_pm()._commit(_("Change node type")); + + return true; + } + break; + + case GDK_KEY_y: + case GDK_KEY_Y: + + /* if Shift+Y is pressed while hovering over a cusp, smooth, or auto node handle, + hold the handle in place; otherwise, process normally. + this handle is guaranteed not to be degenerate. */ + + if (held_only_shift(event->key) && (_parent->_type == NODE_CUSP || + _parent->_type == NODE_SMOOTH || + _parent->_type == NODE_AUTO)) { + + // make opposite handle collinear, and of equal length + other()->setRelativePos(-relativePos()); + _parent->setType(NODE_SYMMETRIC, false); + + // update display + _parent->_pm().update(); + + // update undo history + _parent->_pm()._commit(_("Change node type")); + return true; } break; - default: break; } break; - // new double click event to set the handlers of a node to the default proportion, DEFAULT_START_POWER% + case GDK_2BUTTON_PRESS: + + // double-click event to set the handles of a node + // to the position specified by DEFAULT_START_POWER handle_2button_press(); break; - - default: break; } return ControlPoint::_eventHandler(event_context, event); } -//this function moves the handler and its opposite to the default proportion of DEFAULT_START_POWER +// this function moves the handle and its opposite to the position specified by DEFAULT_START_POWER void Handle::handle_2button_press(){ if(_pm()._isBSpline()){ setPosition(_pm()._bsplineHandleReposition(this, DEFAULT_START_POWER)); @@ -367,7 +404,7 @@ ctrl_constraint = Inkscape::Snapper::SnapConstraint(parent_pos, parent_pos - perp_pos); } new_pos = result; - // moves the handler and its opposite in X fixed positions depending on parameter "steps with control" + // move the handle and its opposite in X fixed positions depending on parameter "steps with control" // by default in live BSpline if(_pm()._isBSpline()){ setPosition(new_pos); @@ -377,7 +414,7 @@ } std::vector unselected; - //if the snap adjustment is activated and it is not bspline + // if the snap adjustment is activated and it is not BSpline if (snap && !_pm()._isBSpline()) { ControlPointSelection::Set &nodes = _parent->_selection.allPoints(); for (ControlPointSelection::Set::iterator i = nodes.begin(); i != nodes.end(); ++i) { @@ -418,7 +455,7 @@ other()->setPosition(_saved_other_pos); } } - //if it is bspline but SHIFT or CONTROL are not pressed it fixes it in the original position + // if it is BSpline, but SHIFT or CONTROL are not pressed, fix it in the original position if(_pm()._isBSpline() && !held_shift(*event) && !held_control(*event)){ new_pos=_last_drag_origin(); } @@ -480,8 +517,9 @@ Glib::ustring Handle::_getTip(unsigned state) const { char const *more; - // a trick to mark as bspline if the node has no strength, we are going to use it later - // to show the appropriate messages. We cannot do it in any different way because the function is constant + /* a trick to mark as BSpline if the node has no strength; + we are going to use it later to show the appropriate messages. + we cannot do it in any different way because the function is constant. */ Handle *h = const_cast(this); bool isBSpline = _pm()._isBSpline(); bool can_shift_rotate = _parent->type() == NODE_CUSP && !other()->isDegenerate(); @@ -640,11 +678,11 @@ _front.setPosition(_front.position() + delta); _back.setPosition(_back.position() + delta); - // if the node has a smooth handle after a line segment, it should be kept colinear + // if the node has a smooth handle after a line segment, it should be kept collinear // with the segment _fixNeighbors(old_pos, new_pos); - // move the affected handlers. First the node ones, later the adjoining ones. + // move the affected handles. First the node ones, later the adjoining ones. if(_pm()._isBSpline()){ _front.setPosition(_pm()._bsplineHandleReposition(this->front(),nodeWeight)); _back.setPosition(_pm()._bsplineHandleReposition(this->back(),nodeWeight)); @@ -685,7 +723,7 @@ * but smooth nodes at ends of linear segments and auto nodes need special treatment */ _fixNeighbors(old_pos, position()); - // move the involved handlers, first the node ones, later the adjoining ones + // move the involved handles. First the node ones, later the adjoining ones. if(_pm()._isBSpline()){ _front.setPosition(_pm()._bsplineHandleReposition(this->front(), nodeWeight)); _back.setPosition(_pm()._bsplineHandleReposition(this->back(), nodeWeight)); @@ -708,10 +746,10 @@ void Node::_fixNeighbors(Geom::Point const &old_pos, Geom::Point const &new_pos) { - /* This method restores handle invariants for neighboring nodes, - * and invariants that are based on positions of those nodes for this one. */ + // This method restores handle invariants for neighboring nodes, + // and invariants that are based on positions of those nodes for this one. - /* Fix auto handles */ + // Fix auto handles if (_type == NODE_AUTO) _updateAutoHandles(); if (old_pos != new_pos) { if (_next() && _next()->_type == NODE_AUTO) _next()->_updateAutoHandles(); @@ -719,8 +757,8 @@ } /* Fix smooth handles at the ends of linear segments. - * Rotate the appropriate handle to be colinear with the segment. - * If there is a smooth node at the other end of the segment, rotate it too. */ + Rotate the appropriate handle to be collinear with the segment. + If there is a smooth node at the other end of the segment, rotate it too. */ Handle *handle, *other_handle; Node *other; if (_is_line_segment(this, _next())) { @@ -744,17 +782,16 @@ void Node::_updateAutoHandles() { - // Recompute the position of automatic handles. - // For endnodes, retract both handles. (It's only possible to create an end auto node - // through the XML editor.) + // Recompute the position of automatic handles. For endnodes, retract both handles. + // (It's only possible to create an end auto node through the XML editor.) if (isEndNode()) { _front.retract(); _back.retract(); return; } - // Auto nodes automatically adjust their handles to give an appearance of smoothness, - // no matter what their surroundings are. + // auto nodes automatically adjust their handles to give + // an appearance of smoothness, no matter what their surroundings are. Geom::Point vec_next = _next()->position() - position(); Geom::Point vec_prev = _prev()->position() - position(); double len_next = vec_next.length(), len_prev = vec_prev.length(); @@ -816,7 +853,7 @@ case NODE_SMOOTH: { // ignore attempts to make smooth endnodes. if (isEndNode()) return; - // rotate handles to be colinear + // rotate handles to be collinear // for degenerate nodes set positions like auto handles bool prev_line = _is_line_segment(_prev(), this); bool next_line = _is_line_segment(this, _next()); @@ -834,9 +871,8 @@ } else if (isDegenerate()) { _updateAutoHandles(); } else if (_front.isDegenerate()) { - // if the front handle is degenerate and this...next is a line segment, - // make back colinear; otherwise pull out the other handle - // to 1/3 of distance to prev + // if the front handle is degenerate and next path segment is a line, make back collinear; + // otherwise, pull out the other handle to 1/3 of distance to prev. if (next_line) { _back.setDirection(*_next(), *this); } else if (_prev()) { @@ -851,10 +887,10 @@ _back.setRelativePos(Geom::distance(_next()->position(), position()) / 3 * dir); } } else { - // both handles are extended. make colinear while keeping length - // first make back colinear with the vector front ---> back, - // then make front colinear with back ---> node - // (not back ---> front because back's position was changed in the first call) + /* both handles are extended. make collinear while keeping length. + first make back collinear with the vector front ---> back, + then make front collinear with back ---> node. + (not back ---> front, because back's position was changed in the first call) */ _back.setDirection(_front, _back); _front.setDirection(_back, *this); } @@ -883,8 +919,8 @@ break; default: break; } - /* in node type changes, about bspline traces, we can maintain them with NO_POWER power in border mode, - or we give them the default power in curve mode */ + // in node type changes, for BSpline traces, we can either maintain them + // with NO_POWER power in border mode, or give them the default power in curve mode. if(_pm()._isBSpline()){ double weight = NO_POWER; if(_pm()._bsplineHandlePosition(this->front()) != NO_POWER ){ @@ -1140,7 +1176,7 @@ case STATE_CLICKED: mgr.setActive(_canvas_item, true); mgr.setPrelight(_canvas_item, false); - //this shows the handlers when selecting the nodes + // show the handles when selecting the nodes if(_pm()._isBSpline()){ this->front()->setPosition(_pm()._bsplineHandleReposition(this->front())); this->back()->setPosition(_pm()._bsplineHandleReposition(this->back()));