summaryrefslogtreecommitdiffstats
path: root/src/object-set.cpp
diff options
context:
space:
mode:
authorAdrian Boguszewski <adrbogus1@student.pg.gda.pl>2016-06-16 22:52:06 +0000
committerAdrian Boguszewski <adrbogus1@student.pg.gda.pl>2016-06-16 22:52:06 +0000
commitc3b5e15737dc84cb2dafbdfb8d735e2dd7c8b08c (patch)
treeadc28ff36e9d801c626f01f994447931d2685ff8 /src/object-set.cpp
parentReplaced old selection containers (diff)
parentMerging lp:~inkscape+alexander/inkscape/comments into lp:inkscape. (diff)
downloadinkscape-c3b5e15737dc84cb2dafbdfb8d735e2dd7c8b08c.tar.gz
inkscape-c3b5e15737dc84cb2dafbdfb8d735e2dd7c8b08c.zip
Moved most functions from Selection to ObjectSet
(bzr r14954.1.7)
Diffstat (limited to 'src/object-set.cpp')
-rw-r--r--src/object-set.cpp259
1 files changed, 252 insertions, 7 deletions
diff --git a/src/object-set.cpp b/src/object-set.cpp
index 8aaa68e70..46c932505 100644
--- a/src/object-set.cpp
+++ b/src/object-set.cpp
@@ -10,15 +10,23 @@
*/
#include <sigc++/sigc++.h>
+#include <glib.h>
#include "object-set.h"
+#include "box3d.h"
+#include "persp3d.h"
+#include "preferences.h"
bool ObjectSet::add(SPObject* object) {
+ g_return_val_if_fail(object != NULL, false);
+ g_return_val_if_fail(SP_IS_OBJECT(object), false);
+
+
// any ancestor is in the set - do nothing
if (_anyAncestorIsInSet(object)) {
return false;
}
- // very nice function, but needs refinement
+ // very nice function, but changes selection behavior (probably needs new selection option to deal with it)
// check if there is mutual ancestor for some elements, which can replace all of them in the set
// object = _getMutualAncestor(object);
@@ -26,19 +34,25 @@ bool ObjectSet::add(SPObject* object) {
_removeDescendantsFromSet(object);
_add(object);
+ _emitSignals();
return true;
}
bool ObjectSet::remove(SPObject* object) {
+ g_return_val_if_fail(object != NULL, false);
+ g_return_val_if_fail(SP_IS_OBJECT(object), false);
+
// object is the top of subtree
- if (contains(object)) {
+ if (includes(object)) {
_remove(object);
+ _emitSignals();
return true;
}
// any ancestor of object is in the set
if (_anyAncestorIsInSet(object)) {
_removeAncestorsFromSet(object);
+ _emitSignals();
return true;
}
@@ -46,7 +60,10 @@ bool ObjectSet::remove(SPObject* object) {
return false;
}
-bool ObjectSet::contains(SPObject* object) {
+bool ObjectSet::includes(SPObject *object) {
+ g_return_val_if_fail(object != NULL, false);
+ g_return_val_if_fail(SP_IS_OBJECT(object), false);
+
return container.get<hashed>().find(object) != container.get<hashed>().end();
}
@@ -54,6 +71,7 @@ void ObjectSet::clear() {
for (auto object: container) {
_remove(object);
}
+ _emitSignals();
}
int ObjectSet::size() {
@@ -63,7 +81,7 @@ int ObjectSet::size() {
bool ObjectSet::_anyAncestorIsInSet(SPObject *object) {
SPObject* o = object;
while (o != nullptr) {
- if (contains(o)) {
+ if (includes(o)) {
return true;
}
o = o->parent;
@@ -74,7 +92,7 @@ bool ObjectSet::_anyAncestorIsInSet(SPObject *object) {
void ObjectSet::_removeDescendantsFromSet(SPObject *object) {
for (auto& child: object->childList(false)) {
- if (contains(child)) {
+ if (includes(child)) {
_remove(child);
// there is certainly no children of this child in the set
continue;
@@ -88,11 +106,15 @@ void ObjectSet::_remove(SPObject *object) {
releaseConnections[object].disconnect();
releaseConnections.erase(object);
container.get<hashed>().erase(object);
+ _remove_3D_boxes_recursively(object);
+ _releaseSignals(object);
}
void ObjectSet::_add(SPObject *object) {
releaseConnections[object] = object->connectRelease(sigc::hide_return(sigc::mem_fun(*this, &ObjectSet::remove)));
container.push_back(object);
+ _add_3D_boxes_recursively(object);
+ _connectSignals(object);
}
SPObject *ObjectSet::_getMutualAncestor(SPObject *object) {
@@ -101,7 +123,7 @@ SPObject *ObjectSet::_getMutualAncestor(SPObject *object) {
bool flag = true;
while (o->parent != nullptr) {
for (auto &child: o->parent->childList(false)) {
- if(child != o && !contains(child)) {
+ if(child != o && !includes(child)) {
flag = false;
break;
}
@@ -122,7 +144,7 @@ void ObjectSet::_removeAncestorsFromSet(SPObject *object) {
_add(child);
}
}
- if (contains(o->parent)) {
+ if (includes(o->parent)) {
_remove(o->parent);
break;
}
@@ -141,3 +163,226 @@ multi_index_container::iterator ObjectSet::begin() {
multi_index_container::iterator ObjectSet::end() {
return container.end();
}
+
+void ObjectSet::toggle(SPObject *obj) {
+ if (includes(obj)) {
+ remove(obj);
+ } else {
+ add(obj);
+ }
+}
+
+bool ObjectSet::isEmpty() {
+ return container.size() == 0;
+}
+
+
+SPObject *ObjectSet::single() {
+ if (container.size() == 1) {
+ return *container.begin();
+ }
+
+ return nullptr;
+}
+
+SPItem *ObjectSet::singleItem() {
+ if (container.size() == 1) {
+ SPObject* obj = *container.begin();
+ if (SP_IS_ITEM(obj)) {
+ return SP_ITEM(obj);
+ }
+ }
+
+ return nullptr;
+}
+
+SPItem *ObjectSet::smallestItem(CompareSize compare) {
+ return _sizeistItem(true, compare);
+}
+
+SPItem *ObjectSet::largestItem(CompareSize compare) {
+ return _sizeistItem(false, compare);
+}
+
+SPItem *ObjectSet::_sizeistItem(bool sml, CompareSize compare) {
+ std::vector<SPItem*> const items = itemList();
+ gdouble max = sml ? 1e18 : 0;
+ SPItem *ist = NULL;
+
+ for ( std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end(); ++i) {
+ Geom::OptRect obox = SP_ITEM(*i)->desktopPreferredBounds();
+ if (!obox || obox.empty()) {
+ continue;
+ }
+
+ Geom::Rect bbox = *obox;
+
+ gdouble size = compare == AREA ? bbox.area() :
+ (compare == VERTICAL ? bbox.width() : bbox.height());
+ size = sml ? size : size * -1;
+ if (size < max) {
+ max = size;
+ ist = SP_ITEM(*i);
+ }
+ }
+
+ return ist;
+}
+
+std::vector<SPObject*> ObjectSet::list() {
+ return std::vector<SPObject*>(container.begin(), container.end());
+}
+
+std::vector<SPItem*> ObjectSet::itemList() {
+ std::vector<SPObject *> tmp = list();
+ std::vector<SPItem*> result;
+ std::remove_if(tmp.begin(), tmp.end(), [](SPObject* o){return !SP_IS_ITEM(o);});
+ std::transform(tmp.begin(), tmp.end(), std::back_inserter(result), [](SPObject* o){return SP_ITEM(o);});
+ return result;
+}
+
+void ObjectSet::set(SPObject *object) {
+ clear();
+ _add(object);
+ // can't emit signal here due to boolean argument in Selection
+// _emitSignals();
+}
+
+void ObjectSet::setList(const std::vector<SPItem *> &objs) {
+ clear();
+ addList(objs);
+}
+
+void ObjectSet::addList(const std::vector<SPItem *> &objs) {
+ for (std::vector<SPItem*>::const_iterator iter = objs.begin(); iter != objs.end(); ++iter) {
+ SPObject *obj = *iter;
+ if (!includes(obj)) {
+ add(obj);
+ }
+ }
+}
+
+void ObjectSet::add(const std::vector<SPItem*>::iterator& from, const std::vector<SPItem*>::iterator& to) {
+ for(auto it = from; it != to; ++it) {
+ _add(*it);
+ }
+}
+
+
+Geom::OptRect ObjectSet::bounds(SPItem::BBoxType type) const
+{
+ return (type == SPItem::GEOMETRIC_BBOX) ?
+ geometricBounds() : visualBounds();
+}
+
+Geom::OptRect ObjectSet::geometricBounds() const
+{
+ std::vector<SPItem*> const items = const_cast<ObjectSet *>(this)->itemList();
+
+ Geom::OptRect bbox;
+ for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end(); ++iter) {
+ bbox.unionWith(SP_ITEM(*iter)->desktopGeometricBounds());
+ }
+ return bbox;
+}
+
+Geom::OptRect ObjectSet::visualBounds() const
+{
+ std::vector<SPItem*> const items = const_cast<ObjectSet *>(this)->itemList();
+
+ Geom::OptRect bbox;
+ for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end(); ++iter) {
+ bbox.unionWith(SP_ITEM(*iter)->desktopVisualBounds());
+ }
+ return bbox;
+}
+
+Geom::OptRect ObjectSet::preferredBounds() const
+{
+ if (Inkscape::Preferences::get()->getInt("/tools/bounding_box") == 0) {
+ return bounds(SPItem::VISUAL_BBOX);
+ } else {
+ return bounds(SPItem::GEOMETRIC_BBOX);
+ }
+}
+
+Geom::OptRect ObjectSet::documentBounds(SPItem::BBoxType type) const
+{
+ Geom::OptRect bbox;
+ std::vector<SPItem*> const items = const_cast<ObjectSet *>(this)->itemList();
+ if (items.empty()) return bbox;
+
+ for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end(); ++iter) {
+ SPItem *item = SP_ITEM(*iter);
+ bbox |= item->documentBounds(type);
+ }
+
+ return bbox;
+}
+
+// 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> ObjectSet::center() const {
+ std::vector<SPItem*> const items = const_cast<ObjectSet *>(this)->itemList();
+ if (!items.empty()) {
+ SPItem *first = items.back(); // from the first item in selection
+ if (first->isCenterSet()) { // only if set explicitly
+ return first->getCenter();
+ }
+ }
+ Geom::OptRect bbox = preferredBounds();
+ if (bbox) {
+ return bbox->midpoint();
+ } else {
+ return boost::optional<Geom::Point>();
+ }
+}
+
+
+std::list<Persp3D *> const ObjectSet::perspList() {
+ std::list<Persp3D *> pl;
+ 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 ObjectSet::box3DList(Persp3D *persp) {
+ std::list<SPBox3D *> boxes;
+ if (persp) {
+ for (std::list<SPBox3D *>::iterator i = _3dboxes.begin(); i != _3dboxes.end(); ++i) {
+ SPBox3D *box = *i;
+ if (persp == box3d_get_perspective(box)) {
+ boxes.push_back(box);
+ }
+ }
+ } else {
+ boxes = _3dboxes;
+ }
+ return boxes;
+}
+
+void ObjectSet::_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;
+ _3dboxes.push_back(box);
+ }
+}
+
+void ObjectSet::_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;
+ 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);
+ }
+} \ No newline at end of file