]> git.mxchange.org Git - simgear.git/blobdiff - simgear/canvas/Canvas.cxx
canvas::Layout: clear parent/canvas after calling onRemove.
[simgear.git] / simgear / canvas / Canvas.cxx
index 7651635b9ba79f1c6fa73aad33650e8cc9384bf7..c7898b4535df604b07de4b0ccda9fa545af708af 100644 (file)
@@ -19,8 +19,8 @@
 #include "Canvas.hxx"
 #include "CanvasEventManager.hxx"
 #include "CanvasEventVisitor.hxx"
-#include <simgear/canvas/MouseEvent.hxx>
-#include <simgear/canvas/CanvasPlacement.hxx>
+#include "CanvasPlacement.hxx"
+#include <simgear/canvas/events/MouseEvent.hxx>
 #include <simgear/scene/util/parse_color.hxx>
 #include <simgear/scene/util/RenderConstants.hxx>
 
@@ -31,7 +31,6 @@
 
 #include <boost/algorithm/string/predicate.hpp>
 #include <boost/foreach.hpp>
-#include <iostream>
 
 namespace simgear
 {
@@ -49,8 +48,12 @@ namespace canvas
   void Canvas::CullCallback::operator()( osg::Node* node,
                                          osg::NodeVisitor* nv )
   {
-    if( (nv->getTraversalMask() & simgear::MODEL_BIT) && !_canvas.expired() )
-      _canvas.lock()->enableRendering();
+    if( (nv->getTraversalMask() & simgear::MODEL_BIT) )
+    {
+      CanvasPtr canvas = _canvas.lock();
+      if( canvas )
+        canvas->enableRendering();
+    }
 
     traverse(node, nv);
   }
@@ -73,25 +76,29 @@ namespace canvas
   {
     _status = 0;
     setStatusFlags(MISSING_SIZE_X | MISSING_SIZE_Y);
-  }
 
-  //----------------------------------------------------------------------------
-  Canvas::~Canvas()
-  {
+    _root_group.reset( new Group(this, _node) );
 
+    // Remove automatically created property listener as we forward them on our
+    // own
+    _root_group->removeListener();
+    _cull_callback = new CullCallback(this);
   }
 
   //----------------------------------------------------------------------------
-  void Canvas::setSystemAdapter(const SystemAdapterPtr& system_adapter)
+  Canvas::~Canvas()
   {
-    _system_adapter = system_adapter;
-    _texture.setSystemAdapter(system_adapter);
+
   }
 
   //----------------------------------------------------------------------------
-  SystemAdapterPtr Canvas::getSystemAdapter() const
+  void Canvas::onDestroy()
   {
-    return _system_adapter;
+    if( _root_group )
+    {
+      _root_group->clearEventListener();
+      _root_group->onDestroy();
+    }
   }
 
   //----------------------------------------------------------------------------
@@ -106,6 +113,12 @@ namespace canvas
     return _canvas_mgr;
   }
 
+  //----------------------------------------------------------------------------
+  bool Canvas::isInit() const
+  {
+    return _texture.serviceable();
+  }
+
   //----------------------------------------------------------------------------
   void Canvas::addParentCanvas(const CanvasWeakPtr& canvas)
   {
@@ -115,7 +128,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;
     }
@@ -132,7 +146,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;
     }
@@ -155,10 +170,33 @@ namespace canvas
   //----------------------------------------------------------------------------
   GroupPtr Canvas::createGroup(const std::string& name)
   {
-    return boost::dynamic_pointer_cast<Group>
-    (
-      _root_group->createChild("group", name)
-    );
+    return _root_group->createChild<Group>(name);
+  }
+
+  //----------------------------------------------------------------------------
+  GroupPtr Canvas::getGroup(const std::string& name)
+  {
+    return _root_group->getChild<Group>(name);
+  }
+
+  //----------------------------------------------------------------------------
+  GroupPtr Canvas::getOrCreateGroup(const std::string& name)
+  {
+    return _root_group->getOrCreateChild<Group>(name);
+  }
+
+  //----------------------------------------------------------------------------
+  GroupPtr Canvas::getRootGroup()
+  {
+    return _root_group;
+  }
+
+  //----------------------------------------------------------------------------
+  void Canvas::setLayout(const LayoutRef& layout)
+  {
+    _layout = layout;
+    _layout->setCanvas(this);
+    _status |= LAYOUT_DIRTY;
   }
 
   //----------------------------------------------------------------------------
