diff --git a/src/selection.cpp b/src/selection.cpp
index 702cc6594ac5579ea4f63c21335f1462f7b74965..3f333e4e24e4569904b7dc90a41c42bc0c5c86fd 100644 (file)
--- a/src/selection.cpp
+++ b/src/selection.cpp
#include "desktop-handles.h"
#include "document.h"
#include "selection.h"
+#include "helper/recthull.h"
#include "xml/repr.h"
#include "sp-shape.h"
+#include "sp-path.h"
+#include "sp-item-group.h"
+#include "box3d.h"
+#include "box3d.h"
+#include "persp3d.h"
+#include <sigc++/functors/mem_fun.h>
#define SP_SELECTION_UPDATE_PRIORITY (G_PRIORITY_HIGH_IDLE + 1)
_items(NULL),
_desktop(desktop),
_selection_context(NULL),
- _context_release_handler_id(0),
_flags(0),
_idle(0)
{
}
}
-void
-Selection::_release(SPObject *obj, Selection *selection)
-{
- selection->remove(obj);
-}
-
/* Handler for selected objects "modified" signal */
-void
-Selection::_schedule_modified(SPObject *obj, guint flags, Selection *selection)
-{
- if (!selection->_idle) {
+void Selection::_schedule_modified(SPObject */*obj*/, guint flags) {
+ if (!this->_idle) {
/* Request handling to be run in _idle loop */
- selection->_idle = g_idle_add_full(SP_SELECTION_UPDATE_PRIORITY, GSourceFunc(&Selection::_emit_modified), selection, NULL);
+ this->_idle = g_idle_add_full(SP_SELECTION_UPDATE_PRIORITY, GSourceFunc(&Selection::_emit_modified), this, NULL);
}
/* Collect all flags */
- selection->_flags |= flags;
+ this->_flags |= flags;
}
gboolean
if (NULL == _selection_context) {
_selection_context = desktop()->currentLayer();
sp_object_ref(_selection_context, NULL);
- _context_release_handler_id = g_signal_connect(
- G_OBJECT(_selection_context), "release",
- G_CALLBACK(&Selection::_releaseSelectionContext),
- this);
+ _context_release_connection = _selection_context->connectRelease(sigc::mem_fun(*this, &Selection::_releaseContext));
}
} else {
_releaseContext(_selection_context);
_changed_signal.emit(this);
}
-void
-Selection::_releaseSelectionContext(SPObject *obj, Selection *selection)
-{
- selection->_releaseContext(obj);
-}
-
void
Selection::_releaseContext(SPObject *obj)
{
if (NULL == _selection_context || _selection_context != obj)
return;
- g_signal_handler_disconnect(G_OBJECT(_selection_context), _context_release_handler_id);
+ _context_release_connection.disconnect();
+
sp_object_unref(_selection_context, NULL);
- _context_release_handler_id = 0;
_selection_context = NULL;
}
_invalidateCachedLists();
while (_objs) {
SPObject *obj=reinterpret_cast<SPObject *>(_objs->data);
- sp_signal_disconnect_by_data(obj, this);
- _objs = g_slist_remove(_objs, obj);
+ _remove(obj);
}
}
@@ -174,6 +162,15 @@ void Selection::add(SPObject *obj, bool persist_selection_context/* = false */)
_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) {
// unselect any of the item's ancestors and descendants which may be selected
// (to prevent double-selection)
_removeObjectAncestors(obj);
_objs = g_slist_prepend(_objs, obj);
- g_signal_connect(G_OBJECT(obj), "release",
- G_CALLBACK(&Selection::_release), this);
- g_signal_connect(G_OBJECT(obj), "modified",
- G_CALLBACK(&Selection::_schedule_modified), this);
-
- /*
- if (!SP_IS_SHAPE(obj)) {
- printf("This is not a shape\n");
- }
- */
+
+ add_3D_boxes_recursively(obj);
+
+ _release_connections[obj] = obj->connectRelease(sigc::mem_fun(*this, (void (Selection::*)(SPObject *))&Selection::remove));
+ _modified_connections[obj] = obj->connectModified(sigc::mem_fun(*this, &Selection::_schedule_modified));
}
void Selection::set(SPObject *object, bool persist_selection_context) {
_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) {
- sp_signal_disconnect_by_data(obj, this);
+ _modified_connections[obj].disconnect();
+ _modified_connections.erase(obj);
+
+ _release_connections[obj].disconnect();
+ _release_connections.erase(obj);
+
+ remove_3D_boxes_recursively(obj);
+
_objs = g_slist_remove(_objs, obj);
}
return _reprs;
}
+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) {
+ 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() {
if ( _objs != NULL && _objs->next == NULL ) {
return reinterpret_cast<SPObject *>(_objs->data);
return obj ? SP_OBJECT_REPR(obj) : NULL;
}
-NRRect *Selection::bounds(NRRect *bbox) const
+NRRect *Selection::bounds(NRRect *bbox, SPItem::BBoxType type) const
{
g_return_val_if_fail (bbox != NULL, NULL);
- NR::Rect const b = bounds();
- bbox->x0 = b.min()[NR::X];
- bbox->y0 = b.min()[NR::Y];
- bbox->x1 = b.max()[NR::X];
- bbox->y1 = b.max()[NR::Y];
+ *bbox = NRRect(bounds(type));
return bbox;
}
-NR::Rect Selection::bounds() const
+Geom::OptRect Selection::bounds(SPItem::BBoxType type) const
{
GSList const *items = const_cast<Selection *>(this)->itemList();
- if (!items) {
- return NR::Rect(NR::Point(0, 0), NR::Point(0, 0));
- }
-
- GSList const *i = items;
- NR::Rect bbox = sp_item_bbox_desktop(SP_ITEM(i->data));
- GSList const *i_start = i;
- while (i != NULL) {
- if (i != i_start)
- bbox = NR::Rect::union_bounds(bbox, sp_item_bbox_desktop(SP_ITEM(i->data)));
- i = i->next;
+ Geom::OptRect bbox;
+ for ( GSList const *i = items ; i != NULL ; i = i->next ) {
+ bbox = unify(bbox, sp_item_bbox_desktop(SP_ITEM(i->data), type));
}
-
return bbox;
}
-NRRect *Selection::boundsInDocument(NRRect *bbox) const {
+NRRect *Selection::boundsInDocument(NRRect *bbox, SPItem::BBoxType type) const {
g_return_val_if_fail (bbox != NULL, NULL);
GSList const *items=const_cast<Selection *>(this)->itemList();
for ( GSList const *iter=items ; iter != NULL ; iter = iter->next ) {
SPItem *item=SP_ITEM(iter->data);
- NR::Matrix const i2doc(sp_item_i2doc_affine(item));
- sp_item_invoke_bbox(item, bbox, i2doc, FALSE);
+ Geom::Matrix i2doc(sp_item_i2doc_affine(item));
+ sp_item_invoke_bbox(item, bbox, i2doc, FALSE, type);
}
return bbox;
}
-NR::Rect Selection::boundsInDocument() const {
+Geom::OptRect Selection::boundsInDocument(SPItem::BBoxType type) const {
NRRect r;
- return NR::Rect(*boundsInDocument(&r));
+ return to_2geom(boundsInDocument(&r, type)->upgrade());
}
/** Extract the position of the center from the first selected object */
-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
- center = first->getCenter();
- } else {
- center = bounds().midpoint();
+ return first->getCenter();
}
+ }
+ Geom::OptRect bbox = bounds();
+ if (bbox) {
+ return bounds()->midpoint();
} else {
- center = bounds().midpoint();
+ return boost::optional<Geom::Point>();
}
- return center;
}
/**
- * 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() 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) {
- sp_item_snappoints(SP_ITEM(iter->data), SnapPointsIter(p));
+ SPItem *this_item = SP_ITEM(iter->data);
+ sp_item_snappoints(this_item, p, &snapprefs_dummy);
+
+ //Include the transformation origin for snapping
+ //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;
- for (GSList const *iter = items; iter != NULL; iter = iter->next) {
- sp_item_snappoints(SP_ITEM(iter->data), SnapPointsIter(p));
- }
- std::vector<NR::Point>::iterator i;
- NR::ConvexHull cvh(*(p.begin()));
- for (i = p.begin(); i != p.end(); i++) {
- // these are the points we get back
- cvh.add(*i);
- }
+ 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
- NR::Rect rHull = cvh.bounds();
- std::vector<NR::Point> pHull(4);
- pHull[0] = rHull.corner(0);
- pHull[1] = rHull.corner(1);
- pHull[2] = rHull.corner(2);
- pHull[3] = rHull.corner(3);
+ std::vector<Inkscape::SnapCandidatePoint> p;
+ for (GSList const *iter = items; iter != NULL; iter = iter->next) {
+ sp_item_snappoints(SP_ITEM(iter->data), p, &snapprefs_dummy);
+ }
- return pHull;
-}
+ std::vector<Inkscape::SnapCandidatePoint> pHull;
+ if (!p.empty()) {
+ 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).getPoint());
+ }
-std::vector<NR::Point> Selection::getBBoxPoints() const {
- GSList const *items = const_cast<Selection *>(this)->itemList();
- std::vector<NR::Point> p;
- for (GSList const *iter = items; iter != NULL; iter = iter->next) {
- NR::Rect b = sp_item_bbox_desktop(SP_ITEM(iter->data));
- p.push_back(b.min());
- p.push_back(b.max());
+ Geom::OptRect rHull = cvh.bounds();
+ if (rHull) {
+ for ( unsigned i = 0 ; i < 4 ; ++i ) {
+ pHull.push_back(Inkscape::SnapCandidatePoint(rHull->corner(i), SNAPSOURCE_CONVEX_HULL_CORNER));
+ }
+ }
}
- return p;
+ return pHull;
}
void Selection::_removeObjectDescendants(SPObject *obj) {
g_return_val_if_fail(repr != NULL, NULL);
gchar const *id = repr->attribute("id");
g_return_val_if_fail(id != NULL, NULL);
- SPObject *object=SP_DT_DOCUMENT(_desktop)->getObjectById(id);
+ SPObject *object=sp_desktop_document(_desktop)->getObjectById(id);
g_return_val_if_fail(object != NULL, NULL);
return object;
}
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;
}
}