diff options
| author | Adrian Boguszewski <adrbogus1@student.pg.gda.pl> | 2016-06-16 22:52:06 +0000 |
|---|---|---|
| committer | Adrian Boguszewski <adrbogus1@student.pg.gda.pl> | 2016-06-16 22:52:06 +0000 |
| commit | c3b5e15737dc84cb2dafbdfb8d735e2dd7c8b08c (patch) | |
| tree | adc28ff36e9d801c626f01f994447931d2685ff8 /src | |
| parent | Replaced old selection containers (diff) | |
| parent | Merging lp:~inkscape+alexander/inkscape/comments into lp:inkscape. (diff) | |
| download | inkscape-c3b5e15737dc84cb2dafbdfb8d735e2dd7c8b08c.tar.gz inkscape-c3b5e15737dc84cb2dafbdfb8d735e2dd7c8b08c.zip | |
Moved most functions from Selection to ObjectSet
(bzr r14954.1.7)
Diffstat (limited to 'src')
| -rw-r--r-- | src/document.cpp | 22 | ||||
| -rw-r--r-- | src/document.h | 2 | ||||
| -rw-r--r-- | src/live_effects/lpe-transform_2pts.cpp | 2 | ||||
| -rw-r--r-- | src/main-cmdlineact.cpp | 2 | ||||
| -rw-r--r-- | src/object-set.cpp | 259 | ||||
| -rw-r--r-- | src/object-set.h | 148 | ||||
| -rw-r--r-- | src/selection.cpp | 300 | ||||
| -rw-r--r-- | src/selection.h | 158 | ||||
| -rw-r--r-- | src/sp-object.cpp | 15 | ||||
| -rw-r--r-- | src/ui/tools/eraser-tool.cpp | 1 | ||||
| -rw-r--r-- | src/ui/widget/style-subject.cpp | 2 |
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(); |