@@ -172,11 +210,10 @@ namespace canvas
   //----------------------------------------------------------------------------
   void Canvas::update(double delta_time_sec)
   {
-    if(    (!_texture.serviceable() && _status != STATUS_DIRTY)
-        || (_status & CREATE_FAILED) )
+    if( _status & (CREATE_FAILED | MISSING_SIZE) )
       return;
 
-    if( _status == STATUS_DIRTY )
+    if( _status & STATUS_DIRTY )
     {
       _texture.setSize(_size_x, _size_y);
 
@@ -195,15 +232,16 @@ namespace canvas
 
       osg::Camera* camera = _texture.getCamera();
 
+      // TODO Allow custom render order? For now just keep in order with
+      //      property tree.
+      camera->setRenderOrder(osg::Camera::PRE_RENDER, _node->getIndex());
+
       osg::Vec4 clear_color(0.0f, 0.0f, 0.0f , 1.0f);
       parseColor(_node->getStringValue("background"), clear_color);
       camera->setClearColor(clear_color);
 
       camera->addChild(_root_group->getMatrixTransform());
 
-      // Ensure objects are drawn in order of traversal
-      camera->getOrCreateStateSet()->setBinName("TraversalOrderBin");
-
       if( _texture.serviceable() )
       {
         setStatusFlags(STATUS_OK);
@@ -217,23 +255,36 @@ namespace canvas
       }
     }
 
+    if( _layout )
+    {
+      if( (_status & LAYOUT_DIRTY) )
+      {
+        _layout->setGeometry(SGRecti(0, 0, _view_width, _view_height));
+        _status &= ~LAYOUT_DIRTY;
+      }
+      else
+        _layout->update();
+    }
+
     if( _visible || _render_always )
     {
-      BOOST_FOREACH(CanvasWeakPtr canvas, _child_canvases)
+      BOOST_FOREACH(CanvasWeakPtr canvas_weak, _child_canvases)
       {
         // TODO should we check if the image the child canvas is displayed
         //      within is really visible?
-        if( !canvas.expired() )
-          canvas.lock()->_visible = true;
+        CanvasPtr canvas = canvas_weak.lock();
+        if( canvas )
+          canvas->_visible = true;
       }
 
       if( _render_dirty )
       {
         // Also mark all canvases this canvas is displayed within as dirty
-        BOOST_FOREACH(CanvasWeakPtr canvas, _parent_canvases)
+        BOOST_FOREACH(CanvasWeakPtr canvas_weak, _parent_canvases)
         {
-          if( !canvas.expired() )
-            canvas.lock()->_render_dirty = true;
+          CanvasPtr canvas = canvas_weak.lock();
+          if( canvas )
+            canvas->_render_dirty = true;
         }
       }
 
@@ -276,11 +327,7 @@ namespace canvas
       if( placement_factory != _placement_factories.end() )
       {
         Placements& placements = _placements[ node->getIndex() ] =
-          placement_factory->second
-          (
-            node,
-            boost::static_pointer_cast<Canvas>(_self.lock())
-          );
+          placement_factory->second(node, this);
         node->setStringValue
         (
           "status-msg",
@@ -293,12 +340,22 @@ namespace canvas
   }
 
   //----------------------------------------------------------------------------
-  naRef Canvas::addEventListener(const nasal::CallContext& ctx)
+  bool Canvas::addEventListener( const std::string& type,
+                                 const EventListener& cb )
   {
     if( !_root_group.get() )
-      naRuntimeError(ctx.c, "Canvas: No root group!");
+      throw std::runtime_error("Canvas::addEventListener: no root group!");
 
-    return _root_group->addEventListener(ctx);
+    return _root_group->addEventListener(type, cb);
+  }
+
+  //----------------------------------------------------------------------------
+  bool Canvas::dispatchEvent(const EventPtr& event)
+  {
+    if( !_root_group.get() )
+      throw std::runtime_error("Canvas::dispatchEvent: no root group!");
+
+    return _root_group->dispatchEvent(event);
   }
 
   //----------------------------------------------------------------------------
@@ -353,6 +410,7 @@ namespace canvas
     if( _view_width == w )
       return;
     _view_width = w;
+    _status |= LAYOUT_DIRTY;
 
     _texture.setViewSize(_view_width, _view_height);
   }
@@ -363,6 +421,7 @@ namespace canvas
     if( _view_height == h )
       return;
     _view_height = h;
+    _status |= LAYOUT_DIRTY;
 
     _texture.setViewSize(_view_width, _view_height);
   }
@@ -379,21 +438,34 @@ namespace canvas
     return _texture.getViewSize().y();
   }
 
