Reimplementation of large parts of the WaveView class
[ardour.git] / libs / canvas / item.cc
index ab68ea2e9512b50666612af13d196e1a18676db8..98fe6362dba6298711206ee0bbb7a930f83ea12f 100644 (file)
@@ -18,7 +18,7 @@
 */
 
 #include "pbd/compose.h"
-#include "pbd/stacktrace.h"
+#include "pbd/demangle.h"
 #include "pbd/convert.h"
 
 #include "ardour/utils.h"
@@ -46,7 +46,7 @@ Item::Item (Canvas* canvas)
        , _ignore_events (false)
 {
        DEBUG_TRACE (DEBUG::CanvasItems, string_compose ("new canvas item %1\n", this));
-}      
+}
 
 Item::Item (Item* parent)
        : Fill (*this)
@@ -66,7 +66,7 @@ Item::Item (Item* parent)
        }
 
        find_scroll_parent ();
-}      
+}
 
 Item::Item (Item* parent, Duple const& p)
        : Fill (*this)
@@ -88,7 +88,7 @@ Item::Item (Item* parent, Duple const& p)
 
        find_scroll_parent ();
 
-}      
+}
 
 Item::~Item ()
 {
@@ -196,7 +196,7 @@ void
 Item::item_to_canvas (Coord& x, Coord& y) const
 {
        Duple d = item_to_canvas (Duple (x, y));
-               
+
        x = d.x;
        y = d.y;
 }
@@ -259,25 +259,25 @@ Item::set_position (Duple p)
                return;
        }
 
-       boost::optional<ArdourCanvas::Rect> bbox = bounding_box ();
-       boost::optional<ArdourCanvas::Rect> pre_change_parent_bounding_box;
+       ArdourCanvas::Rect bbox = bounding_box ();
+       ArdourCanvas::Rect pre_change_parent_bounding_box;
 
        if (bbox) {
                /* see the comment in Canvas::item_moved() to understand
                 * why we use the parent's bounding box here.
                 */
-               pre_change_parent_bounding_box = item_to_parent (bbox.get());
+               pre_change_parent_bounding_box = item_to_parent (bbox);
        }
-       
+
        _position = p;
 
        /* only update canvas and parent if visible. Otherwise, this
           will be done when ::show() is called.
        */
-       
+
        if (visible()) {
                _canvas->item_moved (this, pre_change_parent_bounding_box);
-               
+
 
                if (_parent) {
                        _parent->child_changed ();
@@ -347,7 +347,7 @@ Item::hide ()
                        }
                }
 
-               
+
                propagate_show_hide ();
        }
 }
@@ -376,11 +376,11 @@ void
 Item::propagate_show_hide ()
 {
        /* bounding box may have changed while we were hidden */
-       
+
        if (_parent) {
                _parent->child_changed ();
        }
-       
+
        _canvas->item_shown_or_hidden (this);
 }
 
@@ -410,7 +410,7 @@ Item::unparent ()
 }
 
 void
-Item::reparent (Item* new_parent)
+Item::reparent (Item* new_parent, bool already_added)
 {
        if (new_parent == _parent) {
                return;
@@ -429,7 +429,9 @@ Item::reparent (Item* new_parent)
 
        find_scroll_parent ();
 
-       _parent->add (this);
+       if (!already_added) {
+               _parent->add (this);
+       }
 }
 
 void
@@ -450,7 +452,7 @@ Item::find_scroll_parent ()
                }
                i = i->parent();
        }
-       
+
        _scroll_parent = const_cast<ScrollGroup*> (last_scroll_group);
 }
 
@@ -461,7 +463,7 @@ Item::common_ancestor_within (uint32_t limit, const Item& other) const
        uint32_t d2 = other.depth();
        const Item* i1 = this;
        const Item* i2 = &other;
-       
+
        /* move towards root until we are at the same level
           for both items
        */
@@ -502,7 +504,7 @@ Item::common_ancestor_within (uint32_t limit, const Item& other) const
                        return false;
                }
        }
-       
+
        return true;
 }
 
@@ -544,7 +546,7 @@ Item::closest_ancestor_with (const Item& other) const
                        i2 = i2->parent ();
                }
        }
-       
+
        return i1;
 }
 
@@ -569,9 +571,15 @@ Item::grab_focus ()
        /* XXX */
 }
 
+void
+Item::size_allocate (Rect const & r)
+{
+       _allocation = r;
+}
+
 /** @return Bounding box in this item's coordinates */
