summaryrefslogtreecommitdiffstats
path: root/src/ui/tool
diff options
context:
space:
mode:
authorJabier Arraiza Cenoz <jabier.arraiza@marker.es>2015-07-24 19:53:33 +0000
committerJabiertxof <jtx@jtx.marker.es>2015-07-24 19:53:33 +0000
commit5a37f06c70e0e4e2519812564f4dcdced7c0246a (patch)
treef959f73813cb6f968072aee1100323b24e294136 /src/ui/tool
parentupdate to trunk (diff)
parentFix a bug continuing a bezier path whith a LPE one like spiro or bspline on a... (diff)
downloadinkscape-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.cpp15
-rw-r--r--src/ui/tool/control-point.h6
-rw-r--r--src/ui/tool/curve-drag-point.cpp29
-rw-r--r--src/ui/tool/curve-drag-point.h6
-rw-r--r--src/ui/tool/multi-path-manipulator.cpp8
-rw-r--r--src/ui/tool/multi-path-manipulator.h1
-rw-r--r--src/ui/tool/node.cpp16
-rw-r--r--src/ui/tool/node.h4
-rw-r--r--src/ui/tool/path-manipulator.cpp71
-rw-r--r--src/ui/tool/path-manipulator.h6
-rw-r--r--src/ui/tool/selector.cpp4
-rw-r--r--src/ui/tool/selector.h1
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;