summaryrefslogtreecommitdiffstats
path: root/src/document.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/document.cpp')
-rw-r--r--src/document.cpp109
1 files changed, 75 insertions, 34 deletions
diff --git a/src/document.cpp b/src/document.cpp
index 2ea969910..23d99d78c 100644
--- a/src/document.cpp
+++ b/src/document.cpp
@@ -1335,51 +1335,64 @@ SPItem *SPDocument::getItemFromListAtPointBottom(unsigned int dkey, SPGroup *gro
}
/**
-Returns the topmost (in z-order) item from the descendants of group (recursively) which
-is at the point p, or NULL if none. Honors into_groups on whether to recurse into
-non-layer groups or not. Honors take_insensitive on whether to return insensitive
-items. If upto != NULL, then if item upto is encountered (at any level), stops searching
-upwards in z-order and returns what it has found so far (i.e. the found item is
-guaranteed to be lower than upto).
- */
-static SPItem *find_item_at_point(unsigned int dkey, SPGroup *group, Geom::Point const &p, gboolean into_groups, bool take_insensitive = false, SPItem *upto = NULL)
+Turn the SVG DOM into a flat list of nodes that can be searched from top-down.
+The list can be persisted, which improves "find at multiple points" speed.
+Returns true if upto is reached.
+*/
+static bool build_flat_item_list(std::deque<SPItem*> *nodes, unsigned int dkey, SPGroup *group, gboolean into_groups, bool take_insensitive = false, SPItem *upto = NULL)
{
- SPItem *seen = NULL;
- SPItem *newseen = NULL;
- Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- gdouble delta = prefs->getDouble("/options/cursortolerance/value", 1.0);
-
+ bool found_upto = false;
for ( SPObject *o = group->firstChild() ; o ; o = o->getNext() ) {
if (!SP_IS_ITEM(o)) {
continue;
}
if (upto && SP_ITEM(o) == upto) {
+ found_upto = true;
break;
}
if (SP_IS_GROUP(o) && (SP_GROUP(o)->effectiveLayerMode(dkey) == SPGroup::LAYER || into_groups)) {
- // if nothing found yet, recurse into the group
- newseen = find_item_at_point(dkey, SP_GROUP(o), p, into_groups, take_insensitive, upto);
- if (newseen) {
- seen = newseen;
- newseen = NULL;
- }
-
- if (item_is_in_group(upto, SP_GROUP(o))) {
+ found_upto = build_flat_item_list(nodes, dkey, SP_GROUP(o), into_groups, take_insensitive, upto);
+ if (found_upto)
break;
- }
} else {
SPItem *child = SP_ITEM(o);
- Inkscape::DrawingItem *arenaitem = child->get_arenaitem(dkey);
- // seen remembers the last (topmost) of items pickable at this point
- if (arenaitem && arenaitem->pick(p, delta, 1) != NULL
- && (take_insensitive || child->isVisibleAndUnlocked(dkey))) {
- seen = child;
+ if (take_insensitive || child->isVisibleAndUnlocked(dkey)) {
+ nodes->push_front(child);
}
}
}
+ return found_upto;
+}
+
+/**
+Returns the topmost (in z-order) item from the descendants of group (recursively) which
+is at the point p, or NULL if none. Honors into_groups on whether to recurse into
+non-layer groups or not. Honors take_insensitive on whether to return insensitive
+items. If upto != NULL, then if item upto is encountered (at any level), stops searching
+upwards in z-order and returns what it has found so far (i.e. the found item is
+guaranteed to be lower than upto). Requires a list of nodes built by
+build_flat_item_list.
+ */
+static SPItem *find_item_at_point(std::deque<SPItem*> *nodes, unsigned int dkey, Geom::Point const &p)
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gdouble delta = prefs->getDouble("/options/cursortolerance/value", 1.0);
+
+ SPItem *seen = NULL;
+ SPItem *child;
+ for (unsigned long i = 0; i < nodes->size(); ++i) {
+ child = nodes->at(i);
+ Inkscape::DrawingItem *arenaitem = child->get_arenaitem(dkey);
+
+ if (arenaitem && arenaitem->pick(p, delta, 1) != NULL) {
+ seen = child;
+ break;
+ }
+ }
+
return seen;
}
@@ -1443,7 +1456,7 @@ std::vector<SPItem*> SPDocument::getItemsPartiallyInBox(unsigned int dkey, Geom:
return find_items_in_area(x, SP_GROUP(this->root), dkey, box, overlaps);
}
-std::vector<SPItem*> SPDocument::getItemsAtPoints(unsigned const key, std::vector<Geom::Point> points) const
+std::vector<SPItem*> SPDocument::getItemsAtPoints(unsigned const key, std::vector<Geom::Point> points, bool all_layers, size_t limit) const
{
std::vector<SPItem*> items;
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
@@ -1454,11 +1467,28 @@ std::vector<SPItem*> SPDocument::getItemsAtPoints(unsigned const key, std::vecto
gdouble saved_delta = prefs->getDouble("/options/cursortolerance/value", 1.0);
prefs->setDouble("/options/cursortolerance/value", 0.25);
+ // Cache a flattened SVG DOM to speed up selection.
+ std::deque<SPItem*> nodes;
+ build_flat_item_list(&nodes, key, SP_GROUP(this->root), true, false, NULL);
+ SPObject *current_layer = SP_ACTIVE_DESKTOP->currentLayer();
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ Inkscape::LayerModel *layer_model = NULL;
+ if(desktop){
+ layer_model = desktop->layers;
+ }
+ size_t item_counter = 0;
for(int i = points.size()-1;i>=0; i--) {
- SPItem *item = getItemAtPoint(key, points[i],
- false, NULL);
+ SPItem *item = find_item_at_point(&nodes, key, points[i]);
if (item && items.end()==find(items.begin(),items.end(), item))
- items.push_back(item);
+ if(all_layers || (layer_model && layer_model->layerForObject(item) == current_layer)){
+ items.push_back(item);
+ item_counter++;
+ //limit 0 = no limit
+ if(item_counter == limit){
+ prefs->setDouble("/options/cursortolerance/value", saved_delta);
+ return items;
+ }
+ }
}
// and now we restore it back
@@ -1472,7 +1502,11 @@ SPItem *SPDocument::getItemAtPoint( unsigned const key, Geom::Point const &p,
{
g_return_val_if_fail(this->priv != NULL, NULL);
- return find_item_at_point(key, SP_GROUP(this->root), p, into_groups, false, upto);
+ // Build a flattened SVG DOM for find_item_at_point.
+ std::deque<SPItem*> nodes;
+ build_flat_item_list(&nodes, key, SP_GROUP(this->root), into_groups, false, upto);
+
+ return find_item_at_point(&nodes, key, p);
}
SPItem *SPDocument::getGroupAtPoint(unsigned int key, Geom::Point const &p) const
@@ -1482,7 +1516,6 @@ SPItem *SPDocument::getGroupAtPoint(unsigned int key, Geom::Point const &p) cons
return find_group_at_point(key, SP_GROUP(this->root), p);
}
-
// Resource management
bool SPDocument::addResource(gchar const *key, SPObject *object)
@@ -1501,7 +1534,15 @@ bool SPDocument::addResource(gchar const *key, SPObject *object)
g_hash_table_insert(priv->resources, (gpointer) key, rlist);
GQuark q = g_quark_from_string(key);
- priv->resources_changed_signals[q].emit();
+
+ /*in general, do not send signal if the object has no id (yet),
+ it means the object is not completely built.
+ (happens when pasting swatches across documents, cf bug 1495106)
+ [this check should be more generally presend on emit() calls since
+ the backtrace is unusable with crashed from this cause]
+ */
+ if(object->getId() || dynamic_cast<SPGroup*>(object) )
+ priv->resources_changed_signals[q].emit();
result = true;
}