]> git.mxchange.org Git - flightgear.git/blobdiff - src/Canvas/window.cxx
Fix starting on carrier.
[flightgear.git] / src / Canvas / window.cxx
index 40dc855002c88bdae2f2f15b00438a72903b79e8..012915faf80bbee9d5917093b3ee212b53d3b18f 100644 (file)
 // along with this program; if not, write to the Free Software
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
+#include "canvas_mgr.hxx"
 #include "window.hxx"
-#include <Canvas/canvas.hxx>
+#include <Main/globals.hxx>
+#include <simgear/canvas/Canvas.hxx>
+#include <simgear/scene/util/OsgMath.hxx>
 
-#include <osg/BlendFunc>
-#include <osg/Geometry>
-#include <osg/Texture2D>
 #include <osgGA/GUIEventHandler>
 
-/**
- * Callback to enable/disable rendering of canvas displayed inside windows
- */
-class CullCallback:
-  public osg::Drawable::CullCallback
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/foreach.hpp>
+
+namespace canvas
 {
-  public:
-    CullCallback(Canvas::CameraCullCallback* camera_cull);
+  namespace sc = simgear::canvas;
 
-  private:
-    Canvas::CameraCullCallback *_camera_cull;
+  //----------------------------------------------------------------------------
+  const std::string Window::TYPE_NAME = "window";
 
-    virtual bool cull( osg::NodeVisitor* nv,
-                       osg::Drawable* drawable,
-                       osg::RenderInfo* renderInfo ) const;
-};
+  //----------------------------------------------------------------------------
+  Window::Window( const simgear::canvas::CanvasWeakPtr& canvas,
+                  const SGPropertyNode_ptr& node,
+                  const Style& parent_style,
+                  Element* parent ):
+    Image(canvas, node, parent_style, parent),
+    _attributes_dirty(0),
+    _resizable(false),
+    _capture_events(true),
+    _resize_top(node, "resize-top"),
+    _resize_right(node, "resize-right"),
+    _resize_bottom(node, "resize-bottom"),
+    _resize_left(node, "resize-left"),
+    _resize_status(node, "resize-status")
+  {
+    node->setFloatValue("source/right", 1);
+    node->setFloatValue("source/bottom", 1);
+    node->setBoolValue("source/normalized", true);
+  }
 
-//------------------------------------------------------------------------------
-CullCallback::CullCallback(Canvas::CameraCullCallback* camera_cull):
-  _camera_cull( camera_cull )
-{
+  //----------------------------------------------------------------------------
+  Window::~Window()
+  {
+    if( _canvas_decoration )
+      _canvas_decoration->destroy();
+  }
 
-}
+  //----------------------------------------------------------------------------
+  void Window::update(double delta_time_sec)
+  {
+    if( _attributes_dirty & DECORATION )
+    {
+      updateDecoration();
+      _attributes_dirty &= ~DECORATION;
+    }
 
-//------------------------------------------------------------------------------
-bool CullCallback::cull( osg::NodeVisitor* nv,
-                         osg::Drawable* drawable,
-                         osg::RenderInfo* renderInfo ) const
-{
-  _camera_cull->enableRendering();
-  return false;
-}
+    Image::update(delta_time_sec);
+  }
 
-namespace canvas
-{
   //----------------------------------------------------------------------------
-  Window::Window(SGPropertyNode* node):
-    PropertyBasedElement(node),
-    _dirty(true),
-    _geometry( new osg::Geometry ),
-    _vertices( new osg::Vec3Array(4) ),
-    _tex_coords( new osg::Vec2Array(4) ),
-    _x(node, "x"),
-    _y(node, "y"),
-    _width(node, "size[0]"),
-    _height(node, "size[1]")
-  {
-    _x = 50;
-    _y = 100;
-    _width = 400;
-    _height = 300;
-
-    _geometry->setVertexArray(_vertices);
-    _geometry->setTexCoordArray(0,_tex_coords);
-
-    osg::Vec4Array* colors = new osg::Vec4Array(1);
-    (*colors)[0].set(1.0f,1.0f,1.0,1.0f);
-    _geometry->setColorArray(colors);
-    _geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
-
-    _geometry->addPrimitiveSet(
-      new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4)
-    );
-    _geometry->setDataVariance(osg::Object::DYNAMIC);
-
-    osg::StateSet* stateSet = _geometry->getOrCreateStateSet();
-    stateSet->setRenderBinDetails(1000, "RenderBin");
+  void Window::valueChanged(SGPropertyNode * node)
+  {
+    bool handled = false;
+    if( node->getParent() == _node )
+    {
+      handled = true;
+      const std::string& name = node->getNameString();
+      if( name  == "resize" )
+        _resizable = node->getBoolValue();
+      else if( name == "update" )
+        update(0);
+      else if( name == "capture-events" )
+        _capture_events = node->getBoolValue();
+      else if( name == "decoration-border" )
+        parseDecorationBorder(node->getStringValue());
+      else if(    boost::starts_with(name, "shadow-")
+               || name == "content-size" )
+        _attributes_dirty |= DECORATION;
+      else
+        handled = false;
+    }
 
-    // speed optimization?
-    stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
-    stateSet->setAttribute(new osg::BlendFunc(
-      osg::BlendFunc::SRC_ALPHA,
-      osg::BlendFunc::ONE_MINUS_SRC_ALPHA)
-    );
-    stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
-    stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
-    stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
-    stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
-    stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON);
+    if( !handled )
+      Image::valueChanged(node);
   }
 
   //----------------------------------------------------------------------------
