From 4c8b4484d62b2a47d96b62a8dff90e2b9124edca Mon Sep 17 00:00:00 2001 From: Diederik van Lierop Date: Tue, 19 Jan 2010 21:16:06 +0100 Subject: [PATCH] When snapping to a bounding box, flash that bounding box together with the snap indicator --- src/display/snap-indicator.cpp | 27 +++++++++++++++++++--- src/display/snap-indicator.h | 1 + src/object-snapper.cpp | 17 +++++++------- src/snap-candidate.h | 33 +++++++++++++++++++-------- src/snapped-curve.cpp | 41 ++++++++++++++++++++-------------- src/snapped-curve.h | 2 +- src/snapped-point.cpp | 15 ++++++------- src/snapped-point.h | 8 +++---- 8 files changed, 94 insertions(+), 50 deletions(-) diff --git a/src/display/snap-indicator.cpp b/src/display/snap-indicator.cpp index 84bc1709b..54671cb28 100644 --- a/src/display/snap-indicator.cpp +++ b/src/display/snap-indicator.cpp @@ -16,7 +16,9 @@ #include "desktop.h" #include "desktop-handles.h" #include "display/sodipodi-ctrl.h" +#include "display/sodipodi-ctrlrect.h" #include "display/canvas-text.h" +#include "display/sp-canvas-util.h" #include "knot.h" #include "preferences.h" #include @@ -27,6 +29,7 @@ namespace Display { SnapIndicator::SnapIndicator(SPDesktop * desktop) : _snaptarget(NULL), _snaptarget_tooltip(NULL), + _snaptarget_bbox(NULL), _snapsource(NULL), _desktop(desktop) { @@ -216,7 +219,7 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p) "anchor", GTK_ANCHOR_CENTER, "size", 10.0, "stroked", TRUE, - "stroke_color", 0xf000f0ff, + "stroke_color", 0xff0000ff, "mode", SP_KNOT_MODE_XOR, "shape", SP_KNOT_SHAPE_DIAMOND, NULL ); @@ -226,7 +229,7 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p) "anchor", GTK_ANCHOR_CENTER, "size", 10.0, "stroked", TRUE, - "stroke_color", 0xf000f0ff, + "stroke_color", 0xff0000ff, "mode", SP_KNOT_MODE_XOR, "shape", SP_KNOT_SHAPE_CROSS, NULL ); @@ -245,6 +248,19 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p) sp_canvastext_set_anchor((SPCanvasText* )canvas_tooltip, -1, 1); _snaptarget_tooltip = _desktop->add_temporary_canvasitem(canvas_tooltip, timeout_val); + + Geom::OptRect const bbox = p.getTargetBBox(); + if (bbox) { + SPCanvasItem* box = sp_canvas_item_new(sp_desktop_tempgroup (_desktop), + SP_TYPE_CTRLRECT, + NULL); + + SP_CTRLRECT(box)->setRectangle(*bbox); + SP_CTRLRECT(box)->setColor(0xff0000ff, 0, 0); + SP_CTRLRECT(box)->setDashed(true); + sp_canvas_item_move_to_z(box, 0); + _snaptarget_bbox = _desktop->add_temporary_canvasitem(box, timeout_val); + } } } @@ -261,6 +277,11 @@ SnapIndicator::remove_snaptarget() _snaptarget_tooltip = NULL; } + if (_snaptarget_bbox) { + _desktop->remove_temporary_canvasitem(_snaptarget_bbox); + _snaptarget_bbox = NULL; + } + } void @@ -279,7 +300,7 @@ SnapIndicator::set_new_snapsource(Inkscape::SnapCandidatePoint const &p) "anchor", GTK_ANCHOR_CENTER, "size", 6.0, "stroked", TRUE, - "stroke_color", 0xf000f0ff, + "stroke_color", 0xff0000ff, "mode", SP_KNOT_MODE_XOR, "shape", SP_KNOT_SHAPE_CIRCLE, NULL ); diff --git a/src/display/snap-indicator.h b/src/display/snap-indicator.h index d896042a2..feb118baa 100644 --- a/src/display/snap-indicator.h +++ b/src/display/snap-indicator.h @@ -35,6 +35,7 @@ public: protected: TemporaryItem *_snaptarget; TemporaryItem *_snaptarget_tooltip; + TemporaryItem *_snaptarget_bbox; TemporaryItem *_snapsource; SPDesktop *_desktop; diff --git a/src/object-snapper.cpp b/src/object-snapper.cpp index 6396569e9..47d419629 100644 --- a/src/object-snapper.cpp +++ b/src/object-snapper.cpp @@ -266,7 +266,7 @@ void Inkscape::ObjectSnapper::_snapNodes(SnappedConstraints &sc, for (std::vector::const_iterator k = _points_to_snap_to->begin(); k != _points_to_snap_to->end(); k++) { Geom::Coord dist = Geom::L2((*k).getPoint() - p.getPoint()); if (dist < getSnapperTolerance() && dist < s.getSnapDistance()) { - s = SnappedPoint((*k).getPoint(), p.getSourceType(), p.getSourceNum(), (*k).getTargetType(), dist, getSnapperTolerance(), getSnapperAlwaysSnap(), true); + s = SnappedPoint((*k).getPoint(), p.getSourceType(), p.getSourceNum(), (*k).getTargetType(), dist, getSnapperTolerance(), getSnapperAlwaysSnap(), true, (*k).getTargetBBox()); success = true; } } @@ -301,7 +301,7 @@ void Inkscape::ObjectSnapper::_snapTranslatingGuideToNodes(SnappedConstraints &s Geom::Coord dist = Geom::L2((*k).getPoint() - p_proj); // distance from node to the guide Geom::Coord dist2 = Geom::L2(p - p_proj); // distance from projection of node on the guide, to the mouse location if ((dist < tol && dist2 < tol) || getSnapperAlwaysSnap()) { - s = SnappedPoint((*k).getPoint(), SNAPSOURCE_GUIDE, 0, (*k).getTargetType(), dist, tol, getSnapperAlwaysSnap(), true); + s = SnappedPoint((*k).getPoint(), SNAPSOURCE_GUIDE, 0, (*k).getTargetType(), dist, tol, getSnapperAlwaysSnap(), true, (*k).getTargetBBox()); sc.points.push_back(s); } } @@ -338,7 +338,7 @@ void Inkscape::ObjectSnapper::_collectPaths(Inkscape::SnapPreferences::PointType if (_snapmanager->snapprefs.getSnapToPageBorder()) { Geom::PathVector *border_path = _getBorderPathv(); if (border_path != NULL) { - _paths_to_snap_to->push_back(Inkscape::SnapCandidatePath(border_path, SNAPTARGET_PAGE_BORDER)); + _paths_to_snap_to->push_back(Inkscape::SnapCandidatePath(border_path, SNAPTARGET_PAGE_BORDER, Geom::OptRect())); } } @@ -386,7 +386,7 @@ void Inkscape::ObjectSnapper::_collectPaths(Inkscape::SnapPreferences::PointType if (curve) { // We will get our own copy of the path, which must be freed at some point Geom::PathVector *borderpathv = pathvector_for_curve(root_item, curve, true, true, Geom::identity(), (*i).additional_affine); - _paths_to_snap_to->push_back(Inkscape::SnapCandidatePath(borderpathv, SNAPTARGET_PATH)); // Perhaps for speed, get a reference to the Geom::pathvector, and store the transformation besides it. + _paths_to_snap_to->push_back(Inkscape::SnapCandidatePath(borderpathv, SNAPTARGET_PATH, Geom::OptRect())); // Perhaps for speed, get a reference to the Geom::pathvector, and store the transformation besides it. curve->unref(); } } @@ -403,7 +403,8 @@ void Inkscape::ObjectSnapper::_collectPaths(Inkscape::SnapPreferences::PointType sp_item_invoke_bbox(root_item, rect, i2doc, TRUE, bbox_type); if (rect) { Geom::PathVector *path = _getPathvFromRect(*rect); - _paths_to_snap_to->push_back(Inkscape::SnapCandidatePath(path, SNAPTARGET_BBOX_EDGE)); + rect = sp_item_bbox_desktop(root_item, bbox_type); + _paths_to_snap_to->push_back(Inkscape::SnapCandidatePath(path, SNAPTARGET_BBOX_EDGE, rect)); } } } @@ -437,7 +438,7 @@ void Inkscape::ObjectSnapper::_snapPaths(SnappedConstraints &sc, SPCurve *curve = curve_for_item(SP_ITEM(selected_path)); if (curve) { Geom::PathVector *pathv = pathvector_for_curve(SP_ITEM(selected_path), curve, true, true, Geom::identity(), Geom::identity()); // We will get our own copy of the path, which must be freed at some point - _paths_to_snap_to->push_back(Inkscape::SnapCandidatePath(pathv, SNAPTARGET_PATH, true)); + _paths_to_snap_to->push_back(Inkscape::SnapCandidatePath(pathv, SNAPTARGET_PATH, Geom::OptRect(), true)); curve->unref(); } } @@ -484,7 +485,7 @@ void Inkscape::ObjectSnapper::_snapPaths(SnappedConstraints &sc, if (!being_edited || (c1 && c2)) { Geom::Coord const dist = Geom::distance(sp_doc, p_doc); if (dist < getSnapperTolerance()) { - sc.curves.push_back(Inkscape::SnappedCurve(sp_dt, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), false, curve, p.getSourceType(), p.getSourceNum(), it_p->target_type)); + sc.curves.push_back(Inkscape::SnappedCurve(sp_dt, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), false, curve, p.getSourceType(), p.getSourceNum(), it_p->target_type, it_p->target_bbox)); } } } @@ -556,7 +557,7 @@ void Inkscape::ObjectSnapper::_snapPathsConstrained(SnappedConstraints &sc, // When it's within snapping range, then return it // (within snapping range == between p_min_on_cl and p_max_on_cl == 0 < ta < 1) Geom::Coord dist = Geom::L2(_snapmanager->getDesktop()->dt2doc(p_proj_on_cl) - p_inters); - SnappedPoint s(_snapmanager->getDesktop()->doc2dt(p_inters), p.getSourceType(), p.getSourceNum(), k->target_type, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), true); + SnappedPoint s(_snapmanager->getDesktop()->doc2dt(p_inters), p.getSourceType(), p.getSourceNum(), k->target_type, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), true, k->target_bbox); sc.points.push_back(s); } } diff --git a/src/snap-candidate.h b/src/snap-candidate.h index 13f1d069c..be0b2e490 100644 --- a/src/snap-candidate.h +++ b/src/snap-candidate.h @@ -73,24 +73,38 @@ enum SnapSourceType { class SnapCandidatePoint { public: - SnapCandidatePoint(Geom::Point const &point, Inkscape::SnapSourceType const source, long const source_num, Inkscape::SnapTargetType const target, Geom::Rect const &bbox) - : _point(point), _source_type(source), _target_type(target), _source_num(source_num), _target_bbox(bbox) {}; + SnapCandidatePoint(Geom::Point const &point, Inkscape::SnapSourceType const source, long const source_num, Inkscape::SnapTargetType const target, Geom::OptRect const &bbox) + : _point(point), + _source_type(source), + _target_type(target), + _source_num(source_num), + _target_bbox(bbox) + { + }; SnapCandidatePoint(Geom::Point const &point, Inkscape::SnapSourceType const source, Inkscape::SnapTargetType const target) - : _point(point), _source_type(source), _target_type(target) + : _point(point), + _source_type(source), + _target_type(target) { _source_num = 0; - _target_bbox = Geom::Rect(); + _target_bbox = Geom::OptRect(); } SnapCandidatePoint(Geom::Point const &point, Inkscape::SnapSourceType const source, long const source_num = 0) - : _point(point), _source_type(source), _target_type(Inkscape::SNAPTARGET_UNDEFINED), _source_num(source_num) {_target_bbox = Geom::Rect();} + : _point(point), + _source_type(source), + _target_type(Inkscape::SNAPTARGET_UNDEFINED), + _source_num(source_num) + { + _target_bbox = Geom::OptRect(); + } inline Geom::Point const & getPoint() const {return _point;} inline Inkscape::SnapSourceType getSourceType() const {return _source_type;} inline Inkscape::SnapTargetType getTargetType() const {return _target_type;} inline long getSourceNum() const {return _source_num;} - inline Geom::Rect const & getTargetBBox() const {return _target_bbox;} + inline Geom::OptRect const getTargetBBox() const {return _target_bbox;} private: // Coordinates of the point @@ -107,7 +121,7 @@ private: // If this is a target and it belongs to a bounding box, e.g. when the target type is // SNAPTARGET_BBOX_EDGE_MIDPOINT, then _target_bbox stores the relevant bounding box - Geom::Rect _target_bbox; + Geom::OptRect _target_bbox; }; class SnapCandidateItem @@ -132,12 +146,13 @@ class SnapCandidatePath { public: - SnapCandidatePath(Geom::PathVector* path, SnapTargetType target, bool edited = false) - : path_vector(path), target_type(target), currently_being_edited(edited) {} + SnapCandidatePath(Geom::PathVector* path, SnapTargetType target, Geom::OptRect bbox, bool edited = false) + : path_vector(path), target_type(target), target_bbox(bbox), currently_being_edited(edited) {}; ~SnapCandidatePath() {}; Geom::PathVector* path_vector; SnapTargetType target_type; + Geom::OptRect target_bbox; bool currently_being_edited; // true for the path that's currently being edited in the node tool (if any) }; diff --git a/src/snapped-curve.cpp b/src/snapped-curve.cpp index 334038638..d4ef0a83f 100644 --- a/src/snapped-curve.cpp +++ b/src/snapped-curve.cpp @@ -12,7 +12,7 @@ #include <2geom/crossing.h> #include <2geom/path-intersection.h> -Inkscape::SnappedCurve::SnappedCurve(Geom::Point const &snapped_point, Geom::Coord const &snapped_distance, Geom::Coord const &snapped_tolerance, bool const &always_snap, bool const &fully_constrained, Geom::Curve const *curve, SnapSourceType source, long source_num, SnapTargetType target) +Inkscape::SnappedCurve::SnappedCurve(Geom::Point const &snapped_point, Geom::Coord const &snapped_distance, Geom::Coord const &snapped_tolerance, bool const &always_snap, bool const &fully_constrained, Geom::Curve const *curve, SnapSourceType source, long source_num, SnapTargetType target, Geom::OptRect target_bbox) { _distance = snapped_distance; _tolerance = std::max(snapped_tolerance, 1.0); @@ -27,6 +27,7 @@ Inkscape::SnappedCurve::SnappedCurve(Geom::Point const &snapped_point, Geom::Coo _source = source; _source_num = source_num; _target = target; + _target_bbox = target_bbox; } Inkscape::SnappedCurve::SnappedCurve() @@ -44,6 +45,7 @@ Inkscape::SnappedCurve::SnappedCurve() _source = SNAPSOURCE_UNDEFINED; _source_num = 0; _target = SNAPTARGET_UNDEFINED; + _target_bbox = Geom::OptRect(); } Inkscape::SnappedCurve::~SnappedCurve() @@ -114,22 +116,27 @@ bool getClosestIntersectionCS(std::list const &list, Geo bool success = false; for (std::list::const_iterator i = list.begin(); i != list.end(); i++) { - std::list::const_iterator j = i; - j++; - for (; j != list.end(); j++) { - Inkscape::SnappedPoint sp = (*i).intersect(*j, p, dt2doc); - if (sp.getAtIntersection()) { - // if it's the first point - bool const c1 = !success; - // or, if it's closer - bool const c2 = sp.getSnapDistance() < result.getSnapDistance(); - // or, if it's just as close then look at the other distance - // (only relevant for snapped points which are at an intersection) - bool const c3 = (sp.getSnapDistance() == result.getSnapDistance()) && (sp.getSecondSnapDistance() < result.getSecondSnapDistance()); - // then prefer this point over the previous one - if (c1 || c2 || c3) { - result = sp; - success = true; + if ((*i).getTarget() != Inkscape::SNAPTARGET_BBOX_EDGE) { // We don't support snapping to intersections of bboxes, + // as this would require two bboxes two be flashed in the snap indicator + std::list::const_iterator j = i; + j++; + for (; j != list.end(); j++) { + if ((*j).getTarget() != Inkscape::SNAPTARGET_BBOX_EDGE) { // We don't support snapping to intersections of bboxes + Inkscape::SnappedPoint sp = (*i).intersect(*j, p, dt2doc); + if (sp.getAtIntersection()) { + // if it's the first point + bool const c1 = !success; + // or, if it's closer + bool const c2 = sp.getSnapDistance() < result.getSnapDistance(); + // or, if it's just as close then look at the other distance + // (only relevant for snapped points which are at an intersection) + bool const c3 = (sp.getSnapDistance() == result.getSnapDistance()) && (sp.getSecondSnapDistance() < result.getSecondSnapDistance()); + // then prefer this point over the previous one + if (c1 || c2 || c3) { + result = sp; + success = true; + } + } } } } diff --git a/src/snapped-curve.h b/src/snapped-curve.h index 4eea6e734..21124c678 100644 --- a/src/snapped-curve.h +++ b/src/snapped-curve.h @@ -24,7 +24,7 @@ class SnappedCurve : public SnappedPoint { public: SnappedCurve(); - SnappedCurve(Geom::Point const &snapped_point, Geom::Coord const &snapped_distance, Geom::Coord const &snapped_tolerance, bool const &always_snap, bool const &fully_constrained, Geom::Curve const *curve, SnapSourceType source, long source_num, SnapTargetType target); + SnappedCurve(Geom::Point const &snapped_point, Geom::Coord const &snapped_distance, Geom::Coord const &snapped_tolerance, bool const &always_snap, bool const &fully_constrained, Geom::Curve const *curve, SnapSourceType source, long source_num, SnapTargetType target, Geom::OptRect target_bbox); ~SnappedCurve(); Inkscape::SnappedPoint intersect(SnappedCurve const &curve, Geom::Point const &p, Geom::Matrix dt2doc) const; //intersect with another SnappedCurve diff --git a/src/snapped-point.cpp b/src/snapped-point.cpp index e3559d655..089aa4323 100644 --- a/src/snapped-point.cpp +++ b/src/snapped-point.cpp @@ -14,8 +14,8 @@ #include "preferences.h" // overloaded constructor -Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &fully_constrained) - : _point(p), _source(source), _source_num(source_num), _target(target), _distance(d), _tolerance(std::max(t,1.0)), _always_snap(a) +Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &fully_constrained, Geom::OptRect target_bbox) + : _point(p), _source(source), _source_num(source_num), _target(target), _distance(d), _tolerance(std::max(t,1.0)), _always_snap(a), _target_bbox(target_bbox) { // tolerance should never be smaller than 1 px, as it is used for normalization in isOtherSnapBetter. We don't want a division by zero. _at_intersection = false; @@ -25,7 +25,6 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const _second_always_snap = false; _transformation = Geom::Point(1,1); _pointer_distance = NR_HUGE; - _target_bbox = Geom::Rect(); } Inkscape::SnappedPoint::SnappedPoint(Inkscape::SnapCandidatePoint const &p, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &fully_constrained) @@ -41,7 +40,7 @@ Inkscape::SnappedPoint::SnappedPoint(Inkscape::SnapCandidatePoint const &p, Snap _second_always_snap = false; _transformation = Geom::Point(1,1); _pointer_distance = NR_HUGE; - _target_bbox = Geom::Rect(); + _target_bbox = p.getTargetBBox(); } @@ -53,7 +52,7 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const // isOtherSnapBetter. We don't want a division by zero. _transformation = Geom::Point(1,1); _pointer_distance = NR_HUGE; - _target_bbox = Geom::Rect(); + _target_bbox = Geom::OptRect(); } Inkscape::SnappedPoint::SnappedPoint() @@ -72,7 +71,7 @@ Inkscape::SnappedPoint::SnappedPoint() _second_always_snap = false; _transformation = Geom::Point(1,1); _pointer_distance = NR_HUGE; - _target_bbox = Geom::Rect(); + _target_bbox = Geom::OptRect(); } Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p) @@ -91,7 +90,7 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p) _second_always_snap = false; _transformation = Geom::Point(1,1); _pointer_distance = NR_HUGE; - _target_bbox = Geom::Rect(); + _target_bbox = Geom::OptRect(); } Inkscape::SnappedPoint::~SnappedPoint() @@ -104,7 +103,7 @@ void Inkscape::SnappedPoint::getPoint(Geom::Point &p) const if (getSnapped()) { // then return the snapped point by overwriting p p = _point; - } //otherwise p will be left untouched; this way the caller doesn't have to check wether we've snapped + } //otherwise p will be left untouched; this way the caller doesn't have to check whether we've snapped } // search for the closest snapped point diff --git a/src/snapped-point.h b/src/snapped-point.h index 1497802c0..33230e212 100644 --- a/src/snapped-point.h +++ b/src/snapped-point.h @@ -29,7 +29,7 @@ public: SnappedPoint(); SnappedPoint(Geom::Point const &p); SnappedPoint(Geom::Point const &p, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &at_intersection, bool const &fully_constrained, Geom::Coord const &d2, Geom::Coord const &t2, bool const &a2); - SnappedPoint(Geom::Point const &p, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &fully_constrained); + SnappedPoint(Geom::Point const &p, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &fully_constrained, Geom::OptRect target_bbox = Geom::OptRect()); SnappedPoint(SnapCandidatePoint const &p, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &fully_constrained); ~SnappedPoint(); @@ -65,8 +65,8 @@ public: void setTransformation(Geom::Point const t) {_transformation = t;} void setTarget(SnapTargetType const target) {_target = target;} SnapTargetType getTarget() const {return _target;} - void setTargetBBox(Geom::Rect const target) {_target_bbox = target;} - Geom::Rect & getTargetBBox() {return _target_bbox;} + void setTargetBBox(Geom::OptRect const target) {_target_bbox = target;} + Geom::OptRect const getTargetBBox() const {return _target_bbox;} void setSource(SnapSourceType const source) {_source = source;} SnapSourceType getSource() const {return _source;} long getSourceNum() const {return _source_num;} @@ -118,7 +118,7 @@ protected: /* The transformation (translation, scale, skew, or stretch) from the original point to the snapped point */ Geom::Point _transformation; /* The bounding box we've snapped to (when applicable); will be used by the snapindicator */ - Geom::Rect _target_bbox; + Geom::OptRect _target_bbox; /* Distance from the un-transformed point to the mouse pointer, measured at the point in time when dragging started */ Geom::Coord _pointer_distance; }; -- 2.30.2