From 17e8c293a1792714f56eba5547874234e9ea0dea Mon Sep 17 00:00:00 2001 From: dvlierop2 Date: Tue, 2 Jun 2009 04:36:17 +0000 Subject: [PATCH] When dragging the origin of a guide along that guide, we should use constrained snapping instead of free snapping. Also make sure that we snap to paths too, not just to guides --- src/desktop-events.cpp | 50 ++++++++++++++++++++++------------ src/display/snap-indicator.cpp | 5 +++- src/object-snapper.cpp | 37 +++++++++++++++++-------- src/object-snapper.h | 8 ++++-- src/snap.cpp | 40 +++++++++++++++++++++++++-- src/snap.h | 4 ++- src/snapped-point.h | 1 + 7 files changed, 110 insertions(+), 35 deletions(-) diff --git a/src/desktop-events.cpp b/src/desktop-events.cpp index 3d8e88fba..17b077890 100644 --- a/src/desktop-events.cpp +++ b/src/desktop-events.cpp @@ -161,7 +161,7 @@ static gint sp_dt_ruler_event(GtkWidget *widget, GdkEvent *event, SPDesktopWidge m.setup(desktop); // We only have a temporary guide which is not stored in our document yet. Because the guide snapper only looks // in the document for guides to snap to, we don't have to worry about a guide snapping to itself here - m.guideSnap(event_dt, normal); + m.guideFreeSnap(event_dt, normal); sp_guideline_set_position(SP_GUIDELINE(guide), from_2geom(event_dt)); desktop->set_coordinate_status(to_2geom(event_dt)); @@ -178,7 +178,7 @@ static gint sp_dt_ruler_event(GtkWidget *widget, GdkEvent *event, SPDesktopWidge m.setup(desktop); // We only have a temporary guide which is not stored in our document yet. Because the guide snapper only looks // in the document for guides to snap to, we don't have to worry about a guide snapping to itself here - m.guideSnap(event_dt, normal); + m.guideFreeSnap(event_dt, normal); dragging = false; @@ -226,17 +226,15 @@ int sp_dt_vruler_event(GtkWidget *widget, GdkEvent *event, SPDesktopWidget *dtw) } /* Guides */ - -static Geom::Point drag_origin; - enum SPGuideDragType { SP_DRAG_TRANSLATE, - SP_DRAG_TRANSLATE_CONSTRAINED, + SP_DRAG_TRANSLATE_CONSTRAINED, // Is not being used currently! SP_DRAG_ROTATE, SP_DRAG_MOVE_ORIGIN, SP_DRAG_NONE }; +static Geom::Point drag_origin; static SPGuideDragType drag_type = SP_DRAG_NONE; gint sp_dt_guide_event(SPCanvasItem *item, GdkEvent *event, gpointer data) @@ -304,7 +302,17 @@ gint sp_dt_guide_event(SPCanvasItem *item, GdkEvent *event, gpointer data) // which are dragged off the ruler, are being snapped in sp_dt_ruler_event SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop, true, NULL, NULL, guide); - m.guideSnap(motion_dt, to_2geom(guide->normal_to_line)); + if (drag_type == SP_DRAG_MOVE_ORIGIN) { + // If we snap in guideConstrainedSnap() below, then motion_dt will be forced to be on the guide + // If we don't snap however, then it the origin should still be constrained to the guide + // So let's do that explicitly first: + Geom::Line line(guide->point_on_line, guide->angle()); + Geom::Coord t = line.nearestPoint(motion_dt); + motion_dt = line.pointAt(t); + m.guideConstrainedSnap(motion_dt, *guide); + } else { + m.guideFreeSnap(motion_dt, guide->normal_to_line); + } switch (drag_type) { case SP_DRAG_TRANSLATE: @@ -312,7 +320,7 @@ gint sp_dt_guide_event(SPCanvasItem *item, GdkEvent *event, gpointer data) sp_guide_moveto(*guide, guide->point_on_line + motion_dt - drag_origin, false); break; } - case SP_DRAG_TRANSLATE_CONSTRAINED: + case SP_DRAG_TRANSLATE_CONSTRAINED: // Is not being used currently! { Geom::Point pt_constr = Geom::constrain_angle(guide->point_on_line, motion_dt); sp_guide_moveto(*guide, pt_constr, false); @@ -326,10 +334,8 @@ gint sp_dt_guide_event(SPCanvasItem *item, GdkEvent *event, gpointer data) } case SP_DRAG_MOVE_ORIGIN: { - Geom::Line line(guide->point_on_line, guide->angle()); - Geom::Coord t = line.nearestPoint(motion_dt); - sp_guide_moveto(*guide, line.pointAt(t), false); - break; + sp_guide_moveto(*guide, motion_dt, false); + break; } case SP_DRAG_NONE: g_assert_not_reached(); @@ -351,7 +357,17 @@ gint sp_dt_guide_event(SPCanvasItem *item, GdkEvent *event, gpointer data) SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop, true, NULL, NULL, guide); - m.guideSnap(event_dt, guide->normal_to_line); + if (drag_type == SP_DRAG_MOVE_ORIGIN) { + // If we snap in guideConstrainedSnap() below, then motion_dt will be forced to be on the guide + // If we don't snap however, then it the origin should still be constrained to the guide + // So let's do that explicitly first: + Geom::Line line(guide->point_on_line, guide->angle()); + Geom::Coord t = line.nearestPoint(event_dt); + event_dt = line.pointAt(t); + m.guideConstrainedSnap(event_dt, *guide); + } else { + m.guideFreeSnap(event_dt, guide->normal_to_line); + } if (sp_canvas_world_pt_inside_window(item->canvas, event_w)) { switch (drag_type) { @@ -360,7 +376,7 @@ gint sp_dt_guide_event(SPCanvasItem *item, GdkEvent *event, gpointer data) sp_guide_moveto(*guide, guide->point_on_line + event_dt - drag_origin, true); break; } - case SP_DRAG_TRANSLATE_CONSTRAINED: + case SP_DRAG_TRANSLATE_CONSTRAINED: // Is not being used currently! { Geom::Point pt_constr = Geom::constrain_angle(guide->point_on_line, event_dt); sp_guide_moveto(*guide, pt_constr, true); @@ -374,10 +390,8 @@ gint sp_dt_guide_event(SPCanvasItem *item, GdkEvent *event, gpointer data) } case SP_DRAG_MOVE_ORIGIN: { - Geom::Line line(guide->point_on_line, guide->angle()); - Geom::Coord t = line.nearestPoint(event_dt); - sp_guide_moveto(*guide, line.pointAt(t), true); - break; + sp_guide_moveto(*guide, event_dt, true); + break; } case SP_DRAG_NONE: g_assert_not_reached(); diff --git a/src/display/snap-indicator.cpp b/src/display/snap-indicator.cpp index e73eef796..081496fd0 100644 --- a/src/display/snap-indicator.cpp +++ b/src/display/snap-indicator.cpp @@ -56,7 +56,7 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const p) bool value = prefs->getBool("/options/snapindicator/value", true); if (value) { - // TRANSLATORS: undefined target for snapping + // TRANSLATORS: undefined target for snapping gchar *target_name = _("UNDEFINED"); switch (p.getTarget()) { case SNAPTARGET_UNDEFINED: @@ -180,6 +180,9 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const p) case SNAPSOURCE_GUIDE: source_name = _("Guide"); break; + case SNAPSOURCE_GUIDE_ORIGIN: + source_name = _("Guide origin"); + break; case SNAPSOURCE_CONVEX_HULL_CORNER: source_name = _("Convex hull corner"); break; diff --git a/src/object-snapper.cpp b/src/object-snapper.cpp index 70377cb66..5dd9350dc 100644 --- a/src/object-snapper.cpp +++ b/src/object-snapper.cpp @@ -330,6 +330,7 @@ void Inkscape::ObjectSnapper::_collectPaths(Inkscape::SnapPreferences::PointType SPItem::BBoxType bbox_type = SPItem::GEOMETRIC_BBOX; bool p_is_a_node = t & Inkscape::SnapPreferences::SNAPPOINT_NODE; + bool p_is_a_guide = t & Inkscape::SnapPreferences::SNAPPOINT_GUIDE; if (_snapmanager->snapprefs.getSnapToBBoxPath()) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); @@ -365,7 +366,7 @@ void Inkscape::ObjectSnapper::_collectPaths(Inkscape::SnapPreferences::PointType //Add the item's path to snap to if (_snapmanager->snapprefs.getSnapToItemPath()) { - if (!(_snapmanager->snapprefs.getStrictSnapping() && !p_is_a_node)) { + if (p_is_a_guide || !(_snapmanager->snapprefs.getStrictSnapping() && !p_is_a_node)) { // Snapping to the path of characters is very cool, but for a large // chunk of text this will take ages! So limit snapping to text paths // containing max. 240 characters. Snapping the bbox will not be affected @@ -399,7 +400,7 @@ void Inkscape::ObjectSnapper::_collectPaths(Inkscape::SnapPreferences::PointType //Add the item's bounding box to snap to if (_snapmanager->snapprefs.getSnapToBBoxPath()) { - if (!(_snapmanager->snapprefs.getStrictSnapping() && p_is_a_node)) { + if (p_is_a_guide || !(_snapmanager->snapprefs.getStrictSnapping() && p_is_a_node)) { // Discard the bbox of a clipped path / mask, because we don't want to snap to both the bbox // of the item AND the bbox of the clipping path at the same time if (!(*i).clip_or_mask) { @@ -663,7 +664,7 @@ void Inkscape::ObjectSnapper::constrainedSnap( SnappedConstraints &sc, // This method is used to snap a guide to nodes, while dragging the guide around -void Inkscape::ObjectSnapper::guideSnap(SnappedConstraints &sc, +void Inkscape::ObjectSnapper::guideFreeSnap(SnappedConstraints &sc, Geom::Point const &p, Geom::Point const &guide_normal) const { @@ -680,15 +681,29 @@ void Inkscape::ObjectSnapper::guideSnap(SnappedConstraints &sc, snap_dim = ANGLED_GUIDE_TRANSL_SNAP; } - // We don't support ANGLED_GUIDE_ROT_SNAP yet. + _findCandidates(sp_document_root(_snapmanager->getDocument()), &it, true, Geom::Rect(p, p), snap_dim, false, Geom::identity()); + _snapTranslatingGuideToNodes(sc, Inkscape::SnapPreferences::SNAPPOINT_GUIDE, p, guide_normal); + // _snapRotatingGuideToNodes has not been implemented yet. +} - // It would be cool to allow the user to rotate a guide by dragging it, instead of - // only translating it. (For example when CTRL is pressed). We will need an UI part - // for that first; and some important usability choices need to be made: - // E.g. which point should be used for pivoting? A previously snapped point, - // or a transformation center (which can be moved after clicking for the - // second time on an object; but should this point then be constrained to the - // line, or can it be located anywhere?) +// This method is used to snap the origin of a guide to nodes/paths, while dragging the origin along the guide +void Inkscape::ObjectSnapper::guideConstrainedSnap(SnappedConstraints &sc, + Geom::Point const &p, + Geom::Point const &guide_normal, + ConstraintLine const &c) const +{ + /* Get a list of all the SPItems that we will try to snap to */ + std::vector cand; + std::vector const it; //just an empty list + + DimensionToSnap snap_dim; + if (guide_normal == to_2geom(component_vectors[Geom::Y])) { + snap_dim = GUIDE_TRANSL_SNAP_Y; + } else if (guide_normal == to_2geom(component_vectors[Geom::X])) { + snap_dim = GUIDE_TRANSL_SNAP_X; + } else { + snap_dim = ANGLED_GUIDE_TRANSL_SNAP; + } _findCandidates(sp_document_root(_snapmanager->getDocument()), &it, true, Geom::Rect(p, p), snap_dim, false, Geom::identity()); _snapTranslatingGuideToNodes(sc, Inkscape::SnapPreferences::SNAPPOINT_GUIDE, p, guide_normal); diff --git a/src/object-snapper.h b/src/object-snapper.h index f220106e3..baa60a096 100644 --- a/src/object-snapper.h +++ b/src/object-snapper.h @@ -53,13 +53,17 @@ public: GUIDE_TRANSL_SNAP_X, // For snapping a vertical guide (normal in the X-direction) to objects, GUIDE_TRANSL_SNAP_Y, // For snapping a horizontal guide (normal in the Y-direction) to objects ANGLED_GUIDE_TRANSL_SNAP, // For snapping an angled guide, while translating it accross the desktop - ANGLED_GUIDE_ROT_SNAP, // For snapping an angled guide, while rotating it around some pivot point TRANSL_SNAP_XY}; // All other cases; for snapping to objects, other than guides - void guideSnap(SnappedConstraints &sc, + void guideFreeSnap(SnappedConstraints &sc, Geom::Point const &p, Geom::Point const &guide_normal) const; + void guideConstrainedSnap(SnappedConstraints &sc, + Geom::Point const &p, + Geom::Point const &guide_normal, + ConstraintLine const &c) const; + bool ThisSnapperMightSnap() const; bool GuidesMightSnap() const; diff --git a/src/snap.cpp b/src/snap.cpp index 9ca9b7838..aa0e4af5c 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -330,7 +330,8 @@ Inkscape::SnappedPoint SnapManager::constrainedSnap(Inkscape::SnapPreferences::P return findBestSnap(p, source_type, sc, true); } -void SnapManager::guideSnap(Geom::Point &p, Geom::Point const &guide_normal) const +// guideFreeSnap is used when dragging or rotating the guide +void SnapManager::guideFreeSnap(Geom::Point &p, Geom::Point const &guide_normal) const { // This method is used to snap a guide to nodes or to other guides, while dragging the guide around. Will not snap to grids! @@ -350,7 +351,7 @@ void SnapManager::guideSnap(Geom::Point &p, Geom::Point const &guide_normal) con // Snap to nodes SnappedConstraints sc; if (object.GuidesMightSnap()) { - object.guideSnap(sc, p, guide_normal); + object.guideFreeSnap(sc, p, guide_normal); } // Snap to guides @@ -364,6 +365,41 @@ void SnapManager::guideSnap(Geom::Point &p, Geom::Point const &guide_normal) con s.getPoint(p); } +// guideConstrainedSnap is used when dragging the origin of the guide along the guide itself +void SnapManager::guideConstrainedSnap(Geom::Point &p, SPGuide const &guideline) const +{ + // This method is used to snap a guide to paths or to other guides, while dragging the origin of the guide around. Will not snap to grids! + + if (_desktop->event_context && _desktop->event_context->_snap_window_open == false) { + g_warning("The current tool tries to snap, but it hasn't yet opened the snap window. Please report this!"); + // When the context goes into dragging-mode, then Inkscape should call this: sp_event_context_snap_window_open(event_context); + } + + if (!snapprefs.getSnapEnabledGlobally() || snapprefs.getSnapPostponedGlobally()) { + return; + } + + if (!(object.ThisSnapperMightSnap() || snapprefs.getSnapToGuides())) { + return; + } + + // Snap to nodes or paths + SnappedConstraints sc; + Inkscape::Snapper::ConstraintLine cl(guideline.point_on_line, Geom::rot90(guideline.normal_to_line)); + if (object.ThisSnapperMightSnap()) { + object.constrainedSnap(sc, Inkscape::SnapPreferences::SNAPPOINT_GUIDE, p, Inkscape::SNAPSOURCE_GUIDE_ORIGIN, true, Geom::OptRect(), cl, NULL); + } + + // Snap to guides + if (snapprefs.getSnapToGuides()) { + guide.constrainedSnap(sc, Inkscape::SnapPreferences::SNAPPOINT_GUIDE, p, Inkscape::SNAPSOURCE_GUIDE_ORIGIN, true, Geom::OptRect(), cl, NULL); + } + + // We won't snap to grids, what's the use? + + Inkscape::SnappedPoint const s = findBestSnap(p, Inkscape::SNAPSOURCE_GUIDE, sc, false); + s.getPoint(p); +} /** * Main internal snapping method, which is called by the other, friendlier, public diff --git a/src/snap.h b/src/snap.h index 5290ef081..ba920510f 100644 --- a/src/snap.h +++ b/src/snap.h @@ -23,6 +23,7 @@ #include "guide-snapper.h" #include "object-snapper.h" #include "snap-preferences.h" +//#include "sp-guide.h" class SPNamedView; @@ -98,7 +99,8 @@ public: bool first_point = true, Geom::OptRect const &bbox_to_snap = Geom::OptRect()) const; - void guideSnap(Geom::Point &p, Geom::Point const &guide_normal) const; + void guideFreeSnap(Geom::Point &p, Geom::Point const &guide_normal) const; + void guideConstrainedSnap(Geom::Point &p, SPGuide const &guideline) const; Inkscape::SnappedPoint freeSnapTranslation(Inkscape::SnapPreferences::PointType point_type, std::vector > const &p, diff --git a/src/snapped-point.h b/src/snapped-point.h index ee7c12aa7..d071afddc 100644 --- a/src/snapped-point.h +++ b/src/snapped-point.h @@ -62,6 +62,7 @@ enum SnapSourceType { SNAPSOURCE_HANDLE, SNAPSOURCE_PATH_INTERSECTION, SNAPSOURCE_GUIDE, + SNAPSOURCE_GUIDE_ORIGIN, SNAPSOURCE_CONVEX_HULL_CORNER, SNAPSOURCE_ELLIPSE_QUADRANT_POINT, SNAPSOURCE_CENTER, // of ellipse -- 2.30.2