13
0

Add an optional ArdourCanvas::Item::prepare_for_render interface

Called when an item has requested a redraw and intersects with visible
canvas area.

Also add Canvas::prepare_for_render that will call Item::prepare_for_render for
items visible on the canvas.
This commit is contained in:
Tim Mayberry 2017-04-01 23:02:49 +10:00
parent 265f52535a
commit c4e31fc322
6 changed files with 93 additions and 1 deletions

View File

@ -144,6 +144,22 @@ Canvas::render (Rect const & area, Cairo::RefPtr<Cairo::Context> const & context
} }
void
Canvas::prepare_for_render (Rect const & area) const
{
Rect root_bbox = _root.bounding_box();
if (!root_bbox) {
/* the root has no bounding box, so there's nothing to render */
return;
}
Rect draw = root_bbox.intersection (area);
if (draw) {
_root.prepare_for_render (draw);
}
}
ostream& ostream&
operator<< (ostream& o, Canvas& c) operator<< (ostream& o, Canvas& c)
{ {
@ -231,9 +247,17 @@ Canvas::item_changed (Item* item, Rect pre_change_bounding_box)
Rect post_change_bounding_box = item->bounding_box (); Rect post_change_bounding_box = item->bounding_box ();
if (post_change_bounding_box) { if (post_change_bounding_box) {
if (item->item_to_window (post_change_bounding_box).intersection (window_bbox)) { Rect const window_intersection =
item->item_to_window (post_change_bounding_box).intersection (window_bbox);
if (window_intersection) {
/* request a redraw of the item's new bounding box */ /* request a redraw of the item's new bounding box */
queue_draw_item_area (item, post_change_bounding_box); queue_draw_item_area (item, post_change_bounding_box);
// Allow item to do any work necessary to prepare for being rendered.
item->prepare_for_render (window_intersection);
} else {
// No intersection with visible window area
} }
} }
} }
@ -937,6 +961,13 @@ GtkCanvas::on_expose_event (GdkEventExpose* ev)
return true; return true;
} }
void
GtkCanvas::prepare_for_render () const
{
Rect window_bbox = visible_area ();
Canvas::prepare_for_render (window_bbox);
}
/** Handler for GDK scroll events. /** Handler for GDK scroll events.
* @param ev Event. * @param ev Event.
* @return true if the event was handled. * @return true if the event was handled.

View File

@ -87,6 +87,8 @@ public:
void render (Rect const &, Cairo::RefPtr<Cairo::Context> const &) const; void render (Rect const &, Cairo::RefPtr<Cairo::Context> const &) const;
void prepare_for_render (Rect const &) const;
/** @return root group */ /** @return root group */
Item* root () { Item* root () {
return &_root; return &_root;
@ -214,6 +216,8 @@ public:
Canvas::render (rect, ctx); Canvas::render (rect, ctx);
} }
void prepare_for_render () const;
uint32_t background_color() { return Canvas::background_color (); } uint32_t background_color() { return Canvas::background_color (); }
protected: protected:

View File

@ -53,6 +53,12 @@ public:
* (just call Item::render_children()). It can be overridden as necessary. * (just call Item::render_children()). It can be overridden as necessary.
*/ */
void render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const; void render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const;
/** The prepare_for_render() method is likely to be identical in all
* containers (just call Item::prepare_for_render_children()). It can be
* overridden as necessary.
*/
void prepare_for_render (Rect const & area) const;
}; };
} }

View File

@ -75,6 +75,13 @@ public:
*/ */
virtual void render (Rect const & area, Cairo::RefPtr<Cairo::Context>) const = 0; virtual void render (Rect const & area, Cairo::RefPtr<Cairo::Context>) const = 0;
/** Item has changed will be rendered in next render pass so give item a
* chance to perhaps schedule work in another thread etc.
*
* @param area Area to draw, in **window** coordinates
*/
virtual void prepare_for_render (Rect const & area) const { }
/** Adds one or more items to the vector @param items based on their /** Adds one or more items to the vector @param items based on their
* covering @param point which is in **window** coordinates * covering @param point which is in **window** coordinates
* *
@ -309,6 +316,7 @@ protected:
void add_child_bounding_boxes (bool include_hidden = false) const; void add_child_bounding_boxes (bool include_hidden = false) const;
void render_children (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const; void render_children (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const;
void prepare_for_render_children (Rect const & area) const;
Duple scroll_offset() const; Duple scroll_offset() const;
Duple position_offset() const; Duple position_offset() const;

View File

@ -37,6 +37,12 @@ Container::Container (Item* parent, Duple const & p)
{ {
} }
void
Container::prepare_for_render (Rect const & area) const
{
Item::prepare_for_render_children (area);
}
void void
Container::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const Container::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
{ {

View File

@ -830,6 +830,43 @@ Item::render_children (Rect const & area, Cairo::RefPtr<Cairo::Context> context)
--render_depth; --render_depth;
} }
void
Item::prepare_for_render_children (Rect const & area) const
{
if (_items.empty()) {
return;
}
ensure_lut ();
std::vector<Item*> items = _lut->get (area);
for (std::vector<Item*>::const_iterator i = items.begin(); i != items.end(); ++i) {
if (!(*i)->visible ()) {
continue;
}
Rect item_bbox = (*i)->bounding_box ();
if (!item_bbox) {
continue;
}
Rect item = (*i)->item_to_window (item_bbox, false);
Rect d = item.intersection (area);
if (d) {
Rect draw = d;
if (draw.width() && draw.height()) {
(*i)->prepare_for_render (area);
}
} else {
// Item does not intersect with visible canvas area
}
}
}
void void
Item::add_child_bounding_boxes (bool include_hidden) const Item::add_child_bounding_boxes (bool include_hidden) const
{ {