X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fcanvas%2Fitem.cc;h=e4e3c3054667ee54143bd67435933178a5e9da2e;hb=e36f74e071d4c14862d23da5ff0d49df0940d536;hp=4108c0e0d6b4eafd919ec848028b18761041abe0;hpb=84fb0a8dceda063d58b946cb891c3e21214c8f75;p=ardour.git diff --git a/libs/canvas/item.cc b/libs/canvas/item.cc index 4108c0e0d6..e4e3c30546 100644 --- a/libs/canvas/item.cc +++ b/libs/canvas/item.cc @@ -1,6 +1,24 @@ +/* + Copyright (C) 2011-2013 Paul Davis + Author: Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + #include "pbd/compose.h" #include "pbd/stacktrace.h" -#include "pbd/xml++.h" #include "pbd/convert.h" #include "ardour/utils.h" @@ -52,13 +70,13 @@ Item::init () Item::~Item () { - if (_canvas) { - _canvas->item_going_away (this, _bounding_box); - } - if (_parent) { _parent->remove (this); } + + if (_canvas) { + _canvas->item_going_away (this, _bounding_box); + } } ArdourCanvas::Rect @@ -109,6 +127,20 @@ Item::canvas_to_item (ArdourCanvas::Duple const & d) const return d.translate (offset); } +ArdourCanvas::Rect +Item::canvas_to_item (ArdourCanvas::Rect const & d) const +{ + Item const * i = this; + Duple offset; + + while (i) { + offset = offset.translate (-(i->position())); + i = i->parent(); + } + + return d.translate (offset); +} + void Item::item_to_canvas (Coord& x, Coord& y) const { @@ -127,10 +159,32 @@ Item::canvas_to_item (Coord& x, Coord& y) const y = d.y; } +Duple +Item::item_to_window (ArdourCanvas::Duple const & d) const +{ + return _canvas->canvas_to_window (item_to_canvas (d)); +} + +Duple +Item::window_to_item (ArdourCanvas::Duple const & d) const +{ + return _canvas->window_to_canvas (canvas_to_item (d)); +} + +ArdourCanvas::Rect +Item::item_to_window (ArdourCanvas::Rect const & r) const +{ + return _canvas->canvas_to_window (item_to_canvas (r)); +} + /** Set the position of this item in the parent's coordinates */ void Item::set_position (Duple p) { + if (p == _position) { + return; + } + boost::optional bbox = bounding_box (); boost::optional pre_change_parent_bounding_box; @@ -186,15 +240,19 @@ Item::lower_to_bottom () void Item::hide () { - _visible = false; - _canvas->item_shown_or_hidden (this); + if (_visible) { + _visible = false; + _canvas->item_shown_or_hidden (this); + } } void Item::show () { - _visible = true; - _canvas->item_shown_or_hidden (this); + if (!_visible) { + _visible = true; + _canvas->item_shown_or_hidden (this); + } } Duple @@ -218,13 +276,14 @@ Item::parent_to_item (ArdourCanvas::Rect const & d) const void Item::unparent () { - _canvas = 0; _parent = 0; } void Item::reparent (Group* new_parent) { + assert (_canvas == _parent->canvas()); + if (_parent) { _parent->remove (this); } @@ -236,6 +295,103 @@ Item::reparent (Group* new_parent) _parent->add (this); } +bool +Item::common_ancestor_within (uint32_t limit, const Item& other) const +{ + uint32_t d1 = depth(); + 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 + */ + + while (d1 != d2) { + if (d1 > d2) { + i1 = i1->parent(); + d1--; + limit--; + } else { + i2 = i2->parent(); + d2--; + limit--; + } + if (limit == 0) { + return false; + } + } + + /* now see if there is a common parent */ + + while (i1 != i2) { + if (i1) { + i1 = i1->parent(); + } + if (i2) { + i2 = i2->parent (); + } + + limit--; + if (limit == 0) { + return false; + } + } + + return true; +} + +const Item* +Item::closest_ancestor_with (const Item& other) const +{ + uint32_t d1 = depth(); + 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 + */ + + while (d1 != d2) { + if (d1 > d2) { + i1 = i1->parent(); + d1--; + } else { + i2 = i2->parent(); + d2--; + } + } + + /* now see if there is a common parent */ + + while (i1 != i2) { + if (i1) { + i1 = i1->parent(); + } + if (i2) { + i2 = i2->parent (); + } + } + + return i1; +} + +bool +Item::is_descendant_of (const Item& candidate) const +{ + Item const * i = _parent; + + while (i) { + if (i == &candidate) { + return true; + } + i = i->parent(); + } + + return false; +} + void Item::grab_focus () { @@ -248,9 +404,9 @@ Item::bounding_box () const { if (_bounding_box_dirty) { compute_bounding_box (); + assert (!_bounding_box_dirty); } - assert (!_bounding_box_dirty); return _bounding_box; } @@ -277,7 +433,14 @@ Item::width () const return 0; } -/* XXX may be called even if bbox is not changing ... bit grotty */ +void +Item::redraw () const +{ + if (_visible && _bounding_box && _canvas) { + _canvas->request_redraw (item_to_canvas (_bounding_box.get())); + } +} + void Item::begin_change () { @@ -294,6 +457,17 @@ Item::end_change () } } +void +Item::begin_visual_change () +{ +} + +void +Item::end_visual_change () +{ + _canvas->item_visual_property_changed (this); +} + void Item::move (Duple movement) { @@ -342,7 +516,7 @@ Item::dump (ostream& o) const { boost::optional bb = bounding_box(); - o << _canvas->indent() << whatami() << ' ' << this; + o << _canvas->indent() << whatami() << ' ' << this << " Visible ? " << _visible; o << " @ " << position(); #ifdef CANVAS_DEBUG @@ -368,9 +542,40 @@ Item::whatami () const return type.substr (type.find_last_of (':') + 1); } +uint32_t +Item::depth () const +{ + Item* i = _parent; + int d = 0; + while (i) { + ++d; + i = i->parent(); + } + return d; +} + +bool +Item::covers (Duple const & point) const +{ + Duple p = canvas_to_item (point); + + if (_bounding_box_dirty) { + compute_bounding_box (); + } + + boost::optional r = bounding_box(); + + if (!r) { + return false; + } + + return r.get().contains (p); +} + ostream& ArdourCanvas::operator<< (ostream& o, const Item& i) { i.dump (o); return o; } +