-  Window::~Window()
+  osg::Group* Window::getGroup()
   {
+    return getMatrixTransform();
+  }
 
+  //----------------------------------------------------------------------------
+  const SGVec2<float> Window::getPosition() const
+  {
+    const osg::Matrix& m = getMatrixTransform()->getMatrix();
+    return SGVec2<float>( m(3, 0), m(3, 1) );
   }
 
   //----------------------------------------------------------------------------
-  void Window::update(double delta_time_sec)
+  const SGRect<float> Window::getScreenRegion() const
   {
-    if( !_dirty )
-      return;
-    _dirty = false;
+    return getPosition() + getRegion();
+  }
 
-    _region.set(_x, _y, _width, _height);
+  //----------------------------------------------------------------------------
+  void Window::setCanvasContent(sc::CanvasPtr canvas)
+  {
+    _canvas_content = canvas;
 
-    int z = 0; // TODO do we need to use z for depth ordering?
+    if( _image_content )
+      // Placement within decoration canvas
+      _image_content->setSrcCanvas(canvas);
+    else
+      setSrcCanvas(canvas);
+  }
 
-    (*_vertices)[0].set(_region.l(), _region.t(), z);
-    (*_vertices)[1].set(_region.r(), _region.t(), z);
-    (*_vertices)[2].set(_region.r(), _region.b(), z);
-    (*_vertices)[3].set(_region.l(), _region.b(), z);
+  //----------------------------------------------------------------------------
+  sc::CanvasWeakPtr Window::getCanvasContent() const
+  {
+    return _canvas_content;
+  }
 
-    float l = 0, t = 1, b = 0, r = 1;
-    (*_tex_coords)[0].set(l,t);
-    (*_tex_coords)[1].set(r,t);
-    (*_tex_coords)[2].set(r,b);
-    (*_tex_coords)[3].set(l,b);
+  //----------------------------------------------------------------------------
+  sc::CanvasPtr Window::getCanvasDecoration()
+  {
+    return _canvas_decoration;
+  }
 
-    _geometry->dirtyDisplayList();
+  //----------------------------------------------------------------------------
+  bool Window::isResizable() const
+  {
+    return _resizable;
   }
 
   //----------------------------------------------------------------------------
-  void Window::valueChanged (SGPropertyNode * node)
+  bool Window::isCapturingEvents() const
   {
-    if( node->getParent() != _node )
-      return;
+    return _capture_events;
+  }
 
-    const std::string& name = node->getNameString();
-    if(    name == "x" || name == "y" || name == "size" )
-      _dirty = true;
+  //----------------------------------------------------------------------------
+  void Window::raise()
+  {
+    // on writing the z-index the window always is moved to the top of all other
+    // windows with the same z-index.
+    set<int>("z-index", get<int>("z-index", 0));
   }
 
   //----------------------------------------------------------------------------
-  void Window::setCanvas(CanvasPtr canvas)
+  void Window::handleResize( uint8_t mode,
+                             const osg::Vec2f& offset )
   {
-    _canvas = canvas;
-    _geometry->getOrCreateStateSet()
-             ->setTextureAttribute(0, canvas ? canvas->getTexture() : 0);
-    _geometry->dirtyDisplayList();
-    _geometry->setCullCallback(
-      canvas ? new CullCallback(canvas->getCameraCullCallback()) : 0
-    );
+    if( mode == NONE )
+    {
+      _resize_status = 0;
+      return;
+    }
+    else if( mode & INIT )
+    {
+      _resize_top    = getRegion().t();
+      _resize_right  = getRegion().r();
+      _resize_bottom = getRegion().b();
+      _resize_left   = getRegion().l();
+      _resize_status = 1;
+    }
+
+    if( mode & BOTTOM )
+      _resize_bottom = getRegion().b() + offset.y();
+    else if( mode & TOP )
+      _resize_top = getRegion().t() + offset.y();
+
+    if( mode & canvas::Window::RIGHT )
+      _resize_right = getRegion().r() + offset.x();
+    else if( mode & canvas::Window::LEFT )
+      _resize_left = getRegion().l() + offset.x();
   }
 
   //----------------------------------------------------------------------------
