diff options
| author | Jabier Arraiza Cenoz <jabier.arraiza@marker.es> | 2015-07-24 19:53:33 +0000 |
|---|---|---|
| committer | Jabiertxof <jtx@jtx.marker.es> | 2015-07-24 19:53:33 +0000 |
| commit | 5a37f06c70e0e4e2519812564f4dcdced7c0246a (patch) | |
| tree | f959f73813cb6f968072aee1100323b24e294136 /src/ui/tool | |
| parent | update to trunk (diff) | |
| parent | Fix a bug continuing a bezier path whith a LPE one like spiro or bspline on a... (diff) | |
| download | inkscape-5a37f06c70e0e4e2519812564f4dcdced7c0246a.tar.gz inkscape-5a37f06c70e0e4e2519812564f4dcdced7c0246a.zip | |
update to trunk
(bzr r13879.1.17)
Diffstat (limited to 'src/ui/tool')
| -rw-r--r-- | src/ui/tool/control-point.cpp | 15 | ||||
| -rw-r--r-- | src/ui/tool/control-point.h | 6 | ||||
| -rw-r--r-- | src/ui/tool/curve-drag-point.cpp | 29 | ||||
| -rw-r--r-- | src/ui/tool/curve-drag-point.h | 6 | ||||
| -rw-r--r-- | src/ui/tool/multi-path-manipulator.cpp | 8 | ||||
| -rw-r--r-- | src/ui/tool/multi-path-manipulator.h | 1 | ||||
| -rw-r--r-- | src/ui/tool/node.cpp | 16 | ||||
| -rw-r--r-- | src/ui/tool/node.h | 4 | ||||
| -rw-r--r-- | src/ui/tool/path-manipulator.cpp | 71 | ||||
| -rw-r--r-- | src/ui/tool/path-manipulator.h | 6 | ||||
| -rw-r--r-- | src/ui/tool/selector.cpp | 4 | ||||
| -rw-r--r-- | src/ui/tool/selector.h | 1 |
12 files changed, 125 insertions, 42 deletions
diff --git a/src/ui/tool/control-point.cpp b/src/ui/tool/control-point.cpp index bcf5c9fce..636595016 100644 --- a/src/ui/tool/control-point.cpp +++ b/src/ui/tool/control-point.cpp @@ -71,7 +71,8 @@ ControlPoint::ControlPoint(SPDesktop *d, Geom::Point const &initial_pos, SPAncho _cset(cset), _state(STATE_NORMAL), _position(initial_pos), - _lurking(false) + _lurking(false), + _double_clicked(false) { _canvas_item = sp_canvas_item_new( group ? group : _desktop->getControls(), SP_TYPE_CTRL, @@ -80,6 +81,7 @@ ControlPoint::ControlPoint(SPDesktop *d, Geom::Point const &initial_pos, SPAncho "filled", TRUE, "fill_color", _cset.normal.fill, "stroked", TRUE, "stroke_color", _cset.normal.stroke, "mode", SP_CTRL_MODE_XOR, NULL); + _commonInit(); } @@ -91,7 +93,8 @@ ControlPoint::ControlPoint(SPDesktop *d, Geom::Point const &initial_pos, SPAncho _cset(cset), _state(STATE_NORMAL), _position(initial_pos), - _lurking(false) + _lurking(false), + _double_clicked(false) { _canvas_item = ControlManager::getManager().createControl(group ? group : _desktop->getControls(), type); g_object_set(_canvas_item, @@ -245,7 +248,8 @@ bool ControlPoint::_eventHandler(Inkscape::UI::Tools::ToolBase *event_context, G static Geom::Point pointer_offset; // number of last doubleclicked button static unsigned next_release_doubleclick = 0; - + _double_clicked = false; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); int drag_tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); GdkEventMotion em; @@ -278,6 +282,7 @@ bool ControlPoint::_eventHandler(Inkscape::UI::Tools::ToolBase *event_context, G Ca = _desktop->canvas; em = event->motion; combine_motion_events(Ca, em, 0); + if (_event_grab && ! event_context->space_panning) { _desktop->snapindicator->remove_snaptarget(); bool transferred = false; @@ -298,6 +303,7 @@ bool ControlPoint::_eventHandler(Inkscape::UI::Tools::ToolBase *event_context, G _drag_initiated = true; } } + if (!transferred) { // dragging in progress Geom::Point new_pos = _desktop->w2d(event_point(event->motion)) + pointer_offset; @@ -305,7 +311,7 @@ bool ControlPoint::_eventHandler(Inkscape::UI::Tools::ToolBase *event_context, G dragged(new_pos, &em); move(new_pos); _updateDragTip(&em); // update dragging tip after moving to new position - + _desktop->scroll_to_point(new_pos); _desktop->set_coordinate_status(_position); sp_event_context_snap_delay_handler(event_context, NULL, @@ -342,6 +348,7 @@ bool ControlPoint::_eventHandler(Inkscape::UI::Tools::ToolBase *event_context, G } else { // it is the end of a click if (next_release_doubleclick) { + _double_clicked = true; return doubleclicked(&event->button); } else { return clicked(&event->button); diff --git a/src/ui/tool/control-point.h b/src/ui/tool/control-point.h index b3ed9545e..4a01b9f21 100644 --- a/src/ui/tool/control-point.h +++ b/src/ui/tool/control-point.h @@ -193,6 +193,8 @@ public: virtual bool _eventHandler(Inkscape::UI::Tools::ToolBase *event_context, GdkEvent *event); SPDesktop *const _desktop; ///< The desktop this control point resides on. + bool doubleClicked() {return _double_clicked;} + protected: struct ColorEntry { @@ -361,6 +363,8 @@ protected: /** Events which should be captured when a handle is being dragged. */ static int const _grab_event_mask; + static bool _drag_initiated; + private: ControlPoint(ControlPoint const &other); @@ -397,7 +401,7 @@ private: static bool _event_grab; - static bool _drag_initiated; + bool _double_clicked; }; diff --git a/src/ui/tool/curve-drag-point.cpp b/src/ui/tool/curve-drag-point.cpp index 23640456e..e460b0fb7 100644 --- a/src/ui/tool/curve-drag-point.cpp +++ b/src/ui/tool/curve-drag-point.cpp @@ -15,6 +15,8 @@ #include "ui/tool/multi-path-manipulator.h" #include "ui/tool/path-manipulator.h" #include "ui/tool/node.h" +#include "sp-namedview.h" +#include "snap.h" namespace Inkscape { namespace UI { @@ -77,6 +79,16 @@ void CurveDragPoint::dragged(Geom::Point &new_pos, GdkEventMotion *event) return; } + if (_drag_initiated && !(event->state & GDK_SHIFT_MASK)) { + SnapManager &m = _desktop->namedview->snap_manager; + SPItem *path = static_cast<SPItem *>(_pm._path); + m.setup(_desktop, true, path); // We will not try to snap to "path" itself + Inkscape::SnapCandidatePoint scp(new_pos, Inkscape::SNAPSOURCE_OTHER_HANDLE); + Inkscape::SnappedPoint sp = m.freeSnap(scp, Geom::OptRect(), false); + new_pos = sp.getPoint(); + m.unSetup(); + } + // Magic Bezier Drag Equations follow! // "weight" describes how the influence of the drag should be distributed // among the handles; 0 = front handle only, 1 = back handle only. @@ -166,14 +178,8 @@ void CurveDragPoint::_insertNode(bool take_selection) // Otherwise clicks on the new node would only work after the user moves the mouse a bit. // PathManipulator will restore visibility when necessary. setVisible(false); - NodeList::iterator inserted = _pm.subdivideSegment(first, _t); - if (take_selection) { - _pm._selection.clear(); - } - _pm._selection.insert(inserted.ptr()); - _pm.update(true); - _pm._commit(_("Add node")); + _pm.insertNode(first, _t, take_selection); } Glib::ustring CurveDragPoint::_getTip(unsigned state) const @@ -181,6 +187,10 @@ Glib::ustring CurveDragPoint::_getTip(unsigned state) const if (_pm.empty()) return ""; if (!first || !first.next()) return ""; bool linear = first->front()->isDegenerate() && first.next()->back()->isDegenerate(); + if(state_held_shift(state) && _pm._isBSpline()){ + return C_("Path segment tip", + "<b>Shift</b>: drag to open or move BSpline handles"); + } if (state_held_shift(state)) { return C_("Path segment tip", "<b>Shift</b>: click to toggle segment selection"); @@ -189,6 +199,11 @@ Glib::ustring CurveDragPoint::_getTip(unsigned state) const return C_("Path segment tip", "<b>Ctrl+Alt</b>: click to insert a node"); } + if(_pm._isBSpline()){ + return C_("Path segment tip", + "<b>BSpline segment</b>: drag to shape the segment, doubleclick to insert node, " + "click to select (more: Shift, Ctrl+Alt)"); + } if (linear) { return C_("Path segment tip", "<b>Linear segment</b>: drag to convert to a Bezier segment, " diff --git a/src/ui/tool/curve-drag-point.h b/src/ui/tool/curve-drag-point.h index ea83978e0..c1d40575f 100644 --- a/src/ui/tool/curve-drag-point.h +++ b/src/ui/tool/curve-drag-point.h @@ -34,7 +34,9 @@ public: CurveDragPoint(PathManipulator &pm); void setSize(double sz) { _setSize(sz); } void setTimeValue(double t) { _t = t; } + double getTimeValue() { return _t; } void setIterator(NodeList::iterator i) { first = i; } + NodeList::iterator getIterator() { return first; } virtual bool _eventHandler(Inkscape::UI::Tools::ToolBase *event_context, GdkEvent *event); protected: @@ -47,9 +49,6 @@ protected: virtual bool doubleclicked(GdkEventButton *); private: - - void _insertNode(bool take_selection); - double _t; PathManipulator &_pm; NodeList::iterator first; @@ -57,6 +56,7 @@ private: static bool _drags_stroke; static bool _segment_was_degenerate; static Geom::Point _stroke_drag_origin; + void _insertNode(bool take_selection); }; } // namespace UI diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp index f53cef5f4..46c6246a1 100644 --- a/src/ui/tool/multi-path-manipulator.cpp +++ b/src/ui/tool/multi-path-manipulator.cpp @@ -339,6 +339,14 @@ void MultiPathManipulator::insertNodesAtExtrema(ExtremumType extremum) _done(_("Add extremum nodes")); } +void MultiPathManipulator::insertNode(Geom::Point pt) +{ + // When double clicking to insert nodes, we might not have a selection of nodes (and we don't need one) + // so don't check for "_selection.empty()" here, contrary to the other methods above and below this one + invokeForAll(&PathManipulator::insertNode, pt); + _done(_("Add nodes")); +} + void MultiPathManipulator::duplicateNodes() { if (_selection.empty()) return; diff --git a/src/ui/tool/multi-path-manipulator.h b/src/ui/tool/multi-path-manipulator.h index 1bbcdd7ec..c908cede2 100644 --- a/src/ui/tool/multi-path-manipulator.h +++ b/src/ui/tool/multi-path-manipulator.h @@ -53,6 +53,7 @@ public: void insertNodesAtExtrema(ExtremumType extremum); void insertNodes(); + void insertNode(Geom::Point pt); void alertLPE(); void duplicateNodes(); void joinNodes(); diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp index aa5365265..ca6f5abb1 100644 --- a/src/ui/tool/node.cpp +++ b/src/ui/tool/node.cpp @@ -356,8 +356,8 @@ void Handle::dragged(Geom::Point &new_pos, GdkEventMotion *event) Geom::Line perp_line(parent_pos, parent_pos + Geom::rot90(origin - parent_pos)); Geom::Point snap_pos = parent_pos + Geom::constrain_angle( Geom::Point(0,0), new_pos - parent_pos, snaps, Geom::Point(1,0)); - Geom::Point orig_pos = original_line.pointAt(original_line.nearestPoint(new_pos)); - Geom::Point perp_pos = perp_line.pointAt(perp_line.nearestPoint(new_pos)); + Geom::Point orig_pos = original_line.pointAt(original_line.nearestTime(new_pos)); + Geom::Point perp_pos = perp_line.pointAt(perp_line.nearestTime(new_pos)); Geom::Point result = snap_pos; ctrl_constraint = Inkscape::Snapper::SnapConstraint(parent_pos, parent_pos - snap_pos); @@ -1464,13 +1464,14 @@ Glib::ustring Node::_getTip(unsigned state) const // No modifiers: assemble tip from node type char const *nodetype = node_type_to_localized_string(_type); + double power = _pm()._bsplineHandlePosition(h,h2); if (_selection.transformHandlesEnabled() && selected()) { if (_selection.size() == 1 && !isBSpline) { return format_tip(C_("Path node tip", "<b>%s</b>: drag to shape the path (more: Shift, Ctrl, Alt)"), nodetype); }else if(_selection.size() == 1){ return format_tip(C_("Path node tip", - "<b>BSpline node</b>: drag to shape the path (more: Shift, Ctrl, Alt). %g power"),_pm()._bsplineHandlePosition(h,h2)); + "<b>BSpline node</b>: drag to shape the path (more: Shift, Ctrl, Alt). %g power"), power); } return format_tip(C_("Path node tip", "<b>%s</b>: drag to shape the path, click to toggle scale/rotation handles (more: Shift, Ctrl, Alt)"), nodetype); @@ -1480,7 +1481,7 @@ Glib::ustring Node::_getTip(unsigned state) const "<b>%s</b>: drag to shape the path, click to select only this node (more: Shift, Ctrl, Alt)"), nodetype); }else{ return format_tip(C_("Path node tip", - "<b>BSpline node</b>: drag to shape the path, click to select only this node (more: Shift, Ctrl, Alt). %g power"),_pm()._bsplineHandlePosition(h,h2)); + "<b>BSpline node</b>: drag to shape the path, click to select only this node (more: Shift, Ctrl, Alt). %g power"), power); } } @@ -1567,6 +1568,13 @@ NodeList::iterator NodeList::before(double t, double *fracpart) return ret; } +NodeList::iterator NodeList::before(Geom::PathTime const &pvp) +{ + iterator ret = begin(); + std::advance(ret, pvp.curve_index); + return ret; +} + NodeList::iterator NodeList::insert(iterator pos, Node *x) { ListNode *ins = pos._node; diff --git a/src/ui/tool/node.h b/src/ui/tool/node.h index 101af4817..025c460e2 100644 --- a/src/ui/tool/node.h +++ b/src/ui/tool/node.h @@ -406,9 +406,13 @@ public: void setClosed(bool c) { _closed = c; } iterator before(double t, double *fracpart = NULL); + iterator before(Geom::PathTime const &pvp); const_iterator before(double t, double *fracpart = NULL) const { return const_iterator(before(t, fracpart)._node); } + const_iterator before(Geom::PathTime const &pvp) const { + return const_iterator(before(pvp)._node); + } // list operations diff --git a/src/ui/tool/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp index 6b0c95f68..848b10373 100644 --- a/src/ui/tool/path-manipulator.cpp +++ b/src/ui/tool/path-manipulator.cpp @@ -174,7 +174,8 @@ bool PathManipulator::event(Inkscape::UI::Tools::ToolBase * /*event_context*/, G case GDK_MOTION_NOTIFY: _updateDragPoint(event_point(event->motion)); break; - default: break; + default: + break; } return false; } @@ -275,6 +276,27 @@ void PathManipulator::insertNodes() } } +void PathManipulator::insertNode(Geom::Point pt) +{ + Geom::Coord dist = _updateDragPoint(pt); + if (dist < 1e-5) { // 1e-6 is too small, as observed occasionally when inserting a node at a snapped intersection of paths + insertNode(_dragpoint->getIterator(), _dragpoint->getTimeValue(), true); + } +} + +void PathManipulator::insertNode(NodeList::iterator first, double t, bool take_selection) +{ + NodeList::iterator inserted = subdivideSegment(first, t); + if (take_selection) { + _selection.clear(); + } + _selection.insert(inserted.ptr()); + + update(true); + _commit(_("Add node")); +} + + static void add_or_replace_if_extremum(std::vector< std::pair<NodeList::iterator, double> > &vec, double & extrvalue, double testvalue, NodeList::iterator const& node, double t) @@ -996,7 +1018,7 @@ NodeList::iterator PathManipulator::subdivideSegment(NodeList::iterator first, d Geom::CubicBezier temp(first->position(), first->front()->position(), second->back()->position(), second->position()); std::pair<Geom::CubicBezier, Geom::CubicBezier> div = temp.subdivide(t); - std::vector<Geom::Point> seg1 = div.first.points(), seg2 = div.second.points(); + std::vector<Geom::Point> seg1 = div.first.controlPoints(), seg2 = div.second.controlPoints(); // set new handle positions Node *n = new Node(_multi_path_manipulator._path_data.node_data, seg2[0]); @@ -1141,22 +1163,22 @@ void PathManipulator::_createControlPointsFromGeometry() pathv *= (_edit_transform * _i2d_transform); // in this loop, we know that there are no zero-segment subpaths - for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit) { + for (Geom::PathVector::iterator pit = pathv.begin(); pit != pathv.end(); ++pit) { // prepare new subpath SubpathPtr subpath(new NodeList(_subpaths)); _subpaths.push_back(subpath); Node *previous_node = new Node(_multi_path_manipulator._path_data.node_data, pit->initialPoint()); subpath->push_back(previous_node); - Geom::Curve const &cseg = pit->back_closed(); - bool fuse_ends = pit->closed() - && Geom::are_near(cseg.initialPoint(), cseg.finalPoint()); - for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) { + + bool closed = pit->closed(); + + for (Geom::Path::iterator cit = pit->begin(); cit != pit->end(); ++cit) { Geom::Point pos = cit->finalPoint(); Node *current_node; // if the closing segment is degenerate and the path is closed, we need to move // the handle of the first node instead of creating a new one - if (fuse_ends && cit == --(pit->end_open())) { + if (closed && cit == --(pit->end())) { current_node = subpath->begin().get_pointer(); } else { /* regardless of segment type, create a new node at the end @@ -1271,7 +1293,7 @@ double PathManipulator::_bsplineHandlePosition(Handle *h, Handle *h2) line_inside_nodes->moveto(n->position()); line_inside_nodes->lineto(next_node->position()); if(!are_near(h->position(), n->position())){ - pos = Geom::nearest_point(Geom::Point(h->position()[X] - HANDLE_CUBIC_GAP, h->position()[Y] - HANDLE_CUBIC_GAP), *line_inside_nodes->first_segment()); + pos = Geom::nearest_time(Geom::Point(h->position()[X] - HANDLE_CUBIC_GAP, h->position()[Y] - HANDLE_CUBIC_GAP), *line_inside_nodes->first_segment()); } } if (pos == NO_POWER && !h2){ @@ -1425,7 +1447,7 @@ void PathManipulator::_updateOutline() Geom::PathVector arrows; for (Geom::PathVector::iterator i = pv.begin(); i != pv.end(); ++i) { Geom::Path &path = *i; - for (Geom::Path::const_iterator j = path.begin(); j != path.end_default(); ++j) { + for (Geom::Path::iterator j = path.begin(); j != path.end_default(); ++j) { Geom::Point at = j->pointAt(0.5); Geom::Point ut = j->unitTangentAt(0.5); // rotate the point @@ -1643,33 +1665,40 @@ void PathManipulator::_commit(Glib::ustring const &annotation, gchar const *key) /** Update the position of the curve drag point such that it is over the nearest * point of the path. */ -void PathManipulator::_updateDragPoint(Geom::Point const &evp) +Geom::Coord PathManipulator::_updateDragPoint(Geom::Point const &evp) { + Geom::Coord dist = HUGE_VAL; + Geom::Affine to_desktop = _edit_transform * _i2d_transform; Geom::PathVector pv = _spcurve->get_pathvector(); - boost::optional<Geom::PathVectorPosition> pvp - = Geom::nearestPoint(pv, _desktop->w2d(evp) * to_desktop.inverse()); - if (!pvp) return; - Geom::Point nearest_point = _desktop->d2w(pv.at(pvp->path_nr).pointAt(pvp->t) * to_desktop); - - double fracpart; + + boost::optional<Geom::PathVectorTime> pvp = + pv.nearestTime(_desktop->w2d(evp) * to_desktop.inverse()); + if (!pvp) return dist; + Geom::Point nearest_pt = _desktop->d2w(pv.pointAt(*pvp) * to_desktop); + + double fracpart = pvp->t; std::list<SubpathPtr>::iterator spi = _subpaths.begin(); - for (unsigned i = 0; i < pvp->path_nr; ++i, ++spi) {} - NodeList::iterator first = (*spi)->before(pvp->t, &fracpart); + for (unsigned i = 0; i < pvp->path_index; ++i, ++spi) {} + NodeList::iterator first = (*spi)->before(pvp->asPathTime()); + dist = Geom::distance(evp, nearest_pt); + double stroke_tolerance = _getStrokeTolerance(); if (first && first.next() && fracpart != 0.0 && - Geom::distance(evp, nearest_point) < stroke_tolerance) + dist < stroke_tolerance) { _dragpoint->setVisible(true); - _dragpoint->setPosition(_desktop->w2d(nearest_point)); + _dragpoint->setPosition(_desktop->w2d(nearest_pt)); _dragpoint->setSize(2 * stroke_tolerance); _dragpoint->setTimeValue(fracpart); _dragpoint->setIterator(first); } else { _dragpoint->setVisible(false); } + + return dist; } /// This is called on zoom change to update the direction arrows diff --git a/src/ui/tool/path-manipulator.h b/src/ui/tool/path-manipulator.h index 2219af849..4c6f74ba4 100644 --- a/src/ui/tool/path-manipulator.h +++ b/src/ui/tool/path-manipulator.h @@ -70,6 +70,8 @@ public: void insertNodeAtExtremum(ExtremumType extremum); void insertNodes(); + void insertNode(Geom::Point); + void insertNode(NodeList::iterator first, double t, bool take_selection); void duplicateNodes(); void weldNodes(NodeList::iterator preserve_pos = NodeList::iterator()); void weldSegments(); @@ -133,7 +135,7 @@ private: void _removeNodesFromSelection(); void _commit(Glib::ustring const &annotation); void _commit(Glib::ustring const &annotation, gchar const *key); - void _updateDragPoint(Geom::Point const &); + Geom::Coord _updateDragPoint(Geom::Point const &); void _updateOutlineOnZoomChange(); double _getStrokeTolerance(); Handle *_chooseHandle(Node *n, int which); @@ -143,7 +145,7 @@ private: SPPath *_path; ///< can be an SPPath or an Inkscape::LivePathEffect::Effect !!! SPCurve *_spcurve; // in item coordinates SPCanvasItem *_outline; - CurveDragPoint *_dragpoint; // an invisible control point hoverng over curve + CurveDragPoint *_dragpoint; // an invisible control point hovering over curve PathManipulatorObserver *_observer; Geom::Affine _d2i_transform; ///< desktop-to-item transform Geom::Affine _i2d_transform; ///< item-to-desktop transform, inverse of _d2i_transform diff --git a/src/ui/tool/selector.cpp b/src/ui/tool/selector.cpp index e4e701785..051cb41ae 100644 --- a/src/ui/tool/selector.cpp +++ b/src/ui/tool/selector.cpp @@ -129,6 +129,10 @@ bool Selector::event(Inkscape::UI::Tools::ToolBase *event_context, GdkEvent *eve return false; } +bool Selector::doubleClicked() { + return _dragger->doubleClicked(); +} + } // namespace UI } // namespace Inkscape diff --git a/src/ui/tool/selector.h b/src/ui/tool/selector.h index dbe751ede..bd8d3e1aa 100644 --- a/src/ui/tool/selector.h +++ b/src/ui/tool/selector.h @@ -29,6 +29,7 @@ public: Selector(SPDesktop *d); virtual ~Selector(); virtual bool event(Inkscape::UI::Tools::ToolBase *, GdkEvent *); + virtual bool doubleClicked(); sigc::signal<void, Geom::Rect const &, GdkEventButton*> signal_area; sigc::signal<void, Geom::Point const &, GdkEventButton*> signal_point; |
