Code

Use g_base64_encode_step when importing images via drag and drop.
[inkscape.git] / src / seltrans.cpp
index 614ce7584f7d4c0de05bd3ec9e5f151f36afe512..f3ad2849c4ed802d04397b9f2cd2254b9fe98c37 100644 (file)
@@ -285,38 +285,41 @@ void Inkscape::SelTrans::grab(Geom::Point const &p, gdouble x, gdouble y, bool s
 
     // Next, get all points to consider for snapping
     SnapManager const &m = _desktop->namedview->snap_manager;
+       Inkscape::SnapPreferences local_snapprefs = m.snapprefs;
+       local_snapprefs.setSnapToItemNode(true); // We should get at least the cusp nodes here. This might
+       // have been turned off because (for example) the user only want paths as a snap target, not nodes
+       // but as a snap source we still need some nodes though!
     _snap_points.clear();
-    _snap_points = selection->getSnapPoints(&m.snapprefs);
-    std::vector<Geom::Point> snap_points_hull = selection->getSnapPointsConvexHull(&m.snapprefs);
-    if (_snap_points.size() > 100) {
-        /* Snapping a huge number of nodes will take way too long, so limit the number of snappable nodes
-        An average user would rarely ever try to snap such a large number of nodes anyway, because
-        (s)he could hardly discern which node would be snapping */
-        _snap_points = snap_points_hull;
-        // Unfortunately, by now we will have lost the font-baseline snappoints :-(
-    }
+       _snap_points = selection->getSnapPoints(&local_snapprefs);
+       std::vector<std::pair<Geom::Point, int> > snap_points_hull = selection->getSnapPointsConvexHull(&local_snapprefs);
+       if (_snap_points.size() > 100) {
+               /* Snapping a huge number of nodes will take way too long, so limit the number of snappable nodes
+               An average user would rarely ever try to snap such a large number of nodes anyway, because
+               (s)he could hardly discern which node would be snapping */
+               _snap_points = snap_points_hull;
+               // Unfortunately, by now we will have lost the font-baseline snappoints :-(
+       }
 
     // Find bbox hulling all special points, which excludes stroke width. Here we need to include the
     // path nodes, for example because a rectangle which has been converted to a path doesn't have
     // any other special points
     Geom::Rect snap_points_bbox;
     if ( snap_points_hull.empty() == false ) {
-        std::vector<Geom::Point>::iterator i = snap_points_hull.begin();
-        snap_points_bbox = Geom::Rect(*i, *i);
+       std::vector<std::pair<Geom::Point, int> >::iterator i = snap_points_hull.begin();
+        snap_points_bbox = Geom::Rect((*i).first, (*i).first);
         i++;
         while (i != snap_points_hull.end()) {
-            snap_points_bbox.expandTo(*i);
+            snap_points_bbox.expandTo((*i).first);
             i++;
         }
     }
 
     _bbox_points.clear();
     if (_bbox) {
-        // ... and add the bbox corners to _bbox_points
-        for ( unsigned i = 0 ; i < 4 ; i++ ) {
-            _bbox_points.push_back(_bbox->corner(i));
-        }
-        // There are two separate "opposites" (i.e. opposite w.r.t. the handle being dragged):
+       if (m.snapprefs.getSnapModeBBox()) {
+               getBBoxPoints(_bbox, &_bbox_points, false, true, m.snapprefs.getSnapBBoxEdgeMidpoints(), m.snapprefs.getSnapBBoxMidpoints());
+       }
+       // There are two separate "opposites" (i.e. opposite w.r.t. the handle being dragged):
         //  - one for snapping the boundingbox, which can be either visual or geometric
         //  - one for snapping the special points
         // The "opposite" in case of a geometric boundingbox always coincides with the "opposite" for the special points
@@ -327,19 +330,45 @@ void Inkscape::SelTrans::grab(Geom::Point const &p, gdouble x, gdouble y, bool s
         _opposite = _opposite_for_bboxpoints;
     }
 
-    // The lines below are usefull 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<Geom::Point>::const_iterator i = _snap_points.begin(); i != _snap_points.end(); i++)
-    {
-        std::cout << "    " << *i << std::endl;
+    // When snapping the node closest to the mouse pointer is absolutely preferred over the closest snap
+    // (i.e. when weight == 1), then we will not even try to snap to other points and discard those other
+    // points immediately.
+    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+       if (prefs->getBool("/options/snapclosestonly/value", false)) {
+       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)).first - p) < Geom::L2((_bbox_points.at(0)).first - p)) {
+                       _bbox_points.clear();
+               } else {
+                       _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 (m.snapprefs.getSnapEnabledGlobally()) {
+                       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));
+                       }
+       }
     }
 
-    std::cout << "Number of bbox points:  " << _bbox_points.size() << std::endl;
-    for (std::vector<Geom::Point>::const_iterator i = _bbox_points.begin(); i != _bbox_points.end(); i++)
-    {
-        std::cout << "    " << *i << std::endl;
-    }*/
+       sp_canvas_set_snap_delay_active(_desktop->canvas, true);
 
     if ((x != -1) && (y != -1)) {
         sp_canvas_item_show(_norm);
@@ -393,6 +422,10 @@ void Inkscape::SelTrans::ungrab()
     _grabbed = false;
     _show_handles = true;
 
+    sp_canvas_set_snap_delay_active(_desktop->canvas, false);
+
+    _desktop->snapindicator->remove_snapsource();
+
     Inkscape::Selection *selection = sp_desktop_selection(_desktop);
     _updateVolatileState();
 
@@ -953,15 +986,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
@@ -1055,13 +1088,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
@@ -1154,10 +1187,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();
         }
     }
 
