avoid recursing through the entire canvas when scrolling - only scroll explicitly identified ScrollGroups

This commit is contained in:
Paul Davis 2014-05-21 10:25:28 -04:00
parent a551181842
commit c9f890bd7c
3 changed files with 32 additions and 13 deletions

View file

@ -66,12 +66,14 @@ Editor::initialize_canvas ()
{
_track_canvas_viewport = new ArdourCanvas::GtkCanvasViewport (horizontal_adjustment, vertical_adjustment);
_track_canvas = _track_canvas_viewport->canvas ();
_track_canvas->set_global_scroll (false);
hv_scroll_group = new ArdourCanvas::ScrollGroup (_track_canvas->root(),
ArdourCanvas::ScrollGroup::ScrollSensitivity (ArdourCanvas::ScrollGroup::ScrollsVertically|
ArdourCanvas::ScrollGroup::ScrollsHorizontally));
ArdourCanvas::ScrollGroup* hsg;
hv_scroll_group = hsg = new ArdourCanvas::ScrollGroup (_track_canvas->root(),
ArdourCanvas::ScrollGroup::ScrollSensitivity (ArdourCanvas::ScrollGroup::ScrollsVertically|
ArdourCanvas::ScrollGroup::ScrollsHorizontally));
CANVAS_DEBUG_NAME (hv_scroll_group, "canvas hv scroll");
_track_canvas->add_scroller (*hsg);
_verbose_cursor = new VerboseCursor (this);

View file

@ -33,6 +33,7 @@
#include "canvas/canvas.h"
#include "canvas/debug.h"
#include "canvas/line.h"
#include "canvas/scroll_group.h"
using namespace std;
using namespace ArdourCanvas;
@ -40,7 +41,6 @@ using namespace ArdourCanvas;
/** Construct a new Canvas */
Canvas::Canvas ()
: _root (this)
, _global_scroll (true)
{
set_epoch ();
}
@ -48,19 +48,29 @@ Canvas::Canvas ()
void
Canvas::scroll_to (Coord x, Coord y)
{
Duple d (x, y);
_scroll_offset = d;
_scroll_offset = Duple (x, y);
_root.scroll_to (d);
/* We do things this way because we do not want to recurse through
the canvas for every scroll. In the presence of large MIDI
tracks this means traversing item lists that include
thousands of items (notes).
This design limits us to moving only those items (groups, typically)
that should move in certain ways as we scroll. In other terms, it
becomes O(1) rather than O(N).
*/
for (list<ScrollGroup*>::iterator i = scrollers.begin(); i != scrollers.end(); ++i) {
(*i)->scroll_to (_scroll_offset);
}
pick_current_item (0); // no current mouse position
}
void
Canvas::set_global_scroll (bool yn)
Canvas::add_scroller (ScrollGroup& i)
{
_global_scroll = yn;
scrollers.push_back (&i);
}
void
@ -602,6 +612,11 @@ GtkCanvas::item_going_away (Item* item, boost::optional<Rect> bounding_box)
_focused_item = 0;
}
ScrollGroup* sg = dynamic_cast<ScrollGroup*>(item);
if (sg) {
scrollers.remove (sg);
}
if (_current_item == item) {
/* no need to send a leave event to this item, since it is going away
*/

View file

@ -43,6 +43,7 @@ namespace ArdourCanvas
class Rect;
class Group;
class ScrollGroup;
/** The base class for our different types of canvas.
*
@ -108,7 +109,7 @@ public:
}
void scroll_to (Coord x, Coord y);
void set_global_scroll (bool);
void add_scroller (ScrollGroup& i);
virtual Rect visible_area () const = 0;
@ -125,10 +126,11 @@ protected:
RootGroup _root;
Duple _scroll_offset;
bool _global_scroll;
virtual void pick_current_item (int state) = 0;
virtual void pick_current_item (Duple const &, int state) = 0;
std::list<ScrollGroup*> scrollers;
};
/** A canvas which renders onto a GTK EventBox */