From d34c9aff3f56c74e28d7115f276c4390c5ff0f1b Mon Sep 17 00:00:00 2001 From: dvlierop2 Date: Wed, 26 Nov 2008 19:55:59 +0000 Subject: [PATCH] When snapping only the closest node, draw an indicator at that node --- src/context-fns.cpp | 2 +- src/display/snap-indicator.cpp | 57 ++++++++++++--- src/display/snap-indicator.h | 10 ++- src/gradient-drag.cpp | 2 +- src/nodepath.cpp | 8 +-- src/seltrans.cpp | 45 ++++++++---- src/seltrans.h | 1 + src/snap.cpp | 127 +++++++++++++++++++++++---------- src/snap.h | 31 +++++--- 9 files changed, 204 insertions(+), 79 deletions(-) diff --git a/src/context-fns.cpp b/src/context-fns.cpp index c394e38ca..399e85154 100644 --- a/src/context-fns.cpp +++ b/src/context-fns.cpp @@ -204,7 +204,7 @@ Geom::Rect Inkscape::snap_rectangular_box(SPDesktop const *desktop, SPItem *item } if (snappoint.getSnapped()) { - desktop->snapindicator->set_new_snappoint(snappoint); + desktop->snapindicator->set_new_snaptarget(snappoint); } p[0] = sp_desktop_dt2root_xy_point(desktop, p[0]); diff --git a/src/display/snap-indicator.cpp b/src/display/snap-indicator.cpp index 441b64c02..e48f48ced 100644 --- a/src/display/snap-indicator.cpp +++ b/src/display/snap-indicator.cpp @@ -23,7 +23,8 @@ namespace Inkscape { namespace Display { SnapIndicator::SnapIndicator(SPDesktop * desktop) - : _tempitem(NULL), + : _snaptarget(NULL), + _snapsource(NULL), _desktop(desktop) { } @@ -31,13 +32,14 @@ SnapIndicator::SnapIndicator(SPDesktop * desktop) SnapIndicator::~SnapIndicator() { // remove item that might be present - remove_snappoint(); + remove_snaptarget(); + remove_snapsource(); } void -SnapIndicator::set_new_snappoint(Inkscape::SnappedPoint const p) +SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const p) { - remove_snappoint(); + remove_snaptarget(); g_assert(_desktop != NULL); @@ -66,19 +68,56 @@ SnapIndicator::set_new_snappoint(Inkscape::SnappedPoint const p) NULL ); SP_CTRL(canvasitem)->moveto(p.getPoint()); - _tempitem = _desktop->add_temporary_canvasitem(canvasitem, 1000); // TODO add preference for snap indicator timeout + remove_snapsource(); // Don't set both the source and target indicators, as these will overlap + _snaptarget = _desktop->add_temporary_canvasitem(canvasitem, 1000); // TODO add preference for snap indicator timeout } } void -SnapIndicator::remove_snappoint() +SnapIndicator::remove_snaptarget() { - if (_tempitem) { - _desktop->remove_temporary_canvasitem(_tempitem); - _tempitem = NULL; + if (_snaptarget) { + _desktop->remove_temporary_canvasitem(_snaptarget); + _snaptarget = NULL; } } +void +SnapIndicator::set_new_snapsource(Geom::Point const p) +{ + remove_snapsource(); + + g_assert(_desktop != NULL); + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + bool value = prefs->getBool("/options/snapindicator/value", true); + + if (value) { + SPCanvasItem * canvasitem = sp_canvas_item_new( sp_desktop_tempgroup (_desktop), + SP_TYPE_CTRL, + "anchor", GTK_ANCHOR_CENTER, + "size", 10.0, + "stroked", TRUE, + "stroke_color", 0xf000f0ff, + "mode", SP_KNOT_MODE_XOR, + "shape", SP_KNOT_SHAPE_DIAMOND, + NULL ); + + SP_CTRL(canvasitem)->moveto(p); + _snapsource = _desktop->add_temporary_canvasitem(canvasitem, 1000); + } +} + +void +SnapIndicator::remove_snapsource() +{ + if (_snapsource) { + _desktop->remove_temporary_canvasitem(_snapsource); + _snapsource = NULL; + } +} + + } //namespace Display } /* namespace Inkscape */ diff --git a/src/display/snap-indicator.h b/src/display/snap-indicator.h index 1d291bcdf..d2c6dba8e 100644 --- a/src/display/snap-indicator.h +++ b/src/display/snap-indicator.h @@ -26,11 +26,15 @@ public: SnapIndicator(SPDesktop *desktop); virtual ~SnapIndicator(); - void set_new_snappoint(Inkscape::SnappedPoint const p); - void remove_snappoint(); + void set_new_snaptarget(Inkscape::SnappedPoint const p); + void remove_snaptarget(); + + void set_new_snapsource(Geom::Point const p); + void remove_snapsource(); protected: - TemporaryItem *_tempitem; + TemporaryItem *_snaptarget; + TemporaryItem *_snapsource; SPDesktop *_desktop; private: diff --git a/src/gradient-drag.cpp b/src/gradient-drag.cpp index 1394cd758..08be1a849 100644 --- a/src/gradient-drag.cpp +++ b/src/gradient-drag.cpp @@ -625,7 +625,7 @@ gr_knot_moved_handler(SPKnot *knot, Geom::Point const &ppointer, guint state, gp } } if (was_snapped) { - desktop->snapindicator->set_new_snappoint(s); + desktop->snapindicator->set_new_snaptarget(s); } } } diff --git a/src/nodepath.cpp b/src/nodepath.cpp index 7165dab98..5a13588ab 100644 --- a/src/nodepath.cpp +++ b/src/nodepath.cpp @@ -1404,9 +1404,9 @@ static void sp_nodepath_selected_nodes_move(Inkscape::NodePath::Path *nodepath, } if (best.getSnapped()) { - nodepath->desktop->snapindicator->set_new_snappoint(best); + nodepath->desktop->snapindicator->set_new_snaptarget(best); } else { - nodepath->desktop->snapindicator->remove_snappoint(); + nodepath->desktop->snapindicator->remove_snaptarget(); } } @@ -3649,7 +3649,7 @@ node_request(SPKnot */*knot*/, Geom::Point const &p, guint state, gpointer data) Inkscape::NodePath::Node *n = (Inkscape::NodePath::Node *) data; - n->subpath->nodepath->desktop->snapindicator->remove_snappoint(); + n->subpath->nodepath->desktop->snapindicator->remove_snaptarget(); // If either (Shift and some handle retracted), or (we're already dragging out a handle) if ( (!n->subpath->nodepath->straight_path) && @@ -3936,7 +3936,7 @@ static gboolean node_handle_request(SPKnot *knot, Geom::Point const &p, guint st if ((state & GDK_SHIFT_MASK) != 0) { // We will not try to snap when the shift-key is pressed // so remove the old snap indicator and don't wait for it to time-out - desktop->snapindicator->remove_snappoint(); + desktop->snapindicator->remove_snaptarget(); } Inkscape::NodePath::Node *othernode = opposite->other; diff --git a/src/seltrans.cpp b/src/seltrans.cpp index 4bb1b3d2b..32a46f775 100644 --- a/src/seltrans.cpp +++ b/src/seltrans.cpp @@ -332,8 +332,19 @@ void Inkscape::SelTrans::grab(Geom::Point const &p, gdouble x, gdouble y, bool s // points immediately. Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if (prefs->getBool("/options/snapclosestonly/value", false)) { - _keepClosestPointOnly(_snap_points, p); - _keepClosestPointOnly(_bbox_points, p); + if (m.snapprefs.getSnapModeNode()) { + _keepClosestPointOnly(_snap_points, p); + } else { + _snap_points.clear(); // don't keep any point + } + + if (m.snapprefs.getSnapModeBBox()) { + _keepClosestPointOnly(_bbox_points, p); + } else { + _bbox_points.clear(); // don't keep any point + } + + g_assert(_bbox_points.size() < 2 && _snap_points.size() < 2); if (_snap_points.size() == 1 && _bbox_points.size() == 1) { //both vectors can only have either one or zero elements // So we have exactly one bbox corner and one node left; now find out which is closest and delete the other one if (Geom::L2(_snap_points.at(0) - p) < Geom::L2(_bbox_points.at(0) - p)) { @@ -342,9 +353,17 @@ void Inkscape::SelTrans::grab(Geom::Point const &p, gdouble x, gdouble y, bool s _snap_points.clear(); } } + + // Now either _bbox_points or _snap_points has a single element, the other one has zero..... or both have zero elements + g_assert((_bbox_points.size() + _snap_points.size()) < 2); + if (_bbox_points.size() == 1) { + _desktop->snapindicator->set_new_snapsource(_bbox_points.at(0)); + } else if (_snap_points.size() == 1){ + _desktop->snapindicator->set_new_snapsource(_snap_points.at(0)); + } } - // The lines below are usefull for debugging any snapping issues, as they'll spit out all points that are considered for snapping + // The lines below are useful for debugging any snapping issues, as they'll spit out all points that are considered for snapping /*std::cout << "Number of snap points: " << _snap_points.size() << std::endl; for (std::vector::const_iterator i = _snap_points.begin(); i != _snap_points.end(); i++) @@ -970,15 +989,15 @@ gboolean Inkscape::SelTrans::scaleRequest(Geom::Point &pt, guint state) if (!(bb.getSnapped() || sn.getSnapped())) { // We didn't snap at all! Don't update the handle position, just calculate the new transformation _calcAbsAffineDefault(default_scale); - _desktop->snapindicator->remove_snappoint(); + _desktop->snapindicator->remove_snaptarget(); } else if (bd < sd) { // We snapped the bbox (which is either visual or geometric) - _desktop->snapindicator->set_new_snappoint(bb); + _desktop->snapindicator->set_new_snaptarget(bb); default_scale = Geom::Scale(bb.getTransformation()); // Calculate the new transformation and update the handle position pt = _calcAbsAffineDefault(default_scale); } else { - _desktop->snapindicator->set_new_snappoint(sn); + _desktop->snapindicator->set_new_snaptarget(sn); // We snapped the special points (e.g. nodes), which are not at the visual bbox // The handle location however (pt) might however be at the visual bbox, so we // will have to calculate pt taking the stroke width into account @@ -1072,13 +1091,13 @@ gboolean Inkscape::SelTrans::stretchRequest(SPSelTransHandle const &handle, Geom if (!(bb.getSnapped() || sn.getSnapped())) { // We didn't snap at all! Don't update the handle position, just calculate the new transformation _calcAbsAffineDefault(default_scale); - _desktop->snapindicator->remove_snappoint(); + _desktop->snapindicator->remove_snaptarget(); } else if (bd < sd) { - _desktop->snapindicator->set_new_snappoint(bb); + _desktop->snapindicator->set_new_snaptarget(bb); // Calculate the new transformation and update the handle position pt = _calcAbsAffineDefault(default_scale); } else { - _desktop->snapindicator->set_new_snappoint(sn); + _desktop->snapindicator->set_new_snaptarget(sn); // We snapped the special points (e.g. nodes), which are not at the visual bbox // The handle location however (pt) might however be at the visual bbox, so we // will have to calculate pt taking the stroke width into account @@ -1171,10 +1190,10 @@ gboolean Inkscape::SelTrans::skewRequest(SPSelTransHandle const &handle, Geom::P if (sn.getSnapped()) { // We snapped something, so change the skew to reflect it Geom::Coord const sd = sn.getSnapped() ? sn.getTransformation()[0] : NR_HUGE; - _desktop->snapindicator->set_new_snappoint(sn); + _desktop->snapindicator->set_new_snaptarget(sn); skew[dim_a] = sd; } else { - _desktop->snapindicator->remove_snappoint(); + _desktop->snapindicator->remove_snaptarget(); } } @@ -1439,10 +1458,10 @@ void Inkscape::SelTrans::moveTo(Geom::Point const &xy, guint state) } } if (best_snapped_point.getSnapped()) { - _desktop->snapindicator->set_new_snappoint(best_snapped_point); + _desktop->snapindicator->set_new_snaptarget(best_snapped_point); } else { // We didn't snap, so remove any previous snap indicator - _desktop->snapindicator->remove_snappoint(); + _desktop->snapindicator->remove_snaptarget(); if (control) { // If we didn't snap, then we should still constrain horizontally or vertically // (When we did snap, then this constraint has already been enforced by diff --git a/src/seltrans.h b/src/seltrans.h index a472f3366..42effff7c 100644 --- a/src/seltrans.h +++ b/src/seltrans.h @@ -103,6 +103,7 @@ private: Geom::Point _calcAbsAffineDefault(Geom::Scale const default_scale); Geom::Point _calcAbsAffineGeom(Geom::Scale const geom_scale); void _keepClosestPointOnly(std::vector &points, const Geom::Point &reference); + void _display_snapsource(); enum State { STATE_SCALE, //scale or stretch diff --git a/src/snap.cpp b/src/snap.cpp index e89063b43..e13809256 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -35,6 +35,7 @@ #include "inkscape.h" #include "desktop.h" #include "sp-guide.h" +#include "preferences.h" using std::vector; /** @@ -356,36 +357,7 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( for (std::vector::const_iterator i = points.begin(); i != points.end(); i++) { /* Work out the transformed version of this point */ - Geom::Point transformed; - switch (transformation_type) { - case TRANSLATION: - transformed = *i + transformation; - break; - case SCALE: - transformed = (*i - origin) * Geom::Scale(transformation[Geom::X], transformation[Geom::Y]) + origin; - break; - case STRETCH: - { - Geom::Scale s(1, 1); - if (uniform) - s[Geom::X] = s[Geom::Y] = transformation[dim]; - else { - s[dim] = transformation[dim]; - s[1 - dim] = 1; - } - transformed = ((*i - origin) * s) + origin; - break; - } - case SKEW: - // Apply the skew factor - transformed[dim] = (*i)[dim] + transformation[0] * ((*i)[1 - dim] - origin[1 - dim]); - // While skewing, mirroring and scaling (by integer multiples) in the opposite direction is also allowed. - // Apply that scale factor here - transformed[1-dim] = (*i - origin)[1 - dim] * transformation[1] + origin[1 - dim]; - break; - default: - g_assert_not_reached(); - } + Geom::Point transformed = _transformPoint(*i, transformation_type, transformation, origin, dim, uniform); // add the current transformed point to the box hulling all transformed points if (i == points.begin()) { @@ -600,7 +572,11 @@ Inkscape::SnappedPoint SnapManager::freeSnapTranslation(Inkscape::SnapPreference Geom::Point const &pointer, Geom::Point const &tr) const { - return _snapTransformed(point_type, p, pointer, false, Geom::Point(0,0), TRANSLATION, tr, Geom::Point(0,0), Geom::X, false); + if (p.size() == 1) { + _displaySnapsource(point_type, _transformPoint(p.at(0), TRANSLATION, tr, Geom::Point(0,0), Geom::X, false)); + } + + return _snapTransformed(point_type, p, pointer, false, Geom::Point(0,0), TRANSLATION, tr, Geom::Point(0,0), Geom::X, false); } @@ -622,7 +598,11 @@ Inkscape::SnappedPoint SnapManager::constrainedSnapTranslation(Inkscape::SnapPre Inkscape::Snapper::ConstraintLine const &constraint, Geom::Point const &tr) const { - return _snapTransformed(point_type, p, pointer, true, constraint, TRANSLATION, tr, Geom::Point(0,0), Geom::X, false); + if (p.size() == 1) { + _displaySnapsource(point_type, _transformPoint(p.at(0), TRANSLATION, tr, Geom::Point(0,0), Geom::X, false)); + } + + return _snapTransformed(point_type, p, pointer, true, constraint, TRANSLATION, tr, Geom::Point(0,0), Geom::X, false); } @@ -643,7 +623,11 @@ Inkscape::SnappedPoint SnapManager::freeSnapScale(Inkscape::SnapPreferences::Poi Geom::Scale const &s, Geom::Point const &o) const { - return _snapTransformed(point_type, p, pointer, false, Geom::Point(0,0), SCALE, Geom::Point(s[Geom::X], s[Geom::Y]), o, Geom::X, false); + if (p.size() == 1) { + _displaySnapsource(point_type, _transformPoint(p.at(0), SCALE, Geom::Point(s[Geom::X], s[Geom::Y]), o, Geom::X, false)); + } + + return _snapTransformed(point_type, p, pointer, false, Geom::Point(0,0), SCALE, Geom::Point(s[Geom::X], s[Geom::Y]), o, Geom::X, false); } @@ -666,7 +650,11 @@ Inkscape::SnappedPoint SnapManager::constrainedSnapScale(Inkscape::SnapPreferenc Geom::Point const &o) const { // When constrained scaling, only uniform scaling is supported. - return _snapTransformed(point_type, p, pointer, true, Geom::Point(0,0), SCALE, Geom::Point(s[Geom::X], s[Geom::Y]), o, Geom::X, true); + if (p.size() == 1) { + _displaySnapsource(point_type, _transformPoint(p.at(0), SCALE, Geom::Point(s[Geom::X], s[Geom::Y]), o, Geom::X, true)); + } + + return _snapTransformed(point_type, p, pointer, true, Geom::Point(0,0), SCALE, Geom::Point(s[Geom::X], s[Geom::Y]), o, Geom::X, true); } @@ -691,7 +679,11 @@ Inkscape::SnappedPoint SnapManager::constrainedSnapStretch(Inkscape::SnapPrefere Geom::Dim2 d, bool u) const { - return _snapTransformed(point_type, p, pointer, true, Geom::Point(0,0), STRETCH, Geom::Point(s, s), o, d, u); + if (p.size() == 1) { + _displaySnapsource(point_type, _transformPoint(p.at(0), STRETCH, Geom::Point(s, s), o, d, u)); + } + + return _snapTransformed(point_type, p, pointer, true, Geom::Point(0,0), STRETCH, Geom::Point(s, s), o, d, u); } @@ -723,6 +715,11 @@ Inkscape::SnappedPoint SnapManager::constrainedSnapSkew(Inkscape::SnapPreference // so it's corners have a different transformation. The snappers cannot handle this, therefore snapping // of bounding boxes is not allowed here. g_assert(!(point_type & Inkscape::SnapPreferences::SNAPPOINT_BBOX)); + + if (p.size() == 1) { + _displaySnapsource(point_type, _transformPoint(p.at(0), SKEW, s, o, d, false)); + } + return _snapTransformed(point_type, p, pointer, true, constraint, SKEW, s, o, d, false); } @@ -825,9 +822,9 @@ Inkscape::SnappedPoint SnapManager::findBestSnap(Geom::Point const &p, SnappedCo // Update the snap indicator, if requested if (_snapindicator) { if (bestSnappedPoint.getSnapped()) { - _desktop->snapindicator->set_new_snappoint(bestSnappedPoint); + _desktop->snapindicator->set_new_snaptarget(bestSnappedPoint); } else { - _desktop->snapindicator->remove_snappoint(); + _desktop->snapindicator->remove_snaptarget(); } } @@ -860,6 +857,62 @@ SPDocument *SnapManager::getDocument() const return _named_view->document; } +Geom::Point SnapManager::_transformPoint(Geom::Point const &p, + Transformation const transformation_type, + Geom::Point const &transformation, + Geom::Point const &origin, + Geom::Dim2 const dim, + bool const uniform) const +{ + /* Work out the transformed version of this point */ + Geom::Point transformed; + switch (transformation_type) { + case TRANSLATION: + transformed = p + transformation; + break; + case SCALE: + transformed = (p - origin) * Geom::Scale(transformation[Geom::X], transformation[Geom::Y]) + origin; + break; + case STRETCH: + { + Geom::Scale s(1, 1); + if (uniform) + s[Geom::X] = s[Geom::Y] = transformation[dim]; + else { + s[dim] = transformation[dim]; + s[1 - dim] = 1; + } + transformed = ((p - origin) * s) + origin; + break; + } + case SKEW: + // Apply the skew factor + transformed[dim] = p[dim] + transformation[0] * (p[1 - dim] - origin[1 - dim]); + // While skewing, mirroring and scaling (by integer multiples) in the opposite direction is also allowed. + // Apply that scale factor here + transformed[1-dim] = (p - origin)[1 - dim] * transformation[1] + origin[1 - dim]; + break; + default: + g_assert_not_reached(); + } + + return transformed; +} + +void SnapManager::_displaySnapsource(Inkscape::SnapPreferences::PointType point_type, Geom::Point const &p) const { + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (prefs->getBool("/options/snapclosestonly/value")) { + bool p_is_a_node = point_type & Inkscape::SnapPreferences::SNAPPOINT_NODE; + bool p_is_a_bbox = point_type & Inkscape::SnapPreferences::SNAPPOINT_BBOX; + if ((p_is_a_node && snapprefs.getSnapModeNode()) || (p_is_a_bbox && snapprefs.getSnapModeBBox())) { + _desktop->snapindicator->set_new_snapsource(p); + } else { + _desktop->snapindicator->remove_snapsource(); + } + } +} + /* Local Variables: mode:c++ diff --git a/src/snap.h b/src/snap.h index 05af0d202..b8d9fdd25 100644 --- a/src/snap.h +++ b/src/snap.h @@ -42,7 +42,14 @@ class SPNamedView; class SnapManager { public: - SnapManager(SPNamedView const *v); + enum Transformation { + TRANSLATION, + SCALE, + STRETCH, + SKEW + }; + + SnapManager(SPNamedView const *v); typedef std::list SnapperList; @@ -119,7 +126,7 @@ public: Geom::Point const &s, // s[0] = skew factor, s[1] = scale factor Geom::Point const &o, Geom::Dim2 d) const; - + Inkscape::GuideSnapper guide; ///< guide snapper Inkscape::ObjectSnapper object; ///< snapper to other objects Inkscape::SnapPreferences snapprefs; @@ -135,14 +142,7 @@ protected: SPNamedView const *_named_view; private: - enum Transformation { - TRANSLATION, - SCALE, - STRETCH, - SKEW - }; - - std::vector *_items_to_ignore; + std::vector *_items_to_ignore; SPItem const *_item_to_ignore; SPDesktop const *_desktop; bool _snapindicator; @@ -158,7 +158,16 @@ private: Geom::Point const &origin, Geom::Dim2 dim, bool uniform) const; - + + Geom::Point _transformPoint(Geom::Point const &p, + Transformation const transformation_type, + Geom::Point const &transformation, + Geom::Point const &origin, + Geom::Dim2 const dim, + bool const uniform) const; + + void _displaySnapsource(Inkscape::SnapPreferences::PointType point_type, Geom::Point const &p) const; + Inkscape::SnappedPoint findBestSnap(Geom::Point const &p, SnappedConstraints &sc, bool constrained) const; }; -- 2.30.2