summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/document.cpp22
-rw-r--r--src/document.h2
-rw-r--r--src/live_effects/lpe-transform_2pts.cpp2
-rw-r--r--src/main-cmdlineact.cpp2
-rw-r--r--src/object-set.cpp259
-rw-r--r--src/object-set.h148
-rw-r--r--src/selection.cpp300
-rw-r--r--src/selection.h158
-rw-r--r--src/sp-object.cpp15
-rw-r--r--src/ui/tools/eraser-tool.cpp1
-rw-r--r--src/ui/widget/style-subject.cpp2
11 files changed, 475 insertions, 436 deletions
diff --git a/src/document.cpp b/src/document.cpp
index d8c3f1269..902dabbc3 100644
--- a/src/document.cpp
+++ b/src/document.cpp
@@ -1602,11 +1602,22 @@ static unsigned int count_objects_recursive(SPObject *obj, unsigned int count)
return count;
}
+/**
+ * Count the number of objects in a given document recursively using the count_objects_recursive helper function
+ *
+ * @param[in] document Pointer to the document for counting objects
+ * @return Numer of objects in the document
+ */
static unsigned int objects_in_document(SPDocument *document)
{
return count_objects_recursive(document->getRoot(), 0);
}
+/**
+ * Remove unused definitions etc. recursively from an object and its siblings
+ *
+ * @param[inout] obj Object which shall be "cleaned"
+ */
static void vacuum_document_recursive(SPObject *obj)
{
if (SP_IS_DEFS(obj)) {
@@ -1621,6 +1632,11 @@ static void vacuum_document_recursive(SPObject *obj)
}
}
+/**
+ * Remove unused definitions etc. recursively from an entire document.
+ *
+ * @return Number of removed objects
+ */
unsigned int SPDocument::vacuumDocument()
{
unsigned int start = objects_in_document(this);
@@ -1639,6 +1655,7 @@ unsigned int SPDocument::vacuumDocument()
newend = objects_in_document(this);
} while (iterations < 100 && newend < end);
+ // We stop if vacuum_document_recursive doesn't remove any more objects or after 100 iterations, whichever occurs first.
return start - newend;
}
@@ -1647,6 +1664,11 @@ bool SPDocument::isSeeking() const {
return priv->seeking;
}
+/**
+ * Indicate to the user if the document has been modified since the last save by displaying a "*" in front of the name of the file in the window title.
+ *
+ * @param[in] modified True if the document has been modified.
+ */
void SPDocument::setModifiedSinceSave(bool modified) {
this->modified_since_save = modified;
if (SP_ACTIVE_DESKTOP) {
diff --git a/src/document.h b/src/document.h
index e95042155..813d4ae49 100644
--- a/src/document.h
+++ b/src/document.h
@@ -198,7 +198,7 @@ public:
bool isSeeking() const;
bool isModifiedSinceSave() const { return modified_since_save; }
- void setModifiedSinceSave(bool modified = true);
+ void setModifiedSinceSave(bool const modified = true);
private:
SPDocument(SPDocument const &); // no copy
diff --git a/src/live_effects/lpe-transform_2pts.cpp b/src/live_effects/lpe-transform_2pts.cpp
index 1cd59b7fa..3c4ce0708 100644
--- a/src/live_effects/lpe-transform_2pts.cpp
+++ b/src/live_effects/lpe-transform_2pts.cpp
@@ -434,7 +434,7 @@ LPETransform2Pts::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<
}
if(!lock_angle && lock_lenght) {
char const * svgd;
- svgd = "m 7.07,7.07 c -3.9,3.91 -10.24,3.91 -14.14,0 -3.91,-3.9 -3.91,-10.24 0,-14.14 3.9,-3.91 10.24,-3.91 14.14,0 l -2.83,-4.24 -0.7,2.12";
+ svgd = "M 0,9.94 C -2.56,9.91 -5.17,8.98 -7.07,7.07 c -3.91,-3.9 -3.91,-10.24 0,-14.14 1.97,-1.97 4.51,-3.02 7.07,-3.04 2.56,0.02 5.1,1.07 7.07,3.04 3.91,3.9 3.91,10.24 0,14.14 C 5.17,8.98 2.56,9.91 0,9.94 Z";
PathVector pathv_turn = sp_svg_read_pathv(svgd);
pathv_turn *= Geom::Rotate(previous_angle);
pathv_turn *= Affine(r,0,0,r,0,0) * Translate(Geom::Point(end));
diff --git a/src/main-cmdlineact.cpp b/src/main-cmdlineact.cpp
index 496c16d5d..76d707131 100644
--- a/src/main-cmdlineact.cpp
+++ b/src/main-cmdlineact.cpp
@@ -62,7 +62,7 @@ CmdLineAction::doIt (ActionContext const & context) {
}
Inkscape::Selection * selection = context.getSelection();
- selection->add(obj, false);
+ selection->add(obj);
}
return;
}
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
diff --git a/src/object-set.h b/src/object-set.h
index 7a52788f3..391046ab8 100644
--- a/src/object-set.h
+++ b/src/object-set.h
@@ -20,6 +20,10 @@
#include <boost/multi_index/hashed_index.hpp>
#include <sigc++/connection.h>
#include "sp-object.h"
+#include "sp-item.h"
+
+class SPBox3D;
+class Persp3D;
struct hashed{};
@@ -34,26 +38,164 @@ typedef boost::multi_index_container<
class ObjectSet {
public:
+ enum CompareSize {HORIZONTAL, VERTICAL, AREA};
+
ObjectSet() {};
- ~ObjectSet();
+ virtual ~ObjectSet();
+
+ /**
+ * Add an SPObject to the set of selected objects.
+ *
+ * @param obj the SPObject to add
+ */
bool add(SPObject* object);
+
+ /** Add items from an STL iterator range to the selection.
+ * \param from the begin iterator
+ * \param to the end iterator
+ */
+ void add(const std::vector<SPItem*>::iterator& from, const std::vector<SPItem*>::iterator& to);
+
+ /**
+ * Removes an item from the set of selected objects.
+ *
+ * It is ok to call this method for an unselected item.
+ *
+ * @param item the item to unselect
+ *
+ * @return is success
+ */
bool remove(SPObject* object);
- bool contains(SPObject* object);
+
+ /**
+ * Returns true if the given object is selected.
+ */
+ bool includes(SPObject *object);
+
+ /**
+ * Set the selection to a single specific object.
+ *
+ * @param obj the object to select
+ */
+ void set(SPObject *object);
+
+ /**
+ * Unselects all selected objects.
+ */
void clear();
+
+ /**
+ * Returns size of the selection.
+ */
int size();
+
+ /**
+ * Returns true if no items are selected.
+ */
+ bool isEmpty();
+
+ /**
+ * Removes an item if selected, adds otherwise.
+ *
+ * @param item the item to unselect
+ */
+ void toggle(SPObject *obj);
+
+ /**
+ * Returns a single selected object.
+ *
+ * @return NULL unless exactly one object is selected
+ */
+ SPObject *single();
+
+ /**
+ * Returns a single selected item.
+ *
+ * @return NULL unless exactly one object is selected
+ */
+ SPItem *singleItem();
+
+ /**
+ * Returns the smallest item from this selection.
+ */
+ SPItem *smallestItem(CompareSize compare);
+
+ /**
+ * Returns the largest item from this selection.
+ */
+ SPItem *largestItem(CompareSize compare);
+
+ /** Returns the list of selected objects. */
+ std::vector<SPObject*> list();
+
+ /** Returns the list of selected SPItems. */
+ std::vector<SPItem*> itemList();
+
+ /**
+ * Selects exactly the specified objects.
+ *
+ * @param objs the objects to select
+ */
+ void setList(const std::vector<SPItem *> &objs);
+
+ /**
+ * Adds the specified objects to selection, without deselecting first.
+ *
+ * @param objs the objects to select
+ */
+ void addList(std::vector<SPItem*> const &objs);
+
+ /** Returns the bounding rectangle of the selection. */
+ Geom::OptRect bounds(SPItem::BBoxType type) const;
+ Geom::OptRect visualBounds() const;
+ Geom::OptRect geometricBounds() const;
+
+ /**
+ * Returns either the visual or geometric bounding rectangle of the selection, based on the
+ * preferences specified for the selector tool
+ */
+ Geom::OptRect preferredBounds() const;
+
+ /* Returns the bounding rectangle of the selectionin document coordinates.*/
+ Geom::OptRect documentBounds(SPItem::BBoxType type) const;
+
+ /**
+ * Returns the rotation/skew center of the selection.
+ */
+ boost::optional<Geom::Point> center() const;
+
+ /** Returns a list of all perspectives which have a 3D box in the current selection.
+ (these may also be nested in groups) */
+ std::list<Persp3D *> const perspList();
+
+ /**
+ * Returns a list of all 3D boxes in the current selection which are associated to @c
+ * persp. If @c pers is @c NULL, return all selected boxes.
+ */
+ std::list<SPBox3D *> const box3DList(Persp3D *persp = NULL);
+
+
multi_index_container::iterator begin();
multi_index_container::iterator end();
-private:
+protected:
+ virtual void _connectSignals(SPObject* object) {};
+ virtual void _releaseSignals(SPObject* object) {};
+ virtual void _emitSignals() {};
void _add(SPObject* object);
void _remove(SPObject* object);
bool _anyAncestorIsInSet(SPObject *object);
void _removeDescendantsFromSet(SPObject *object);
void _removeAncestorsFromSet(SPObject *object);
+ SPItem *_sizeistItem(bool sml, CompareSize compare);
SPObject *_getMutualAncestor(SPObject *object);
+ virtual void _add_3D_boxes_recursively(SPObject *obj);
+ virtual void _remove_3D_boxes_recursively(SPObject *obj);
multi_index_container container;
+ std::list<SPBox3D *> _3dboxes;
std::unordered_map<SPObject*, sigc::connection> releaseConnections;
+
};
diff --git a/src/selection.cpp b/src/selection.cpp
index 146d07a9d..32e27f2d4 100644
--- a/src/selection.cpp
+++ b/src/selection.cpp
@@ -7,8 +7,10 @@
* bulia byak <buliabyak@users.sf.net>
* Andrius R. <knutux@gmail.com>
* Abhishek Sharma
+ * Adrian Boguszewski
*
- * Copyright (C) 2006 Andrius R.
+ * Copyright (C) 2016 Adrian Boguszewski
+ * Copyright (C) 2006 Andrius R.
* Copyright (C) 2004-2005 MenTaLguY
* Copyright (C) 1999-2002 Lauris Kaplinski
* Copyright (C) 2001-2002 Ximian, Inc.
@@ -20,17 +22,12 @@
#endif
#include "inkscape.h"
-#include "document.h"
#include "xml/repr.h"
#include "preferences.h"
#include "sp-shape.h"
#include "sp-path.h"
-#include "sp-item-group.h"
-#include "box3d.h"
-#include "persp3d.h"
-#include <boost/lambda/lambda.hpp>
-#include <boost/lambda/casts.hpp>
+#include "document.h"
#define SP_SELECTION_UPDATE_PRIORITY (G_PRIORITY_HIGH_IDLE + 1)
@@ -46,7 +43,6 @@ Selection::Selection(LayerModel *layers, SPDesktop *desktop) :
}
Selection::~Selection() {
- _clear();
_layers = NULL;
if (_idle) {
g_source_remove(_idle);
@@ -66,8 +62,7 @@ void Selection::_schedule_modified(SPObject */*obj*/, guint flags) {
this->_flags |= flags;
}
-gboolean
-Selection::_emit_modified(Selection *selection)
+gboolean Selection::_emit_modified(Selection *selection)
{
/* force new handler to be created if requested before we return */
selection->_idle = 0;
@@ -100,8 +95,7 @@ void Selection::_emitChanged(bool persist_selection_context/* = false */) {
_changed_signal.emit(this);
}
-void
-Selection::_releaseContext(SPObject *obj)
+void Selection::_releaseContext(SPObject *obj)
{
if (NULL == _selection_context || _selection_context != obj)
return;
@@ -112,148 +106,30 @@ Selection::_releaseContext(SPObject *obj)
_selection_context = NULL;
}
-void Selection::_clear() {
- _selectionSet.clear();
-}
-
SPObject *Selection::activeContext() {
if (NULL != _selection_context)
return _selection_context;
return _layers->currentLayer();
- }
-
-bool Selection::includes(SPObject *obj) {
- g_return_val_if_fail(obj != NULL, false);
- g_return_val_if_fail(SP_IS_OBJECT(obj), false);
-
- return _selectionSet.contains(obj);
-}
-
-void Selection::add(SPObject *obj, bool persist_selection_context/* = false */) {
- g_return_if_fail(obj != NULL);
- g_return_if_fail(SP_IS_OBJECT(obj));
- g_return_if_fail(obj->document != NULL);
-
- _add(obj);
- _emitChanged(persist_selection_context);
-}
-
-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;
- _3dboxes.push_back(box);
- }
-}
-
-void Selection::_add(SPObject *obj) {
- _selectionSet.add(obj);
- add_3D_boxes_recursively(obj);
- _modified_connections[obj] = obj->connectModified(sigc::mem_fun(*this, &Selection::_schedule_modified));
}
void Selection::set(SPObject *object, bool persist_selection_context) {
- _clear();
- add(object, persist_selection_context);
-}
-
-void Selection::toggle(SPObject *obj) {
- if (includes(obj)) {
- remove(obj);
- } else {
- add(obj);
- }
-}
-
-void Selection::remove(SPObject *obj) {
- g_return_if_fail(obj != NULL);
- g_return_if_fail(SP_IS_OBJECT(obj));
-
- _remove(obj);
- _emitChanged();
-}
-
-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;
- 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);
- }
-}
-
-void Selection::_remove(SPObject *obj) {
- _modified_connections[obj].disconnect();
- _modified_connections.erase(obj);
-
- _selectionSet.remove(obj);
- remove_3D_boxes_recursively(obj);
-}
-
-void Selection::setList(std::vector<SPItem*> const &list) {
- // Clear and add, or just clear with emit.
- if (!list.empty()) {
- _clear();
- addList(list);
- } else {
- clear();
- }
-}
-
-void Selection::addList(std::vector<SPItem*> const &list) {
- if (list.empty())
- return;
-
- for (std::vector<SPItem*>::const_iterator iter = list.begin(); iter != list.end(); ++iter) {
- SPObject *obj = *iter;
- if (!includes(obj)) {
- _add(obj);
- }
- }
-
- _emitChanged();
+ ObjectSet::set(object);
+ _emitChanged(persist_selection_context);
}
void Selection::setReprList(std::vector<XML::Node*> const &list) {
- _clear();
+ clear();
for (std::vector<XML::Node*>::const_reverse_iterator iter = list.rbegin(); iter != list.rend(); ++iter) {
SPObject *obj = _objectForXMLNode(*iter);
if (obj) {
- _add(obj);
+ add(obj);
}
}
_emitChanged();
}
-void Selection::clear() {
- _clear();
- _emitChanged();
-}
-
-bool Selection::isEmpty() {
- return _selectionSet.size() == 0;
-}
-
-std::vector<SPObject*> Selection::list() {
- return std::vector<SPObject*>(_selectionSet.begin(), _selectionSet.end());
-}
-
-std::vector<SPItem*> Selection::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;
-}
-
std::vector<XML::Node*> Selection::reprList() {
std::vector<SPItem*> list = itemList();
std::vector<XML::Node*> result;
@@ -261,154 +137,11 @@ std::vector<XML::Node*> Selection::reprList() {
return result;
}
-std::list<Persp3D *> const Selection::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 Selection::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;
-}
-
-SPObject *Selection::single() {
- if (_selectionSet.size() == 1) {
- return *_selectionSet.begin();
- }
-
- return nullptr;
-}
-
-SPItem *Selection::singleItem() {
- if (_selectionSet.size() == 1) {
- SPObject* obj = *_selectionSet.begin();
- if (SP_IS_ITEM(obj)) {
- return SP_ITEM(obj);
- }
- }
-
- return nullptr;
-}
-
-SPItem *Selection::smallestItem(Selection::CompareSize compare) {
- return _sizeistItem(true, compare);
-}
-
-SPItem *Selection::largestItem(Selection::CompareSize compare) {
- return _sizeistItem(false, compare);
-}
-
-SPItem *Selection::_sizeistItem(bool sml, Selection::CompareSize compare) {
- std::vector<SPItem*> const items = const_cast<Selection *>(this)->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 == 2 ? bbox.area() :
- (compare == 1 ? bbox.width() : bbox.height());
- size = sml ? size : size * -1;
- if (size < max) {
- max = size;
- ist = SP_ITEM(*i);
- }
- }
-
- return ist;
-}
-
Inkscape::XML::Node *Selection::singleRepr() {
SPObject *obj = single();
return obj ? obj->getRepr() : nullptr;
}
-Geom::OptRect Selection::bounds(SPItem::BBoxType type) const
-{
- return (type == SPItem::GEOMETRIC_BBOX) ?
- geometricBounds() : visualBounds();
-}
-
-Geom::OptRect Selection::geometricBounds() const
-{
- std::vector<SPItem*> const items = const_cast<Selection *>(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 Selection::visualBounds() const
-{
- std::vector<SPItem*> const items = const_cast<Selection *>(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 Selection::preferredBounds() const
-{
- if (Inkscape::Preferences::get()->getInt("/tools/bounding_box") == 0) {
- return bounds(SPItem::VISUAL_BBOX);
- } else {
- return bounds(SPItem::GEOMETRIC_BBOX);
- }
-}
-
-Geom::OptRect Selection::documentBounds(SPItem::BBoxType type) const
-{
- Geom::OptRect bbox;
- std::vector<SPItem*> const items = const_cast<Selection *>(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> Selection::center() const {
- std::vector<SPItem*> const items = const_cast<Selection *>(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::vector<Inkscape::SnapCandidatePoint> Selection::getSnapPoints(SnapPreferences const *snapprefs) const {
std::vector<Inkscape::SnapCandidatePoint> p;
@@ -461,6 +194,19 @@ size_t Selection::numberOfParents() {
return parents.size();
}
+void Selection::_emitSignals() {
+ _emitChanged();
+}
+
+void Selection::_connectSignals(SPObject *object) {
+ _modified_connections[object] = object->connectModified(sigc::mem_fun(*this, &Selection::_schedule_modified));
+}
+
+void Selection::_releaseSignals(SPObject *object) {
+ _modified_connections[object].disconnect();
+ _modified_connections.erase(object);
+}
+
}
/*
diff --git a/src/selection.h b/src/selection.h
index 91d033d58..8f43d51e7 100644
--- a/src/selection.h
+++ b/src/selection.h
@@ -5,7 +5,9 @@
* Lauris Kaplinski <lauris@kaplinski.com>
* MenTaLguY <mental@rydia.net>
* bulia byak <buliabyak@users.sf.net>
+ * Adrian Boguszewski
*
+ * Copyright (C) 2016 Adrian Boguszewski
* Copyright (C) 2004-2005 MenTaLguY
* Copyright (C) 1999-2002 Lauris Kaplinski
* Copyright (C) 2001-2002 Ximian, Inc.
@@ -15,8 +17,6 @@
#include <vector>
#include <map>
-#include <list>
-#include <set>
#include <stddef.h>
#include <sigc++/sigc++.h>
@@ -27,11 +27,8 @@
#include "sp-item.h"
#include "object-set.h"
-
class SPDesktop;
class SPItem;
-class SPBox3D;
-class Persp3D;
namespace Inkscape {
class LayerModel;
@@ -62,10 +59,10 @@ namespace Inkscape {
*/
class Selection : public Inkscape::GC::Managed<>,
public Inkscape::GC::Finalized,
- public Inkscape::GC::Anchored
+ public Inkscape::GC::Anchored,
+ public ObjectSet
{
public:
- enum CompareSize { HORIZONTAL, VERTICAL, AREA };
/**
* Constructs an selection object, bound to a particular
* layer model
@@ -98,12 +95,7 @@ public:
*/
SPObject *activeContext();
- /**
- * Add an SPObject to the set of selected objects.
- *
- * @param obj the SPObject to add
- */
- void add(SPObject *obj, bool persist_selection_context = false);
+ using ObjectSet::add;
/**
* Add an XML node's SPObject to the set of selected objects.
@@ -130,21 +122,7 @@ public:
set(_objectForXMLNode(repr));
}
- /**
- * Removes an item from the set of selected objects.
- *
- * It is ok to call this method for an unselected item.
- *
- * @param item the item to unselect
- */
- void remove(SPObject *obj);
-
- /**
- * Removes an item if selected, adds otherwise.
- *
- * @param item the item to unselect
- */
- void toggle(SPObject *obj);
+ using ObjectSet::remove;
/**
* Removes an item from the set of selected objects.
@@ -153,21 +131,9 @@ public:
*
* @param repr the xml node of the item to remove
*/
- void remove(XML::Node *repr) { remove(_objectForXMLNode(repr)); }
-
- /**
- * Selects exactly the specified objects.
- *
- * @param objs the objects to select
- */
- void setList(std::vector<SPItem*> const &objs);
-
- /**
- * Adds the specified objects to selection, without deselecting first.
- *
- * @param objs the objects to select
- */
- void addList(std::vector<SPItem*> const &objs);
+ void remove(XML::Node *repr) {
+ remove(_objectForXMLNode(repr));
+ }
/**
* Clears the selection and selects the specified objects.
@@ -176,33 +142,7 @@ public:
*/
void setReprList(std::vector<XML::Node*> const &reprs);
- /** Add items from an STL iterator range to the selection.
- * \param from the begin iterator
- * \param to the end iterator
- */
- template <typename InputIterator>
- void add(InputIterator from, InputIterator to) {
- while (from != to) {
- _add(*from);
- ++from;
- }
- _emitChanged();
- }
-
- /**
- * Unselects all selected objects..
- */
- void clear();
-
- /**
- * Returns true if no items are selected.
- */
- bool isEmpty();
-
- /**
- * Returns true if the given object is selected.
- */
- bool includes(SPObject *obj);
+ using ObjectSet::includes;
/**
* Returns true if the given item is selected.
@@ -212,80 +152,21 @@ public:
}
/**
- * Returns a single selected object.
- *
- * @return NULL unless exactly one object is selected
- */
- SPObject *single();
-
- /**
- * Returns a single selected item.
- *
- * @return NULL unless exactly one object is selected
- */
- SPItem *singleItem();
-
- /**
- * Returns the smallest item from this selection.
- */
- SPItem *smallestItem(CompareSize compare);
-
- /**
- * Returns the largest item from this selection.
- */
- SPItem *largestItem(CompareSize compare);
-
- /**
* Returns a single selected object's xml node.
*
* @return NULL unless exactly one object is selected
*/
XML::Node *singleRepr();
- /** Returns the list of selected objects. */
- std::vector<SPObject*> list();
- /** Returns the list of selected SPItems. */
- std::vector<SPItem*> itemList();
/** Returns a list of the xml nodes of all selected objects. */
- /// \todo only returns reprs of SPItems currently; need a separate
- /// method for that
std::vector<XML::Node*> reprList();
- /** Returns a list of all perspectives which have a 3D box in the current selection.
- (these may also be nested in groups) */
- std::list<Persp3D *> const perspList();
-
- /**
- * Returns a list of all 3D boxes in the current selection which are associated to @c
- * persp. If @c pers is @c NULL, return all selected boxes.
- */
- std::list<SPBox3D *> const box3DList(Persp3D *persp = NULL);
-
/** Returns the number of layers in which there are selected objects. */
size_t numberOfLayers();
/** Returns the number of parents to which the selected objects belong. */
size_t numberOfParents();
- /** Returns the bounding rectangle of the selection. */
- Geom::OptRect bounds(SPItem::BBoxType type) const;
- Geom::OptRect visualBounds() const;
- Geom::OptRect geometricBounds() const;
-
- /**
- * Returns either the visual or geometric bounding rectangle of the selection, based on the
- * preferences specified for the selector tool
- */
- Geom::OptRect preferredBounds() const;
-
- /// Returns the bounding rectangle of the selectionin document coordinates.
- Geom::OptRect documentBounds(SPItem::BBoxType type) const;
-
- /**
- * Returns the rotation/skew center of the selection.
- */
- boost::optional<Geom::Point> center() const;
-
/**
* Compute the list of points in the selection that are to be considered for snapping from.
*
@@ -332,6 +213,11 @@ public:
return _modified_signal.slots().insert(_modified_signal.slots().begin(), slot);
}
+protected:
+ void _emitSignals();
+ void _connectSignals(SPObject* object);
+ void _releaseSignals(SPObject* object);
+
private:
/** no copy. */
Selection(Selection const &);
@@ -347,25 +233,11 @@ private:
void _emitModified(unsigned int flags);
/** Issues changed selection signal. */
void _emitChanged(bool persist_selection_context = false);
- /** clears the selection (without issuing a notification). */
- void _clear();
- /** adds an object (without issuing a notification). */
- void _add(SPObject *obj);
- /** removes an object (without issuing a notification). */
- void _remove(SPObject *obj);
/** returns the SPObject corresponding to an xml node (if any). */
SPObject *_objectForXMLNode(XML::Node *repr) const;
/** Releases an active layer object that is being removed. */
void _releaseContext(SPObject *obj);
- ObjectSet _selectionSet;
-
- void add_3D_boxes_recursively(SPObject *obj);
- void remove_3D_boxes_recursively(SPObject *obj);
- SPItem *_sizeistItem(bool sml, CompareSize compare);
-
- std::list<SPBox3D *> _3dboxes;
-
LayerModel *_layers;
GC::soft_ptr<SPDesktop> _desktop;
SPObject* _selection_context;
diff --git a/src/sp-object.cpp b/src/sp-object.cpp
index db66eb3e6..d1659eedc 100644
--- a/src/sp-object.cpp
+++ b/src/sp-object.cpp
@@ -71,13 +71,17 @@ Inkscape::XML::NodeEventVector object_event_vector = {
SPObject::repr_order_changed
};
-// A friend class used to set internal members on SPObject so as to not expose settors in SPObject's public API
+/**
+ * A friend class used to set internal members on SPObject so as to not expose settors in SPObject's public API
+ */
class SPObjectImpl
{
public:
/**
* Null's the id member of an SPObject without attempting to free prior contents.
+ *
+ * @param[inout] obj Pointer to the object which's id shall be nulled.
*/
static void setIdNull( SPObject* obj ) {
if (obj) {
@@ -87,6 +91,9 @@ public:
/**
* Sets the id member of an object, freeing any prior content.
+ *
+ * @param[inout] obj Pointer to the object which's id shall be set.
+ * @param[in] id New id
*/
static void setId( SPObject* obj, gchar const* id ) {
if (obj && (id != obj->id) ) {
@@ -104,6 +111,9 @@ public:
static gchar *sp_object_get_unique_id(SPObject *object,
gchar const *defid);
+/**
+ * Constructor, sets all attributes to default values.
+ */
SPObject::SPObject()
: cloned(0), uflags(0), mflags(0), hrefcount(0), _total_hrefcount(0),
document(NULL), parent(NULL), children(NULL), _last_child(NULL),
@@ -126,6 +136,9 @@ SPObject::SPObject()
this->context_style = NULL;
}
+/**
+ * Destructor, frees the used memory and unreferences a potential successor of the object.
+ */
SPObject::~SPObject() {
g_free(this->_label);
g_free(this->_default_label);
diff --git a/src/ui/tools/eraser-tool.cpp b/src/ui/tools/eraser-tool.cpp
index 6b32b5901..cb7747b2b 100644
--- a/src/ui/tools/eraser-tool.cpp
+++ b/src/ui/tools/eraser-tool.cpp
@@ -708,7 +708,6 @@ void EraserTool::set_to_accumulated() {
item->deleteObject(true);
sp_object_unref(item);
workDone = true;
- workDone = true;
} else if (SP_IS_GROUP(item) || use ) {
/*Do nothing*/
} else {
diff --git a/src/ui/widget/style-subject.cpp b/src/ui/widget/style-subject.cpp
index da3bbcd20..47a899c0f 100644
--- a/src/ui/widget/style-subject.cpp
+++ b/src/ui/widget/style-subject.cpp
@@ -55,7 +55,7 @@ Inkscape::Selection *StyleSubject::Selection::_getSelection() const {
}
}
-std::vector<SPObject*> StyleSubject::Selection::list(){
+std::vector<SPObject*> StyleSubject::Selection::list() {
Inkscape::Selection *selection = _getSelection();
if(selection)
return selection->list();