Code

Avoid self-snapping when dragging a rotation center, and draw the rotation center...
authorDiederik van Lierop <mailat-signdiedenrezidotnl>
Sat, 24 Jul 2010 12:37:50 +0000 (14:37 +0200)
committerDiederik van Lierop <mailat-signdiedenrezidotnl>
Sat, 24 Jul 2010 12:37:50 +0000 (14:37 +0200)
src/object-snapper.cpp
src/selection.cpp
src/seltrans.cpp
src/snap.cpp
src/snap.h
src/sp-shape.cpp

index ef5dcc7d0f3bb395ad33a075c0538c5dbf3a7e85..c1ed08f12f7610b7d0004001078ddcad98423f58 100644 (file)
@@ -228,11 +228,17 @@ void Inkscape::ObjectSnapper::_collectNodes(Inkscape::SnapSourceType const &t,
                     _snapmanager->snapprefs.setSnapIntersectionCS(false);
                 }
 
+                bool old_pref2 = _snapmanager->snapprefs.getIncludeItemCenter();
+                if ((*i).item == _snapmanager->getRotationCenterSource()) {
+                    // don't snap to this item's rotation center
+                    _snapmanager->snapprefs.setIncludeItemCenter(false);
+                }
+
                 sp_item_snappoints(root_item, *_points_to_snap_to, &_snapmanager->snapprefs);
 
-                if (_snapmanager->snapprefs.getSnapToItemPath()) {
-                    _snapmanager->snapprefs.setSnapIntersectionCS(old_pref);
-                }
+                // restore the original snap preferences
+                _snapmanager->snapprefs.setSnapIntersectionCS(old_pref);
+                _snapmanager->snapprefs.setIncludeItemCenter(old_pref2);
             }
 
             //Collect the bounding box's corners so we can snap to them
index 96c66e0c506496ec96ac1b8f99e425fb103a66e0..3f333e4e24e4569904b7dc90a41c42bc0c5c86fd 100644 (file)
@@ -406,6 +406,8 @@ Geom::OptRect Selection::boundsInDocument(SPItem::BBoxType type) const {
 }
 
 /** Extract the position of the center from the first selected object */