-boost::optional<ArdourCanvas::Rect>
-Item::bounding_box () const
+ArdourCanvas::Rect
+Item::bounding_box (bool for_own_purposes) const
 {
        if (_bounding_box_dirty) {
                compute_bounding_box ();
@@ -579,16 +587,22 @@ Item::bounding_box () const
                add_child_bounding_boxes ();
        }
 
+       if (!for_own_purposes) {
+               if (_allocation) {
+                       return _allocation;
+               }
+       }
+
        return _bounding_box;
 }
 
 Coord
 Item::height () const
 {
-       boost::optional<ArdourCanvas::Rect> bb  = bounding_box();
+       ArdourCanvas::Rect bb  = bounding_box();
 
        if (bb) {
-               return bb->height ();
+               return bb.height ();
        }
        return 0;
 }
@@ -596,10 +610,10 @@ Item::height () const
 Coord
 Item::width () const
 {
-       boost::optional<ArdourCanvas::Rect> bb = bounding_box();
+       ArdourCanvas::Rect bb = bounding_box();
 
        if (bb) {
-               return bb->width ();
+               return bb.width ();
        }
 
        return 0;
@@ -609,9 +623,9 @@ void
 Item::redraw () const
 {
        if (visible() && _bounding_box && _canvas) {
-               _canvas->request_redraw (item_to_window (_bounding_box.get()));
+               _canvas->request_redraw (item_to_window (_bounding_box));
        }
-}      
+}
 
 void
 Item::begin_change ()
@@ -624,7 +638,7 @@ Item::end_change ()
 {
        if (visible()) {
                _canvas->item_changed (this, _pre_change_bounding_box);
-               
+
                if (_parent) {
                        _parent->child_changed ();
                }
@@ -677,7 +691,7 @@ Item::get_data (string const & key) const
        if (i == _data.end ()) {
                return 0;
        }
-       
+
        return i->second;
 }
 
@@ -715,13 +729,13 @@ Item::covers (Duple const & point) const
                compute_bounding_box ();
        }
 
-       boost::optional<Rect> r = bounding_box();
+       Rect r = bounding_box();
 
        if (!r) {
                return false;
        }
 
-       return r.get().contains (p);
+       return r.contains (p);
 }
 
 /* nesting/grouping API */
@@ -745,7 +759,7 @@ Item::render_children (Rect const & area, Cairo::RefPtr<Cairo::Context> context)
 #endif
 
        ++render_depth;
