diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp index 9223b44def6f37222cb0a3bc1d9437fcbd674d9b..4f2c42f7c882c962c2e75e546739160839ca168e 100644 --- a/src/ui/tool/node.cpp +++ b/src/ui/tool/node.cpp @@ -158,9 +158,8 @@ void Handle::move(Geom::Point const &new_pos) 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 @@ void Handle::move(Geom::Point const &new_pos) } 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 @@ void Handle::move(Geom::Point const &new_pos) / 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 @@ void Handle::move(Geom::Point const &new_pos) _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 @@ void Handle::move(Geom::Point const &new_pos) } 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); @@ -266,13 +265,24 @@ void Handle::setDirection(Geom::Point const &dir) char const *Handle::handle_type_to_localized_string(NodeType type) { + char const *s = ""; + switch(type) { - case NODE_CUSP: return _("Cusp node handle"); - case NODE_SMOOTH: return _("Smooth node handle"); - case NODE_SYMMETRIC: return _("Symmetric node handle"); - case NODE_AUTO: return _("Auto-smooth node handle"); - default: return ""; + case NODE_CUSP: + s = _("Corner node handle"); + break; + case NODE_SMOOTH: + s = _("Smooth node handle"); + break; + case NODE_SYMMETRIC: + s = _("Symmetric node handle"); + break; + case NODE_AUTO: + s = _("Auto-smooth node handle"); + break; } + + return (s); } bool Handle::_eventHandler(Inkscape::UI::Tools::ToolBase *event_context, GdkEvent *event) @@ -280,37 +290,75 @@ bool Handle::_eventHandler(Inkscape::UI::Tools::ToolBase *event_context, GdkEven 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 +415,7 @@ void Handle::dragged(Geom::Point &new_pos, GdkEventMotion *event) 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 +425,7 @@ void Handle::dragged(Geom::Point &new_pos, GdkEventMotion *event) } 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 +466,7 @@ void Handle::dragged(Geom::Point &new_pos, GdkEventMotion *event) 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(); } @@ -477,78 +525,147 @@ static double snap_increment_degrees() { return 180.0 / snaps; } +#define DRAG_TO_SHAPE "drag to shape the path" +#define HOVER_TO_LOCK "hover to lock" +#define MAKE_SMOOTH "Shift+S to make smooth" +#define MAKE_SYMMETRIC "Shift+Y to make symmetric" +#define META_KEYS "(more: %s)" + 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(); - if (can_shift_rotate && !isBSpline) { - more = C_("Path handle tip", "more: Shift, Ctrl, Alt"); - } else if(isBSpline){ - more = C_("Path handle tip", "more: Ctrl"); - }else { - more = C_("Path handle tip", "more: Ctrl, Alt"); - } + Glib::ustring s = C_("Path handle tip", + "node control handle"); // not expected + if (state_held_alt(state) && !isBSpline) { if (state_held_control(state)) { if (state_held_shift(state) && can_shift_rotate) { - return format_tip(C_("Path handle tip", - "Shift+Ctrl+Alt: preserve length and snap rotation angle to %g° " - "increments while rotating both handles"), + s = format_tip(C_("Path handle tip", + "Shift+Ctrl+Alt: " + "preserve length and snap rotation angle to %g° increments, " + "and rotate both handles"), snap_increment_degrees()); - } else { - return format_tip(C_("Path handle tip", - "Ctrl+Alt: preserve length and snap rotation angle to %g° increments"), + } + else { + s = format_tip(C_("Path handle tip", + "Ctrl+Alt: " + "preserve length and snap rotation angle to %g° increments"), snap_increment_degrees()); } - } else { + } + else { if (state_held_shift(state) && can_shift_rotate) { - return C_("Path handle tip", + s = C_("Path handle tip", "Shift+Alt: preserve handle length and rotate both handles"); - } else { - return C_("Path handle tip", + } + else { + s = C_("Path handle tip", "Alt: preserve handle length while dragging"); } } - } else { + } + else { if (state_held_control(state)) { if (state_held_shift(state) && can_shift_rotate && !isBSpline) { - return format_tip(C_("Path handle tip", - "Shift+Ctrl: snap rotation angle to %g° increments and rotate both handles"), + s = format_tip(C_("Path handle tip", + "Shift+Ctrl: " + "snap rotation angle to %g° increments, and rotate both handles"), snap_increment_degrees()); - } else if(isBSpline){ - return format_tip(C_("Path handle tip", - "Ctrl: Snap handle to steps defined in BSpline Live Path Effect")); - }else{ - return format_tip(C_("Path handle tip", - "Ctrl: snap rotation angle to %g° increments, click to retract"), + } + else if (isBSpline) { + s = C_("Path handle tip", + "Ctrl: " + "Snap handle to steps defined in BSpline Live Path Effect"); + } + else { + s = format_tip(C_("Path handle tip", + "Ctrl: " + "snap rotation angle to %g° increments, click to retract"), snap_increment_degrees()); } - } else if (state_held_shift(state) && can_shift_rotate && !isBSpline) { - return C_("Path hande tip", + } + else if (state_held_shift(state) && can_shift_rotate && !isBSpline) { + s = C_("Path handle tip", "Shift: rotate both handles by the same angle"); - } else if(state_held_shift(state) && isBSpline){ - return C_("Path hande tip", + } + else if (state_held_shift(state) && isBSpline) { + s = C_("Path handle tip", "Shift: move handle"); } - } + else { + char const *handletype = handle_type_to_localized_string(_parent->_type); + char const *more; - switch (_parent->type()) { - case NODE_AUTO: - return format_tip(C_("Path handle tip", - "Auto node handle: drag to convert to smooth node (%s)"), more); - default: - if(!isBSpline){ - return format_tip(C_("Path handle tip", - "Auto node handle: drag to convert to smooth node (%s)"), more); - }else{ - return format_tip(C_("Path handle tip", - "BSpline node handle: Shift to drag, double click to reset (%s). %g power"),more,_pm()._bsplineHandlePosition(h)); + if (can_shift_rotate && !isBSpline) { + more = C_("Path handle tip", + "Shift, Ctrl, Alt"); + } + else if (isBSpline) { + more = C_("Path handle tip", + "Ctrl"); + } + else { + more = C_("Path handle tip", + "Ctrl, Alt"); + } + + if (_parent->type() == NODE_CUSP) { + s = format_tip(C_("Path handle tip", + "%s: " + DRAG_TO_SHAPE ", " + HOVER_TO_LOCK ", " + MAKE_SMOOTH ", " + MAKE_SYMMETRIC ". " + META_KEYS), + handletype, more); + } + else if (_parent->type() == NODE_SMOOTH) { + s = format_tip(C_("Path handle tip", + "%s: " + DRAG_TO_SHAPE ", " + HOVER_TO_LOCK ", " + MAKE_SYMMETRIC ". " + META_KEYS), + handletype, more); + } + else if (_parent->type() == NODE_AUTO) { + s = format_tip(C_("Path handle tip", + "%s: " + "drag to make smooth, " + HOVER_TO_LOCK ", " + MAKE_SYMMETRIC ". " + META_KEYS), + handletype, more); + } + else if (_parent->type() == NODE_SYMMETRIC) { + s = format_tip(C_("Path handle tip", + "%s: " + DRAG_TO_SHAPE ". " + META_KEYS), + handletype, more); + } + else if (isBSpline) { + double power = _pm()._bsplineHandlePosition(h); + s = format_tip(C_("Path handle tip", + "BSpline node handle (%.3g power): " + "Shift-drag to move, " + "double-click to reset. " + "(more: %s)"), + power, more); + } + else { + s = C_("Path handle tip", + "unknown node handle"); // not expected + } } } + + return (s); } Glib::ustring Handle::_getDragTip(GdkEventMotion */*event*/) const @@ -640,11 +757,11 @@ void Node::move(Geom::Point const &new_pos) _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 +802,7 @@ void Node::transform(Geom::Affine const &m) * 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 +825,10 @@ Geom::Rect Node::bounds() const 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 +836,8 @@ void Node::_fixNeighbors(Geom::Point const &old_pos, Geom::Point const &new_pos) } /* 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 +861,16 @@ void Node::_fixNeighbors(Geom::Point const &old_pos, Geom::Point const &new_pos) 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 +932,7 @@ void Node::setType(NodeType type, bool update_handles) 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 +950,8 @@ void Node::setType(NodeType type, bool update_handles) } 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 +966,10 @@ void Node::setType(NodeType type, bool update_handles) _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 +998,8 @@ void Node::setType(NodeType type, bool update_handles) 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 +1255,7 @@ void Node::_setState(State state) 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())); @@ -1398,58 +1513,101 @@ Node *Node::nodeAwayFrom(Handle *h) return nullptr; } +#define CLICK_TO_SELECT "click to select only this node" +#define CLICK_TO_TOGGLE "click to toggle scale/rotation handles" +#define SHIFT_CTRL_ALT "(more: Shift, Ctrl, Alt)" + Glib::ustring Node::_getTip(unsigned state) const { bool isBSpline = _pm()._isBSpline(); Handle *h = const_cast(&_front); + Glib::ustring s = C_("Path node tip", + "node handle"); // not expected + if (state_held_shift(state)) { - bool can_drag_out = (_next() && _front.isDegenerate()) || (_prev() && _back.isDegenerate()); + bool can_drag_out = (_next() && _front.isDegenerate()) || + (_prev() && _back.isDegenerate()); + if (can_drag_out) { /*if (state_held_control(state)) { - return format_tip(C_("Path node tip", + s = format_tip(C_("Path node tip", "Shift+Ctrl: drag out a handle and snap its angle " "to %f° increments"), snap_increment_degrees()); }*/ - return C_("Path node tip", + s = C_("Path node tip", "Shift: drag out a handle, click to toggle selection"); } - return C_("Path node tip", "Shift: click to toggle selection"); + else { + s = C_("Path node tip", + "Shift: click to toggle selection"); + } } - if (state_held_control(state)) { + else if (state_held_control(state)) { if (state_held_alt(state)) { - return C_("Path node tip", "Ctrl+Alt: move along handle lines, click to delete node"); + s = C_("Path node tip", + "Ctrl+Alt: move along handle lines, click to delete node"); } - return C_("Path node tip", + else { + s = C_("Path node tip", "Ctrl: move along axes, click to change node type"); + } } - if (state_held_alt(state)) { - return C_("Path node tip", "Alt: sculpt nodes"); + else if (state_held_alt(state)) { + s = C_("Path node tip", + "Alt: sculpt nodes"); } - // No modifiers: assemble tip from node type - char const *nodetype = node_type_to_localized_string(_type); - double power = _pm()._bsplineHandlePosition(h); - if (_selection.transformHandlesEnabled() && selected()) { - if (_selection.size() == 1 && !isBSpline) { - return format_tip(C_("Path node tip", - "%s: drag to shape the path (more: Shift, Ctrl, Alt)"), nodetype); - }else if(_selection.size() == 1){ - return format_tip(C_("Path node tip", - "BSpline node: drag to shape the path (more: Shift, Ctrl, Alt). %g power"), power); + else { // No modifiers: assemble tip from node type + char const *nodetype = node_type_to_localized_string(_type); + double power = _pm()._bsplineHandlePosition(h); + + if (_selection.transformHandlesEnabled() && selected()) { + if (_selection.size() == 1) { + if (!isBSpline) { + s = format_tip(C_("Path node tip", + "%s: " + DRAG_TO_SHAPE ". " + SHIFT_CTRL_ALT), + nodetype); + } + else { + s = format_tip(C_("Path node tip", + "BSpline node (%.3g power): " + DRAG_TO_SHAPE ". " + SHIFT_CTRL_ALT), + power); + } + } + else { + s = format_tip(C_("Path node tip", + "%s: " + DRAG_TO_SHAPE ", " + CLICK_TO_TOGGLE ". " + SHIFT_CTRL_ALT), + nodetype); + } + } + else if (!isBSpline) { + s = format_tip(C_("Path node tip", + "%s: " + DRAG_TO_SHAPE ", " + CLICK_TO_SELECT ". " + SHIFT_CTRL_ALT), + nodetype); + } + else { + s = format_tip(C_("Path node tip", + "BSpline node (%.3g power): " + DRAG_TO_SHAPE ", " + CLICK_TO_SELECT ". " + SHIFT_CTRL_ALT), + power); } - return format_tip(C_("Path node tip", - "%s: drag to shape the path, click to toggle scale/rotation handles (more: Shift, Ctrl, Alt)"), nodetype); - } - if (!isBSpline) { - return format_tip(C_("Path node tip", - "%s: drag to shape the path, click to select only this node (more: Shift, Ctrl, Alt)"), nodetype); - }else{ - return format_tip(C_("Path node tip", - "BSpline node: drag to shape the path, click to select only this node (more: Shift, Ctrl, Alt). %g power"), power); - } + + return (s); } Glib::ustring Node::_getDragTip(GdkEventMotion */*event*/) const @@ -1466,13 +1624,24 @@ Glib::ustring Node::_getDragTip(GdkEventMotion */*event*/) const char const *Node::node_type_to_localized_string(NodeType type) { + char const *s = ""; + switch (type) { - case NODE_CUSP: return _("Cusp node"); - case NODE_SMOOTH: return _("Smooth node"); - case NODE_SYMMETRIC: return _("Symmetric node"); - case NODE_AUTO: return _("Auto-smooth node"); - default: return ""; + case NODE_CUSP: + s = _("Corner node"); + break; + case NODE_SMOOTH: + s = _("Smooth node"); + break; + case NODE_SYMMETRIC: + s = _("Symmetric node"); + break; + case NODE_AUTO: + s = _("Auto-smooth node"); + break; } + + return (s); } bool Node::_is_line_segment(Node *first, Node *second) diff --git a/src/ui/tool/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp index 2369a75d416f86560aab6e835326d0564afd2e5f..d49e9bfdc513eae4fa061228b2819b6e8fcd89a8 100644 --- a/src/ui/tool/path-manipulator.cpp +++ b/src/ui/tool/path-manipulator.cpp @@ -192,20 +192,23 @@ void PathManipulator::writeXML() { if (!_live_outline) _updateOutline(); + _setGeometry(); - if (!_path) return; - _observer->block(); - if (!empty()) { - _path->updateRepr(); - _getXMLNode()->setAttribute(_nodetypesKey().data(), _createTypeString().data()); - } else { - // this manipulator will have to be destroyed right after this call - _getXMLNode()->removeObserver(*_observer); - _path->deleteObject(true, true); - _path = nullptr; + if (_path) { + _observer->block(); + if (!empty()) { + _path->updateRepr(); + _getXMLNode()->setAttribute(_nodetypesKey().data(), _createTypeString().data()); + } + else { + // this manipulator will have to be destroyed right after this call + _getXMLNode()->removeObserver(*_observer); + _path->deleteObject(true, true); + _path = nullptr; + } + _observer->unblock(); } - _observer->unblock(); } /** Remove all nodes from the path. */ @@ -1526,8 +1529,12 @@ void PathManipulator::_setGeometry() /** Figure out in what attribute to store the nodetype string. */ Glib::ustring PathManipulator::_nodetypesKey() { - if (_lpe_key.empty()) return "sodipodi:nodetypes"; - return _lpe_key + "-nodetypes"; + // temporary fix + // if (_lpe_key.empty()) + if (false) + return ("sodipodi:nodetypes"); + else + return (_lpe_key + "-nodetypes"); } /** Return the XML node we are editing.