]> git.mxchange.org Git - simgear.git/commitdiff
Restructure Canvas/PropertyBasedElement
authorThomas Geymayer <tomgey@gmail.com>
Sat, 8 Jun 2013 09:28:49 +0000 (11:28 +0200)
committerThomas Geymayer <tomgey@gmail.com>
Sat, 8 Jun 2013 09:28:49 +0000 (11:28 +0200)
Nodes inside the osg scenegraph now hold a strong reference to
the according canvas element. Canvas elements in turn now only
hold a weak reference to the according node. This simplifies
for example the canvas::Group as it does not need to keep a
list of children on its own anymore. This is now stored inside
the scenegraph (as it was already before).

The restructuring will also allow to use a canvas::Group for
the canvas gui inside FlightGear and share for example the
handling of stacking based on z-index.

simgear/canvas/Canvas.cxx
simgear/canvas/Canvas.hxx
simgear/canvas/elements/CanvasElement.cxx
simgear/canvas/elements/CanvasElement.hxx
simgear/canvas/elements/CanvasGroup.cxx
simgear/canvas/elements/CanvasGroup.hxx
simgear/canvas/elements/CanvasImage.cxx
simgear/props/PropertyBasedElement.cxx
simgear/props/PropertyBasedElement.hxx
simgear/props/PropertyBasedMgr.cxx

index 37877d5f3abbb63b5922b4e2da1c287da870399d..25345e761744ff74d722532acf25bc728d0ac86a 100644 (file)
@@ -75,9 +75,13 @@ namespace canvas
   }
 
   //----------------------------------------------------------------------------
-  Canvas::~Canvas()
+  void Canvas::onDestroy()
   {
-
+    if( _root_group )
+    {
+      _root_group->clearEventListener();
+      _root_group->onDestroy();
+    }
   }
 
   //----------------------------------------------------------------------------
@@ -111,19 +115,6 @@ namespace canvas
     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)
   {
@@ -133,7 +124,8 @@ namespace canvas
       (
         SG_GENERAL,
         SG_WARN,
-        "Canvas::addParentCanvas: got an expired parent: " << _node->getPath()
+        "Canvas::addParentCanvas(" << _node->getPath(true) << "): "
+        "got an expired parent!"
       );
       return;
     }
@@ -150,7 +142,8 @@ namespace canvas
       (
         SG_GENERAL,
         SG_WARN,
-        "Canvas::addChildCanvas: got an expired child: " << _node->getPath()
+        "Canvas::addChildCanvas(" << _node->getPath(true) << "): "
+        " got an expired child!"
       );
       return;
     }
index 3504b46c9ce0f8f73d8c3cd07ae50bd5fcef32f2..f132a7cf7a60f6c9be6646b2e3112f98cfeba3be 100644 (file)
@@ -71,7 +71,7 @@ namespace canvas
       typedef osg::ref_ptr<CullCallback> CullCallbackPtr;
 
       Canvas(SGPropertyNode* node);
-      virtual ~Canvas();
+      virtual void onDestroy();
 
       void setSystemAdapter(const SystemAdapterPtr& system_adapter);
       SystemAdapterPtr getSystemAdapter() const;
@@ -80,7 +80,6 @@ namespace canvas
       CanvasMgr* getCanvasMgr() const;
 
       bool isInit() const;
-      void destroy();
 
       /**
        * Add a canvas which should be marked as dirty upon any change to this
index af725d570a1a21892054458ec83376c1013d3168..522a2ef7bd0d5ff33e7ff74d089b41f8d4011249 100644 (file)
@@ -43,19 +43,40 @@ namespace canvas
   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());
     }
   }
 
@@ -239,14 +260,15 @@ namespace canvas
   }
 
   //----------------------------------------------------------------------------
-  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();
   }
 
   //----------------------------------------------------------------------------
index b7d06f757832dc739643924a583d110170acf00e..693aec88c893d1761c22d86701de5d019f912268 100644 (file)
@@ -45,6 +45,18 @@ namespace canvas
     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*)>
@@ -61,20 +73,14 @@ namespace canvas
         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;
 
       /**
@@ -102,8 +108,8 @@ namespace canvas
        */
       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 );
@@ -154,8 +160,8 @@ namespace canvas
       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;
index 4b6591f9aca5937a5f824710f4c294d25d6f8587..e0ad87e07673ea44235172fbbe4d6e24caafbeb2 100644 (file)
@@ -96,25 +96,13 @@ namespace canvas
   //----------------------------------------------------------------------------
   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);
   }
 
   //----------------------------------------------------------------------------
@@ -147,10 +135,10 @@ namespace canvas
   {
     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);
@@ -171,8 +159,9 @@ namespace canvas
   //----------------------------------------------------------------------------
   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();
   }
@@ -180,8 +169,8 @@ namespace canvas
   //----------------------------------------------------------------------------
   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);
   }
@@ -190,9 +179,9 @@ namespace canvas
   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;
@@ -210,9 +199,9 @@ namespace canvas
       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;
     }
 
@@ -224,16 +213,17 @@ namespace canvas
   {
     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
         )
       );
     }
@@ -255,10 +245,9 @@ namespace canvas
 
       // 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;
     }
@@ -279,8 +268,8 @@ namespace canvas
 
     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,
@@ -289,8 +278,9 @@ namespace canvas
         );
       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
@@ -306,56 +296,52 @@ namespace canvas
   {
     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,
@@ -365,14 +351,34 @@ namespace canvas
   }
 
   //----------------------------------------------------------------------------
-  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
index 43fa36812c9edd360ba7e0007680c4edf0adb181..f3ba781e9ce6dac2b72086daec6306de3469946d 100644 (file)
@@ -99,15 +99,16 @@ 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
index 077d004289895c5523f3181e598749d9755f04c0..5500f32d01b93de7c111e7e82fbb1fbcb704e778 100644 (file)
@@ -350,22 +350,27 @@ 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);
+      }
     }
   }
 
index b1667e8c80623a85ae13a0b5cf7cd5244e261ac4..d0e4f4614e1e1f6560228cbdab76f8b6dc0470eb 100644 (file)
@@ -30,10 +30,29 @@ namespace simgear
 
   //------------------------------------------------------------------------------
   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
   {
index bdae05370fa01c2105a9f74995fb1115c761d9fc..b2ccd30b74fd0c3f1802bb8b1ac647dfe62a6f58 100644 (file)
@@ -43,6 +43,20 @@ namespace simgear
       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;
@@ -67,6 +81,7 @@ namespace simgear
       }
 
       virtual void setSelf(const PropertyBasedElementPtr& self);
+      virtual void onDestroy() {};
 
     protected:
 
index 46f3c736d0bad49a08f81d623eb6f8710cedb8cf..621d11db67efd2401ad43c049d22e59505917261 100644 (file)
@@ -126,6 +126,7 @@ namespace simgear
       _elements.resize(index + 1);
     }
     else if( _elements[index] )
+    {
       SG_LOG
       (
         SG_GENERAL,
@@ -133,6 +134,10 @@ namespace simgear
         _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;
@@ -158,8 +163,11 @@ namespace simgear
         "can't removed unknown " << _name_elements << "[" << index << "]!"
       );
     else
+    {
       // remove the element...
+      _elements[index]->onDestroy();
       _elements[index].reset();
+    }
   }
 
 } // namespace simgear