Code

Merge and cleanup of GSoC C++-ification project.
[inkscape.git] / src / selection.cpp
index 41540c95c99b982333230c8fbafd614b8da70113..9cef87076db5dd20c0179fd888ead40d975f9c61 100644 (file)
@@ -6,6 +6,7 @@
  *   MenTaLguY <mental@rydia.net>
  *   bulia byak <buliabyak@users.sf.net>
  *   Andrius R. <knutux@gmail.com>
+ *   Abhishek Sharma
  *
  * Copyright (C)      2006 Andrius R.
  * Copyright (C) 2004-2005 MenTaLguY
@@ -24,6 +25,7 @@
 #include "desktop-handles.h"
 #include "document.h"
 #include "selection.h"
+#include "helper/recthull.h"
 #include "xml/repr.h"
 
 #include "sp-shape.h"
@@ -161,24 +163,12 @@ void Selection::add(SPObject *obj, bool persist_selection_context/* = false */)
     _emitChanged(persist_selection_context);
 }
 
-void Selection::add_box_perspective(SPBox3D *box) {
-    Persp3D *persp = box3d_get_perspective(box);
-    std::map<Persp3D *, unsigned int>::iterator p = _persps.find(persp);
-    if (p != _persps.end()) {
-        (*p).second++;
-    } else {
-        _persps[persp] = 1;
-    }
-}
-
 void Selection::add_3D_boxes_recursively(SPObject *obj) {
     std::list<SPBox3D *> boxes = box3d_extract_boxes(obj);
 
     for (std::list<SPBox3D *>::iterator i = boxes.begin(); i != boxes.end(); ++i) {
         SPBox3D *box = *i;
-        box3d_add_to_selection(box);
         _3dboxes.push_back(box);
-        add_box_perspective(box);
     }
 }
 
@@ -219,33 +209,17 @@ void Selection::remove(SPObject *obj) {
     _emitChanged();
 }
 
-void Selection::remove_box_perspective(SPBox3D *box) {
-    Persp3D *persp = box3d_get_perspective(box);
-    std::map<Persp3D *, unsigned int>::iterator p = _persps.find(persp);
-    if (p == _persps.end()) {
-        g_print ("Warning! Trying to remove unselected perspective from selection!\n");
-        return;
-    }
-    if ((*p).second > 1) {
-        _persps[persp]--;
-    } else {
-        _persps.erase(p);
-    }
-}
-
 void Selection::remove_3D_boxes_recursively(SPObject *obj) {
     std::list<SPBox3D *> boxes = box3d_extract_boxes(obj);
 
     for (std::list<SPBox3D *>::iterator i = boxes.begin(); i != boxes.end(); ++i) {
         SPBox3D *box = *i;
-        box3d_remove_from_selection(box);
         std::list<SPBox3D *>::iterator b = std::find(_3dboxes.begin(), _3dboxes.end(), box);
         if (b == _3dboxes.end()) {
             g_print ("Warning! Trying to remove unselected box from selection.\n");
             return;
         }
         _3dboxes.erase(b);
-        remove_box_perspective(box);
     }
 }
 
