]> git.mxchange.org Git - simgear.git/commitdiff
Canvas: move window from flightgear.
authorThomas Geymayer <tomgey@gmail.com>
Fri, 9 May 2014 14:01:25 +0000 (16:01 +0200)
committerThomas Geymayer <tomgey@gmail.com>
Fri, 9 May 2014 14:17:40 +0000 (16:17 +0200)
simgear/canvas/CMakeLists.txt
simgear/canvas/CanvasMgr.hxx
simgear/canvas/CanvasSystemAdapter.hxx
simgear/canvas/CanvasWindow.cxx [new file with mode: 0644]
simgear/canvas/CanvasWindow.hxx [new file with mode: 0644]
simgear/canvas/canvas_fwd.hxx

index 086c83cb32d7563f2accb43bb0fe4e5f515ad472..cbeffbaa5ffc329e7628ef0f3ca7fd0330898aca 100644 (file)
@@ -11,6 +11,7 @@ set(HEADERS
   CanvasObjectPlacement.hxx
   CanvasPlacement.hxx
   CanvasSystemAdapter.hxx
+  CanvasWindow.hxx
   MouseEvent.hxx
   ODGauge.hxx
   VGInitOperation.hxx
@@ -24,6 +25,7 @@ set(SOURCES
   CanvasMgr.cxx
   CanvasObjectPlacement.cxx
   CanvasPlacement.cxx
+  CanvasWindow.cxx
   ODGauge.cxx
   VGInitOperation.cxx
 )
index 084364e392cf38598910d6d0ad2c7b2e61197b11..51ffa576bc2cbfb9cec246e9d3f40d0f8b3cb8cc 100644 (file)
@@ -33,7 +33,7 @@ namespace canvas
     public:
 
       /**
-       * @param node            Root node of branch used to control canvasses
+       * @param node    Root node of branch used to control canvasses
        */
       CanvasMgr(SGPropertyNode_ptr node);
 
index a5c184872a867d2be9edcb081ff8d9fbb9fd770b..2492bb91c5b82a01f5653ffb318134d56821cb6a 100644 (file)
@@ -21,6 +21,8 @@
 
 #include "canvas_fwd.hxx"
 
+class SGSubsystem;
+
 namespace simgear
 {
 namespace HTTP { class Client; }
@@ -36,6 +38,7 @@ namespace canvas
       virtual void addCamera(osg::Camera* camera) const = 0;
       virtual void removeCamera(osg::Camera* camera) const = 0;
       virtual osg::Image* getImage(const std::string& path) const = 0;
+      virtual SGSubsystem* getSubsystem(const std::string& name) const = 0;
       virtual HTTP::Client* getHTTPClient() const = 0;
   };
 
diff --git a/simgear/canvas/CanvasWindow.cxx b/simgear/canvas/CanvasWindow.cxx
new file mode 100644 (file)
index 0000000..55f4d9b
--- /dev/null
@@ -0,0 +1,315 @@
+// Window for placing a Canvas onto it (for dialogs, menus, etc.)
+//
+// Copyright (C) 2012  Thomas Geymayer <tomgey@gmail.com>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
+
+#include "CanvasMgr.hxx"
+#include "CanvasSystemAdapter.hxx"
+#include "CanvasWindow.hxx"
+
+#include <simgear/canvas/Canvas.hxx>
+#include <simgear/scene/util/OsgMath.hxx>
+
+#include <osgGA/GUIEventHandler>
+
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/foreach.hpp>
+
+namespace simgear
+{
+namespace canvas
+{
+
+  //----------------------------------------------------------------------------
+  const std::string Window::TYPE_NAME = "window";
+
+  //----------------------------------------------------------------------------
+  Window::Window( const 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);
+  }
+
+  //----------------------------------------------------------------------------
+  Window::~Window()
+  {
+    if( _canvas_decoration )
+      _canvas_decoration->destroy();
+  }
+
+  //----------------------------------------------------------------------------
+  void Window::update(double delta_time_sec)
+  {
+    if( _attributes_dirty & DECORATION )
+    {
+      updateDecoration();
+      _attributes_dirty &= ~DECORATION;
+    }
+
+    Image::update(delta_time_sec);
+  }
+
+  //----------------------------------------------------------------------------
+  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;
+    }
+
+    if( !handled )
+      Image::valueChanged(node);
+  }
+
+  //----------------------------------------------------------------------------
+  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) );
+  }
+
+  //----------------------------------------------------------------------------
+  const SGRect<float> Window::getScreenRegion() const
+  {
+    return getPosition() + getRegion();
+  }
+
+  //----------------------------------------------------------------------------
+  void Window::setCanvasContent(CanvasPtr canvas)
+  {
+    _canvas_content = canvas;
+
+    if( _image_content )
+      // Placement within decoration canvas
+      _image_content->setSrcCanvas(canvas);
+    else
+      setSrcCanvas(canvas);
+  }
+
+  //----------------------------------------------------------------------------
+  CanvasWeakPtr Window::getCanvasContent() const
+  {
+    return _canvas_content;
+  }
+
+  //----------------------------------------------------------------------------
+  CanvasPtr Window::getCanvasDecoration() const
+  {
+    return _canvas_decoration;
+  }
+
+  //----------------------------------------------------------------------------
+  bool Window::isResizable() const
+  {
+    return _resizable;
+  }
+
+  //----------------------------------------------------------------------------
+  bool Window::isCapturingEvents() const
+  {
+    return _capture_events;
+  }
+
+  //----------------------------------------------------------------------------
+  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::handleResize( uint8_t mode,
+                             const osg::Vec2f& offset )
+  {
+    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();
+  }
+
+  //----------------------------------------------------------------------------
+  void Window::parseDecorationBorder(const std::string& str)
+  {
+    _decoration_border = simgear::CSSBorder::parse(str);
+    _attributes_dirty |= DECORATION;
+  }
+
+  //----------------------------------------------------------------------------
+  void Window::updateDecoration()
+  {
+    int shadow_radius = get<float>("shadow-radius") + 0.5;
+    if( shadow_radius < 2 )
+      shadow_radius = 0;
+
+    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*>(
+        Canvas::getSystemAdapter()->getSubsystem("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<Image>("content");
+      _image_content->setSrcCanvas(content);
+
+      // Draw content on top of decoration
+      _image_content->set<int>("z-index", 1);
+    }
+
+    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?
+
+    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<Image>("shadow");
+    _image_shadow->set<std::string>("src", "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
+} // namespace simgear
diff --git a/simgear/canvas/CanvasWindow.hxx b/simgear/canvas/CanvasWindow.hxx
new file mode 100644 (file)
index 0000000..74bdf33
--- /dev/null
@@ -0,0 +1,126 @@
+// Window for placing a Canvas onto it (for dialogs, menus, etc.)
+//
+// Copyright (C) 2012  Thomas Geymayer <tomgey@gmail.com>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
+
+#ifndef CANVAS_WINDOW_HXX_
+#define CANVAS_WINDOW_HXX_
+
+#include <simgear/canvas/elements/CanvasImage.hxx>
+#include <simgear/canvas/MouseEvent.hxx>
+#include <simgear/props/PropertyBasedElement.hxx>
+#include <simgear/props/propertyObject.hxx>
+#include <simgear/misc/CSSBorder.hxx>
+
+#include <osg/Geode>
+#include <osg/Geometry>
+
+namespace simgear
+{
+namespace canvas
+{
+
+  class Window:
+    public Image
+  {
+    public:
+      static const std::string TYPE_NAME;
+
+      enum Resize
+      {
+        NONE    = 0,
+        LEFT    = 1,
+        RIGHT   = LEFT << 1,
+        TOP     = RIGHT << 1,
+        BOTTOM  = TOP << 1,
+        INIT    = BOTTOM << 1
+      };
+
+      /**
+       * @param node    Property node containing settings for this window:
+       *                  capture-events    Disable/Enable event capturing
+       *                  content-size[0-1] Size of content area (excluding
+       *                                    decoration border)
+       *                  decoration-border Size of decoration border
+       *                  resize            Enable resize cursor and properties
+       *                  shadow-inset      Inset of shadow image
+       *                  shadow-radius     Radius/outset of shadow image
+       */
+      Window( const CanvasWeakPtr& canvas,
+              const SGPropertyNode_ptr& node,
+              const Style& parent_style = Style(),
+              Element* parent = 0 );
+      virtual ~Window();
+
+      virtual void update(double delta_time_sec);
+      virtual void valueChanged(SGPropertyNode* node);
+
+      osg::Group* getGroup();
+      const SGVec2<float> getPosition() const;
+      const SGRect<float>  getScreenRegion() const;
+
+      void setCanvasContent(CanvasPtr canvas);
+      simgear::canvas::CanvasWeakPtr getCanvasContent() const;
+
+      CanvasPtr getCanvasDecoration() const;
+
+      bool isResizable() const;
+      bool isCapturingEvents() const;
+
+      /**
+       * Moves window on top of all other windows with the same z-index.
+       *
+       * @note If no z-index is set it defaults to 0.
+       */
+      void raise();
+
+      void handleResize( uint8_t mode,
+                         const osg::Vec2f& offset = osg::Vec2f() );
+
+    protected:
+
+      enum Attributes
+      {
+        DECORATION = 1
+      };
+
+      uint32_t  _attributes_dirty;
+
+      CanvasPtr        _canvas_decoration;
+      CanvasWeakPtr    _canvas_content;
+
+      ImagePtr _image_content,
+               _image_shadow;
+
+      bool _resizable,
+           _capture_events;
+
+      PropertyObject<int> _resize_top,
+                          _resize_right,
+                          _resize_bottom,
+                          _resize_left,
+                          _resize_status;
+
+      CSSBorder _decoration_border;
+
+      void parseDecorationBorder(const std::string& str);
+      void updateDecoration();
+  };
+
+} // namespace canvas
+} // namespace simgear
+
+#endif /* CANVAS_WINDOW_HXX_ */
index d91696eb3b28fee751a873f5f14617d9c63610f8..6b34e028f0f4147954ce25e357eb5cf61ebe9b39 100644 (file)
@@ -49,6 +49,7 @@ namespace canvas
   SG_FWD_DECL(Map)
   SG_FWD_DECL(Path)
   SG_FWD_DECL(Text)
+  SG_FWD_DECL(Window)
 
 #undef SG_FWD_DECL