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:
@@ -114,6 +114,9 @@ namespace canvas
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void Canvas::destroy()
|
void Canvas::destroy()
|
||||||
{
|
{
|
||||||
|
if( _root_group )
|
||||||
|
_root_group->clearEventListener();
|
||||||
|
|
||||||
// TODO check if really not in use anymore
|
// TODO check if really not in use anymore
|
||||||
getProps()->getParent()
|
getProps()->getParent()
|
||||||
->removeChild( getProps()->getName(),
|
->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()
|
GroupPtr Canvas::getRootGroup()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -102,8 +102,25 @@ namespace canvas
|
|||||||
void removeParentCanvas(const CanvasWeakPtr& canvas);
|
void removeParentCanvas(const CanvasWeakPtr& canvas);
|
||||||
void removeChildCanvas(const CanvasWeakPtr& canvas);
|
void removeChildCanvas(const CanvasWeakPtr& canvas);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new group
|
||||||
|
*/
|
||||||
GroupPtr createGroup(const std::string& name = "");
|
GroupPtr createGroup(const std::string& name = "");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an existing group with the given name
|
||||||
|
*/
|
||||||
GroupPtr getGroup(const std::string& 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();
|
GroupPtr getRootGroup();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -188,13 +188,12 @@ namespace canvas
|
|||||||
// http://www.w3.org/TR/DOM-Level-3-Events/#event-flow
|
// http://www.w3.org/TR/DOM-Level-3-Events/#event-flow
|
||||||
|
|
||||||
// Capturing phase
|
// Capturing phase
|
||||||
// for( EventTargets::iterator it = _target_path.begin();
|
// for( EventPropagationPath::const_iterator it = path.begin();
|
||||||
// it != _target_path.end();
|
// it != path.end();
|
||||||
// ++it )
|
// ++it )
|
||||||
// {
|
// {
|
||||||
// if( it->element )
|
// if( !it->element.expired() )
|
||||||
// std::cout << it->element->getProps()->getPath() << " "
|
// std::cout << it->element.lock()->getProps()->getPath() << std::endl;
|
||||||
// << "(" << it->local_pos.x() << "|" << it->local_pos.y() << ")\n";
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// Bubbling phase
|
// Bubbling phase
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ namespace canvas
|
|||||||
// Don't check collision with root element (2nd element in _target_path)
|
// Don't check collision with root element (2nd element in _target_path)
|
||||||
// do event listeners attached to the canvas itself (its root group)
|
// do event listeners attached to the canvas itself (its root group)
|
||||||
// always get called even if no element has been hit.
|
// 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;
|
return false;
|
||||||
|
|
||||||
const osg::Vec2f& delta = _target_path.back().local_delta;
|
const osg::Vec2f& delta = _target_path.back().local_delta;
|
||||||
|
|||||||
@@ -179,6 +179,12 @@ namespace canvas
|
|||||||
return naNil();
|
return naNil();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void Element::clearEventListener()
|
||||||
|
{
|
||||||
|
_listener.clear();
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
bool Element::accept(EventVisitor& visitor)
|
bool Element::accept(EventVisitor& visitor)
|
||||||
{
|
{
|
||||||
@@ -220,15 +226,10 @@ namespace canvas
|
|||||||
|
|
||||||
// Drawables have a bounding box...
|
// Drawables have a bounding box...
|
||||||
if( _drawable )
|
if( _drawable )
|
||||||
{
|
return _drawable->getBound().contains(osg::Vec3f(local_pos, 0));
|
||||||
if( !_drawable->getBound().contains(osg::Vec3f(local_pos, 0)) )
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// ... for other elements, i.e. groups only a bounding sphere is available
|
// ... for other elements, i.e. groups only a bounding sphere is available
|
||||||
else if( !_transform->getBound().contains(osg::Vec3f(pos, 0)) )
|
else
|
||||||
return false;
|
return _transform->getBound().contains(osg::Vec3f(pos, 0));
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ namespace canvas
|
|||||||
virtual void update(double dt);
|
virtual void update(double dt);
|
||||||
|
|
||||||
naRef addEventListener(const nasal::CallContext& ctx);
|
naRef addEventListener(const nasal::CallContext& ctx);
|
||||||
|
virtual void clearEventListener();
|
||||||
|
|
||||||
virtual bool accept(EventVisitor& visitor);
|
virtual bool accept(EventVisitor& visitor);
|
||||||
virtual bool ascend(EventVisitor& visitor);
|
virtual bool ascend(EventVisitor& visitor);
|
||||||
|
|||||||
@@ -133,6 +133,15 @@ namespace canvas
|
|||||||
return ElementPtr();
|
return ElementPtr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void Group::clearEventListener()
|
||||||
|
{
|
||||||
|
BOOST_FOREACH( ChildList::value_type child, _children )
|
||||||
|
child.second->clearEventListener();
|
||||||
|
|
||||||
|
Element::clearEventListener();
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void Group::update(double dt)
|
void Group::update(double dt)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ namespace canvas
|
|||||||
*/
|
*/
|
||||||
ElementPtr getElementById(const std::string& id);
|
ElementPtr getElementById(const std::string& id);
|
||||||
|
|
||||||
|
virtual void clearEventListener();
|
||||||
|
|
||||||
virtual void update(double dt);
|
virtual void update(double dt);
|
||||||
|
|
||||||
virtual bool traverse(EventVisitor& visitor);
|
virtual bool traverse(EventVisitor& visitor);
|
||||||
|
|||||||
Reference in New Issue
Block a user