]> git.mxchange.org Git - flightgear.git/blobdiff - src/Canvas/gui_mgr.cxx
Fix cursor hide timeout if hovering on canvas windows
[flightgear.git] / src / Canvas / gui_mgr.cxx
index 0190ba9f6b0afd7f023522edfc52295daf3dc262..cfee29c0747a1cf3419cae75566320f1693a2b90 100644 (file)
 
 #include <simgear/canvas/Canvas.hxx>
 #include <simgear/canvas/CanvasPlacement.hxx>
+#include <simgear/scene/util/OsgMath.hxx>
 
 #include <osg/BlendFunc>
 #include <osgViewer/Viewer>
 #include <osgGA/GUIEventHandler>
 
 #include <boost/bind.hpp>
+#include <boost/lexical_cast.hpp>
 
 /**
  * Event handler
@@ -46,7 +48,7 @@ class GUIEventHandler:
     {}
 
     bool handle( const osgGA::GUIEventAdapter& ea,
-                 osgGA::GUIActionAdapter& aa,
+                 osgGA::GUIActionAdapter&,
                  osg::Object*,
                  osg::NodeVisitor* )
     {
@@ -82,8 +84,8 @@ class WindowPlacement:
       canvas::WindowPtr window = _window.lock();
       simgear::canvas::CanvasPtr canvas = _canvas.lock();
 
-      if( window && canvas && canvas == window->getCanvas().lock() )
-        window->setCanvas( simgear::canvas::CanvasPtr() );
+      if( window && canvas && canvas == window->getCanvasContent().lock() )
+        window->setCanvasContent( simgear::canvas::CanvasPtr() );
     }
 
   private:
@@ -91,48 +93,35 @@ class WindowPlacement:
     simgear::canvas::CanvasWeakPtr _canvas;
 };
 
-/**
- * Store pointer to window as user data
- */
-class WindowUserData:
-  public osg::Referenced
-{
-  public:
-    canvas::WindowWeakPtr window;
-    WindowUserData(canvas::WindowPtr window):
-      window(window)
-    {}
-};
-
-//------------------------------------------------------------------------------
-typedef boost::shared_ptr<canvas::Window> WindowPtr;
-WindowPtr windowFactory(SGPropertyNode* node)
-{
-  return WindowPtr(new canvas::Window(node));
-}
-
 //------------------------------------------------------------------------------
 GUIMgr::GUIMgr():
-  PropertyBasedMgr( fgGetNode("/sim/gui/canvas", true),
-                    "window",
-                    &windowFactory ),
+  Group(simgear::canvas::CanvasPtr(), fgGetNode("/sim/gui/canvas", true)),
   _event_handler( new GUIEventHandler(this) ),
-  _transform( new osg::MatrixTransform ),
-  _width(_props, "size[0]"),
-  _height(_props, "size[1]"),
+  _cb_mouse_mode( this,
+                  &GUIMgr::handleMouseMode,
+                  fgGetNode("/devices/status/mice/mouse[0]/mode") ),
+  _handle_events(true),
+  _width(_node, "size[0]"),
+  _height(_node, "size[1]"),
   _resize(canvas::Window::NONE),
   _last_cursor(MOUSE_CURSOR_NONE),
