2 #include <cairomm/context.h>
4 #include "pbd/stacktrace.h"
5 #include "pbd/compose.h"
7 #include "canvas/group.h"
8 #include "canvas/types.h"
9 #include "canvas/debug.h"
10 #include "canvas/item.h"
11 #include "canvas/canvas.h"
14 using namespace ArdourCanvas;
16 int Group::default_items_per_cell = 64;
19 Group::Group (Canvas* canvas)
26 Group::Group (Group* parent)
33 Group::Group (Group* parent, Duple position)
34 : Item (parent, position)
42 for (list<Item*>::iterator i = _items.begin(); i != _items.end(); ++i) {
49 /** @param area Area to draw in this group's coordinates.
50 * @param context Context, set up with its origin at this group's position.
53 Group::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
56 vector<Item*> items = _lut->get (area);
61 if (DEBUG_ENABLED(PBD::DEBUG::CanvasRender)) {
62 cerr << string_compose ("%1GROUP %2 render %3 items out of %4\n",
63 _canvas->render_indent(), (name.empty() ? string ("[unnamed]") : name), items.size(), _items.size());
67 for (vector<Item*>::const_iterator i = items.begin(); i != items.end(); ++i) {
69 if (!(*i)->visible ()) {
71 if (DEBUG_ENABLED(PBD::DEBUG::CanvasRender)) {
72 cerr << _canvas->render_indent() << "Item " << (*i)->whatami() << " [" << (*i)->name << "] invisible - skipped\n";
78 boost::optional<Rect> item_bbox = (*i)->bounding_box ();
82 if (DEBUG_ENABLED(PBD::DEBUG::CanvasRender)) {
83 cerr << _canvas->render_indent() << "Item " << (*i)->whatami() << " [" << (*i)->name << "] empty - skipped\n";
89 /* convert the render area to our child's coordinates */
90 Rect const item_area = (*i)->parent_to_item (area);
92 /* intersect the child's render area with the child's bounding box */
93 boost::optional<Rect> r = item_bbox.get().intersection (item_area);
96 /* render the intersection */
98 context->translate ((*i)->position().x, (*i)->position().y);
100 if (DEBUG_ENABLED(PBD::DEBUG::CanvasRender)) {
101 cerr << string_compose ("%1render %2 %3\n", _canvas->render_indent(), (*i)->whatami(),
105 (*i)->render (r.get(), context);
110 if (DEBUG_ENABLED(PBD::DEBUG::CanvasRender)) {
111 cerr << string_compose ("%1skip render of %2 %3, no intersection\n", _canvas->render_indent(), (*i)->whatami(),
122 Group::compute_bounding_box () const
125 bool have_one = false;
127 for (list<Item*>::const_iterator i = _items.begin(); i != _items.end(); ++i) {
128 boost::optional<Rect> item_bbox = (*i)->bounding_box ();
133 Rect group_bbox = (*i)->item_to_parent (item_bbox.get ());
135 bbox = bbox.extend (group_bbox);
143 _bounding_box = boost::optional<Rect> ();
145 _bounding_box = bbox;
148 _bounding_box_dirty = false;
154 _items.push_back (i);
156 _bounding_box_dirty = true;
158 DEBUG_TRACE (PBD::DEBUG::CanvasItemsDirtied, "canvas item dirty: group add\n");
162 Group::remove (Item* i)
166 _bounding_box_dirty = true;
168 DEBUG_TRACE (PBD::DEBUG::CanvasItemsDirtied, "canvas item dirty: group remove\n");
172 Group::raise_child_to_top (Item* i)
175 _items.push_back (i);
180 Group::raise_child (Item* i, int levels)
182 list<Item*>::iterator j = find (_items.begin(), _items.end(), i);
183 assert (j != _items.end ());
188 while (levels > 0 && j != _items.end ()) {
193 _items.insert (j, i);
198 Group::lower_child_to_bottom (Item* i)
201 _items.push_front (i);
206 Group::ensure_lut () const
209 _lut = new DumbLookupTable (*this);
214 Group::invalidate_lut () const
221 Group::child_changed ()
224 _bounding_box_dirty = true;
227 _parent->child_changed ();
232 Group::add_items_at_point (Duple const point, vector<Item const *>& items) const
234 boost::optional<Rect> const bbox = bounding_box ();
236 if (!bbox || !bbox.get().contains (point)) {
240 Item::add_items_at_point (point, items);
244 vector<Item*> our_items = _lut->items_at_point (point);
245 for (vector<Item*>::iterator i = our_items.begin(); i != our_items.end(); ++i) {
246 (*i)->add_items_at_point (point - (*i)->position(), items);
251 Group::dump (ostream& o) const
253 o << _canvas->indent();
254 o << "Group " << this << " [" << name << ']';
255 o << " @ " << position();
256 o << " Items: " << _items.size();
257 o << " Visible ? " << _visible;
259 boost::optional<Rect> bb = bounding_box();
262 o << endl << _canvas->indent() << " bbox: " << bb.get();
263 o << endl << _canvas->indent() << " CANVAS bbox: " << item_to_canvas (bb.get());
270 ArdourCanvas::dump_depth++;
272 for (list<Item*>::const_iterator i = _items.begin(); i != _items.end(); ++i) {
276 ArdourCanvas::dump_depth--;