@@ -343,14 +317,27 @@ GSList const *Selection::reprList() {
 
 std::list<Persp3D *> const Selection::perspList() {
     std::list<Persp3D *> pl;
-    for (std::map<Persp3D *, unsigned int>::iterator p = _persps.begin(); p != _persps.end(); ++p) {
-        pl.push_back((*p).first);
+    for (std::list<SPBox3D *>::iterator i = _3dboxes.begin(); i != _3dboxes.end(); ++i) {
+        Persp3D *persp = box3d_get_perspective(*i);
+        if (std::find(pl.begin(), pl.end(), persp) == pl.end())
+            pl.push_back(persp);
     }
     return pl;
 }
 
-std::list<SPBox3D *> const Selection::box3DList() {
-    return _3dboxes;
+std::list<SPBox3D *> const Selection::box3DList(Persp3D *persp) {
+    std::list<SPBox3D *> boxes;
+    if (persp) {
+        SPBox3D *box;
+        for (std::list<SPBox3D *>::iterator i = _3dboxes.begin(); i != _3dboxes.end(); ++i) {
+            box = *i;
+            if (persp == box3d_get_perspective(box))
+                boxes.push_back(box);
+        }
+    } else {
+        boxes = _3dboxes;
+    }
+    return boxes;
 }
 
 SPObject *Selection::single() {
@@ -382,13 +369,13 @@ NRRect *Selection::bounds(NRRect *bbox, SPItem::BBoxType type) const
     return bbox;
 }
 
-NR::Maybe<NR::Rect> Selection::bounds(SPItem::BBoxType type) const
+Geom::OptRect Selection::bounds(SPItem::BBoxType type) const
 {
     GSList const *items = const_cast<Selection *>(this)->itemList();
 
-    NR::Maybe<NR::Rect> bbox = NR::Nothing();
+    Geom::OptRect bbox;
     for ( GSList const *i = items ; i != NULL ; i = i->next ) {
-        bbox = NR::union_bounds(bbox, sp_item_bbox_desktop(SP_ITEM(i->data), type));
+        bbox = unify(bbox, SP_ITEM(i->data)->getBboxDesktop(type));
     }
     return bbox;
 }
@@ -407,76 +394,89 @@ NRRect *Selection::boundsInDocument(NRRect *bbox, SPItem::BBoxType type) const {
 
     for ( GSList const *iter=items ; iter != NULL ; iter = iter->next ) {
         SPItem *item=SP_ITEM(iter->data);
-        NR::Matrix i2doc(sp_item_i2doc_affine(item));
-        sp_item_invoke_bbox(item, bbox, i2doc, FALSE, type);
+        Geom::Matrix i2doc(item->i2doc_affine());
+        item->invoke_bbox( bbox, i2doc, FALSE, type);
     }
 
     return bbox;
 }
 
-NR::Maybe<NR::Rect> Selection::boundsInDocument(SPItem::BBoxType type) const {
+Geom::OptRect Selection::boundsInDocument(SPItem::BBoxType type) const {
     NRRect r;
-    return boundsInDocument(&r, type)->upgrade();
+    return to_2geom(boundsInDocument(&r, type)->upgrade());
 }
 
 /** Extract the position of the center from the first selected object */
-NR::Maybe<NR::Point> Selection::center() const {
+// 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();
-    NR::Point center;
+    Geom::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
             return first->getCenter();
         }
     }
-    NR::Maybe<NR::Rect> bbox = bounds();
+    Geom::OptRect bbox = bounds();
     if (bbox) {
         return bounds()->midpoint();
     } else {
-        return NR::Nothing();
+        return boost::optional<Geom::Point>();
     }
 }
 
 /**
- * Compute the list of points in the selection that are to be considered for snapping.
+ * Compute the list of points in the selection that are to be considered for snapping from.
  */
-std::vector<NR::Point> Selection::getSnapPoints(bool includeItemCenter) const {
+std::vector<Inkscape::SnapCandidatePoint> Selection::getSnapPoints(SnapPreferences const *snapprefs) const {
     GSList const *items = const_cast<Selection *>(this)->itemList();
-    std::vector<NR::Point> p;
+
+    SnapPreferences snapprefs_dummy = *snapprefs; // create a local copy of the snapping prefs
+    snapprefs_dummy.setIncludeItemCenter(false); // locally disable snapping to the item center
+    snapprefs_dummy.setSnapToItemNode(true); // consider any type of nodes as a snap source
+    snapprefs_dummy.setSnapSmoothNodes(true); // i.e. disregard the smooth / cusp node preference
+    std::vector<Inkscape::SnapCandidatePoint> p;
     for (GSList const *iter = items; iter != NULL; iter = iter->next) {
         SPItem *this_item = SP_ITEM(iter->data);
-        sp_item_snappoints(this_item, false, SnapPointsIter(p));
+        this_item->getSnappoints(p, &snapprefs_dummy);
+
         //Include the transformation origin for snapping
-        //For a group only the group's origin is considered
-        if (includeItemCenter) {
-               p.push_back(this_item->getCenter());
-        }  
+        //For a selection or group only the overall origin is considered
+        if (snapprefs != NULL && snapprefs->getIncludeItemCenter()) {
+            p.push_back(Inkscape::SnapCandidatePoint(this_item->getCenter(), SNAPSOURCE_ROTATION_CENTER));
+        }
     }
 
     return p;
 }
-
-std::vector<NR::Point> Selection::getSnapPointsConvexHull() const {
+// TODO: both getSnapPoints and getSnapPointsConvexHull are called, subsequently. Can we do this more efficient?
+// Why do we need to include the transformation center in one case and not the other?
+std::vector<Inkscape::SnapCandidatePoint> Selection::getSnapPointsConvexHull(SnapPreferences const *snapprefs) const {
     GSList const *items = const_cast<Selection *>(this)->itemList();
 
-    std::vector<NR::Point> p;
+    SnapPreferences snapprefs_dummy = *snapprefs; // create a local copy of the snapping prefs
+    snapprefs_dummy.setSnapToItemNode(true); // consider any type of nodes as a snap source
+    snapprefs_dummy.setSnapSmoothNodes(true); // i.e. disregard the smooth / cusp node preference
+
+    std::vector<Inkscape::SnapCandidatePoint> p;
     for (GSList const *iter = items; iter != NULL; iter = iter->next) {
-               sp_item_snappoints(SP_ITEM(iter->data), false, SnapPointsIter(p));
+        SP_ITEM(iter->data)->getSnappoints(p, &snapprefs_dummy);
     }
 
-    std::vector<NR::Point> pHull;
+    std::vector<Inkscape::SnapCandidatePoint> pHull;
     if (!p.empty()) {
-        std::vector<NR::Point>::iterator i;
-        NR::ConvexHull cvh(p.front());
+        std::vector<Inkscape::SnapCandidatePoint>::iterator i;
+        Geom::RectHull cvh((p.front()).getPoint());
         for (i = p.begin(); i != p.end(); i++) {
             // these are the points we get back
-            cvh.add(*i);
+            cvh.add((*i).getPoint());
         }
 
-        NR::Maybe<NR::Rect> rHull = cvh.bounds();
+        Geom::OptRect rHull = cvh.bounds();
         if (rHull) {
             for ( unsigned i = 0 ; i < 4 ; ++i ) {
-                pHull.push_back(rHull->corner(i));
+                pHull.push_back(Inkscape::SnapCandidatePoint(rHull->corner(i), SNAPSOURCE_CONVEX_HULL_CORNER));
             }
         }
     }
@@ -520,31 +520,31 @@ SPObject *Selection::_objectForXMLNode(Inkscape::XML::Node *repr) const {
 }
 
 guint Selection::numberOfLayers() {
-      GSList const *items = const_cast<Selection *>(this)->itemList();
-       GSList *layers = NULL;
-       for (GSList const *iter = items; iter != NULL; iter = iter->next) {
-               SPObject *layer = desktop()->layerForObject(SP_OBJECT(iter->data));
-               if (g_slist_find (layers, layer) == NULL) {
-                       layers = g_slist_prepend (layers, layer);
-               }
-       }
-       guint ret = g_slist_length (layers);
-       g_slist_free (layers);
-       return ret;
+    GSList const *items = const_cast<Selection *>(this)->itemList();
+    GSList *layers = NULL;
+    for (GSList const *iter = items; iter != NULL; iter = iter->next) {
+        SPObject *layer = desktop()->layerForObject(SP_OBJECT(iter->data));
+        if (g_slist_find (layers, layer) == NULL) {
+            layers = g_slist_prepend (layers, layer);
+        }
+    }
+    guint ret = g_slist_length (layers);
+    g_slist_free (layers);
+    return ret;
 }
 
 guint Selection::numberOfParents() {
-      GSList const *items = const_cast<Selection *>(this)->itemList();
-       GSList *parents = NULL;
-       for (GSList const *iter = items; iter != NULL; iter = iter->next) {
-               SPObject *parent = SP_OBJECT_PARENT(iter->data);
-               if (g_slist_find (parents, parent) == NULL) {
-                       parents = g_slist_prepend (parents, parent);
-               }
-       }
-       guint ret = g_slist_length (parents);
-       g_slist_free (parents);
-       return ret;
+    GSList const *items = const_cast<Selection *>(this)->itemList();
+    GSList *parents = NULL;
+    for (GSList const *iter = items; iter != NULL; iter = iter->next) {
+        SPObject *parent = SP_OBJECT_PARENT(iter->data);
+        if (g_slist_find (parents, parent) == NULL) {
+            parents = g_slist_prepend (parents, parent);
+        }
+    }
+    guint ret = g_slist_length (parents);
+    g_slist_free (parents);
+    return ret;
 }
 
 }
@@ -558,4 +558,4 @@ guint Selection::numberOfParents() {
   fill-column:99
   End:
 */
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :