2 #include <cairomm/context.h>
4 #include "pbd/stacktrace.h"
5 #include "pbd/compose.h"
8 #include "canvas/group.h"
9 #include "canvas/types.h"
10 #include "canvas/debug.h"
11 #include "canvas/item.h"
12 #include "canvas/canvas.h"
15 using namespace ArdourCanvas;
17 int Group::default_items_per_cell = 64;
20 Group::Group (Canvas* canvas)
27 Group::Group (Group* parent)
34 Group::Group (Group* parent, Duple position)
35 : Item (parent, position)
43 for (list<Item*>::iterator i = _items.begin(); i != _items.end(); ++i) {
50 /** @param area Area to draw in this group's coordinates.
51 * @param context Context, set up with its origin at this group's position.
54 Group::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
57 vector<Item*> items = _lut->get (area);
62 if (DEBUG_ENABLED(PBD::DEBUG::CanvasRender)) {
63 cerr << string_compose ("%1GROUP %2 render %3 items out of %4\n",
64 _canvas->render_indent(), (name.empty() ? string ("[unnamed]") : name), items.size(), _items.size());
68 for (vector<Item*>::const_iterator i = items.begin(); i != items.end(); ++i) {
70 if (!(*i)->visible ()) {
72 if (DEBUG_ENABLED(PBD::DEBUG::CanvasRender)) {
73 cerr << _canvas->render_indent() << "Item " << (*i)->whatami() << " [" << (*i)->name << "] invisible - skipped\n";
79 boost::optional<Rect> item_bbox = (*i)->bounding_box ();
83 if (DEBUG_ENABLED(PBD::DEBUG::CanvasRender)) {
84 cerr << _canvas->render_indent() << "Item " << (*i)->whatami() << " [" << (*i)->name << "] empty - skipped\n";
90 /* convert the render area to our child's coordinates */
91 Rect const item_area = (*i)->parent_to_item (area);
93 /* intersect the child's render area with the child's bounding box */
94 boost::optional<Rect> r = item_bbox.get().intersection (item_area);
97 /* render the intersection */
99 context->translate ((*i)->position().x, (*i)->position().y);
101 if (DEBUG_ENABLED(PBD::DEBUG::CanvasRender)) {
102 cerr << string_compose ("%1render %2 %3\n", _canvas->render_indent(), (*i)->whatami(),
106 (*i)->render (r.get(), context);
111 if (DEBUG_ENABLED(PBD::DEBUG::CanvasRender)) {
112 cerr << string_compose ("%1skip render of %2 %3, no intersection\n", _canvas->render_indent(), (*i)->whatami(),
123 Group::compute_bounding_box () const
126 bool have_one = false;
128 for (list<Item*>::const_iterator i = _items.begin(); i != _items.end(); ++i) {
129 boost::optional<Rect> item_bbox = (*i)->bounding_box ();
134 Rect group_bbox = (*i)->item_to_parent (item_bbox.get ());
136 bbox = bbox.extend (group_bbox);
144 _bounding_box = boost::optional<Rect> ();
146 _bounding_box = bbox;
149 _bounding_box_dirty = false;
155 _items.push_back (i);
157 _bounding_box_dirty = true;
159 DEBUG_TRACE (PBD::DEBUG::CanvasItemsDirtied, "canvas item dirty: group add\n");
163 Group::remove (Item* i)
167 _bounding_box_dirty = true;
169 DEBUG_TRACE (PBD::DEBUG::CanvasItemsDirtied, "canvas item dirty: group remove\n");
173 Group::raise_child_to_top (Item* i)
176 _items.push_back (i);
181 Group::raise_child (Item* i, int levels)
183 list<Item*>::iterator j = find (_items.begin(), _items.end(), i);
184 assert (j != _items.end ());
189 while (levels > 0 && j != _items.end ()) {
194 _items.insert (j, i);
199 Group::lower_child_to_bottom (Item* i)
202 _items.push_front (i);
207 Group::ensure_lut () const
210 _lut = new DumbLookupTable (*this);
215 Group::invalidate_lut () const
222 Group::child_changed ()
225 _bounding_box_dirty = true;
228 _parent->child_changed ();
233 Group::add_items_at_point (Duple const point, vector<Item const *>& items) const
235 boost::optional<Rect> const bbox = bounding_box ();
237 if (!bbox || !bbox.get().contains (point)) {
241 Item::add_items_at_point (point, items);
245 vector<Item*> our_items = _lut->items_at_point (point);
246 for (vector<Item*>::iterator i = our_items.begin(); i != our_items.end(); ++i) {
247 (*i)->add_items_at_point (point - (*i)->position(), items);
252 Group::dump (ostream& o) const
254 o << _canvas->indent();
255 o << "Group " << this << " [" << name << ']';
256 o << " @ " << position();
257 o << " Items: " << _items.size();
258 o << " Visible ? " << _visible;
260 boost::optional<Rect> bb = bounding_box();
263 o << endl << _canvas->indent() << " bbox: " << bb.get();
264 o << endl << _canvas->indent() << " CANVAS bbox: " << item_to_canvas (bb.get());
271 ArdourCanvas::dump_depth++;
273 for (list<Item*>::const_iterator i = _items.begin(); i != _items.end(); ++i) {
277 ArdourCanvas::dump_depth--;