-               
+
        for (std::vector<Item*>::const_iterator i = items.begin(); i != items.end(); ++i) {
 
                if (!(*i)->visible ()) {
@@ -756,8 +770,8 @@ Item::render_children (Rect const & area, Cairo::RefPtr<Cairo::Context> context)
 #endif
                        continue;
                }
-               
-               boost::optional<Rect> item_bbox = (*i)->bounding_box ();
+
+               Rect item_bbox = (*i)->bounding_box ();
 
                if (!item_bbox) {
 #ifdef CANVAS_DEBUG
@@ -767,12 +781,12 @@ Item::render_children (Rect const & area, Cairo::RefPtr<Cairo::Context> context)
 #endif
                        continue;
                }
-               
-               Rect item = (*i)->item_to_window (item_bbox.get(), false);
-               boost::optional<Rect> d = item.intersection (area);
-               
+
+               Rect item = (*i)->item_to_window (item_bbox, false);
+               Rect d = item.intersection (area);
+
                if (d) {
-                       Rect draw = d.get();
+                       Rect draw = d;
                        if (draw.width() && draw.height()) {
 #ifdef CANVAS_DEBUG
                                if (DEBUG_ENABLED(PBD::DEBUG::CanvasRender)) {
@@ -785,7 +799,7 @@ Item::render_children (Rect const & area, Cairo::RefPtr<Cairo::Context> context)
                                                     << ' '
                                                     << (*i)->name
                                                     << " item "
-                                                    << item_bbox.get()
+                                                    << item_bbox
                                                     << " window = "
                                                     << item
                                                     << " intersect = "
@@ -817,30 +831,67 @@ Item::render_children (Rect const & area, Cairo::RefPtr<Cairo::Context> context)
 }
 
 void
-Item::add_child_bounding_boxes() const
+Item::prepare_for_render_children (Rect const & area) const
 {
-       boost::optional<Rect> self;
+       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
+Item::add_child_bounding_boxes (bool include_hidden) const
+{
+       Rect self;
        Rect bbox;
        bool have_one = false;
 
        if (_bounding_box) {
-               bbox = _bounding_box.get();
+               bbox = _bounding_box;
                have_one = true;
        }
 
        for (list<Item*>::const_iterator i = _items.begin(); i != _items.end(); ++i) {
 
-               if (!(*i)->visible()) {
+               if (!(*i)->visible() && !include_hidden) {
                        continue;
                }
 
-               boost::optional<Rect> item_bbox = (*i)->bounding_box ();
+               Rect item_bbox = (*i)->bounding_box ();
 
                if (!item_bbox) {
                        continue;
                }
 
-               Rect group_bbox = (*i)->item_to_parent (item_bbox.get ());
+               Rect group_bbox = (*i)->item_to_parent (item_bbox);
                if (have_one) {
                        bbox = bbox.extend (group_bbox);
                } else {
@@ -850,7 +901,7 @@ Item::add_child_bounding_boxes() const
        }
 
        if (!have_one) {
-               _bounding_box = boost::optional<Rect> ();
+               _bounding_box = Rect ();
        } else {
                _bounding_box = bbox;
        }
@@ -862,7 +913,18 @@ Item::add (Item* i)
        /* XXX should really notify canvas about this */
 
        _items.push_back (i);
-       i->reparent (this);
+       i->reparent (this, true);
+       invalidate_lut ();
+       _bounding_box_dirty = true;
+}
+
+void
+Item::add_front (Item* i)
+{
+       /* XXX should really notify canvas about this */
+
+       _items.push_front (i);
+       i->reparent (this, true);
        invalidate_lut ();
        _bounding_box_dirty = true;
 }
@@ -891,7 +953,7 @@ Item::remove (Item* i)
        _items.remove (i);
        invalidate_lut ();
        _bounding_box_dirty = true;
-       
+
        end_change ();
 }
 
@@ -925,7 +987,7 @@ Item::clear_items (bool with_delete)
 
                _items.erase (i);
                item->unparent ();
-               
+
                if (with_delete) {
                        delete item;
                }
@@ -1012,11 +1074,11 @@ Item::child_changed ()
 void
 Item::add_items_at_point (Duple const point, vector<Item const *>& items) const
 {
-       boost::optional<Rect> const bbox = bounding_box ();
+       Rect const bbox = bounding_box ();
 
        /* Point is in window coordinate system */
 
-       if (!bbox || !item_to_window (bbox.get()).contains (point)) {
+       if (!bbox || !item_to_window (bbox).contains (point)) {
                return;
        }
 
@@ -1065,11 +1127,11 @@ Item::stop_tooltip_timeout ()
 void
 Item::dump (ostream& o) const
 {
-       boost::optional<ArdourCanvas::Rect> bb = bounding_box();
+       ArdourCanvas::Rect bb = bounding_box();
 
        o << _canvas->indent() << whatami() << ' ' << this << " self-Visible ? " << self_visible() << " visible ? " << visible();
        o << " @ " << position();
-       
+
 #ifdef CANVAS_DEBUG
        if (!name.empty()) {
                o << ' ' << name;
@@ -1077,8 +1139,8 @@ Item::dump (ostream& o) const
 #endif
 
        if (bb) {
-               o << endl << _canvas->indent() << "\tbbox: " << bb.get();
-               o << endl << _canvas->indent() << "\tCANVAS bbox: " << item_to_canvas (bb.get());
+               o << endl << _canvas->indent() << "\tbbox: " << bb;
+               o << endl << _canvas->indent() << "\tCANVAS bbox: " << item_to_canvas (bb);
        } else {
                o << " bbox unset";
        }
@@ -1093,25 +1155,25 @@ Item::dump (ostream& o) const
                o << " Items: " << _items.size();
                o << " Self-Visible ? " << self_visible();
                o << " Visible ? " << visible();
-               
-               boost::optional<Rect> bb = bounding_box();
-               
+
+               Rect bb = bounding_box();
+
                if (bb) {
-                       o << endl << _canvas->indent() << "  bbox: " << bb.get();
-                       o << endl << _canvas->indent() << "  CANVAS bbox: " << item_to_canvas (bb.get());
+                       o << endl << _canvas->indent() << "  bbox: " << bb;
+                       o << endl << _canvas->indent() << "  CANVAS bbox: " << item_to_canvas (bb);
                } else {
                        o << "  bbox unset";
                }
-               
+
                o << endl;
 #endif
-               
+
                ArdourCanvas::dump_depth++;
-               
+
                for (list<Item*>::const_iterator i = _items.begin(); i != _items.end(); ++i) {
                        o << **i;
                }
-               
+
                ArdourCanvas::dump_depth--;
        }
 }