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:27 +02:00
parent c3af88dfc1
commit 7fe16d99be
8 changed files with 57 additions and 15 deletions
+13
View File
@@ -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()
{ {
+17
View File
@@ -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();
/** /**
+5 -6
View File
@@ -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
+1 -1
View File
@@ -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;
+9 -8
View File
@@ -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);
+9
View File
@@ -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)
{ {
+2
View File
@@ -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);