+  _last_x(-1),
+  _last_y(-1),
   _last_scroll_time(0)
 {
+  // We handle the property listener manually within ::init and ::shutdown.
+  removeListener();
+
   _width = _height = -1;
 
+  // Do not change values on reinit
+  _width.node()->setAttribute(SGPropertyNode::PRESERVE, true);
+  _height.node()->setAttribute(SGPropertyNode::PRESERVE, true);
+
   osg::Camera* camera =
     flightgear::getGUICamera( flightgear::CameraGroup::getDefault() );
   assert(camera);
-  camera->addChild(_transform);
-
-  osg::Viewport* vp = camera->getViewport();
-  handleResize(vp->x(), vp->y(), vp->width(), vp->height());
+  camera->addChild( getMatrixTransform() );
 
   simgear::canvas::Canvas::addPlacementFactory
   (
@@ -156,22 +145,44 @@ GUIMgr::GUIMgr():
   stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
 }
 
+//------------------------------------------------------------------------------
+canvas::WindowPtr GUIMgr::createWindow(const std::string& name)
+{
+  canvas::WindowPtr window = createChild<canvas::Window>(name);
+  if( name.empty() )
+    window->set<std::string>
+    (
+      "id",
+      boost::lexical_cast<std::string>(window->getProps()->getIndex())
+    );
+  return window;
+}
+
 //------------------------------------------------------------------------------
 void GUIMgr::init()
 {
-  PropertyBasedMgr::init();
+  handleResize
+  (
+    0,
+    0,
+    fgGetInt("/sim/startup/xsize"),
+    fgGetInt("/sim/startup/ysize")
+  );
 
   globals->get_renderer()
          ->getViewer()
          ->getEventHandlers()
          // GUI is on top of everything so lets install as first event handler
          .push_front( _event_handler );
+
+  _node->addChangeListener(this);
+  _node->fireCreatedRecursive();
 }
 
 //------------------------------------------------------------------------------
 void GUIMgr::shutdown()
 {
-  PropertyBasedMgr::shutdown();
+  _node->removeChangeListener(this);
 
   globals->get_renderer()
          ->getViewer()
@@ -179,29 +190,9 @@ void GUIMgr::shutdown()
 }
 
 //------------------------------------------------------------------------------
-void GUIMgr::elementCreated(simgear::PropertyBasedElementPtr element)
+void GUIMgr::update(double dt)
 {
-  canvas::WindowPtr window =
-    boost::static_pointer_cast<canvas::Window>(element);
-
-  size_t layer_index = std::max(0, window->getProps()->getIntValue("layer", 1));
-  osg::Group *layer = 0;
-
-  if( layer_index < _transform->getNumChildren() )
-  {
-    layer = _transform->getChild(layer_index)->asGroup();
-    assert(layer);
-  }
-  else
-  {
-    while( _transform->getNumChildren() <= layer_index )
-    {
-      layer = new osg::Group;
-      _transform->addChild(layer);
-    }
-  }
-  window->getGroup()->setUserData(new WindowUserData(window));
-  layer->addChild(window->getGroup());
+  Group::update(dt);
 }
 
 //------------------------------------------------------------------------------
@@ -229,9 +220,12 @@ bool GUIMgr::handleEvent(const osgGA::GUIEventAdapter& ea)
 }
 
 //------------------------------------------------------------------------------
-canvas::WindowPtr GUIMgr::getWindow(size_t i)
+GUIMgr::ElementFactory GUIMgr::getChildFactory(const std::string& type) const
 {
-  return boost::static_pointer_cast<canvas::Window>(_elements[i]);
+  if( type == "window" )
+    return &Element::create<canvas::Window>;
+
+  return Group::getChildFactory(type);
 }
 
 //------------------------------------------------------------------------------
