}
//----------------------------------------------------------------------------
- Canvas::~Canvas()
+ void Canvas::onDestroy()
{
-
+ if( _root_group )
+ {
+ _root_group->clearEventListener();
+ _root_group->onDestroy();
+ }
}
//----------------------------------------------------------------------------
return _texture.serviceable();
}
- //----------------------------------------------------------------------------
- void Canvas::destroy()
- {
- if( _root_group )
- _root_group->clearEventListener();
-
- // TODO check if really not in use anymore
- getProps()->getParent()
- ->removeChild( getProps()->getName(),
- getProps()->getIndex(),
- false );
- }
-
//----------------------------------------------------------------------------
void Canvas::addParentCanvas(const CanvasWeakPtr& canvas)
{
(
SG_GENERAL,
SG_WARN,
- "Canvas::addParentCanvas: got an expired parent: " << _node->getPath()
+ "Canvas::addParentCanvas(" << _node->getPath(true) << "): "
+ "got an expired parent!"
);
return;
}
(
SG_GENERAL,
SG_WARN,
- "Canvas::addChildCanvas: got an expired child: " << _node->getPath()
+ "Canvas::addChildCanvas(" << _node->getPath(true) << "): "
+ " got an expired child!"
);
return;
}
typedef osg::ref_ptr<CullCallback> CullCallbackPtr;
Canvas(SGPropertyNode* node);
- virtual ~Canvas();
+ virtual void onDestroy();
void setSystemAdapter(const SystemAdapterPtr& system_adapter);
SystemAdapterPtr getSystemAdapter() const;
CanvasMgr* getCanvasMgr() const;
bool isInit() const;
- void destroy();
/**
* Add a canvas which should be marked as dirty upon any change to this
const std::string NAME_TRANSFORM = "tf";
//----------------------------------------------------------------------------
- void Element::removeListener()
+ Element::OSGUserData::OSGUserData(ElementPtr element):
+ element(element)
{
- _node->removeChangeListener(this);
+
}
//----------------------------------------------------------------------------
Element::~Element()
{
- removeListener();
+ }
+
+ //----------------------------------------------------------------------------
+ void Element::setSelf(const PropertyBasedElementPtr& self)
+ {
+ PropertyBasedElement::setSelf(self);
+
+ _transform->setUserData
+ (
+ new OSGUserData(boost::static_pointer_cast<Element>(self))
+ );
+ }
+
+ //----------------------------------------------------------------------------
+ void Element::onDestroy()
+ {
+ if( !_transform.valid() )
+ return;
+
+ // The transform node keeps a reference on this element, so ensure it is
+ // deleted.
BOOST_FOREACH(osg::Group* parent, _transform->getParents())
{
- parent->removeChild(_transform);
+ parent->removeChild(_transform.get());
}
}
}
//----------------------------------------------------------------------------
- osg::ref_ptr<osg::MatrixTransform> Element::getMatrixTransform()
+ osg::MatrixTransform* Element::getMatrixTransform()
{
- return _transform;
+ return _transform.get();
}
- osg::ref_ptr<osg::MatrixTransform const> Element::getMatrixTransform() const
+ //----------------------------------------------------------------------------
+ osg::MatrixTransform const* Element::getMatrixTransform() const
{
- return _transform;
+ return _transform.get();
}
//----------------------------------------------------------------------------
public PropertyBasedElement
{
public:
+
+ /**
+ * Store pointer to window as user data
+ */
+ class OSGUserData:
+ public osg::Referenced
+ {
+ public:
+ ElementPtr element;
+ OSGUserData(ElementPtr element);
+ };
+
typedef boost::function<bool(Element&, const SGPropertyNode*)>
StyleSetterFunc;
typedef boost::function<void(Element&, const SGPropertyNode*)>
std::string type; ///!< Interpolation type
};
- /**
- * Remove the property listener of the element.
- *
- * You will need to call the appropriate methods (#childAdded,
- * #childRemoved, #valueChanged) yourself to ensure the element still
- * receives the needed events.
- */
- void removeListener();
-
/**
*
*/
virtual ~Element() = 0;
+ virtual void setSelf(const PropertyBasedElementPtr& self);
+ virtual void onDestroy();
+
ElementWeakPtr getWeakPtr() const;
/**
*/
bool isVisible() const;
- osg::ref_ptr<osg::MatrixTransform> getMatrixTransform();
- osg::ref_ptr<osg::MatrixTransform const> getMatrixTransform() const;
+ osg::MatrixTransform* getMatrixTransform();
+ osg::MatrixTransform const* getMatrixTransform() const;
virtual void childAdded( SGPropertyNode * parent,
SGPropertyNode * child );
uint32_t _attributes_dirty;
bool _transform_dirty;
- osg::ref_ptr<osg::MatrixTransform> _transform;
- std::vector<TransformType> _transform_types;
+ osg::observer_ptr<osg::MatrixTransform> _transform;
+ std::vector<TransformType> _transform_types;
Style _style;
std::vector<SGPropertyNode_ptr> _bounding_box;
//----------------------------------------------------------------------------
ElementPtr Group::getChild(const SGPropertyNode* node)
{
- ChildList::iterator child = findChild(node);
- if( child == _children.end() )
- return ElementPtr();
-
- return child->second;
+ return findChild(node, "");
}
//----------------------------------------------------------------------------
ElementPtr Group::getChild(const std::string& id)
{
- for( ChildList::iterator child = _children.begin();
- child != _children.end();
- ++child )
- {
- if( child->second->get<std::string>("id") == id )
- return child->second;
- }
-
- return ElementPtr();
+ return findChild(0, id);
}
//----------------------------------------------------------------------------
{
std::vector<GroupPtr> groups;
- BOOST_FOREACH( ChildList::value_type child, _children )
+ for(size_t i = 0; i < _transform->getNumChildren(); ++i)
{
- const ElementPtr& el = child.second;
- if( el->getProps()->getStringValue("id") == id )
+ const ElementPtr& el = getChildByIndex(i);
+ if( el->get<std::string>("id") == id )
return el;
GroupPtr group = boost::dynamic_pointer_cast<Group>(el);
//----------------------------------------------------------------------------
void Group::clearEventListener()
{
- BOOST_FOREACH( ChildList::value_type child, _children )
- child.second->clearEventListener();
+
+ for(size_t i = 0; i < _transform->getNumChildren(); ++i)
+ getChildByIndex(i)->clearEventListener();
Element::clearEventListener();
}
//----------------------------------------------------------------------------
void Group::update(double dt)
{
- BOOST_FOREACH( ChildList::value_type child, _children )
- child.second->update(dt);
+ for(size_t i = 0; i < _transform->getNumChildren(); ++i)
+ getChildByIndex(i)->update(dt);
Element::update(dt);
}
bool Group::traverse(EventVisitor& visitor)
{
// Iterate in reverse order as last child is displayed on top
- BOOST_REVERSE_FOREACH( ChildList::value_type child, _children )
+ for(size_t i = _transform->getNumChildren(); i --> 0;)
{
- if( child.second->accept(visitor) )
+ if( getChildByIndex(i)->accept(visitor) )
return true;
}
return false;
return false;
bool handled = false;
- BOOST_FOREACH( ChildList::value_type child, _children )
+ for(size_t i = 0; i < _transform->getNumChildren(); ++i)
{
- if( child.second->setStyle(style) )
+ if( getChildByIndex(i)->setStyle(style) )
handled = true;
}
{
osg::BoundingBox bb;
- BOOST_FOREACH( ChildList::value_type child, _children )
+ for(size_t i = 0; i < _transform->getNumChildren(); ++i)
{
- if( !child.second->getMatrixTransform()->getNodeMask() )
+ const ElementPtr& child = getChildByIndex(i);
+ if( !child->getMatrixTransform()->getNodeMask() )
continue;
bb.expandBy
(
- child.second->getTransformedBounds
+ child->getTransformedBounds
(
- child.second->getMatrixTransform()->getMatrix() * m
+ child->getMatrixTransform()->getMatrix() * m
)
);
}
// Add to osg scene graph...
_transform->addChild( element->getMatrixTransform() );
- _children.push_back( ChildList::value_type(child, element) );
// ...and ensure correct ordering
- handleZIndexChanged( --_children.end() );
+ handleZIndexChanged(element);
return;
}
if( _child_factories.find(node->getNameString()) != _child_factories.end() )
{
- ChildList::iterator child = findChild(node);
- if( child == _children.end() )
+ ElementPtr child = getChild(node);
+ if( !child )
SG_LOG
(
SG_GL,
);
else
{
- _transform->removeChild( child->second->getMatrixTransform() );
- _children.erase(child);
+ // Remove child from the scenegraph (this automatically invalidates the
+ // reference on the element hold by the MatrixTransform)
+ child->onDestroy();
}
}
else
{
if( node->getParent()->getParent() == _node
&& node->getNameString() == "z-index" )
- return handleZIndexChanged( findChild(node->getParent()),
+ return handleZIndexChanged( getChild(node->getParent()),
node->getIntValue() );
}
//----------------------------------------------------------------------------
- void Group::handleZIndexChanged(ChildList::iterator child, int z_index)
+ void Group::handleZIndexChanged(ElementPtr child, int z_index)
{
- if( child == _children.end() )
+ if( !child )
return;
- osg::Node* tf = child->second->getMatrixTransform();
- int index = _transform->getChildIndex(tf),
- index_new = index;
-
- ChildList::iterator next = child;
- ++next;
+ osg::ref_ptr<osg::MatrixTransform> tf = child->getMatrixTransform();
+ size_t index = _transform->getChildIndex(tf),
+ index_new = index;
- while( next != _children.end()
- && next->first->getIntValue("z-index", 0) <= z_index )
+ for(;; ++index_new)
{
- ++index_new;
- ++next;
- }
+ if( index_new + 1 == _transform->getNumChildren() )
+ break;
- if( index_new != index )
- {
- _children.insert(next, *child);
+ // Move to end of block with same index (= move upwards until the next
+ // element has a higher index)
+ if( getChildByIndex(index_new + 1)->get<int>("z-index", 0) > z_index )
+ break;
}
- else
+
+ if( index_new == index )
{
- ChildList::iterator prev = child,
- check = child;
- while( check != _children.begin()
- && (--check)->first->getIntValue("z-index", 0) > z_index )
+ // We were not able to move upwards so now try downwards
+ for(;; --index_new)
{
- --index_new;
- --prev;
+ if( index_new == 0 )
+ break;
+
+ // Move to end of block with same index (= move downwards until the
+ // previous element has the same or a lower index)
+ if( getChildByIndex(index_new - 1)->get<int>("z-index", 0) <= z_index )
+ break;
}
if( index == index_new )
return;
-
- _children.insert(prev, *child);
}
_transform->removeChild(index);
_transform->insertChild(index_new, tf);
- _children.erase(child);
-
SG_LOG
(
SG_GENERAL,
}
//----------------------------------------------------------------------------
- Group::ChildList::iterator Group::findChild(const SGPropertyNode* node)
+ ElementPtr Group::getChildByIndex(size_t index) const
{
- return std::find_if
- (
- _children.begin(),
- _children.end(),
- boost::bind(&ChildList::value_type::first, _1) == node
- );
+ OSGUserData* ud =
+ static_cast<OSGUserData*>(_transform->getChild(index)->getUserData());
+ return ud->element;
+ }
+
+ //----------------------------------------------------------------------------
+ ElementPtr Group::findChild( const SGPropertyNode* node,
+ const std::string& id ) const
+ {
+ for(size_t i = 0; i < _transform->getNumChildren(); ++i)
+ {
+ ElementPtr el = getChildByIndex(i);
+
+ if( node )
+ {
+ if( el->getProps() == node )
+ return el;
+ }
+ else
+ {
+ if( el->get<std::string>("id") == id )
+ return el;
+ }
+ }
+
+ return ElementPtr();
}
} // namespace canvas
protected:
static ElementFactories _child_factories;
- ChildList _children;
virtual void childAdded(SGPropertyNode * child);
virtual void childRemoved(SGPropertyNode * child);
virtual void childChanged(SGPropertyNode * child);
- void handleZIndexChanged(ChildList::iterator child, int z_index = 0);
+ void handleZIndexChanged(ElementPtr child, int z_index = 0);
- ChildList::iterator findChild(const SGPropertyNode* node);
+ ElementPtr getChildByIndex(size_t index) const;
+ ElementPtr findChild( const SGPropertyNode* node,
+ const std::string& id ) const;
};
} // namespace canvas
//----------------------------------------------------------------------------
void Image::setSrcCanvas(CanvasPtr canvas)
{
- if( !_src_canvas.expired() )
- _src_canvas.lock()->removeParentCanvas(_canvas);
- if( !_canvas.expired() )
- _canvas.lock()->removeChildCanvas(_src_canvas);
+ CanvasPtr src_canvas = _src_canvas.lock(),
+ self_canvas = _canvas.lock();
+
+ if( src_canvas )
+ src_canvas->removeParentCanvas(self_canvas);
+ if( self_canvas )
+ self_canvas->removeChildCanvas(src_canvas);
- _src_canvas = canvas;
+ _src_canvas = src_canvas = canvas;
_attributes_dirty |= SRC_CANVAS;
_geom->setCullCallback(canvas ? new CullCallback(canvas) : 0);
- if( !_src_canvas.expired() )
+ if( src_canvas )
{
setupDefaultDimensions();
- _src_canvas.lock()->addParentCanvas(_canvas);
- if( !_canvas.expired() )
- _canvas.lock()->addChildCanvas(_src_canvas);
+ if( self_canvas )
+ {
+ self_canvas->addChildCanvas(src_canvas);
+ src_canvas->addParentCanvas(self_canvas);
+ }
}
}
//------------------------------------------------------------------------------
PropertyBasedElement::~PropertyBasedElement()
+ {
+ onDestroy();
+ removeListener();
+ }
+
+ //----------------------------------------------------------------------------
+ void PropertyBasedElement::removeListener()
{
_node->removeChangeListener(this);
}
+ //----------------------------------------------------------------------------
+ void PropertyBasedElement::destroy()
+ {
+ if( !_node )
+ return;
+
+ // TODO check if really not in use anymore
+ if( _node->getParent() )
+ _node->getParent()
+ ->removeChild(_node->getName(), _node->getIndex(), false);
+ }
+
//------------------------------------------------------------------------------
SGConstPropertyNode_ptr PropertyBasedElement::getProps() const
{
PropertyBasedElement(SGPropertyNode* node);
virtual ~PropertyBasedElement();
+ /**
+ * Remove the property listener of the element.
+ *
+ * You will need to call the appropriate methods (#childAdded,
+ * #childRemoved, #valueChanged) yourself to ensure the element still
+ * receives the needed events.
+ */
+ void removeListener();
+
+ /**
+ * Destroys this element (removes node from property tree)
+ */
+ void destroy();
+
virtual void update(double delta_time_sec) = 0;
SGConstPropertyNode_ptr getProps() const;
}
virtual void setSelf(const PropertyBasedElementPtr& self);
+ virtual void onDestroy() {};
protected:
_elements.resize(index + 1);
}
else if( _elements[index] )
+ {
SG_LOG
(
SG_GENERAL,
_name_elements << "[" << index << "] already exists!"
);
+ // Give anything holding a reference to this element to release it
+ _elements[index]->onDestroy();
+ }
+
PropertyBasedElementPtr el = _element_factory(child);
el->setSelf( el );
_elements[index] = el;
"can't removed unknown " << _name_elements << "[" << index << "]!"
);
else
+ {
// remove the element...
+ _elements[index]->onDestroy();
_elements[index].reset();
+ }
}
} // namespace simgear