Canvas: clear event listeners on destroy

Removing all event listeneres on destroying a canvas
prevents circular references due to Nasal event listeners
keeping a reference to the canvas in their closure.

Also fix event handling with direct children of the root
group and add some more helpers to the Canvas.
This commit is contained in:
Thomas Geymayer 2013-06-03 23:39:11 +02:00
parent c3af88dfc1
commit 7fe16d99be
8 changed files with 57 additions and 15 deletions

View File

@ -114,6 +114,9 @@ namespace canvas
//----------------------------------------------------------------------------
void Canvas::destroy()
{
if( _root_group )
_root_group->clearEventListener();
// TODO check if really not in use anymore
getProps()->getParent()
->removeChild( getProps()->getName(),
@ -185,6 +188,16 @@ namespace canvas
);
}
//----------------------------------------------------------------------------
GroupPtr Canvas::getOrCreateGroup(const std::string& name)
{
GroupPtr group = getGroup(name);
if( group )
return group;
return createGroup(name);
}
//----------------------------------------------------------------------------
GroupPtr Canvas::getRootGroup()
{

View File

@ -102,8 +102,25 @@ namespace canvas
void removeParentCanvas(const CanvasWeakPtr& canvas);
void removeChildCanvas(const CanvasWeakPtr& canvas);
/**
* Create a new group
*/
GroupPtr createGroup(const std::string& name = "");
/**
* Get an existing group with the given name
*/
GroupPtr getGroup(const std::string& name);
/**
* Get an existing group with the given name or otherwise create a new
* group
*/
GroupPtr getOrCreateGroup(const std::string& name);
/**
* Get the root group of the canvas
*/
GroupPtr getRootGroup();
/**

View File

@ -188,13 +188,12 @@ namespace canvas
// http://www.w3.org/TR/DOM-Level-3-Events/#event-flow
// Capturing phase
// for( EventTargets::iterator it = _target_path.begin();
// it != _target_path.end();
// ++it )
// for( EventPropagationPath::const_iterator it = path.begin();
// it != path.end();
// ++it )
// {
// if( it->element )
// std::cout << it->element->getProps()->getPath() << " "
// << "(" << it->local_pos.x() << "|" << it->local_pos.y() << ")\n";
// if( !it->element.expired() )
// std::cout << it->element.lock()->getProps()->getPath() << std::endl;
// }
// Bubbling phase

View File

@ -73,7 +73,7 @@ namespace canvas
// Don't check collision with root element (2nd element in _target_path)
// do event listeners attached to the canvas itself (its root group)
// always get called even if no element has been hit.
if( _target_path.size() > 2 && !el.hitBound(pos, local_pos) )
if( _target_path.size() > 1 && !el.hitBound(pos, local_pos) )
return false;
const osg::Vec2f& delta = _target_path.back().local_delta;

View File

@ -179,6 +179,12 @@ namespace canvas
return naNil();
}
//----------------------------------------------------------------------------
void Element::clearEventListener()
{
_listener.clear();
}
//----------------------------------------------------------------------------
bool Element::accept(EventVisitor& visitor)
{
@ -220,15 +226,10 @@ namespace canvas
// Drawables have a bounding box...
if( _drawable )
{
if( !_drawable->getBound().contains(osg::Vec3f(local_pos, 0)) )
return false;
}
return _drawable->getBound().contains(osg::Vec3f(local_pos, 0));
// ... for other elements, i.e. groups only a bounding sphere is available
else if( !_transform->getBound().contains(osg::Vec3f(pos, 0)) )
return false;
return true;
else
return _transform->getBound().contains(osg::Vec3f(pos, 0));
}
//----------------------------------------------------------------------------

View File

@ -85,6 +85,7 @@ namespace canvas
virtual void update(double dt);
naRef addEventListener(const nasal::CallContext& ctx);
virtual void clearEventListener();
virtual bool accept(EventVisitor& visitor);
virtual bool ascend(EventVisitor& visitor);

View File

@ -133,6 +133,15 @@ namespace canvas
return ElementPtr();
}
//----------------------------------------------------------------------------
void Group::clearEventListener()
{
BOOST_FOREACH( ChildList::value_type child, _children )
child.second->clearEventListener();
Element::clearEventListener();
}
//----------------------------------------------------------------------------
void Group::update(double dt)
{

View File

@ -57,6 +57,8 @@ namespace canvas
*/
ElementPtr getElementById(const std::string& id);
virtual void clearEventListener();
virtual void update(double dt);
virtual bool traverse(EventVisitor& visitor);