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_factory.h"
12 #include "canvas/item.h"
13 #include "canvas/canvas.h"
16 using namespace ArdourCanvas;
18 int Group::default_items_per_cell = 64;
21 Group::Group (Canvas* canvas)
28 Group::Group (Group* parent)
35 Group::Group (Group* parent, Duple position)
36 : Item (parent, position)
44 for (list<Item*>::iterator i = _items.begin(); i != _items.end(); ++i) {
51 /** @param area Area to draw in this group's coordinates.
52 * @param context Context, set up with its origin at this group's position.
55 Group::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
58 vector<Item*> items = _lut->get (area);
63 if (DEBUG_ENABLED(PBD::DEBUG::CanvasRender)) {
64 cerr << string_compose ("%1GROUP %2 render %3 items out of %4\n",
65 _canvas->render_indent(), (name.empty() ? string ("[unnamed]") : name), items.size(), _items.size());
69 for (vector<Item*>::const_iterator i = items.begin(); i != items.end(); ++i) {
71 if (!(*i)->visible ()) {
73 if (DEBUG_ENABLED(PBD::DEBUG::CanvasRender)) {
74 cerr << _canvas->render_indent() << "Item " << (*i)->whatami() << ' ' << (*i)->name << " invisible - skipped\n";
80 boost::optional<Rect> item_bbox = (*i)->bounding_box ();
84 if (DEBUG_ENABLED(PBD::DEBUG::CanvasRender)) {
85 cerr << _canvas->render_indent() << "Item " << (*i)->whatami() << ' ' << (*i)->name << " empty - skipped\n";
91 /* convert the render area to our child's coordinates */
92 Rect const item_area = (*i)->parent_to_item (area);
94 /* intersect the child's render area with the child's bounding box */
95 boost::optional<Rect> r = item_bbox.get().intersection (item_area);
98 /* render the intersection */
100 context->translate ((*i)->position().x, (*i)->position().y);
102 if (DEBUG_ENABLED(PBD::DEBUG::CanvasRender)) {
103 cerr << string_compose ("%1render %2 %3\n", _canvas->render_indent(), (*i)->whatami(),
107 (*i)->render (r.get(), context);
112 if (DEBUG_ENABLED(PBD::DEBUG::CanvasRender)) {
113 cerr << string_compose ("%1skip render of %2 %3, no intersection\n", _canvas->render_indent(), (*i)->whatami(),
124 Group::compute_bounding_box () const
127 bool have_one = false;
129 for (list<Item*>::const_iterator i = _items.begin(); i != _items.end(); ++i) {
130 boost::optional<Rect> item_bbox = (*i)->bounding_box ();
135 Rect group_bbox = (*i)->item_to_parent (item_bbox.get ());
137 bbox = bbox.extend (group_bbox);
145 _bounding_box = boost::optional<Rect> ();
147 _bounding_box = bbox;
150 _bounding_box_dirty = false;
156 _items.push_back (i);
158 _bounding_box_dirty = true;
160 DEBUG_TRACE (PBD::DEBUG::CanvasItemsDirtied, "canvas item dirty: group add\n");
164 Group::remove (Item* i)
168 _bounding_box_dirty = true;
170 DEBUG_TRACE (PBD::DEBUG::CanvasItemsDirtied, "canvas item dirty: group remove\n");
174 Group::raise_child_to_top (Item* i)
177 _items.push_back (i);
182 Group::raise_child (Item* i, int levels)
184 list<Item*>::iterator j = find (_items.begin(), _items.end(), i);
185 assert (j != _items.end ());
190 while (levels > 0 && j != _items.end ()) {
195 _items.insert (j, i);
200 Group::lower_child_to_bottom (Item* i)
203 _items.push_front (i);
208 Group::ensure_lut () const
211 _lut = new DumbLookupTable (*this);
216 Group::invalidate_lut () const
223 Group::child_changed ()
226 _bounding_box_dirty = true;
229 _parent->child_changed ();
234 Group::add_items_at_point (Duple const point, vector<Item const *>& items) const
236 boost::optional<Rect> const bbox = bounding_box ();
238 if (!bbox || !bbox.get().contains (point)) {
242 Item::add_items_at_point (point, items);
246 vector<Item*> our_items = _lut->items_at_point (point);
247 for (vector<Item*>::iterator i = our_items.begin(); i != our_items.end(); ++i) {
248 (*i)->add_items_at_point (point - (*i)->position(), items);
253 Group::get_state () const
255 XMLNode* node = new XMLNode ("Group");
256 for (list<Item*>::const_iterator i = _items.begin(); i != _items.end(); ++i) {
257 node->add_child_nocopy (*(*i)->get_state ());
260 add_item_state (node);
265 Group::set_state (XMLNode const * node)
267 set_item_state (node);
269 XMLNodeList const & children = node->children ();
270 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
271 /* this will create the item and add it to this group */
272 create_item (this, *i);
277 Group::dump (ostream& o) const
279 o << _canvas->indent();
280 o << "Group " << this;
281 o << " Items: " << _items.size();
283 boost::optional<Rect> bb = bounding_box();
286 o << endl << _canvas->indent() << " bbox: " << bb.get();
293 ArdourCanvas::dump_depth++;
295 for (list<Item*>::const_iterator i = _items.begin(); i != _items.end(); ++i) {
299 ArdourCanvas::dump_depth--;