]> git.mxchange.org Git - flightgear.git/commitdiff
Add window decoration support to Canvas GUI.
authorThomas Geymayer <tomgey@gmail.com>
Thu, 6 Jun 2013 20:32:09 +0000 (22:32 +0200)
committerThomas Geymayer <tomgey@gmail.com>
Thu, 6 Jun 2013 20:37:16 +0000 (22:37 +0200)
canvas::Window now optionally creates a second canvas for showing
window decoration. After setting its dimensions with the property
"decoration-border" a Nasal based window decorator should add the
required elements to the decoration canvas.

Using the properties "shadow-radius" and "shadow-inset" a drop
shadow can be added to the window.

src/Canvas/gui_mgr.cxx
src/Canvas/window.cxx
src/Canvas/window.hxx
src/Scripting/NasalCanvas.cxx

index 3bb86bc6960e6b989fbfeac8f385f71ce81979d3..5ea1d8166b7949a74e832ecf52d4b7da4f4ec597 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <simgear/canvas/Canvas.hxx>
 #include <simgear/canvas/CanvasPlacement.hxx>
+#include <simgear/scene/util/OsgMath.hxx>
 
 #include <osg/BlendFunc>
 #include <osgViewer/Viewer>
@@ -351,9 +352,9 @@ bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea)
         continue;
 
       float margin = window->isResizable() ? resize_margin_pos : 0;
-      if( window->getRegion().contains( event->getScreenX(),
-                                        event->getScreenY(),
-                                        margin ) )
+      if( window->getScreenRegion().contains( event->getScreenX(),
+                                              event->getScreenY(),
+                                              margin ) )
       {
         window_at_cursor = window;
         break;
@@ -366,7 +367,7 @@ bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea)
 
   if( window_at_cursor )
   {
-    const SGRect<float>& reg = window_at_cursor->getRegion();
+    const SGRect<float>& reg = window_at_cursor->getScreenRegion();
 
     if(     window_at_cursor->isResizable()
         && (  ea.getEventType() == osgGA::GUIEventAdapter::MOVE
@@ -459,6 +460,8 @@ bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea)
       {
         sc::MouseEventPtr move_event( new sc::MouseEvent(*event) );
         move_event->type = sc::Event::MOUSE_LEAVE;
+        move_event->client_pos -= toOsg(last_mouse_over->getPosition());
+        move_event->local_pos = move_event->client_pos;
 
         last_mouse_over->handleMouseEvent(move_event);
       }
@@ -482,7 +485,11 @@ bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea)
   }
 
   if( target_window )
+  {
+    event->client_pos -= toOsg(target_window->getPosition());
+    event->local_pos = event->client_pos;
     return target_window->handleMouseEvent(event);
+  }
   else
     return false;
 }
index cdebb5d0e12df21c0bbf206e1b96f2855d696202..8deed486ca09f55f0cbf2ec2d4b9f15d2f8906a5 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 <Main/globals.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 canvas
@@ -28,9 +32,8 @@ namespace canvas
   //----------------------------------------------------------------------------
   Window::Window(SGPropertyNode* node):
     PropertyBasedElement(node),
-    _image( simgear::canvas::CanvasPtr(),
-            node,
-            simgear::canvas::Style() ),
+    _attributes_dirty(0),
+    _image(simgear::canvas::CanvasPtr(), node),
     _resizable(false),
     _capture_events(true),
     _resize_top(node, "resize-top"),