-  CanvasWeakPtr Window::getCanvas() const
+  void Window::parseDecorationBorder(const std::string& str)
   {
-    return _canvas;
+    _decoration_border = simgear::CSSBorder::parse(str);
+    _attributes_dirty |= DECORATION;
   }
 
   //----------------------------------------------------------------------------
-  bool Window::handleMouseEvent(const MouseEvent& event)
+  void Window::updateDecoration()
   {
-    if( !_canvas.expired() )
-      return _canvas.lock()->handleMouseEvent(event);
-    else
-      return false;
+    int shadow_radius = get<float>("shadow-radius") + 0.5;
+    if( shadow_radius < 2 )
+      shadow_radius = 0;
+
+    sc::CanvasPtr content = _canvas_content.lock();
+    SGRect<int> content_view
+    (
+      0,
+      0,
+      get<int>("content-size[0]", content ? content->getViewWidth()  : 400),
+      get<int>("content-size[1]", content ? content->getViewHeight() : 300)
+    );
+
+    if( _decoration_border.isNone() && !shadow_radius )
+    {
+      setSrcCanvas(content);
+      set<int>("size[0]", content_view.width());
+      set<int>("size[1]", content_view.height());
+
+      _image_content.reset();
+      _image_shadow.reset();
+      if( _canvas_decoration )
+        _canvas_decoration->destroy();
+      _canvas_decoration.reset();
+      return;
+    }
+
+    if( !_canvas_decoration )
+    {
+      CanvasMgr* mgr =
+        dynamic_cast<CanvasMgr*>(globals->get_subsystem("Canvas"));
+
+      if( !mgr )
+      {
+        SG_LOG(SG_GENERAL, SG_WARN, "canvas::Window: no canvas manager!");
+        return;
+      }
+
+      _canvas_decoration = mgr->createCanvas("window-decoration");
+      _canvas_decoration->getProps()
+                        ->setStringValue("background", "rgba(0,0,0,0)");
+      setSrcCanvas(_canvas_decoration);
+
+      _image_content = _canvas_decoration->getRootGroup()
+                                         ->createChild<sc::Image>("content");
+      _image_content->setSrcCanvas(content);
+
+      // Draw content on top of decoration
+      _image_content->set<int>("z-index", 1);
+    }
+
+    sc::GroupPtr group_decoration =
+      _canvas_decoration->getOrCreateGroup("decoration");
+    group_decoration->set<int>("tf/t[0]", shadow_radius);
+    group_decoration->set<int>("tf/t[1]", shadow_radius);
+    // TODO do we need clipping or shall we trust the decorator not to draw over
+    //      the shadow?
+
+    simgear::CSSBorder::Offsets const border =
+      _decoration_border.getAbsOffsets(content_view);
+
+    int shad2 = 2 * shadow_radius,
+        outer_width  = border.l + content_view.width()  + border.r + shad2,
+        outer_height = border.t + content_view.height() + border.b + shad2;
+
+    _canvas_decoration->setSizeX( outer_width );
+    _canvas_decoration->setSizeY( outer_height );
+    _canvas_decoration->setViewWidth( outer_width );
+    _canvas_decoration->setViewHeight( outer_height );
+
+    set<int>("size[0]", outer_width - shad2);
+    set<int>("size[1]", outer_height - shad2);
+    set<int>("outset", shadow_radius);
+
+    assert(_image_content);
+    _image_content->set<int>("x", shadow_radius + border.l);
+    _image_content->set<int>("y", shadow_radius + border.t);
+    _image_content->set<int>("size[0]", content_view.width());
+    _image_content->set<int>("size[1]", content_view.height());
+
+    if( !shadow_radius )
+    {
+      if( _image_shadow )
+      {
+        _image_shadow->destroy();
+        _image_shadow.reset();
+      }
+      return;
+    }
+
+    int shadow_inset = std::max<int>(get<float>("shadow-inset") + 0.5, 0),
+        slice_width  = shadow_radius + shadow_inset;
+
+    _image_shadow = _canvas_decoration->getRootGroup()
+                                      ->getOrCreateChild<sc::Image>("shadow");
+    _image_shadow->set<std::string>("file", "gui/images/shadow.png");
+    _image_shadow->set<float>("slice", 7);
+    _image_shadow->set<std::string>("fill", "#000000");
+    _image_shadow->set<float>("slice-width", slice_width);
+    _image_shadow->set<int>("size[0]", outer_width);
+    _image_shadow->set<int>("size[1]", outer_height);
+
+    // Draw shadow below decoration
+    _image_shadow->set<int>("z-index", -1);
   }
 
 } // namespace canvas