+// If we have a selection of multiple items, then the center of the first item
+// will be returned; this is also the case in SelTrans::centerRequest()
 boost::optional<Geom::Point> Selection::center() const {
     GSList *items = (GSList *) const_cast<Selection *>(this)->itemList();
     Geom::Point center;
index b9bf4c6ce8a9efc280fa1bfb35758e6a8dcae283..764c222a8fe67ba1ea04496e54dfd92002761a8f 100644 (file)
@@ -883,7 +883,11 @@ gboolean Inkscape::SelTrans::handleRequest(SPKnot *knot, Geom::Point *position,
     if (handle.request(this, handle, *position, state)) {
         sp_knot_set_position(knot, *position, state);
         SP_CTRL(_grip)->moveto(*position);
-        SP_CTRL(_norm)->moveto(_origin);
+        if (&handle == &handle_center) {
+            SP_CTRL(_norm)->moveto(*position);
+        } else {
+            SP_CTRL(_norm)->moveto(_origin);
+        }
     }
 
     return TRUE;
@@ -1329,7 +1333,18 @@ gboolean Inkscape::SelTrans::centerRequest(Geom::Point &pt, guint state)
 {
     SnapManager &m = _desktop->namedview->snap_manager;
     m.setup(_desktop);
-    m.freeSnapReturnByRef(pt, Inkscape::SNAPSOURCE_OTHER_HANDLE);
+
+    // Center is being dragged for the first item in the selection only
+    // Find out which item is first ...
+    GSList *items = (GSList *) const_cast<Selection *>(_selection)->itemList();
+    SPItem *first = NULL;
+    if (items) {
+        first = reinterpret_cast<SPItem*>(g_slist_last(items)->data); // from the first item in selection
+    }
+    // ... and store that item because later on we need to make sure that
+    // this transformation center won't snap to itself
+    m.setRotationCenterSource(first);
+    m.freeSnapReturnByRef(pt, Inkscape::SNAPSOURCE_ROTATION_CENTER);
 
     if (state & GDK_CONTROL_MASK) {
         if ( fabs(_point[Geom::X] - pt[Geom::X]) > fabs(_point[Geom::Y] - pt[Geom::Y]) ) {
index ccbd449bd4c461a5757a3323975f28b764d6baa2..fc8837c4315328c892a7b7c8e57a029d36b4e9d5 100644 (file)
@@ -1079,6 +1079,7 @@ void SnapManager::setup(SPDesktop const *desktop,
     _snapindicator = snapindicator;
     _unselected_nodes = unselected_nodes;
     _guide_to_ignore = guide_to_ignore;
+    _rotation_center_source_item = NULL;
 }
 
 /**
@@ -1109,6 +1110,7 @@ void SnapManager::setup(SPDesktop const *desktop,
     _snapindicator = snapindicator;
     _unselected_nodes = unselected_nodes;
     _guide_to_ignore = guide_to_ignore;
+    _rotation_center_source_item = NULL;
 }
 
 /// Setup, taking the list of items to ignore from the desktop's selection.
@@ -1121,6 +1123,7 @@ void SnapManager::setupIgnoreSelection(SPDesktop const *desktop,
     _snapindicator = snapindicator;
     _unselected_nodes = unselected_nodes;
     _guide_to_ignore = guide_to_ignore;
+    _rotation_center_source_item = NULL;
     _items_to_ignore.clear();
 
     Inkscape::Selection *sel = _desktop->selection;
index 26e599cc66773aae66edc20c39b6d8cb682a922b..f740f3c62b900d93a12f1194c3e31a8308e697e4 100644 (file)
@@ -92,11 +92,19 @@ public:
                std::vector<SPItem const *> &items_to_ignore,
                std::vector<Inkscape::SnapCandidatePoint> *unselected_nodes = NULL,
                SPGuide *guide_to_ignore = NULL);
+
     void setupIgnoreSelection(SPDesktop const *desktop,
                               bool snapindicator = true,
                               std::vector<Inkscape::SnapCandidatePoint> *unselected_nodes = NULL,
                               SPGuide *guide_to_ignore = NULL);
 
+    // If we're dragging a rotation center, then setRotationCenterSource() stores the parent item
+    // of this rotation center; this reference is used to make sure that we do not snap a rotation
+    // center to itself
+    // NOTE: Must be called after calling setup(), not before!
+    void setRotationCenterSource(SPItem *item) {_rotation_center_source_item = item;}
+    SPItem* getRotationCenterSource() {return _rotation_center_source_item;}
+
     // freeSnapReturnByRef() is preferred over freeSnap(), because it only returns a
     // point if snapping has occurred (by overwriting p); otherwise p is untouched
     void freeSnapReturnByRef(Geom::Point &p,
@@ -183,6 +191,7 @@ protected:
 
 private:
     std::vector<SPItem const *> _items_to_ignore; ///< Items that should not be snapped to, for example the items that are currently being dragged. Set using the setup() method
+    SPItem *_rotation_center_source_item; // to avoid snapping a rotation center to itself
     SPGuide *_guide_to_ignore; ///< A guide that should not be snapped to, e.g. the guide that is currently being dragged
     SPDesktop const *_desktop;
     bool _snapindicator; ///< When true, an indicator will be drawn at the position that was being snapped to
index 0038908bfd19f6bc869d0aad951a176c9f69761f..b64ad45e0773f5fafbfda24c5bf2b5efcc1304e7 100644 (file)
@@ -1208,57 +1208,57 @@ static void sp_shape_snappoints(SPItem const *item, std::vector<Inkscape::SnapCa
 
     for(Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) {
         if (snapprefs->getSnapToItemNode()) {
-               // Add the first point of the path
-               p.push_back(Inkscape::SnapCandidatePoint(path_it->initialPoint() * i2d, Inkscape::SNAPSOURCE_NODE_CUSP, Inkscape::SNAPTARGET_NODE_CUSP));
+            // Add the first point of the path
+            p.push_back(Inkscape::SnapCandidatePoint(path_it->initialPoint() * i2d, Inkscape::SNAPSOURCE_NODE_CUSP, Inkscape::SNAPTARGET_NODE_CUSP));
         }
 
         Geom::Path::const_iterator curve_it1 = path_it->begin();      // incoming curve
         Geom::Path::const_iterator curve_it2 = ++(path_it->begin());  // outgoing curve
         while (curve_it1 != path_it->end_default())
         {
-               // For each path: consider midpoints of line segments for snapping
-                       if (snapprefs->getSnapLineMidpoints()) { // only do this when we're snapping nodes (enforces strict snapping)
-                               if (Geom::LineSegment const* line_segment = dynamic_cast<Geom::LineSegment const*>(&(*curve_it1))) {
-                                       p.push_back(Inkscape::SnapCandidatePoint(Geom::middle_point(*line_segment) * i2d, Inkscape::SNAPSOURCE_LINE_MIDPOINT, Inkscape::SNAPTARGET_LINE_MIDPOINT));
-                               }
-                       }
-
-                       if (curve_it2 == path_it->end_default()) { // Test will only pass for the last iteration of the while loop
-                               if (snapprefs->getSnapToItemNode() && !path_it->closed()) {
-                                       // Add the last point of the path, but only for open paths
-                                       // (for closed paths the first and last point will coincide)
-                                       p.push_back(Inkscape::SnapCandidatePoint((*curve_it1).finalPoint() * i2d, Inkscape::SNAPSOURCE_NODE_CUSP, Inkscape::SNAPTARGET_NODE_CUSP));
-                               }
-                       } else {
-                               /* Test whether to add the node between curve_it1 and curve_it2.
-                                * Loop to end_default (so only iterating through the stroked part); */
-
-                               Geom::NodeType nodetype = Geom::get_nodetype(*curve_it1, *curve_it2);
-
-                               bool c1 = snapprefs->getSnapToItemNode() && (nodetype == Geom::NODE_CUSP || nodetype == Geom::NODE_NONE);
-                               bool c2 = snapprefs->getSnapSmoothNodes() && (nodetype == Geom::NODE_SMOOTH || nodetype == Geom::NODE_SYMM);
-
-                               if (c1 || c2) {
-                                       Inkscape::SnapSourceType sst;
-                                       Inkscape::SnapTargetType stt;
-                                       switch (nodetype) {
-                                       case Geom::NODE_CUSP:
-                                               sst = Inkscape::SNAPSOURCE_NODE_CUSP;
-                                               stt = Inkscape::SNAPTARGET_NODE_CUSP;
-                                               break;
-                                       case Geom::NODE_SMOOTH:
-                                       case Geom::NODE_SYMM:
-                                               sst = Inkscape::SNAPSOURCE_NODE_SMOOTH;
-                                               stt = Inkscape::SNAPTARGET_NODE_SMOOTH;
-                                               break;
-                                       default:
-                                               sst = Inkscape::SNAPSOURCE_UNDEFINED;
-                                               stt = Inkscape::SNAPTARGET_UNDEFINED;
-                                               break;
-                                       }
-                                       p.push_back(Inkscape::SnapCandidatePoint(curve_it1->finalPoint() * i2d, sst, stt));
-                               }
-                       }
+            // For each path: consider midpoints of line segments for snapping
+            if (snapprefs->getSnapLineMidpoints()) { // only do this when we're snapping nodes (enforces strict snapping)
+                if (Geom::LineSegment const* line_segment = dynamic_cast<Geom::LineSegment const*>(&(*curve_it1))) {
+                    p.push_back(Inkscape::SnapCandidatePoint(Geom::middle_point(*line_segment) * i2d, Inkscape::SNAPSOURCE_LINE_MIDPOINT, Inkscape::SNAPTARGET_LINE_MIDPOINT));
+                }
+            }
+
+            if (curve_it2 == path_it->end_default()) { // Test will only pass for the last iteration of the while loop
+                if (snapprefs->getSnapToItemNode() && !path_it->closed()) {
+                    // Add the last point of the path, but only for open paths
+                    // (for closed paths the first and last point will coincide)
+                    p.push_back(Inkscape::SnapCandidatePoint((*curve_it1).finalPoint() * i2d, Inkscape::SNAPSOURCE_NODE_CUSP, Inkscape::SNAPTARGET_NODE_CUSP));
+                }
+            } else {
+                /* Test whether to add the node between curve_it1 and curve_it2.
+                 * Loop to end_default (so only iterating through the stroked part); */
+
+                Geom::NodeType nodetype = Geom::get_nodetype(*curve_it1, *curve_it2);
+
+                bool c1 = snapprefs->getSnapToItemNode() && (nodetype == Geom::NODE_CUSP || nodetype == Geom::NODE_NONE);
+                bool c2 = snapprefs->getSnapSmoothNodes() && (nodetype == Geom::NODE_SMOOTH || nodetype == Geom::NODE_SYMM);
+
+                if (c1 || c2) {
+                    Inkscape::SnapSourceType sst;
+                    Inkscape::SnapTargetType stt;
+                    switch (nodetype) {
+                    case Geom::NODE_CUSP:
+                        sst = Inkscape::SNAPSOURCE_NODE_CUSP;
+                        stt = Inkscape::SNAPTARGET_NODE_CUSP;
+                        break;
+                    case Geom::NODE_SMOOTH:
+                    case Geom::NODE_SYMM:
+                        sst = Inkscape::SNAPSOURCE_NODE_SMOOTH;
+                        stt = Inkscape::SNAPTARGET_NODE_SMOOTH;
+                        break;
+                    default:
+                        sst = Inkscape::SNAPSOURCE_UNDEFINED;
+                        stt = Inkscape::SNAPTARGET_UNDEFINED;
+                        break;
+                    }
+                    p.push_back(Inkscape::SnapCandidatePoint(curve_it1->finalPoint() * i2d, sst, stt));
+                }
+            }
 
             ++curve_it1;
             ++curve_it2;