diff options
| author | Martin Owens <doctormo@gmail.com> | 2014-03-27 01:33:44 +0000 |
|---|---|---|
| committer | Martin Owens <doctormo@gmail.com> | 2014-03-27 01:33:44 +0000 |
| commit | 5a4fb2325f60d292b47330f540b26a3279341c90 (patch) | |
| tree | d2aa7967be25450b83e625025366c618101ae49f /src/ui/tool/node.cpp | |
| parent | The Polar Arrange Tab of the Arrange Dialog now hides the parametric (diff) | |
| parent | Remove Snap menu item and improve grid menu item text (diff) | |
| download | inkscape-5a4fb2325f60d292b47330f540b26a3279341c90.tar.gz inkscape-5a4fb2325f60d292b47330f540b26a3279341c90.zip | |
Commit a merge to trunk, with probabal errors
(bzr r11073.1.36)
Diffstat (limited to 'src/ui/tool/node.cpp')
| -rw-r--r-- | src/ui/tool/node.cpp | 302 |
1 files changed, 158 insertions, 144 deletions
diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp index ad48b523b..fbbc4be64 100644 --- a/src/ui/tool/node.cpp +++ b/src/ui/tool/node.cpp @@ -1,7 +1,3 @@ -/** - * @file - * Editable node - implementation. - */ /* Authors: * Krzysztof Kosiński <tweenk.pl@gmail.com> * Jon A. Cruz <jon@joncruz.org> @@ -26,33 +22,57 @@ #include "preferences.h" #include "snap.h" #include "snap-preferences.h" -#include "sp-metrics.h" #include "sp-namedview.h" +#include "ui/control-manager.h" #include "ui/tool/control-point-selection.h" #include "ui/tool/event-utils.h" #include "ui/tool/node.h" #include "ui/tool/path-manipulator.h" #include <gdk/gdkkeysyms.h> -#if !GTK_CHECK_VERSION(2,22,0) -#include "compat-key-syms.h" -#endif +namespace { + +Inkscape::ControlType nodeTypeToCtrlType(Inkscape::UI::NodeType type) +{ + Inkscape::ControlType result = Inkscape::CTRL_TYPE_NODE_CUSP; + switch(type) { + case Inkscape::UI::NODE_SMOOTH: + result = Inkscape::CTRL_TYPE_NODE_SMOOTH; + break; + case Inkscape::UI::NODE_AUTO: + result = Inkscape::CTRL_TYPE_NODE_AUTO; + break; + case Inkscape::UI::NODE_SYMMETRIC: + result = Inkscape::CTRL_TYPE_NODE_SYMETRICAL; + break; + case Inkscape::UI::NODE_CUSP: + default: + result = Inkscape::CTRL_TYPE_NODE_CUSP; + break; + } + return result; +} + +} // namespace namespace Inkscape { namespace UI { -static SelectableControlPoint::ColorSet node_colors = { - { - {0xbfbfbf00, 0x000000ff}, // normal fill, stroke - {0xff000000, 0x000000ff}, // mouseover fill, stroke - {0xff000000, 0x000000ff} // clicked fill, stroke - }, +ControlPoint::ColorSet Node::node_colors = { + {0xbfbfbf00, 0x000000ff}, // normal fill, stroke + {0xff000000, 0x000000ff}, // mouseover fill, stroke + {0xff000000, 0x000000ff}, // clicked fill, stroke + // {0x0000ffff, 0x000000ff}, // normal fill, stroke when selected {0xff000000, 0x000000ff}, // mouseover fill, stroke when selected {0xff000000, 0x000000ff} // clicked fill, stroke when selected }; -static ControlPoint::ColorSet handle_colors = { +ControlPoint::ColorSet Handle::_handle_colors = { + {0xffffffff, 0x000000ff}, // normal fill, stroke + {0xff000000, 0x000000ff}, // mouseover fill, stroke + {0xff000000, 0x000000ff}, // clicked fill, stroke + // {0xffffffff, 0x000000ff}, // normal fill, stroke {0xff000000, 0x000000ff}, // mouseover fill, stroke {0xff000000, 0x000000ff} // clicked fill, stroke @@ -75,30 +95,27 @@ static Geom::Point direction(Geom::Point const &first, Geom::Point const &second return Geom::unit_vector(second - first); } -/** - * Control point of a cubic Bezier curve in a path. - * - * Handle keeps the node type invariant only for the opposite handle of the same node. - * Keeping the invariant on node moves is left to the %Node class. - */ Geom::Point Handle::_saved_other_pos(0, 0); + double Handle::_saved_length = 0.0; + bool Handle::_drag_out = false; -Handle::Handle(NodeSharedData const &data, Geom::Point const &initial_pos, Node *parent) - : ControlPoint(data.desktop, initial_pos, SP_ANCHOR_CENTER, SP_CTRL_SHAPE_CIRCLE, 7.0, - &handle_colors, data.handle_group) - , _parent(parent) - , _degenerate(true) +Handle::Handle(NodeSharedData const &data, Geom::Point const &initial_pos, Node *parent) : + ControlPoint(data.desktop, initial_pos, SP_ANCHOR_CENTER, + CTRL_TYPE_ADJ_HANDLE, + _handle_colors, data.handle_group), + _parent(parent), + _handle_line(ControlManager::getManager().createControlLine(data.handle_line_group)), + _degenerate(true) { - _cset = &handle_colors; - _handle_line = SP_CTRLLINE(sp_canvas_item_new(data.handle_line_group, SP_TYPE_CTRLLINE, NULL)); setVisible(false); } + Handle::~Handle() { //sp_canvas_item_hide(_handle_line); - gtk_object_destroy(_handle_line); + sp_canvas_item_destroy(_handle_line); } void Handle::setVisible(bool v) @@ -233,7 +250,7 @@ char const *Handle::handle_type_to_localized_string(NodeType type) } } -bool Handle::_eventHandler(SPEventContext *event_context, GdkEvent *event) +bool Handle::_eventHandler(Inkscape::UI::Tools::ToolBase *event_context, GdkEvent *event) { switch (event->type) { @@ -275,7 +292,7 @@ void Handle::dragged(Geom::Point &new_pos, GdkEventMotion *event) Geom::Point parent_pos = _parent->position(); Geom::Point origin = _last_drag_origin(); SnapManager &sm = _desktop->namedview->snap_manager; - bool snap = sm.someSnapperMightSnap(); + bool snap = held_shift(*event) ? false : sm.someSnapperMightSnap(); boost::optional<Inkscape::Snapper::SnapConstraint> ctrl_constraint; // with Alt, preserve length @@ -387,10 +404,18 @@ bool Handle::clicked(GdkEventButton *event) return true; } +Handle const *Handle::other() const +{ + return const_cast<Handle *>(this)->other(); +} + Handle *Handle::other() { - if (this == &_parent->_front) return &_parent->_back; - return &_parent->_front; + if (this == &_parent->_front) { + return &_parent->_back; + } else { + return &_parent->_front; + } } static double snap_increment_degrees() { @@ -399,7 +424,7 @@ static double snap_increment_degrees() { return 180.0 / snaps; } -Glib::ustring Handle::_getTip(unsigned state) +Glib::ustring Handle::_getTip(unsigned state) const { char const *more; bool can_shift_rotate = _parent->type() == NODE_CUSP && !other()->isDegenerate(); @@ -457,16 +482,20 @@ Glib::ustring Handle::_getTip(unsigned state) } } -Glib::ustring Handle::_getDragTip(GdkEventMotion */*event*/) +Glib::ustring Handle::_getDragTip(GdkEventMotion */*event*/) const { Geom::Point dist = position() - _last_drag_origin(); // report angle in mathematical convention double angle = Geom::angle_between(Geom::Point(-1,0), position() - _parent->position()); angle += M_PI; // angle is (-M_PI...M_PI] - offset by +pi and scale to 0...360 angle *= 360.0 / (2 * M_PI); - GString *x = SP_PX_TO_METRIC_STRING(dist[Geom::X], _desktop->namedview->getDefaultMetric()); - GString *y = SP_PX_TO_METRIC_STRING(dist[Geom::Y], _desktop->namedview->getDefaultMetric()); - GString *len = SP_PX_TO_METRIC_STRING(length(), _desktop->namedview->getDefaultMetric()); + + Inkscape::Util::Quantity x_q = Inkscape::Util::Quantity(dist[Geom::X], "px"); + Inkscape::Util::Quantity y_q = Inkscape::Util::Quantity(dist[Geom::Y], "px"); + Inkscape::Util::Quantity len_q = Inkscape::Util::Quantity(length(), "px"); + GString *x = g_string_new(x_q.string(_desktop->namedview->doc_units).c_str()); + GString *y = g_string_new(y_q.string(_desktop->namedview->doc_units).c_str()); + GString *len = g_string_new(len_q.string(_desktop->namedview->doc_units).c_str()); Glib::ustring ret = format_tip(C_("Path handle tip", "Move handle by %s, %s; angle %.2f°, length %s"), x->str, y->str, angle, len->str); g_string_free(x, TRUE); @@ -475,34 +504,48 @@ Glib::ustring Handle::_getDragTip(GdkEventMotion */*event*/) return ret; } -/** - * Curve endpoint in an editable path. - * - * The method move() keeps node type invariants during translations. - */ -Node::Node(NodeSharedData const &data, Geom::Point const &initial_pos) - : SelectableControlPoint(data.desktop, initial_pos, SP_ANCHOR_CENTER, - SP_CTRL_SHAPE_DIAMOND, 9.0, *data.selection, &node_colors, data.node_group) - , _front(data, initial_pos, this) - , _back(data, initial_pos, this) - , _type(NODE_CUSP) - , _handles_shown(false) +Node::Node(NodeSharedData const &data, Geom::Point const &initial_pos) : + SelectableControlPoint(data.desktop, initial_pos, SP_ANCHOR_CENTER, + CTRL_TYPE_NODE_CUSP, + *data.selection, + node_colors, data.node_group), + _front(data, initial_pos, this), + _back(data, initial_pos, this), + _type(NODE_CUSP), + _handles_shown(false) { // NOTE we do not set type here, because the handles are still degenerate } +Node const *Node::_next() const +{ + return const_cast<Node*>(this)->_next(); +} + // NOTE: not using iterators won't make this much quicker because iterators can be 100% inlined. Node *Node::_next() { NodeList::iterator n = NodeList::get_iterator(this).next(); - if (n) return n.ptr(); - return NULL; + if (n) { + return n.ptr(); + } else { + return NULL; + } +} + +Node const *Node::_prev() const +{ + return const_cast<Node *>(this)->_prev(); } + Node *Node::_prev() { NodeList::iterator p = NodeList::get_iterator(this).prev(); - if (p) return p.ptr(); - return NULL; + if (p) { + return p.ptr(); + } else { + return NULL; + } } void Node::move(Geom::Point const &new_pos) @@ -531,7 +574,7 @@ void Node::transform(Geom::Affine const &m) _fixNeighbors(old_pos, position()); } -Geom::Rect Node::bounds() +Geom::Rect Node::bounds() const { Geom::Rect b(position(), position()); b.expandTo(_front.position()); @@ -608,17 +651,23 @@ void Node::_updateAutoHandles() void Node::showHandles(bool v) { _handles_shown = v; - if (!_front.isDegenerate()) _front.setVisible(v); - if (!_back.isDegenerate()) _back.setVisible(v); + if (!_front.isDegenerate()) { + _front.setVisible(v); + } + if (!_back.isDegenerate()) { + _back.setVisible(v); + } } -/** Sets the node type and optionally restores the invariants associated with the given type. - * @param type The type to set - * @param update_handles Whether to restore invariants associated with the given type. - * Passing false is useful e.g. wen initially creating the path, - * and when making cusp nodes during some node algorithms. - * Pass true when used in response to an UI node type button. - */ +void Node::updateHandles() +{ + _handleControlStyling(); + + _front._handleControlStyling(); + _back._handleControlStyling(); +} + + void Node::setType(NodeType type, bool update_handles) { if (type == NODE_PICK_BEST) { @@ -711,12 +760,10 @@ void Node::setType(NodeType type, bool update_handles) } } _type = type; - _setShape(_node_type_to_shape(type)); + _setControlType(nodeTypeToCtrlType(_type)); updateState(); } -/** Pick the best type for this node, based on the position of its handles. - * This is what assigns types to nodes created using the pen tool. */ void Node::pickBestType() { _type = NODE_CUSP; @@ -762,17 +809,15 @@ void Node::pickBestType() } } } while (false); - _setShape(_node_type_to_shape(_type)); + _setControlType(nodeTypeToCtrlType(_type)); updateState(); } -bool Node::isEndNode() +bool Node::isEndNode() const { return !_prev() || !_next(); } -/** Move the node to the bottom of its canvas group. Useful for node break, to ensure that - * the selected nodes are above the unselected ones. */ void Node::sink() { sp_canvas_item_move_to_z(_canvas_item, 0); @@ -789,8 +834,7 @@ NodeType Node::parse_nodetype(char x) } } -/** Customized event handler to catch scroll events needed for selection grow/shrink. */ -bool Node::_eventHandler(SPEventContext *event_context, GdkEvent *event) +bool Node::_eventHandler(Inkscape::UI::Tools::ToolBase *event_context, GdkEvent *event) { int dir = 0; @@ -834,8 +878,6 @@ bool Node::_eventHandler(SPEventContext *event_context, GdkEvent *event) return ControlPoint::_eventHandler(event_context, event); } -/** Select or deselect a node in this node's subpath based on its path distance from this node. - * @param dir If negative, shrink selection by one node; if positive, grow by one node */ void Node::_linearGrow(int dir) { // Interestingly, we do not need any help from PathManipulator when doing linear grow. @@ -948,29 +990,36 @@ void Node::_linearGrow(int dir) void Node::_setState(State state) { // change node size to match type and selection state - switch (_type) { - case NODE_AUTO: - case NODE_CUSP: - if (selected()) _setSize(11); - else _setSize(9); - break; - default: - if(selected()) _setSize(9); - else _setSize(7); - break; + ControlManager &mgr = ControlManager::getManager(); + mgr.setSelected(_canvas_item, selected()); + switch (state) { + case STATE_NORMAL: + mgr.setActive(_canvas_item, false); + mgr.setPrelight(_canvas_item, false); + break; + case STATE_MOUSEOVER: + mgr.setActive(_canvas_item, false); + mgr.setPrelight(_canvas_item, true); + break; + case STATE_CLICKED: + mgr.setActive(_canvas_item, true); + mgr.setPrelight(_canvas_item, false); + break; } SelectableControlPoint::_setState(state); } bool Node::grabbed(GdkEventMotion *event) { - if (SelectableControlPoint::grabbed(event)) + if (SelectableControlPoint::grabbed(event)) { return true; + } // Dragging out handles with Shift + drag on a node. - if (!held_shift(*event)) return false; + if (!held_shift(*event)) { + return false; + } - Handle *h; Geom::Point evp = event_point(*event); Geom::Point rel_evp = evp - _last_click_event_point(); @@ -991,8 +1040,11 @@ bool Node::grabbed(GdkEventMotion *event) angle_prev = fabs(Geom::angle_between(rel_evp, prev_relpos)); has_degenerate = true; } - if (!has_degenerate) return false; - h = angle_next < angle_prev ? &_front : &_back; + if (!has_degenerate) { + return false; + } + + Handle *h = angle_next < angle_prev ? &_front : &_back; h->setPosition(_desktop->w2d(evp)); h->setVisible(true); @@ -1138,13 +1190,13 @@ bool Node::clicked(GdkEventButton *event) return SelectableControlPoint::clicked(event); } -Inkscape::SnapSourceType Node::_snapSourceType() +Inkscape::SnapSourceType Node::_snapSourceType() const { if (_type == NODE_SMOOTH || _type == NODE_AUTO) return SNAPSOURCE_NODE_SMOOTH; return SNAPSOURCE_NODE_CUSP; } -Inkscape::SnapTargetType Node::_snapTargetType() +Inkscape::SnapTargetType Node::_snapTargetType() const { if (_type == NODE_SMOOTH || _type == NODE_AUTO) return SNAPTARGET_NODE_SMOOTH; @@ -1156,10 +1208,6 @@ Inkscape::SnapCandidatePoint Node::snapCandidatePoint() return SnapCandidatePoint(position(), _snapSourceType(), _snapTargetType()); } -/** - * Gets the handle that faces the given adjacent node. - * Will abort with error if the given node is not adjacent. - */ Handle *Node::handleToward(Node *to) { if (_next() == to) { @@ -1169,12 +1217,9 @@ Handle *Node::handleToward(Node *to) return back(); } g_error("Node::handleToward(): second node is not adjacent!"); + return NULL; } -/** - * Gets the node in the direction of the given handle. - * Will abort with error if the handle doesn't belong to this node. - */ Node *Node::nodeToward(Handle *dir) { if (front() == dir) { @@ -1184,12 +1229,9 @@ Node *Node::nodeToward(Handle *dir) return _prev(); } g_error("Node::nodeToward(): handle is not a child of this node!"); + return NULL; } -/** - * Gets the handle that goes in the direction opposite to the given adjacent node. - * Will abort with error if the given node is not adjacent. - */ Handle *Node::handleAwayFrom(Node *to) { if (_next() == to) { @@ -1199,12 +1241,9 @@ Handle *Node::handleAwayFrom(Node *to) return front(); } g_error("Node::handleAwayFrom(): second node is not adjacent!"); + return NULL; } -/** - * Gets the node in the direction opposite to the given handle. - * Will abort with error if the handle doesn't belong to this node. - */ Node *Node::nodeAwayFrom(Handle *h) { if (front() == h) { @@ -1214,9 +1253,10 @@ Node *Node::nodeAwayFrom(Handle *h) return _next(); } g_error("Node::nodeAwayFrom(): handle is not a child of this node!"); + return NULL; } -Glib::ustring Node::_getTip(unsigned state) +Glib::ustring Node::_getTip(unsigned state) const { if (state_held_shift(state)) { bool can_drag_out = (_next() && _front.isDegenerate()) || (_prev() && _back.isDegenerate()); @@ -1258,13 +1298,15 @@ Glib::ustring Node::_getTip(unsigned state) "<b>%s</b>: drag to shape the path, click to select only this node (more: Shift, Ctrl, Alt)"), nodetype); } -Glib::ustring Node::_getDragTip(GdkEventMotion */*event*/) +Glib::ustring Node::_getDragTip(GdkEventMotion */*event*/) const { Geom::Point dist = position() - _last_drag_origin(); - GString *x = SP_PX_TO_METRIC_STRING(dist[Geom::X], _desktop->namedview->getDefaultMetric()); - GString *y = SP_PX_TO_METRIC_STRING(dist[Geom::Y], _desktop->namedview->getDefaultMetric()); - Glib::ustring ret = format_tip(C_("Path node tip", "Move node by %s, %s"), - x->str, y->str); + + Inkscape::Util::Quantity x_q = Inkscape::Util::Quantity(dist[Geom::X], "px"); + Inkscape::Util::Quantity y_q = Inkscape::Util::Quantity(dist[Geom::Y], "px"); + GString *x = g_string_new(x_q.string(_desktop->namedview->doc_units).c_str()); + GString *y = g_string_new(y_q.string(_desktop->namedview->doc_units).c_str()); + Glib::ustring ret = format_tip(C_("Path node tip", "Move node by %s, %s"), x->str, y->str); g_string_free(x, TRUE); g_string_free(y, TRUE); return ret; @@ -1281,7 +1323,6 @@ char const *Node::node_type_to_localized_string(NodeType type) } } -/** Determine whether two nodes are joined by a linear segment. */ bool Node::_is_line_segment(Node *first, Node *second) { if (!first || !second) return false; @@ -1292,25 +1333,6 @@ bool Node::_is_line_segment(Node *first, Node *second) return false; } -SPCtrlShapeType Node::_node_type_to_shape(NodeType type) -{ - switch(type) { - case NODE_CUSP: return SP_CTRL_SHAPE_DIAMOND; - case NODE_SMOOTH: return SP_CTRL_SHAPE_SQUARE; - case NODE_AUTO: return SP_CTRL_SHAPE_CIRCLE; - case NODE_SYMMETRIC: return SP_CTRL_SHAPE_SQUARE; - default: return SP_CTRL_SHAPE_DIAMOND; - } -} - - -/** - * An editable list of nodes representing a subpath. - * - * It can optionally be cyclic to represent a closed path. - * The list has iterators that act like plain node iterators, but can also be used - * to obtain shared pointers to nodes. - */ NodeList::NodeList(SubpathList &splist) : _list(splist) , _closed(false) @@ -1342,8 +1364,6 @@ bool NodeList::closed() return _closed; } -/** A subpath is degenerate if it has no segments - either one node in an open path - * or no nodes in a closed path */ bool NodeList::degenerate() { return closed() ? empty() : ++begin() == end(); @@ -1360,10 +1380,9 @@ NodeList::iterator NodeList::before(double t, double *fracpart) return ret; } -// insert a node before i -NodeList::iterator NodeList::insert(iterator i, Node *x) +NodeList::iterator NodeList::insert(iterator pos, Node *x) { - ListNode *ins = i._node; + ListNode *ins = pos._node; x->ln_next = ins; x->ln_prev = ins->ln_prev; ins->ln_prev->ln_next = x; @@ -1469,11 +1488,6 @@ NodeList &NodeList::get(iterator const &i) { } -/** - * @class SubpathList - * Editable path composed of one or more subpaths. - */ - } // namespace UI } // namespace Inkscape |