@@ -41,12 +44,6 @@ namespace canvas
   {
     _image.removeListener();
 
-    // TODO probably better remove default position and size
-    node->setFloatValue("x", 50);
-    node->setFloatValue("y", 100);
-    node->setFloatValue("size[0]", 400);
-    node->setFloatValue("size[1]", 300);
-
     node->setFloatValue("source/right", 1);
     node->setFloatValue("source/bottom", 1);
     node->setBoolValue("source/normalized", true);
@@ -55,13 +52,59 @@ namespace canvas
   //----------------------------------------------------------------------------
   Window::~Window()
   {
-
+    if( _canvas_decoration )
+      _canvas_decoration->destroy();
   }
 
   //----------------------------------------------------------------------------
   void Window::update(double delta_time_sec)
   {
     _image.update(delta_time_sec);
+
+    if( _attributes_dirty & SHADOW )
+    {
+      float radius = get<float>("shadow-radius"),
+            inset = get<float>("shadow-inset"),
+            slice_width = radius + inset;
+
+      if( slice_width <= 1 || _canvas_content.expired() )
+      {
+        if( _image_shadow )
+        {
+          getGroup()->removeChild(_image_shadow->getMatrixTransform());
+          _image_shadow.reset();
+        }
+      }
+      else
+      {
+        if( !_image_shadow )
+        {
+          _image_shadow.reset(new simgear::canvas::Image(
+            _canvas_content,
+            _node->getChild("image-shadow", 0, true)
+          ));
+          _image_shadow->set<std::string>("file", "gui/images/shadow.png");
+          _image_shadow->set<float>("slice", 7);
+          _image_shadow->set<std::string>("fill", "#000000");
+          getGroup()->insertChild(0, _image_shadow->getMatrixTransform());
+        }
+
+        simgear::canvas::CanvasPtr canvas = _canvas_decoration
+                                          ? _canvas_decoration
+                                          : _canvas_content.lock();
+
+        _image_shadow->set<float>("slice-width", slice_width);
+        _image_shadow->set<int>("x", -radius);
+        _image_shadow->set<int>("y", -radius);
+        _image_shadow->set<int>("size[0]", canvas->getViewWidth() + 2 * radius);
+        _image_shadow->set<int>("size[1]", canvas->getViewHeight()+ 2 * radius);
+      }
+
+      _attributes_dirty &= ~SHADOW;
+    }
+
+    if( _image_shadow )
+      _image_shadow->update(delta_time_sec);
   }
 
   //----------------------------------------------------------------------------
@@ -71,12 +114,17 @@ namespace canvas
     if( node->getParent() == _node )
     {
       handled = true;
-      if( node->getNameString() == "raise-top" )
+      const std::string& name = node->getNameString();
+      if( name == "raise-top" )
         doRaise(node);
-      else if( node->getNameString()  == "resize" )
+      else if( name  == "resize" )
         _resizable = node->getBoolValue();
-      else if( node->getNameString() == "capture-events" )
+      else if( name == "capture-events" )
         _capture_events = node->getBoolValue();
+      else if( name == "decoration-border" )
+        parseDecorationBorder(node->getStringValue());
+      else if( boost::starts_with(name, "shadow-") )
+        _attributes_dirty |= SHADOW;
       else
         handled = false;
     }
@@ -85,6 +133,18 @@ namespace canvas
       _image.valueChanged(node);
   }
 
+  //----------------------------------------------------------------------------
+  void Window::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
+  {
+    _image.childAdded(parent, child);
+  }
+
+  //----------------------------------------------------------------------------
+  void Window::childRemoved(SGPropertyNode* parent, SGPropertyNode* child)
+  {
+    _image.childRemoved(parent, child);
+  }
+
   //----------------------------------------------------------------------------
   osg::Group* Window::getGroup()
   {
@@ -97,9 +157,23 @@ namespace canvas
     return _image.getRegion();
   }
 
+  //----------------------------------------------------------------------------
+  const SGVec2<float> Window::getPosition() const
+  {
+    const osg::Matrix& m = _image.getMatrixTransform()->getMatrix();
+    return SGVec2<float>( m(3, 0), m(3, 1) );
+  }
+
+  //----------------------------------------------------------------------------
+  const SGRect<float> Window::getScreenRegion() const
+  {
+    return getPosition() + getRegion();
+  }
+
   //----------------------------------------------------------------------------
   void Window::setCanvas(simgear::canvas::CanvasPtr canvas)
   {
+    _canvas_content = canvas;
     _image.setSrcCanvas(canvas);
   }
 
@@ -109,6 +183,12 @@ namespace canvas
     return _image.getSrcCanvas();
   }
 
+  //----------------------------------------------------------------------------
+  simgear::canvas::CanvasPtr Window::getCanvasDecoration()
+  {
+    return _canvas_decoration;
+  }
+
   //----------------------------------------------------------------------------
   bool Window::isVisible() const
   {
@@ -180,4 +260,67 @@ namespace canvas
       node_raise->setBoolValue(false);
   }
 
