diff --git a/src/selection.cpp b/src/selection.cpp
index 763713c9d86923e0242f6399429fb41f01d77313..44f601362e1494eedce9c43b9a8381d5e3be7391 100644 (file)
--- a/src/selection.cpp
+++ b/src/selection.cpp
* Lauris Kaplinski <lauris@kaplinski.com>
* MenTaLguY <mental@rydia.net>
* bulia byak <buliabyak@users.sf.net>
+ * Andrius R. <knutux@gmail.com>
*
+ * Copyright (C) 2006 Andrius R.
* Copyright (C) 2004-2005 MenTaLguY
* Copyright (C) 1999-2002 Lauris Kaplinski
* Copyright (C) 2001-2002 Ximian, Inc.
#include "xml/repr.h"
#include "sp-shape.h"
+#include "sp-path.h"
+#include <sigc++/functors/mem_fun.h>
#define SP_SELECTION_UPDATE_PRIORITY (G_PRIORITY_HIGH_IDLE + 1)
_reprs(NULL),
_items(NULL),
_desktop(desktop),
+ _selection_context(NULL),
_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
_modified_signal.emit(this, flags);
}
-void Selection::_emitChanged() {
+void Selection::_emitChanged(bool persist_selection_context/* = false */) {
+ if (persist_selection_context) {
+ if (NULL == _selection_context) {
+ _selection_context = desktop()->currentLayer();
+ sp_object_ref(_selection_context, NULL);
+ _context_release_connection = _selection_context->connectRelease(sigc::mem_fun(*this, &Selection::_releaseContext));
+ }
+ } else {
+ _releaseContext(_selection_context);
+ }
+
inkscape_selection_changed(this);
_changed_signal.emit(this);
}
+void
+Selection::_releaseContext(SPObject *obj)
+{
+ if (NULL == _selection_context || _selection_context != obj)
+ return;
+
+ _context_release_connection.disconnect();
+
+ sp_object_unref(_selection_context, NULL);
+ _selection_context = NULL;
+}
+
void Selection::_invalidateCachedLists() {
g_slist_free(_items);
_items = 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);
}
}
+SPObject *Selection::activeContext() {
+ if (NULL != _selection_context)
+ return _selection_context;
+ return desktop()->currentLayer();
+ }
+
bool Selection::includes(SPObject *obj) const {
if (obj == NULL)
return FALSE;
return ( g_slist_find(_objs, obj) != NULL );
}
-void Selection::add(SPObject *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));
_invalidateCachedLists();
_add(obj);
- _emitChanged();
+ _emitChanged(persist_selection_context);
}
void Selection::_add(SPObject *obj) {
_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");
- }
- */
+
+ _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) {
+void Selection::set(SPObject *object, bool persist_selection_context) {
_clear();
- add(object);
+ add(object, persist_selection_context);
}
void Selection::toggle(SPObject *obj) {
}
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);
+
_objs = g_slist_remove(_objs, obj);
}
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
+NR::Maybe<NR::Rect> 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;
+ NR::Maybe<NR::Rect> bbox = NR::Nothing();
+ for ( GSList const *i = items ; i != NULL ; i = i->next ) {
+ bbox = NR::union_bounds(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);
+ NR::Matrix i2doc(sp_item_i2doc_affine(item));
+ sp_item_invoke_bbox(item, bbox, i2doc, FALSE, type);
}
return bbox;
}
-NR::Rect Selection::boundsInDocument() const {
+NR::Maybe<NR::Rect> Selection::boundsInDocument(SPItem::BBoxType type) const {
NRRect r;
- return NR::Rect(*boundsInDocument(&r));
+ return boundsInDocument(&r, type)->upgrade();
+}
+
+/** Extract the position of the center from the first selected object */
+NR::Maybe<NR::Point> Selection::center() const {
+ GSList *items = (GSList *) const_cast<Selection *>(this)->itemList();
+ NR::Point center;
+ if (items) {
+ SPItem *first = reinterpret_cast<SPItem*>(g_slist_last(items)->data); // from the first item in selection
+ if (first->isCenterSet()) { // only if set explicitly
+ return first->getCenter();
+ }
+ }
+ NR::Maybe<NR::Rect> bbox = bounds();
+ if (bbox) {
+ return bounds()->midpoint();
+ } else {
+ return NR::Nothing();
+ }
}
/**
* Compute the list of points in the selection that are to be considered for snapping.
+ * This includes all special points of each item in the selection, except path nodes
*/
std::vector<NR::Point> Selection::getSnapPoints() 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));
+ // getSnapPoints() is only being used in the selector tool, which should
+ // not snap path nodes. Only the node tool should snap those.
+ SPItem *this_item = SP_ITEM(iter->data);
+ if (!SP_IS_PATH(this_item)) {
+ // Only snap if we don't have a path at hand
+ // (Same check occurs in sp-item-group)
+ sp_item_snappoints(this_item, SnapPointsIter(p));
+ }
}
return p;
std::vector<NR::Point> Selection::getSnapPointsConvexHull() 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);
- }
-
- 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);
-
- return pHull;
-}
+ std::vector<NR::Point> pHull;
+ if (!p.empty()) {
+ std::vector<NR::Point>::iterator i;
+ NR::ConvexHull cvh(p.front());
+ for (i = p.begin(); i != p.end(); i++) {
+ // these are the points we get back
+ cvh.add(*i);
+ }
-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());
+ NR::Maybe<NR::Rect> rHull = cvh.bounds();
+ if (rHull) {
+ for ( unsigned i = 0 ; i < 4 ; ++i ) {
+ pHull.push_back(rHull->corner(i));
+ }
+ }
}
- 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;
}