+  //----------------------------------------------------------------------------
+  SGRect<int> Canvas::getViewport() const
+  {
+    return SGRect<int>(0, 0, getViewWidth(), getViewHeight());
+  }
+
   //----------------------------------------------------------------------------
   bool Canvas::handleMouseEvent(const MouseEventPtr& event)
   {
-    if( !_root_group.get() )
+    if( !_root_group )
       return false;
 
     EventVisitor visitor( EventVisitor::TRAVERSE_DOWN,
                           event->getClientPos(),
-                          event->getDelta() );
+                          _root_group );
     if( !_root_group->accept(visitor) )
       return false;
 
     return _event_manager->handleEvent(event, visitor.getPropagationPath());
   }
 
+  //----------------------------------------------------------------------------
+  bool Canvas::propagateEvent( EventPtr const& event,
+                               EventPropagationPath const& path )
+  {
+    return _event_manager->propagateEvent(event, path);
+  }
+
   //----------------------------------------------------------------------------
   void Canvas::childAdded( SGPropertyNode * parent,
                            SGPropertyNode * child )
@@ -425,8 +497,10 @@ namespace canvas
   //----------------------------------------------------------------------------
   void Canvas::valueChanged(SGPropertyNode* node)
   {
-    if(    boost::starts_with(node->getNameString(), "status")
-        || node->getParent()->getNameString() == "bounding-box" )
+    const std::string& name = node->getNameString();
+
+    if(    boost::starts_with(name, "status")
+        || boost::starts_with(name, "data-") )
       return;
     _render_dirty = true;
 
@@ -434,21 +508,26 @@ namespace canvas
     if(    node->getParent()->getParent() == _node
         && node->getParent()->getNameString() == "placement" )
     {
-      bool placement_dirty = false;
-      BOOST_FOREACH(Placements& placements, _placements)
+      size_t index = node->getIndex();
+      if( index < _placements.size() )
       {
-        BOOST_FOREACH(PlacementPtr& placement, placements)
+        Placements& placements = _placements[index];
+        if( !placements.empty() )
         {
-          // check if change can be directly handled by placement
-          if(    placement->getProps() == node->getParent()
-              && !placement->childChanged(node) )
-            placement_dirty = true;
+          bool placement_dirty = false;
+          BOOST_FOREACH(PlacementPtr& placement, placements)
+          {
+            // check if change can be directly handled by placement
+            if(    placement->getProps() == node->getParent()
+                && !placement->childChanged(node) )
+              placement_dirty = true;
+          }
+
+          if( !placement_dirty )
+            return;
         }
       }
 
-      if( !placement_dirty )
-        return;
-
       // prevent double updates...
       for( size_t i = 0; i < _dirty_placements.size(); ++i )
       {
@@ -460,7 +539,7 @@ namespace canvas
     }
     else if( node->getParent() == _node )
     {
-      if( node->getNameString() == "background" )
+      if( name == "background" )
       {
         osg::Vec4 color;
         if( _texture.getCamera() && parseColor(node->getStringValue(), color) )
@@ -469,35 +548,41 @@ namespace canvas
           _render_dirty = true;
         }
       }
-      else if(    node->getNameString() == "mipmapping"
-              || node->getNameString() == "coverage-samples"
-              || node->getNameString() == "color-samples" )
+      else if(   name == "mipmapping"
+              || name == "coverage-samples"
+              || name == "color-samples" )
       {
         _sampling_dirty = true;
       }
-      else if( node->getNameString() == "additive-blend" )
+      else if( name == "additive-blend" )
       {
         _texture.useAdditiveBlend( node->getBoolValue() );
       }
-      else if( node->getNameString() == "render-always" )
+      else if( name == "render-always" )
       {
         _render_always = node->getBoolValue();
       }
-      else if( node->getNameString() == "size" )
+      else if( name == "size" )
       {
         if( node->getIndex() == 0 )
           setSizeX( node->getIntValue() );
         else if( node->getIndex() == 1 )
           setSizeY( node->getIntValue() );
       }
-      else if( node->getNameString() == "view" )
+      else if( name == "update" )
+      {
+        if( _root_group )
+          _root_group->update(0);
+        return update(0);
+      }
+      else if( name == "view" )
       {
         if( node->getIndex() == 0 )
           setViewWidth( node->getIntValue() );
         else if( node->getIndex() == 1 )
           setViewHeight( node->getIntValue() );
       }
-      else if( node->getNameString() == "freeze" )
+      else if( name == "freeze" )
         _texture.setRender( node->getBoolValue() );
       else
         handled = false;
@@ -548,27 +633,38 @@ namespace canvas
       (
         SG_GENERAL,
         SG_WARN,
-        "Canvas::addPlacementFactory: replace existing factor for type " << type
+        "Canvas::addPlacementFactory: replace existing factory '" << type << "'"
       );
 
     _placement_factories[type] = factory;
   }
 
   //----------------------------------------------------------------------------
-  void Canvas::setSelf(const PropertyBasedElementPtr& self)
+  void Canvas::removePlacementFactory(const std::string& type)
   {
-    PropertyBasedElement::setSelf(self);
-
-    CanvasPtr canvas = boost::static_pointer_cast<Canvas>(self);
+    PlacementFactoryMap::iterator it = _placement_factories.find(type);
+    if( it == _placement_factories.end() )
+      SG_LOG
+      (
+        SG_GENERAL,
+        SG_WARN,
+        "Canvas::removePlacementFactory: no such factory '" << type << "'"
+      );
+    else
+      _placement_factories.erase(it);
+  }
 
-    _root_group.reset( new Group(canvas, _node) );
-    _root_group->setSelf(_root_group);
 
-    // Remove automatically created property listener as we forward them on our
-    // own
-    _root_group->removeListener();
+  //----------------------------------------------------------------------------
+  void Canvas::setSystemAdapter(const SystemAdapterPtr& system_adapter)
+  {
+    _system_adapter = system_adapter;
+  }
 
-    _cull_callback = new CullCallback(canvas);
+  //----------------------------------------------------------------------------
+  SystemAdapterPtr Canvas::getSystemAdapter()
+  {
+    return _system_adapter;
   }
 
   //----------------------------------------------------------------------------
@@ -587,7 +683,7 @@ namespace canvas
       _status_msg = "Missing size-y";
     else if( _status & CREATE_FAILED )
       _status_msg = "Creating render target failed";
-    else if( _status == STATUS_DIRTY )
+    else if( _status & STATUS_DIRTY )
       _status_msg = "Creation pending...";
     else
       _status_msg = "Ok";
@@ -595,6 +691,7 @@ namespace canvas
 
   //----------------------------------------------------------------------------
   Canvas::PlacementFactoryMap Canvas::_placement_factories;
+  SystemAdapterPtr Canvas::_system_adapter;
 
 } // namespace canvas
 } // namespace simgear