summaryrefslogtreecommitdiffstats
path: root/src/ui/tool
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/tool')
-rw-r--r--src/ui/tool/control-point-selection.cpp55
-rw-r--r--src/ui/tool/control-point-selection.h15
-rw-r--r--src/ui/tool/control-point.cpp81
-rw-r--r--src/ui/tool/control-point.h6
-rw-r--r--src/ui/tool/multi-path-manipulator.cpp52
-rw-r--r--src/ui/tool/multi-path-manipulator.h5
-rw-r--r--src/ui/tool/node-tool.cpp12
-rw-r--r--src/ui/tool/node.cpp124
-rw-r--r--src/ui/tool/node.h6
-rw-r--r--src/ui/tool/path-manipulator.cpp48
-rw-r--r--src/ui/tool/path-manipulator.h3
-rw-r--r--src/ui/tool/selectable-control-point.cpp2
12 files changed, 232 insertions, 177 deletions
diff --git a/src/ui/tool/control-point-selection.cpp b/src/ui/tool/control-point-selection.cpp
index d10045c62..5a84592b6 100644
--- a/src/ui/tool/control-point-selection.cpp
+++ b/src/ui/tool/control-point-selection.cpp
@@ -140,7 +140,60 @@ void ControlPointSelection::clear()
erase(i++);
}
-/** Transform all selected control points by the supplied affine transformation. */
+/** Select all points that this selection can contain. */
+void ControlPointSelection::selectAll()
+{
+ for (set_type::iterator i = _all_points.begin(); i != _all_points.end(); ++i) {
+ insert(*i);
+ }
+}
+/** Select all points inside the given rectangle (in desktop coordinates). */
+void ControlPointSelection::selectArea(Geom::Rect const &r)
+{
+ for (set_type::iterator i = _all_points.begin(); i != _all_points.end(); ++i) {
+ if (r.contains(**i))
+ insert(*i);
+ }
+}
+/** Unselect all selected points and select all unselected points. */
+void ControlPointSelection::invertSelection()
+{
+ for (set_type::iterator i = _all_points.begin(); i != _all_points.end(); ++i) {
+ if ((*i)->selected()) erase(*i);
+ else insert(*i);
+ }
+}
+void ControlPointSelection::spatialGrow(SelectableControlPoint *origin, int dir)
+{
+ bool grow = (dir > 0);
+ Geom::Point p = origin->position();
+ double best_dist = grow ? HUGE_VAL : 0;
+ SelectableControlPoint *match = NULL;
+ for (set_type::iterator i = _all_points.begin(); i != _all_points.end(); ++i) {
+ bool selected = (*i)->selected();
+ if (grow && !selected) {
+ double dist = Geom::distance((*i)->position(), p);
+ if (dist < best_dist) {
+ best_dist = dist;
+ match = *i;
+ }
+ }
+ if (!grow && selected) {
+ double dist = Geom::distance((*i)->position(), p);
+ // use >= to also deselect the origin node when it's the last one selected
+ if (dist >= best_dist) {
+ best_dist = dist;
+ match = *i;
+ }
+ }
+ }
+ if (match) {
+ if (grow) insert(match);
+ else erase(match);
+ }
+}
+
+/** Transform all selected control points by the given affine transformation. */
void ControlPointSelection::transform(Geom::Matrix const &m)
{
for (iterator i = _points.begin(); i != _points.end(); ++i) {
diff --git a/src/ui/tool/control-point-selection.h b/src/ui/tool/control-point-selection.h
index 0f0daffaa..38df5c7e5 100644
--- a/src/ui/tool/control-point-selection.h
+++ b/src/ui/tool/control-point-selection.h
@@ -14,6 +14,7 @@
#include <memory>
#include <tr1/unordered_map>
+#include <tr1/unordered_set>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/optional.hpp>
@@ -43,12 +44,12 @@ public:
typedef std::list<sigc::connection> connlist_type;
typedef std::unordered_map< SelectableControlPoint *,
boost::shared_ptr<connlist_type> > map_type;
+ typedef std::unordered_set< SelectableControlPoint * > set_type;
+ typedef set_type Set; // convenience alias
- // boilerplate typedefs
typedef map_type::iterator iterator;
typedef map_type::const_iterator const_iterator;
typedef map_type::size_type size_type;
-
typedef SelectableControlPoint *value_type;
typedef SelectableControlPoint *key_type;
@@ -80,6 +81,15 @@ public:
// find
iterator find(const key_type &k) { return _points.find(k); }
+ // Sometimes it is very useful to keep a list of all selectable points.
+ set_type const &allPoints() const { return _all_points; }
+ set_type &allPoints() { return _all_points; }
+ // ...for example in these methods. Another useful case is snapping.
+ void selectAll();
+ void selectArea(Geom::Rect const &);
+ void invertSelection();
+ void spatialGrow(SelectableControlPoint *origin, int dir);
+
virtual bool event(GdkEvent *);
void transform(Geom::Matrix const &m);
@@ -113,6 +123,7 @@ private:
void _keyboardTransform(Geom::Matrix const &);
void _commitTransform(CommitEvent ce);
map_type _points;
+ set_type _all_points;
boost::optional<double> _rot_radius;
TransformHandleSet *_handles;
SelectableControlPoint *_grabbed_point;
diff --git a/src/ui/tool/control-point.cpp b/src/ui/tool/control-point.cpp
index 74dd6e31c..0d076a5ab 100644
--- a/src/ui/tool/control-point.cpp
+++ b/src/ui/tool/control-point.cpp
@@ -12,13 +12,14 @@
#include <gdkmm.h>
#include <gtkmm.h>
#include <2geom/point.h>
-#include "ui/tool/control-point.h"
-#include "ui/tool/event-utils.h"
-#include "preferences.h"
#include "desktop.h"
#include "desktop-handles.h"
+#include "display/snap-indicator.h"
#include "event-context.h"
#include "message-context.h"
+#include "preferences.h"
+#include "ui/tool/control-point.h"
+#include "ui/tool/event-utils.h"
namespace Inkscape {
namespace UI {
@@ -397,6 +398,7 @@ bool ControlPoint::_eventHandler(GdkEvent *event)
case GDK_MOTION_NOTIFY:
if (held_button<1>(event->motion) && !_desktop->event_context->space_panning) {
+ _desktop->snapindicator->remove_snaptarget();
bool transferred = false;
if (!_drag_initiated) {
bool t = fabs(event->motion.x - _drag_event_origin[Geom::X]) <= drag_tolerance &&
@@ -414,48 +416,57 @@ bool ControlPoint::_eventHandler(GdkEvent *event)
_drag_initiated = true;
}
}
- if (transferred) return true;
- // the point was moved beyond the drag tolerance
- Geom::Point new_pos = _desktop->w2d(event_point(event->motion)) + pointer_offset;
-
- // the new position is passed by reference and can be changed in the handlers.
- signal_dragged.emit(_position, new_pos, &event->motion);
- move(new_pos);
- _updateDragTip(&event->motion); // update dragging tip after moving to new position
-
- _desktop->scroll_to_point(new_pos);
- _desktop->set_coordinate_status(_position);
+ if (!transferred) {
+ // dragging in progress
+ Geom::Point new_pos = _desktop->w2d(event_point(event->motion)) + pointer_offset;
+
+ // the new position is passed by reference and can be changed in the handlers.
+ signal_dragged.emit(_position, new_pos, &event->motion);
+ move(new_pos);
+ _updateDragTip(&event->motion); // 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(_desktop->event_context, NULL,
+ reinterpret_cast<SPKnot*>(this), &event->motion,
+ DelayedSnapEvent::CONTROL_POINT_HANDLER);
+ }
return true;
}
break;
case GDK_BUTTON_RELEASE:
- if (_event_grab) {
- sp_canvas_item_ungrab(_canvas_item, event->button.time);
- _setMouseover(this, event->button.state);
- _event_grab = false;
+ if (!_event_grab) break;
- if (_drag_initiated) {
- sp_canvas_end_forced_full_redraws(_desktop->canvas);
- }
+ // TODO I think this "feature" is wrong.
+ // sp_event_context_snap_watchdog_callback(_desktop->event_context->_delayed_snap_event);
+ sp_event_context_discard_delayed_snap_event(_desktop->event_context);
+ _desktop->snapindicator->remove_snaptarget();
+
+ sp_canvas_item_ungrab(_canvas_item, event->button.time);
+ _setMouseover(this, event->button.state);
+ _event_grab = false;
- if (event->button.button == next_release_doubleclick) {
+ if (_drag_initiated) {
+ sp_canvas_end_forced_full_redraws(_desktop->canvas);
+ }
+
+ if (event->button.button == next_release_doubleclick) {
+ _drag_initiated = false;
+ return signal_doubleclicked.emit(&event->button);
+ }
+ if (event->button.button == 1) {
+ if (_drag_initiated) {
+ // it is the end of a drag
+ signal_ungrabbed.emit(&event->button);
_drag_initiated = false;
- return signal_doubleclicked.emit(&event->button);
+ return true;
+ } else {
+ // it is the end of a click
+ return signal_clicked.emit(&event->button);
}
- if (event->button.button == 1) {
- if (_drag_initiated) {
- // it is the end of a drag
- signal_ungrabbed.emit(&event->button);
- _drag_initiated = false;
- return true;
- } else {
- // it is the end of a click
- return signal_clicked.emit(&event->button);
- }
- }
- _drag_initiated = false;
}
+ _drag_initiated = false;
break;
case GDK_ENTER_NOTIFY:
diff --git a/src/ui/tool/control-point.h b/src/ui/tool/control-point.h
index c4b0a42be..4997c5ef4 100644
--- a/src/ui/tool/control-point.h
+++ b/src/ui/tool/control-point.h
@@ -90,6 +90,9 @@ public:
static sigc::signal<void, ControlPoint*> signal_mouseover_change;
static Glib::ustring format_tip(char const *format, ...) G_GNUC_PRINTF(1,2);
+ // temporarily public, until snapping is refactored a little
+ virtual bool _eventHandler(GdkEvent *event);
+
protected:
ControlPoint(SPDesktop *d, Geom::Point const &initial_pos, Gtk::AnchorType anchor,
SPCtrlShapeType shape, unsigned int size, ColorSet *cset = 0, SPCanvasGroup *group = 0);
@@ -112,14 +115,13 @@ protected:
void _setPixbuf(Glib::RefPtr<Gdk::Pixbuf>);
/// @}
- virtual bool _eventHandler(GdkEvent *event);
virtual Glib::ustring _getTip(unsigned state) { return ""; }
virtual Glib::ustring _getDragTip(GdkEventMotion *event) { return ""; }
virtual bool _hasDragTips() { return false; }
SPDesktop *const _desktop; ///< The desktop this control point resides on.
SPCanvasItem * _canvas_item; ///< Visual representation of the control point.
- ColorSet *_cset; ///< Describes the colors used to represent the point
+ ColorSet *_cset; ///< Colors used to represent the point
State _state;
static int const _grab_event_mask;
diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp
index ac0165e1a..33d96c706 100644
--- a/src/ui/tool/multi-path-manipulator.cpp
+++ b/src/ui/tool/multi-path-manipulator.cpp
@@ -181,71 +181,21 @@ void MultiPathManipulator::setItems(std::set<ShapeRecord> const &s)
void MultiPathManipulator::selectSubpaths()
{
if (_selection.empty()) {
- invokeForAll(&PathManipulator::selectAll);
+ _selection.selectAll();
} else {
invokeForAll(&PathManipulator::selectSubpaths);
}
}
-void MultiPathManipulator::selectAll()
-{
- invokeForAll(&PathManipulator::selectAll);
-}
-
-void MultiPathManipulator::selectArea(Geom::Rect const &area, bool take)
-{
- if (take) _selection.clear();
- invokeForAll(&PathManipulator::selectArea, area);
-}
void MultiPathManipulator::shiftSelection(int dir)
{
invokeForAll(&PathManipulator::shiftSelection, dir);
}
-void MultiPathManipulator::spatialGrow(NodeList::iterator origin, int dir)
-{
- double extr_dist = dir > 0 ? HUGE_VAL : -HUGE_VAL;
- NodeList::iterator target;
- do { // this substitutes for goto
- if ((dir > 0 && !origin->selected())) {
- target = origin;
- break;
- }
-
- bool closest = dir > 0; // when growing, find closest node
- bool selected = dir < 0; // when growing, consider only unselected nodes
-
- for (MapType::iterator i = _mmap.begin(); i != _mmap.end(); ++i) {
- NodeList::iterator t = i->second->extremeNode(origin, selected, !selected, closest);
- if (!t) continue;
- double dist = Geom::distance(*t, *origin);
- bool cond = closest ? (dist < extr_dist) : (dist > extr_dist);
- if (cond) {
- extr_dist = dist;
- target = t;
- }
- }
- } while (0);
-
- if (!target) return;
- if (dir > 0) {
- _selection.insert(target.ptr());
- } else {
- _selection.erase(target.ptr());
- }
-}
-void MultiPathManipulator::invertSelection()
-{
- invokeForAll(&PathManipulator::invertSelection);
-}
void MultiPathManipulator::invertSelectionInSubpaths()
{
invokeForAll(&PathManipulator::invertSelectionInSubpaths);
}
-void MultiPathManipulator::deselect()
-{
- _selection.clear();
-}
void MultiPathManipulator::setNodeType(NodeType type)
{
diff --git a/src/ui/tool/multi-path-manipulator.h b/src/ui/tool/multi-path-manipulator.h
index 4fbbf1b05..46ad3a8d2 100644
--- a/src/ui/tool/multi-path-manipulator.h
+++ b/src/ui/tool/multi-path-manipulator.h
@@ -45,13 +45,8 @@ public:
void cleanup();
void selectSubpaths();
- void selectAll();
- void selectArea(Geom::Rect const &area, bool take);
void shiftSelection(int dir);
- void spatialGrow(NodeList::iterator center, int dir);
- void invertSelection();
void invertSelectionInSubpaths();
- void deselect();
void setNodeType(NodeType t);
void setSegmentType(SegmentType t);
diff --git a/src/ui/tool/node-tool.cpp b/src/ui/tool/node-tool.cpp
index 735ddf87e..c1ba3394e 100644
--- a/src/ui/tool/node-tool.cpp
+++ b/src/ui/tool/node-tool.cpp
@@ -62,12 +62,15 @@
* it might handle all shapes. Handles XML commit of actions that affect all paths or
* the node selection and removes PathManipulators that have no nodes left after e.g. node
* deletes.
- * - ControlPointSelection: keeps track of node selection. Performs actions that require no
+ * - ControlPointSelection: keeps track of node selection and a set of nodes that can potentially
+ * be selected. There can be more than one selection. Performs actions that require no
* knowledge about the path, only about the nodes, like dragging and transforms. It is not
* specific to nodes and can accomodate any control point derived from SelectableControlPoint.
* Transforms nodes in response to transform handle events.
* - TransformHandleSet: displays nodeset transform handles and emits transform events. The aim
* is to eventually use a common class for object and control point transforms.
+ * - SelectableControlPoint: base for any type of selectable point. It can belong to only one
+ * selection.
*
* @par Plans for the future
* @par
@@ -384,9 +387,6 @@ void ink_node_tool_selection_changed(InkNodeTool *nt, Inkscape::Selection *sel)
std::set<ShapeRecord> shapes;
- // TODO this is ugly!!!
- //typedef std::map<SPItem*, std::pair<Geom::Matrix, guint32> > TransMap;
- //typedef std::map<SPPath*, std::pair<Geom::Matrix, guint32> > PathMap;
GSList const *ilist = sel->itemList();
for (GSList *i = const_cast<GSList*>(ilist); i; i = i->next) {
@@ -477,7 +477,7 @@ gint ink_node_tool_root_handler(SPEventContext *event_context, GdkEvent *event)
case GDK_a:
if (held_control(event->key)) {
if (held_alt(event->key)) {
- nt->_multipath->selectAll();
+ nt->_selected_nodes->selectAll();
} else {
// select all nodes in subpaths that have something selected
// if nothing is selected, select everything
@@ -554,7 +554,7 @@ void ink_node_tool_select_area(InkNodeTool *nt, Geom::Rect const &sel, GdkEventB
selection->setList(items);
g_slist_free(items);
} else {
- nt->_multipath->selectArea(sel, !held_shift(*event));
+ nt->_selected_nodes->selectArea(sel);
}
}
void ink_node_tool_select_point(InkNodeTool *nt, Geom::Point const &sel, GdkEventButton *event)
diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp
index 22d4ddc47..adef8e5a7 100644
--- a/src/ui/tool/node.cpp
+++ b/src/ui/tool/node.cpp
@@ -22,6 +22,8 @@
#include "desktop.h"
#include "desktop-handles.h"
#include "preferences.h"
+#include "snap.h"
+#include "snap-preferences.h"
#include "sp-metrics.h"
#include "sp-namedview.h"
#include "ui/tool/control-point-selection.h"
@@ -638,10 +640,8 @@ bool Node::_eventHandler(GdkEvent *event)
} else if (event->scroll.direction == GDK_SCROLL_DOWN) {
dir = -1;
} else break;
- origin = NodeList::get_iterator(this);
-
if (held_control(event->scroll)) {
- list()->_list._path_manipulator._multi_path_manipulator.spatialGrow(origin, dir);
+ _selection.spatialGrow(this, dir);
} else {
_linearGrow(dir);
}
@@ -658,7 +658,6 @@ static double bezier_length (Geom::Point a0, Geom::Point a1, Geom::Point a2, Geo
double lower = Geom::distance(a0, a3);
double upper = Geom::distance(a0, a1) + Geom::distance(a1, a2) + Geom::distance(a2, a3);
- // TODO maybe EPSILON is this is too big in this case?
if (upper - lower < Geom::EPSILON) return (lower + upper)/2;
Geom::Point // Casteljau subdivision
@@ -732,7 +731,7 @@ void Node::_linearGrow(int dir)
} else {
// both iterators that store last selected nodes are initially empty
NodeList::iterator last_fwd, last_rev;
- double last_distance_back, last_distance_front;
+ double last_distance_back = 0, last_distance_front = 0;
while (rev || fwd) {
if (fwd && (!rev || distance_front <= distance_back)) {
@@ -741,7 +740,7 @@ void Node::_linearGrow(int dir)
last_distance_front = distance_front;
}
NodeList::iterator n = fwd.next();
- distance_front += bezier_length(*fwd, fwd->_front, n->_back, *n);
+ if (n) distance_front += bezier_length(*fwd, fwd->_front, n->_back, *n);
fwd = n;
} else if (rev && (!fwd || distance_front > distance_back)) {
if (rev->selected()) {
@@ -749,13 +748,27 @@ void Node::_linearGrow(int dir)
last_distance_back = distance_back;
}
NodeList::iterator p = rev.prev();
- distance_back += bezier_length(*rev, rev->_back, p->_front, *p);
+ if (p) distance_back += bezier_length(*rev, rev->_back, p->_front, *p);
rev = p;
}
// Check whether we walked the entire cyclic subpath.
// This is initially true because both iterators start from this node,
// so this check cannot go in the while condition.
- if (fwd == rev) break;
+ // When this happens, we need to check the last node, pointed to by the iterators.
+ if (fwd && fwd == rev) {
+ if (!fwd->selected()) break;
+ NodeList::iterator fwdp = fwd.prev(), revn = rev.next();
+ double df = distance_front + bezier_length(*fwdp, fwdp->_front, fwd->_back, *fwd);
+ double db = distance_back + bezier_length(*revn, revn->_back, rev->_front, *rev);
+ if (df > db) {
+ last_fwd = fwd;
+ last_distance_front = df;
+ } else {
+ last_rev = rev;
+ last_distance_back = db;
+ }
+ break;
+ }
}
NodeList::iterator t;
@@ -825,34 +838,97 @@ bool Node::_grabbedHandler(GdkEventMotion *event)
void Node::_draggedHandler(Geom::Point &new_pos, GdkEventMotion *event)
{
+ // For a note on how snapping is implemented in Inkscape, see snap.h.
+ SnapManager &sm = _desktop->namedview->snap_manager;
+ Inkscape::SnapPreferences::PointType t = Inkscape::SnapPreferences::SNAPPOINT_NODE;
+ bool snap = sm.someSnapperMightSnap();
+ std::vector< std::pair<Geom::Point, int> > unselected;
+ if (snap) {
+ // setup
+ // TODO we are doing this every time a snap happens. It should once be done only once
+ // per drag - maybe in the grabbed handler?
+ // TODO "unselected" must be valid during the snap run, because it is not copied.
+ // Fix this in snap.h and snap.cpp, then the above.
+
+ // Build the list of unselected nodes.
+ typedef ControlPointSelection::Set Set;
+ Set nodes = _selection.allPoints();
+ for (Set::iterator i = nodes.begin(); i != nodes.end(); ++i) {
+ if (!(*i)->selected()) {
+ Node *n = static_cast<Node*>(*i);
+ unselected.push_back(std::make_pair((*i)->position(), (int) n->_snapTargetType()));
+ }
+ }
+ sm.setupIgnoreSelection(_desktop, true, &unselected);
+ }
+
if (held_control(*event)) {
+ Geom::Point origin = _last_drag_origin();
if (held_alt(*event)) {
// with Ctrl+Alt, constrain to handle lines
// project the new position onto a handle line that is closer
- Geom::Point origin = _last_drag_origin();
- Geom::Line line_front(origin, origin + _front.relativePos());
- Geom::Line line_back(origin, origin + _back.relativePos());
- double dist_front, dist_back;
- dist_front = Geom::distance(new_pos, line_front);
- dist_back = Geom::distance(new_pos, line_back);
- if (dist_front < dist_back) {
- new_pos = Geom::projection(new_pos, line_front);
+ Inkscape::Snapper::ConstraintLine line_front(origin, _front.relativePos());
+ Inkscape::Snapper::ConstraintLine line_back(origin, _back.relativePos());
+
+ // TODO: combine these two branches by modifying snap.h / snap.cpp
+ if (snap) {
+ Inkscape::SnappedPoint fp, bp;
+ fp = sm.constrainedSnap(t, position(), _snapSourceType(), line_front);
+ bp = sm.constrainedSnap(t, position(), _snapSourceType(), line_back);
+
+ if (fp.isOtherSnapBetter(bp, false)) {
+ bp.getPoint(new_pos);
+ } else {
+ fp.getPoint(new_pos);
+ }
} else {
- new_pos = Geom::projection(new_pos, line_back);
+ Geom::Point p_front = line_front.projection(new_pos);
+ Geom::Point p_back = line_back.projection(new_pos);
+ if (Geom::distance(new_pos, p_front) < Geom::distance(new_pos, p_back)) {
+ new_pos = p_front;
+ } else {
+ new_pos = p_back;
+ }
}
} else {
// with Ctrl, constrain to axes
- // TODO maybe add diagonals when the distance from origin is large enough?
- Geom::Point origin = _last_drag_origin();
- Geom::Point delta = new_pos - origin;
- Geom::Dim2 d = (fabs(delta[Geom::X]) < fabs(delta[Geom::Y])) ? Geom::X : Geom::Y;
- new_pos[d] = origin[d];
+ // TODO combine the two branches
+ if (snap) {
+ Inkscape::SnappedPoint fp, bp;
+ Inkscape::Snapper::ConstraintLine line_x(origin, Geom::Point(1, 0));
+ Inkscape::Snapper::ConstraintLine line_y(origin, Geom::Point(0, 1));
+ fp = sm.constrainedSnap(t, position(), _snapSourceType(), line_x);
+ bp = sm.constrainedSnap(t, position(), _snapSourceType(), line_y);
+
+ if (fp.isOtherSnapBetter(bp, false)) {
+ fp = bp;
+ }
+ fp.getPoint(new_pos);
+ } else {
+ Geom::Point origin = _last_drag_origin();
+ Geom::Point delta = new_pos - origin;
+ Geom::Dim2 d = (fabs(delta[Geom::X]) < fabs(delta[Geom::Y])) ? Geom::X : Geom::Y;
+ new_pos[d] = origin[d];
+ }
}
- } else {
- // TODO snapping?
+ } else if (snap) {
+ sm.freeSnapReturnByRef(Inkscape::SnapPreferences::SNAPPOINT_NODE, new_pos, _snapSourceType());
}
}
+Inkscape::SnapSourceType Node::_snapSourceType()
+{
+ if (_type == NODE_SMOOTH || _type == NODE_AUTO)
+ return SNAPSOURCE_NODE_SMOOTH;
+ return SNAPSOURCE_NODE_CUSP;
+}
+Inkscape::SnapTargetType Node::_snapTargetType()
+{
+ if (_type == NODE_SMOOTH || _type == NODE_AUTO)
+ return SNAPTARGET_NODE_SMOOTH;
+ return SNAPTARGET_NODE_CUSP;
+}
+
Glib::ustring Node::_getTip(unsigned state)
{
if (state_held_shift(state)) {
diff --git a/src/ui/tool/node.h b/src/ui/tool/node.h
index 167cf90b8..a85877d5c 100644
--- a/src/ui/tool/node.h
+++ b/src/ui/tool/node.h
@@ -19,6 +19,7 @@
#include <boost/shared_ptr.hpp>
#include <boost/optional.hpp>
#include <boost/operators.hpp>
+#include "snapped-point.h"
#include "ui/tool/selectable-control-point.h"
#include "ui/tool/node-types.h"
@@ -136,8 +137,9 @@ public:
void sink();
static char const *node_type_to_localized_string(NodeType type);
-protected:
+ // temporarily public
virtual bool _eventHandler(GdkEvent *event);
+protected:
virtual void _setState(State state);
virtual Glib::ustring _getTip(unsigned state);
virtual Glib::ustring _getDragTip(GdkEventMotion *event);
@@ -151,6 +153,8 @@ private:
void _linearGrow(int dir);
Node *_next();
Node *_prev();
+ Inkscape::SnapSourceType _snapSourceType();
+ Inkscape::SnapTargetType _snapTargetType();
static SPCtrlShapeType _node_type_to_shape(NodeType type);
static bool _is_line_segment(Node *first, Node *second);
diff --git a/src/ui/tool/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp
index 2755d6fb3..cfa3846f8 100644
--- a/src/ui/tool/path-manipulator.cpp
+++ b/src/ui/tool/path-manipulator.cpp
@@ -214,42 +214,6 @@ void PathManipulator::selectSubpaths()
}
}
-/** Select all nodes in the path. */
-void PathManipulator::selectAll()
-{
- for (SubpathList::iterator i = _subpaths.begin(); i != _subpaths.end(); ++i) {
- for (NodeList::iterator j = (*i)->begin(); j != (*i)->end(); ++j) {
- _selection.insert(j.ptr());
- }
- }
-}
-
-/** Select points inside the given rectangle. If all points inside it are already selected,
- * they will be deselected.
- * @param area Area to select
- */
-void PathManipulator::selectArea(Geom::Rect const &area)
-{
- bool nothing_selected = true;
- std::vector<Node*> in_area;
- for (SubpathList::iterator i = _subpaths.begin(); i != _subpaths.end(); ++i) {
- for (NodeList::iterator j = (*i)->begin(); j != (*i)->end(); ++j) {
- if (area.contains(j->position())) {
- in_area.push_back(j.ptr());
- if (!j->selected()) {
- _selection.insert(j.ptr());
- nothing_selected = false;
- }
- }
- }
- }
- if (nothing_selected) {
- for (std::vector<Node*>::iterator i = in_area.begin(); i != in_area.end(); ++i) {
- _selection.erase(*i);
- }
- }
-}
-
/** Move the selection forward or backward by one node in each subpath, based on the sign
* of the parameter. */
void PathManipulator::shiftSelection(int dir)
@@ -298,17 +262,6 @@ void PathManipulator::shiftSelection(int dir)
}
}
-/** Invert selection in the entire path. */
-void PathManipulator::invertSelection()
-{
- for (SubpathList::iterator i = _subpaths.begin(); i != _subpaths.end(); ++i) {
- for (NodeList::iterator j = (*i)->begin(); j != (*i)->end(); ++j) {
- if (j->selected()) _selection.erase(j.ptr());
- else _selection.insert(j.ptr());
- }
- }
-}
-
/** Invert selection in the selected subpaths. */
void PathManipulator::invertSelectionInSubpaths()
{
@@ -724,6 +677,7 @@ void PathManipulator::setControlsTransform(Geom::Matrix const &tnew)
_createGeometryFromControlPoints();
}
+/** Hide the curve drag point until the next motion event. */
void PathManipulator::hideDragPoint()
{
_dragpoint->setVisible(false);
diff --git a/src/ui/tool/path-manipulator.h b/src/ui/tool/path-manipulator.h
index 38f66dee0..99e183b45 100644
--- a/src/ui/tool/path-manipulator.h
+++ b/src/ui/tool/path-manipulator.h
@@ -64,10 +64,7 @@ public:
SPPath *item() { return _path; }
void selectSubpaths();
- void selectAll();
- void selectArea(Geom::Rect const &);
void shiftSelection(int dir);
- void invertSelection();
void invertSelectionInSubpaths();
void insertNodes();
diff --git a/src/ui/tool/selectable-control-point.cpp b/src/ui/tool/selectable-control-point.cpp
index b189a713f..5b9aa4fc8 100644
--- a/src/ui/tool/selectable-control-point.cpp
+++ b/src/ui/tool/selectable-control-point.cpp
@@ -50,10 +50,12 @@ SelectableControlPoint::SelectableControlPoint(SPDesktop *d, Geom::Point const &
SelectableControlPoint::~SelectableControlPoint()
{
_selection.erase(this);
+ _selection.allPoints().erase(this);
}
void SelectableControlPoint::_connectHandlers()
{
+ _selection.allPoints().insert(this);
signal_clicked.connect(
sigc::mem_fun(*this, &SelectableControlPoint::_clickedHandler));
signal_grabbed.connect(