summaryrefslogtreecommitdiffstats
path: root/src/ui
diff options
context:
space:
mode:
authorLiam P. White <inkscapebrony@gmail.com>2014-08-08 20:20:44 +0000
committerLiam P. White <inkscapebrony@gmail.com>2014-08-08 20:20:44 +0000
commite9f9ba07739cdb52c649e8e10dca9de76c71114d (patch)
treea24de5816184ce8a772736b8af0ccc1dca66024f /src/ui
parentSmall tweak to bbox calculation (diff)
downloadinkscape-e9f9ba07739cdb52c649e8e10dca9de76c71114d.tar.gz
inkscape-e9f9ba07739cdb52c649e8e10dca9de76c71114d.zip
Massive performance improvment for basic node operations with thousands of nodes
(bzr r13341.1.124)
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/tool/control-point-selection.cpp49
-rw-r--r--src/ui/tool/control-point-selection.h13
-rw-r--r--src/ui/tool/multi-path-manipulator.cpp2
-rw-r--r--src/ui/tool/node.cpp32
-rw-r--r--src/ui/tool/path-manipulator.cpp10
-rw-r--r--src/ui/tool/path-manipulator.h3
-rw-r--r--src/ui/tool/selectable-control-point.h1
-rw-r--r--src/ui/tools/node-tool.cpp2
8 files changed, 93 insertions, 19 deletions
diff --git a/src/ui/tool/control-point-selection.cpp b/src/ui/tool/control-point-selection.cpp
index d10ed0f0d..998f74ee0 100644
--- a/src/ui/tool/control-point-selection.cpp
+++ b/src/ui/tool/control-point-selection.cpp
@@ -74,7 +74,7 @@ ControlPointSelection::~ControlPointSelection()
}
/** Add a control point to the selection. */
-std::pair<ControlPointSelection::iterator, bool> ControlPointSelection::insert(const value_type &x)
+std::pair<ControlPointSelection::iterator, bool> ControlPointSelection::insert(const value_type &x, bool notify)
{
iterator found = _points.find(x);
if (found != _points.end()) {
@@ -86,6 +86,10 @@ std::pair<ControlPointSelection::iterator, bool> ControlPointSelection::insert(c
x->updateState();
_pointChanged(x, true);
+ if (notify) {
+ signal_selection_changed.emit(std::vector<key_type>(1, x), true);
+ }
+
return std::pair<iterator, bool>(found, true);
}
@@ -97,47 +101,75 @@ void ControlPointSelection::erase(iterator pos)
erased->updateState();
_pointChanged(erased, false);
}
-ControlPointSelection::size_type ControlPointSelection::erase(const key_type &k)
+ControlPointSelection::size_type ControlPointSelection::erase(const key_type &k, bool notify)
{
iterator pos = _points.find(k);
if (pos == _points.end()) return 0;
erase(pos);
+
+ if (notify) {
+ signal_selection_changed.emit(std::vector<key_type>(1, k), false);
+ }
return 1;
}
void ControlPointSelection::erase(iterator first, iterator last)
{
+ std::vector<SelectableControlPoint *> out(first, last);
while (first != last) erase(first++);
+ signal_selection_changed.emit(out, false);
}
/** Remove all points from the selection, making it empty. */
void ControlPointSelection::clear()
{
+ std::vector<SelectableControlPoint *> out(begin(), end());
for (iterator i = begin(); i != end(); )
erase(i++);
+ if (!out.empty())
+ signal_selection_changed.emit(out, false);
}
/** Select all points that this selection can contain. */
void ControlPointSelection::selectAll()
{
for (set_type::iterator i = _all_points.begin(); i != _all_points.end(); ++i) {
- insert(*i);
+ insert(*i, false);
}
+ std::vector<SelectableControlPoint *> out(_all_points.begin(), _all_points.end());
+ if (!out.empty())
+ signal_selection_changed.emit(out, true);
}
/** Select all points inside the given rectangle (in desktop coordinates). */
void ControlPointSelection::selectArea(Geom::Rect const &r)
{
+ std::vector<SelectableControlPoint *> out;
for (set_type::iterator i = _all_points.begin(); i != _all_points.end(); ++i) {
- if (r.contains(**i))
- insert(*i);
+ if (r.contains(**i)) {
+ insert(*i, false);
+ out.push_back(*i);
+ }
}
+ if (!out.empty())
+ signal_selection_changed.emit(out, true);
}
/** Unselect all selected points and select all unselected points. */
void ControlPointSelection::invertSelection()
{
+ std::vector<SelectableControlPoint *> in, out;
for (set_type::iterator i = _all_points.begin(); i != _all_points.end(); ++i) {
- if ((*i)->selected()) erase(*i);
- else insert(*i);
+ if ((*i)->selected()) {
+ in.push_back(*i);
+ erase(*i);
+ }
+ else {
+ out.push_back(*i);
+ insert(*i, false);
+ }
}
+ if (!in.empty())
+ signal_selection_changed.emit(in, false);
+ if (!out.empty())
+ signal_selection_changed.emit(out, true);
}
void ControlPointSelection::spatialGrow(SelectableControlPoint *origin, int dir)
{
@@ -166,6 +198,7 @@ void ControlPointSelection::spatialGrow(SelectableControlPoint *origin, int dir)
if (match) {
if (grow) insert(match);
else erase(match);
+ signal_selection_changed.emit(std::vector<value_type>(1, match), grow);
}
}
@@ -389,7 +422,7 @@ void ControlPointSelection::_pointChanged(SelectableControlPoint *p, bool select
_handles->rotationCenter().move(_bounds->midpoint());
}
- signal_point_changed.emit(p, selected);
+ //signal_point_changed.emit(p, selected);
}
void ControlPointSelection::_mouseoverChanged()
diff --git a/src/ui/tool/control-point-selection.h b/src/ui/tool/control-point-selection.h
index a087e0455..2d812c0a3 100644
--- a/src/ui/tool/control-point-selection.h
+++ b/src/ui/tool/control-point-selection.h
@@ -62,18 +62,19 @@ public:
const_iterator end() const { return _points.end(); }
// insert
- std::pair<iterator, bool> insert(const value_type& x);
+ std::pair<iterator, bool> insert(const value_type& x, bool notify = true);
template <class InputIterator>
void insert(InputIterator first, InputIterator last) {
for (; first != last; ++first) {
- insert(*first);
+ insert(*first, false);
}
+ signal_selection_changed.emit(std::vector<key_type>(first, last), true);
}
// erase
void clear();
void erase(iterator pos);
- size_type erase(const key_type& k);
+ size_type erase(const key_type& k, bool notify = true);
void erase(iterator first, iterator last);
// find
@@ -108,7 +109,9 @@ public:
void toggleTransformHandlesMode();
sigc::signal<void> signal_update;
- sigc::signal<void, SelectableControlPoint *, bool> signal_point_changed;
+ // It turns out that emitting a signal after every point is selected or deselected is not too efficient,
+ // so this can be done in a massive group once the selection is finally changed.
+ sigc::signal<void, std::vector<SelectableControlPoint *>, bool> signal_selection_changed;
sigc::signal<void, CommitEvent> signal_commit;
void getOriginalPoints(std::vector<Inkscape::SnapCandidatePoint> &pts);
@@ -166,4 +169,4 @@ private:
fill-column:99
End:
*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8 :
diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp
index 68aaa77a5..b32bafdbf 100644
--- a/src/ui/tool/multi-path-manipulator.cpp
+++ b/src/ui/tool/multi-path-manipulator.cpp
@@ -122,7 +122,7 @@ MultiPathManipulator::MultiPathManipulator(PathSharedData &data, sigc::connectio
{
_selection.signal_commit.connect(
sigc::mem_fun(*this, &MultiPathManipulator::_commit));
- _selection.signal_point_changed.connect(
+ _selection.signal_selection_changed.connect(
sigc::hide( sigc::hide(
signal_coords_changed.make_slot())));
}
diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp
index ed0843b65..e38f82673 100644
--- a/src/ui/tool/node.cpp
+++ b/src/ui/tool/node.cpp
@@ -1623,7 +1623,37 @@ void NodeList::reverse()
void NodeList::clear()
{
- for (iterator i = begin(); i != end();) erase (i++);
+ // ugly but more efficient clearing mechanism
+ std::vector<ControlPointSelection *> to_clear;
+ std::vector<std::pair<SelectableControlPoint *, long> > nodes;
+ long in = -1;
+ for (iterator i = begin(); i != end(); ++i) {
+ SelectableControlPoint *rm = static_cast<Node*>(i._node);
+ if (std::find(to_clear.begin(), to_clear.end(), &rm->_selection) == to_clear.end()) {
+ to_clear.push_back(&rm->_selection);
+ ++in;
+ }
+ nodes.push_back(std::make_pair(rm, in));
+ }
+ for (size_t i = 0, e = nodes.size(); i != e; ++i) {
+ to_clear[nodes[i].second]->erase(nodes[i].first, false);
+ }
+ std::vector<std::vector<SelectableControlPoint *> > emission;
+ for (long i = 0, e = to_clear.size(); i != e; ++i) {
+ emission.push_back(std::vector<SelectableControlPoint *>());
+ for (size_t j = 0, f = nodes.size(); j != f; ++j) {
+ if (nodes[j].second != i)
+ break;
+ emission[i].push_back(nodes[j].first);
+ }
+ }
+
+ for (size_t i = 0, e = emission.size(); i != e; ++i) {
+ to_clear[i]->signal_selection_changed.emit(emission[i], false);
+ }
+
+ for (iterator i = begin(); i != end();)
+ erase (i++);
}
NodeList::iterator NodeList::erase(iterator i)
diff --git a/src/ui/tool/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp
index 9839be437..5f20aece7 100644
--- a/src/ui/tool/path-manipulator.cpp
+++ b/src/ui/tool/path-manipulator.cpp
@@ -140,8 +140,8 @@ PathManipulator::PathManipulator(MultiPathManipulator &mpm, SPPath *path,
_selection.signal_update.connect(
sigc::bind(sigc::mem_fun(*this, &PathManipulator::update), false));
- _selection.signal_point_changed.connect(
- sigc::mem_fun(*this, &PathManipulator::_selectionChanged));
+ _selection.signal_selection_changed.connect(
+ sigc::mem_fun(*this, &PathManipulator::_selectionChangedM));
_desktop->signal_zoom_changed.connect(
sigc::hide( sigc::mem_fun(*this, &PathManipulator::_updateOutlineOnZoomChange)));
@@ -1524,6 +1524,12 @@ bool PathManipulator::_handleClicked(Handle *h, GdkEventButton *event)
return false;
}
+void PathManipulator::_selectionChangedM(std::vector<SelectableControlPoint *> pvec, bool selected) {
+ for (size_t n = 0, e = pvec.size(); n < e; ++n) {
+ _selectionChanged(pvec[n], selected);
+ }
+}
+
void PathManipulator::_selectionChanged(SelectableControlPoint *p, bool selected)
{
if (selected) ++_num_selected;
diff --git a/src/ui/tool/path-manipulator.h b/src/ui/tool/path-manipulator.h
index 151805c83..4d2bf4300 100644
--- a/src/ui/tool/path-manipulator.h
+++ b/src/ui/tool/path-manipulator.h
@@ -122,7 +122,8 @@ private:
Glib::ustring _nodetypesKey();
Inkscape::XML::Node *_getXMLNode();
- void _selectionChanged(SelectableControlPoint *p, bool selected);
+ void _selectionChangedM(std::vector<SelectableControlPoint *> pvec, bool selected);
+ void _selectionChanged(SelectableControlPoint * p, bool selected);
bool _nodeClicked(Node *, GdkEventButton *);
void _handleGrabbed();
bool _handleClicked(Handle *, GdkEventButton *);
diff --git a/src/ui/tool/selectable-control-point.h b/src/ui/tool/selectable-control-point.h
index 8acfc1168..362d4addc 100644
--- a/src/ui/tool/selectable-control-point.h
+++ b/src/ui/tool/selectable-control-point.h
@@ -28,6 +28,7 @@ public:
virtual Geom::Rect bounds() const {
return Geom::Rect(position(), position());
}
+ friend class NodeList;
protected:
diff --git a/src/ui/tools/node-tool.cpp b/src/ui/tools/node-tool.cpp
index d2584ee74..d4d7b2c35 100644
--- a/src/ui/tools/node-tool.cpp
+++ b/src/ui/tools/node-tool.cpp
@@ -245,7 +245,7 @@ void NodeTool::setup() {
)
);
- this->_selected_nodes->signal_point_changed.connect(
+ this->_selected_nodes->signal_selection_changed.connect(
// Hide both signal parameters and bind the function parameter to 0
// sigc::signal<void, SelectableControlPoint *, bool>
// <=>