@@ -1248,11 +1281,12 @@ gboolean Inkscape::SelTrans::rotateRequest(Geom::Point &pt, guint state)
     return TRUE;
 }
 
+// Move the item's transformation center
 gboolean Inkscape::SelTrans::centerRequest(Geom::Point &pt, guint state)
 {
     SnapManager &m = _desktop->namedview->snap_manager;
     m.setup(_desktop);
-    m.freeSnapReturnByRef(SnapPreferences::SNAPPOINT_NODE, pt);
+    m.freeSnapReturnByRef(SnapPreferences::SNAPPOINT_NODE, pt, Inkscape::SNAPSOURCE_HANDLE);
 
     if (state & GDK_CONTROL_MASK) {
         if ( fabs(_point[Geom::X] - pt[Geom::X]) > fabs(_point[Geom::Y] - pt[Geom::Y]) ) {
@@ -1345,7 +1379,6 @@ void sp_sel_trans_center(Inkscape::SelTrans *seltrans, SPSelTransHandle const &,
 void Inkscape::SelTrans::moveTo(Geom::Point const &xy, guint state)
 {
     SnapManager &m = _desktop->namedview->snap_manager;
-    m.setup(_desktop, true, _items_const);
 
     /* The amount that we've moved by during this drag */
     Geom::Point dxy = xy - _point;
@@ -1360,7 +1393,8 @@ void Inkscape::SelTrans::moveTo(Geom::Point const &xy, guint state)
         ** FIXME: this will snap to more than just the grid, nowadays.
         */
 
-        m.freeSnapReturnByRef(SnapPreferences::SNAPPOINT_NODE, dxy);
+       m.setup(_desktop, true, _items_const);
+       m.freeSnapReturnByRef(SnapPreferences::SNAPPOINT_NODE, dxy, Inkscape::SNAPSOURCE_UNDEFINED);
 
     } else if (!shift) {
 
@@ -1369,7 +1403,9 @@ void Inkscape::SelTrans::moveTo(Geom::Point const &xy, guint state)
         ** pick the smallest.
         */
 
-        /* This will be our list of possible translations */
+       m.setup(_desktop, false, _items_const);
+
+       /* This will be our list of possible translations */
         std::list<Inkscape::SnappedPoint> s;
 
         if (control) {
@@ -1384,13 +1420,13 @@ void Inkscape::SelTrans::moveTo(Geom::Point const &xy, guint state)
                 // individually for each point to be snapped; this will be handled however by _snapTransformed()
                 s.push_back(m.constrainedSnapTranslation(Inkscape::SnapPreferences::SNAPPOINT_BBOX,
                                                          _bbox_points,
-                                                         _point, 
+                                                         _point,
                                                          Inkscape::Snapper::ConstraintLine(component_vectors[dim]),
                                                          dxy));
 
                 s.push_back(m.constrainedSnapTranslation(Inkscape::SnapPreferences::SNAPPOINT_NODE,
                                                          _snap_points,
-                                                         _point, 
+                                                         _point,
                                                          Inkscape::Snapper::ConstraintLine(component_vectors[dim]),
                                                          dxy));
             }
@@ -1413,20 +1449,19 @@ void Inkscape::SelTrans::moveTo(Geom::Point const &xy, guint state)
 
         /* Pick one */
         Inkscape::SnappedPoint best_snapped_point;
-        g_assert(best_snapped_point.getDistance() == NR_HUGE);
         for (std::list<Inkscape::SnappedPoint>::const_iterator i = s.begin(); i != s.end(); i++) {
             if (i->getSnapped()) {
-                if (i->getDistance() < best_snapped_point.getDistance()) {
+                if (best_snapped_point.isOtherSnapBetter(*i, true)) {
                     best_snapped_point = *i;
                     dxy = i->getTransformation();
                 }
             }
         }
         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();            
+            // We didn't snap, so remove any previous snap indicator
+            _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
@@ -1439,7 +1474,7 @@ void Inkscape::SelTrans::moveTo(Geom::Point const &xy, guint state)
             }
         }
     }
-    
+
     Geom::Matrix const move((Geom::Translate(dxy)));
     Geom::Point const norm(0, 0);
     transform(move, norm);
@@ -1545,6 +1580,25 @@ Geom::Point Inkscape::SelTrans::_calcAbsAffineGeom(Geom::Scale const geom_scale)
     return visual_bbox.min() + visual_bbox.dimensions() * Geom::Scale(_handle_x, _handle_y);
 }
 
+void Inkscape::SelTrans::_keepClosestPointOnly(std::vector<std::pair<Geom::Point, int> > &points, const Geom::Point &reference)
+{
+       if (points.size() < 2) return;
+
+       std::pair<Geom::Point, int> closest_point = std::make_pair(Geom::Point(NR_HUGE, NR_HUGE), SNAPSOURCE_UNDEFINED);
+       Geom::Coord closest_dist = NR_HUGE;
+
+       for(std::vector<std::pair<Geom::Point, int> >::const_iterator i = points.begin(); i != points.end(); i++) {
+               Geom::Coord dist = Geom::L2((*i).first - reference);
+               if (i == points.begin() || dist < closest_dist) {
+                       closest_point = *i;
+                       closest_dist = dist;
+               }
+    }
+
+       points.clear();
+       points.push_back(closest_point);
+}
+
 /*
   Local Variables:
   mode:c++