@@ -239,19 +233,13 @@ simgear::canvas::Placements
 GUIMgr::addPlacement( SGPropertyNode* node,
                       simgear::canvas::CanvasPtr canvas )
 {
-  int placement_index = node->getIntValue("index", -1);
+  const std::string& id = node->getStringValue("id");
 
   simgear::canvas::Placements placements;
-  for( size_t i = 0; i < _elements.size(); ++i )
+  canvas::WindowPtr window = getChild<canvas::Window>(id);
+  if( window )
   {
-    if( placement_index >= 0 && static_cast<int>(i) != placement_index )
-      continue;
-
-    canvas::WindowPtr window = getWindow(i);
-    if( !window )
-      continue;
-
-    window->setCanvas(canvas);
+    window->setCanvasContent(canvas);
     placements.push_back(
       simgear::canvas::PlacementPtr(new WindowPlacement(node, window, canvas))
     );
@@ -281,12 +269,11 @@ const float resize_corner = 20;
 //------------------------------------------------------------------------------
 bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea)
 {
-  if( !_transform->getNumChildren() )
+  if( !_transform->getNumChildren() || !_handle_events )
     return false;
 
   namespace sc = simgear::canvas;
-  sc::MouseEventPtr event(new sc::MouseEvent);
-  event->time = ea.getTime();
+  sc::MouseEventPtr event(new sc::MouseEvent(ea));
 
   event->screen_pos.x() = 0.5 * (ea.getXnormalized() + 1) * _width + 0.5;
   event->screen_pos.y() = 0.5 * (ea.getYnormalized() + 1) * _height + 0.5;
@@ -300,10 +287,7 @@ bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea)
   _last_x = event->getScreenX();
   _last_y = event->getScreenY();
 
-  event->client_pos = event->screen_pos;
-  event->button = ea.getButton();
-  event->state = ea.getButtonMask();
-  event->mod = ea.getModKeyMask();
+  event->local_pos = event->client_pos = event->screen_pos;
 
   if( !_resize_window.expired() )
   {
@@ -324,34 +308,33 @@ bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea)
   canvas::WindowPtr window_at_cursor;
   for( int i = _transform->getNumChildren() - 1; i >= 0; --i )
   {
-    osg::Group *layer = _transform->getChild(i)->asGroup();
-    assert(layer);
-    if( !layer->getNumChildren() )
+    osg::Group *element = _transform->getChild(i)->asGroup();
+
+    assert(element);
+    assert(element->getUserData());
+
+    canvas::WindowPtr window =
+      boost::static_pointer_cast<canvas::Window>
+      (
+        static_cast<sc::Element::OSGUserData*>(element->getUserData())->element
+      );
+
+    if( !window->isCapturingEvents() || !window->isVisible() )
       continue;
 
-    for( int j = layer->getNumChildren() - 1; j >= 0; --j )
+    float margin = window->isResizable() ? resize_margin_pos : 0;
+    if( window->getScreenRegion().contains( event->getScreenX(),
+                                            event->getScreenY(),
+                                            margin ) )
     {
-      assert(layer->getChild(j)->getUserData());
-      canvas::WindowPtr window =
-        static_cast<WindowUserData*>(layer->getChild(j)->getUserData())
-          ->window.lock();
-      float margin = window->isResizable() ? resize_margin_pos : 0;
-      if( window->getRegion().contains( event->getScreenX(),
-                                        event->getScreenY(),
-                                        margin ) )
-      {
-        window_at_cursor = window;
-        break;
-      }
-    }
-
-    if( window_at_cursor )
+      window_at_cursor = window;
       break;
+    }
   }
 
   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
@@ -392,7 +375,7 @@ bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea)
       if( ea.getEventType() == osgGA::GUIEventAdapter::PUSH )
       {
         _resize_window = window_at_cursor;
-        window_at_cursor->doRaise();
+        window_at_cursor->raise();
         window_at_cursor->handleResize( _resize | canvas::Window::INIT,
                                         event->delta );
       }
@@ -444,13 +427,10 @@ 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;
 
-        // Let the event position be always relative to the top left window
-        // corner
-        move_event->client_pos.x() -= last_mouse_over->getRegion().x();
-        move_event->client_pos.y() -= last_mouse_over->getRegion().y();
-
-        last_mouse_over->handleMouseEvent(move_event);
+        last_mouse_over->handleEvent(move_event);
       }
       _last_mouse_over = window_at_cursor;
       event->type = sc::Event::MOUSE_MOVE;
@@ -473,11 +453,9 @@ bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea)
 
   if( target_window )
   {
-    // Let the event position be always relative to the top left window corner
-    event->client_pos.x() -= target_window->getRegion().x();
-    event->client_pos.y() -= target_window->getRegion().y();
-
-    return target_window->handleMouseEvent(event);
+    event->client_pos -= toOsg(target_window->getPosition());
+    event->local_pos = event->client_pos;
+    return target_window->handleEvent(event);
   }
   else
     return false;
@@ -500,3 +478,11 @@ void GUIMgr::handleResize(int x, int y, int width, int height)
     0, _height, 0, 1
   ));
 }
+
+//------------------------------------------------------------------------------
+void GUIMgr::handleMouseMode(SGPropertyNode* node)
+{
+  // pass-through indicates events should pass through to the UI
+  _handle_events = fgGetNode("/input/mice/mouse[0]/mode", node->getIntValue())
+                     ->getBoolValue("pass-through");
+}