Code

Also consider path nodes for snapping
[inkscape.git] / src / selection.cpp
index 49934cfd39ccb16591d2bcf00d1eae3ca84a542f..68a9a2cd92e719ebd151cbbcb78725a113452743 100644 (file)
@@ -27,6 +27,8 @@
 #include "xml/repr.h"
 
 #include "sp-shape.h"
+#include "sp-path.h"
+#include "sp-item-group.h"
 
 #include <sigc++/functors/mem_fun.h>
 
@@ -56,7 +58,7 @@ Selection::~Selection() {
 
 /* Handler for selected objects "modified" signal */
 
-void Selection::_schedule_modified(SPObject *obj, guint flags) {
+void Selection::_schedule_modified(SPObject */*obj*/, guint flags) {
     if (!this->_idle) {
         /* Request handling to be run in _idle loop */
         this->_idle = g_idle_add_full(SP_SELECTION_UPDATE_PRIORITY, GSourceFunc(&Selection::_emit_modified), this, NULL);
@@ -303,35 +305,25 @@ Inkscape::XML::Node *Selection::singleRepr() {
     return obj ? SP_OBJECT_REPR(obj) : NULL;
 }
 
-NRRect *Selection::bounds(NRRect *bbox) const
+NRRect *Selection::bounds(NRRect *bbox, SPItem::BBoxType type) const
 {
     g_return_val_if_fail (bbox != NULL, NULL);
-    NR::Rect const b = bounds();
-    bbox->x0 = b.min()[NR::X];
-    bbox->y0 = b.min()[NR::Y];
-    bbox->x1 = b.max()[NR::X];
-    bbox->y1 = b.max()[NR::Y];
+    *bbox = NRRect(bounds(type));
     return bbox;
 }
 
-NR::Rect Selection::bounds() const
+NR::Maybe<NR::Rect> Selection::bounds(SPItem::BBoxType type) const
 {
     GSList const *items = const_cast<Selection *>(this)->itemList();
 
     NR::Maybe<NR::Rect> bbox = NR::Nothing();
     for ( GSList const *i = items ; i != NULL ; i = i->next ) {
-        bbox = NR::union_bounds(bbox, sp_item_bbox_desktop(SP_ITEM(i->data)));
-    }
-
-    // TODO: return NR::Maybe<NR::Rect>
-    if (bbox) {
-        return *bbox;
-    } else {
-        return NR::Rect(NR::Point(0, 0), NR::Point(0, 0));
+        bbox = NR::union_bounds(bbox, sp_item_bbox_desktop(SP_ITEM(i->data), type));
     }
+    return bbox;
 }
 
-NRRect *Selection::boundsInDocument(NRRect *bbox) const {
+NRRect *Selection::boundsInDocument(NRRect *bbox, SPItem::BBoxType type) const {
     g_return_val_if_fail (bbox != NULL, NULL);
 
     GSList const *items=const_cast<Selection *>(this)->itemList();
@@ -345,49 +337,50 @@ NRRect *Selection::boundsInDocument(NRRect *bbox) const {
 
     for ( GSList const *iter=items ; iter != NULL ; iter = iter->next ) {
         SPItem *item=SP_ITEM(iter->data);
-        NR::Matrix const i2doc(sp_item_i2doc_affine(item));
-        sp_item_invoke_bbox(item, bbox, i2doc, FALSE);
+        NR::Matrix i2doc(sp_item_i2doc_affine(item));
+        sp_item_invoke_bbox(item, bbox, i2doc, FALSE, type);
     }
 
     return bbox;
 }
 
-NR::Rect Selection::boundsInDocument() const {
+NR::Maybe<NR::Rect> Selection::boundsInDocument(SPItem::BBoxType type) const {
     NRRect r;
-    NR::Maybe<NR::Rect> rect(boundsInDocument(&r)->upgrade());
-    if (rect) {
-        return *rect;
-    } else {
-        // FIXME
-        return NR::Rect(NR::Point(0, 0), NR::Point(0, 0));
-    }
+    return boundsInDocument(&r, type)->upgrade();
 }
 
 /** Extract the position of the center from the first selected object */
-NR::Point Selection::center() const {
+NR::Maybe<NR::Point> Selection::center() const {
     GSList *items = (GSList *) const_cast<Selection *>(this)->itemList();
     NR::Point center;
     if (items) {
         SPItem *first = reinterpret_cast<SPItem*>(g_slist_last(items)->data); // from the first item in selection
         if (first->isCenterSet()) { // only if set explicitly
-            center = first->getCenter();
-        } else {
-            center = bounds().midpoint();
+            return first->getCenter();
         }
+    }
+    NR::Maybe<NR::Rect> bbox = bounds();
+    if (bbox) {
+        return bounds()->midpoint();
     } else {
-        center = bounds().midpoint();
+        return NR::Nothing();
     }
-    return center;
 }
 
 /**
  * Compute the list of points in the selection that are to be considered for snapping.
  */
-std::vector<NR::Point> Selection::getSnapPoints() const {
+std::vector<NR::Point> Selection::getSnapPoints(bool includeItemCenter) const {
     GSList const *items = const_cast<Selection *>(this)->itemList();
     std::vector<NR::Point> p;
     for (GSList const *iter = items; iter != NULL; iter = iter->next) {
-        sp_item_snappoints(SP_ITEM(iter->data), SnapPointsIter(p));
+        SPItem *this_item = SP_ITEM(iter->data);
+        sp_item_snappoints(this_item, false, SnapPointsIter(p));
+        //Include the transformation origin for snapping
+        //For a group only the group's origin is considered
+        if (includeItemCenter) {
+               p.push_back(this_item->getCenter());
+        }  
     }
 
     return p;
@@ -395,46 +388,30 @@ std::vector<NR::Point> Selection::getSnapPoints() const {
 
 std::vector<NR::Point> Selection::getSnapPointsConvexHull() const {
     GSList const *items = const_cast<Selection *>(this)->itemList();
+
     std::vector<NR::Point> p;
     for (GSList const *iter = items; iter != NULL; iter = iter->next) {
-       sp_item_snappoints(SP_ITEM(iter->data), SnapPointsIter(p));
+               sp_item_snappoints(SP_ITEM(iter->data), false, SnapPointsIter(p));
     }
 
-    std::vector<NR::Point>::iterator i;
-    NR::ConvexHull cvh(*(p.begin()));
-    for (i = p.begin(); i != p.end(); i++) {
-       // these are the points we get back
-       cvh.add(*i);
-    }
-
-    NR::Rect rHull = cvh.bounds();
-    std::vector<NR::Point> pHull(4);
-    pHull[0] = rHull.corner(0);
-    pHull[1] = rHull.corner(1);
-    pHull[2] = rHull.corner(2);
-    pHull[3] = rHull.corner(3);
-
-    return pHull;
-}
+    std::vector<NR::Point> pHull;
+    if (!p.empty()) {
+        std::vector<NR::Point>::iterator i;
+        NR::ConvexHull cvh(p.front());
+        for (i = p.begin(); i != p.end(); i++) {
+            // these are the points we get back
+            cvh.add(*i);
+        }
 
-std::vector<NR::Point> Selection::getBBoxPoints() const {
-    GSList const *items = const_cast<Selection *>(this)->itemList();
-    std::vector<NR::Point> p;
-    for (GSList const *iter = items; iter != NULL; iter = iter->next) {
-        NR::Rect b = sp_item_bbox_desktop(SP_ITEM(iter->data));
-        p.push_back(b.min());
-        p.push_back(b.max());
+        NR::Maybe<NR::Rect> rHull = cvh.bounds();
+        if (rHull) {
+            for ( unsigned i = 0 ; i < 4 ; ++i ) {
+                pHull.push_back(rHull->corner(i));
+            }
+        }
     }
 
-    return p;
-}
-
-std::vector<NR::Point> Selection::getBBoxPointsOuter() const {
-    std::vector<NR::Point> p;
-    NR::Rect bbox = bounds();
-    p.push_back(bbox.min());
-    p.push_back(bbox.max());
-    return p;
+    return pHull;
 }
 
 void Selection::_removeObjectDescendants(SPObject *obj) {