+  //----------------------------------------------------------------------------
+  void Window::parseDecorationBorder( const std::string& str )
+  {
+    _decoration_border = simgear::CSSBorder::parse(str);
+    if( _decoration_border.isNone() )
+    {
+      simgear::canvas::CanvasPtr canvas_content = _canvas_content.lock();
+      _image.setSrcCanvas(canvas_content);
+      _image.set<int>("size[0]", canvas_content->getViewWidth());
+      _image.set<int>("size[1]", canvas_content->getViewHeight());
+
+      _image_content.reset();
+      _canvas_decoration->destroy();
+      _canvas_decoration.reset();
+      return;
+    }
+
+    simgear::canvas::CanvasPtr content = _canvas_content.lock();
+    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)");
+      _image.setSrcCanvas(_canvas_decoration);
+
+      // Decoration should be drawn first...
+      _canvas_decoration->createGroup("decoration");
+
+      // ...to allow drawing the actual content on top of the decoration
+      _image_content =
+        boost::dynamic_pointer_cast<simgear::canvas::Image>(
+            _canvas_decoration->getRootGroup()->createChild("image", "content")
+        );
+      _image_content->setSrcCanvas(content);
+    }
+
+    simgear::CSSBorder::Offsets const border =
+      _decoration_border.getAbsOffsets(content->getViewport());
+
+    int outer_width  = border.l + content->getViewWidth()  + border.r,
+        outer_height = border.t + content->getViewHeight() + border.b;
+
+    _canvas_decoration->setSizeX( outer_width );
+    _canvas_decoration->setSizeY( outer_height );
+    _canvas_decoration->setViewWidth( outer_width );
+    _canvas_decoration->setViewHeight( outer_height );
+
+    _image.set<int>("size[0]", outer_width);
+    _image.set<int>("size[1]", outer_height);
+
+    assert(_image_content);
+    _image_content->set<int>("x", border.l);
+    _image_content->set<int>("y", border.t);
+  }
+
 } // namespace canvas
index 44bfafaea61d4a5a8c072a7631360baa7ff758c4..905b0e4c3382c69d29a9b5f650bde0d4fb1419ed 100644 (file)
@@ -23,6 +23,7 @@
 #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>
@@ -49,13 +50,19 @@ namespace canvas
 
       virtual void update(double delta_time_sec);
       virtual void valueChanged(SGPropertyNode* node);
+      virtual void childAdded(SGPropertyNode* parent, SGPropertyNode* child);
+      virtual void childRemoved(SGPropertyNode* parent, SGPropertyNode* child);
 
       osg::Group* getGroup();
       const SGRect<float>& getRegion() const;
+      const SGVec2<float> getPosition() const;
+      const SGRect<float>  getScreenRegion() const;
 
       void setCanvas(simgear::canvas::CanvasPtr canvas);
       simgear::canvas::CanvasWeakPtr getCanvas() const;
 
+      simgear::canvas::CanvasPtr getCanvasDecoration();
+
       bool isVisible() const;
       bool isResizable() const;
       bool isCapturingEvents() const;
@@ -68,7 +75,20 @@ namespace canvas
 
     protected:
 
-      simgear::canvas::Image _image;
+      enum Attributes
+      {
+        SHADOW = 1
+      };
+
+      uint32_t  _attributes_dirty;
+
+      simgear::canvas::CanvasPtr        _canvas_decoration;
+      simgear::canvas::CanvasWeakPtr    _canvas_content;
+
+      simgear::canvas::Image    _image;
+      simgear::canvas::ImagePtr _image_content,
+                                _image_shadow;
+
       bool _resizable,
            _capture_events;
 
@@ -78,6 +98,9 @@ namespace canvas
                                    _resize_left,
                                    _resize_status;
 
+      simgear::CSSBorder    _decoration_border;
+
+      void parseDecorationBorder(const std::string& str);
   };
 } // namespace canvas
 
index f6ab47ac529a9e098defc67e6ca399dd7a0ba3df..78540f90e7a1409adecbb52839715f11460d79b7 100644 (file)
@@ -232,7 +232,8 @@ naRef initNasalCanvas(naRef globals, naContext c, naRef gcSave)
     .method("getNearestCursor", &sc::Text::getNearestCursor);
 
   NasalWindow::init("canvas.Window")
-    .member("_node_ghost", &elementGetNode<canvas::Window>);
+    .member("_node_ghost", &elementGetNode<canvas::Window>)
+    .method("_getCanvasDecoration", &canvas::Window::getCanvasDecoration);
 
   nasal::Hash globals_module(globals, c),
               canvas_module = globals_module.createHash("canvas");