328 lines
4.9 KiB
C++
328 lines
4.9 KiB
C++
#include "pbd/compose.h"
|
|
#include "pbd/stacktrace.h"
|
|
#include "pbd/xml++.h"
|
|
#include "pbd/convert.h"
|
|
|
|
#include "ardour/utils.h"
|
|
|
|
#include "canvas/group.h"
|
|
#include "canvas/item.h"
|
|
#include "canvas/canvas.h"
|
|
#include "canvas/debug.h"
|
|
|
|
using namespace std;
|
|
using namespace PBD;
|
|
using namespace ArdourCanvas;
|
|
|
|
Item::Item (Canvas* canvas)
|
|
: _canvas (canvas)
|
|
, _parent (0)
|
|
{
|
|
init ();
|
|
}
|
|
|
|
Item::Item (Group* parent)
|
|
: _parent (parent)
|
|
{
|
|
assert (parent);
|
|
_canvas = _parent->canvas ();
|
|
|
|
init ();
|
|
}
|
|
|
|
Item::Item (Group* parent, Duple position)
|
|
: _parent (parent)
|
|
, _position (position)
|
|
{
|
|
assert (parent);
|
|
_canvas = _parent->canvas ();
|
|
|
|
init ();
|
|
}
|
|
|
|
void
|
|
Item::init ()
|
|
{
|
|
_visible = true;
|
|
_bounding_box_dirty = true;
|
|
_ignore_events = false;
|
|
|
|
if (_parent) {
|
|
_parent->add (this);
|
|
}
|
|
|
|
DEBUG_TRACE (DEBUG::CanvasItems, string_compose ("new canvas item %1\n", this));
|
|
}
|
|
|
|
Item::~Item ()
|
|
{
|
|
_canvas->item_going_away (this, _bounding_box);
|
|
|
|
if (_parent) {
|
|
_parent->remove (this);
|
|
}
|
|
}
|
|
|
|
Rect
|
|
Item::item_to_parent (Rect const & r) const
|
|
{
|
|
return r.translate (_position);
|
|
}
|
|
|
|
/** Set the position of this item in the parent's coordinates */
|
|
void
|
|
Item::set_position (Duple p)
|
|
{
|
|
boost::optional<Rect> bbox = bounding_box ();
|
|
boost::optional<Rect> pre_change_parent_bounding_box;
|
|
if (bbox) {
|
|
pre_change_parent_bounding_box = item_to_parent (bbox.get());
|
|
}
|
|
|
|
_position = p;
|
|
|
|
_canvas->item_moved (this, pre_change_parent_bounding_box);
|
|
|
|
if (_parent) {
|
|
_parent->child_changed ();
|
|
}
|
|
}
|
|
|
|
void
|
|
Item::set_x_position (Coord x)
|
|
{
|
|
set_position (Duple (x, _position.y));
|
|
}
|
|
|
|
void
|
|
Item::set_y_position (Coord y)
|
|
{
|
|
set_position (Duple (_position.x, y));
|
|
}
|
|
|
|
void
|
|
Item::raise_to_top ()
|
|
{
|
|
assert (_parent);
|
|
_parent->raise_child_to_top (this);
|
|
}
|
|
|
|
void
|
|
Item::raise (int levels)
|
|
{
|
|
assert (_parent);
|
|
_parent->raise_child (this, levels);
|
|
}
|
|
|
|
void
|
|
Item::lower_to_bottom ()
|
|
{
|
|
assert (_parent);
|
|
_parent->lower_child_to_bottom (this);
|
|
}
|
|
|
|
void
|
|
Item::hide ()
|
|
{
|
|
_visible = false;
|
|
_canvas->item_shown_or_hidden (this);
|
|
}
|
|
|
|
void
|
|
Item::show ()
|
|
{
|
|
_visible = true;
|
|
_canvas->item_shown_or_hidden (this);
|
|
}
|
|
|
|
Duple
|
|
Item::item_to_parent (Duple const & d) const
|
|
{
|
|
return d.translate (_position);
|
|
}
|
|
|
|
Duple
|
|
Item::parent_to_item (Duple const & d) const
|
|
{
|
|
return d.translate (- _position);
|
|
}
|
|
|
|
Rect
|
|
Item::parent_to_item (Rect const & d) const
|
|
{
|
|
return d.translate (- _position);
|
|
}
|
|
|
|
void
|
|
Item::unparent ()
|
|
{
|
|
_canvas = 0;
|
|
_parent = 0;
|
|
}
|
|
|
|
void
|
|
Item::reparent (Group* new_parent)
|
|
{
|
|
if (_parent) {
|
|
_parent->remove (this);
|
|
}
|
|
|
|
assert (new_parent);
|
|
|
|
_parent = new_parent;
|
|
_canvas = _parent->canvas ();
|
|
_parent->add (this);
|
|
}
|
|
|
|
void
|
|
Item::grab_focus ()
|
|
{
|
|
/* XXX */
|
|
}
|
|
|
|
/** @return Bounding box in this item's coordinates */
|
|
boost::optional<Rect>
|
|
Item::bounding_box () const
|
|
{
|
|
if (_bounding_box_dirty) {
|
|
compute_bounding_box ();
|
|
}
|
|
|
|
assert (!_bounding_box_dirty);
|
|
return _bounding_box;
|
|
}
|
|
|
|
Coord
|
|
Item::height () const
|
|
{
|
|
boost::optional<Rect> bb = bounding_box().get();
|
|
return bb->height ();
|
|
}
|
|
|
|
Coord
|
|
Item::width () const
|
|
{
|
|
boost::optional<Rect> bb = bounding_box().get();
|
|
return bb->width ();
|
|
}
|
|
|
|
/* XXX may be called even if bbox is not changing ... bit grotty */
|
|
void
|
|
Item::begin_change ()
|
|
{
|
|
_pre_change_bounding_box = bounding_box ();
|
|
}
|
|
|
|
void
|
|
Item::end_change ()
|
|
{
|
|
_canvas->item_changed (this, _pre_change_bounding_box);
|
|
|
|
if (_parent) {
|
|
_parent->child_changed ();
|
|
}
|
|
}
|
|
|
|
void
|
|
Item::move (Duple movement)
|
|
{
|
|
set_position (position() + movement);
|
|
}
|
|
|
|
void
|
|
Item::add_item_state (XMLNode* node) const
|
|
{
|
|
node->add_property ("x-position", string_compose ("%1", _position.x));
|
|
node->add_property ("y-position", string_compose ("%1", _position.y));
|
|
node->add_property ("visible", _visible ? "yes" : "no");
|
|
}
|
|
|
|
void
|
|
Item::set_item_state (XMLNode const * node)
|
|
{
|
|
_position.x = atof (node->property("x-position")->value().c_str());
|
|
_position.y = atof (node->property("y-position")->value().c_str());
|
|
_visible = PBD::string_is_affirmative (node->property("visible")->value());
|
|
}
|
|
|
|
void
|
|
Item::grab ()
|
|
{
|
|
assert (_canvas);
|
|
_canvas->grab (this);
|
|
}
|
|
|
|
void
|
|
Item::ungrab ()
|
|
{
|
|
assert (_canvas);
|
|
_canvas->ungrab ();
|
|
}
|
|
|
|
void
|
|
Item::set_data (string const & key, void* data)
|
|
{
|
|
_data[key] = data;
|
|
}
|
|
|
|
void *
|
|
Item::get_data (string const & key) const
|
|
{
|
|
map<string, void*>::const_iterator i = _data.find (key);
|
|
if (i == _data.end ()) {
|
|
return 0;
|
|
}
|
|
|
|
return i->second;
|
|
}
|
|
|
|
void
|
|
Item::item_to_canvas (Coord& x, Coord& y) const
|
|
{
|
|
Duple d (x, y);
|
|
Item const * i = this;
|
|
|
|
while (i) {
|
|
d = i->item_to_parent (d);
|
|
i = i->_parent;
|
|
}
|
|
|
|
x = d.x;
|
|
y = d.y;
|
|
}
|
|
|
|
void
|
|
Item::canvas_to_item (Coord& x, Coord& y) const
|
|
{
|
|
Duple d (x, y);
|
|
Item const * i = this;
|
|
|
|
while (i) {
|
|
d = i->parent_to_item (d);
|
|
i = i->_parent;
|
|
}
|
|
|
|
x = d.x;
|
|
y = d.y;
|
|
}
|
|
|
|
Rect
|
|
Item::item_to_canvas (Rect const & area) const
|
|
{
|
|
Rect r = area;
|
|
Item const * i = this;
|
|
|
|
while (i) {
|
|
r = i->item_to_parent (r);
|
|
i = i->parent ();
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
void
|
|
Item::set_ignore_events (bool ignore)
|
|
{
|
|
_ignore_events = ignore;
|
|
}
|