]> git.mxchange.org Git - flightgear.git/blobdiff - src/Canvas/gui_mgr.cxx
Fix for bug 1304 - crash loading XML route
[flightgear.git] / src / Canvas / gui_mgr.cxx
index b1a58eea6a1fd0c1330aee630b496023a27bce83..453893886ba6ca100590fb8b7135c330242ab758 100644 (file)
 #include <boost/bind.hpp>
 #include <boost/lexical_cast.hpp>
 
+class DesktopGroup;
+typedef boost::shared_ptr<DesktopGroup> DesktopPtr;
+typedef boost::weak_ptr<DesktopGroup> DesktopWeakPtr;
+
 /**
  * Event handler
  */
@@ -43,22 +47,15 @@ class GUIEventHandler:
   public osgGA::GUIEventHandler
 {
   public:
-    GUIEventHandler(GUIMgr* gui_mgr):
-      _gui_mgr( gui_mgr )
-    {}
+    GUIEventHandler(const DesktopWeakPtr& desktop_group);
 
     bool handle( const osgGA::GUIEventAdapter& ea,
                  osgGA::GUIActionAdapter&,
                  osg::Object*,
-                 osg::NodeVisitor* )
-    {
-      if( ea.getHandled() )
-        return false;
-      return _gui_mgr->handleEvent(ea);
-    }
+                 osg::NodeVisitor* );
 
   protected:
-    GUIMgr *_gui_mgr;
+    DesktopWeakPtr _desktop;
 };
 
 /**
@@ -93,12 +90,79 @@ class WindowPlacement:
     simgear::canvas::CanvasWeakPtr _canvas;
 };
 
+/**
+ * Desktop root group
+ */
+class DesktopGroup:
+  public simgear::canvas::Group
+{
+  public:
+    DesktopGroup();
+    bool handleEvent(const osgGA::GUIEventAdapter& ea);
+
+  protected:
+
+    friend class GUIMgr;
+
+    SGPropertyChangeCallback<DesktopGroup> _cb_mouse_mode;
+    bool                                   _handle_events;
+
+    simgear::PropertyObject<int>        _width,
+                                        _height;
+
+    canvas::WindowWeakPtr _last_push,
+                          _last_mouse_over,
+                          _resize_window;
+    uint8_t _resize;
+    int     _last_cursor;
+
+    osg::Vec2 _drag_start;
+    float _last_x,
+          _last_y;
+    double _last_scroll_time;
+
+    bool handleMouse(const osgGA::GUIEventAdapter& ea);
+    void handleResize(int x, int y, int width, int height);
+    void handleMouseMode(SGPropertyNode* node);
+
+    /**
+     *
+     */
+    simgear::canvas::ElementFactory
+    getChildFactory(const std::string& type) const
+    {
+      if( type == "window" )
+        return &Element::create<canvas::Window>;
+
+      return Group::getChildFactory(type);
+    }
+};
+
+//------------------------------------------------------------------------------
+GUIEventHandler::GUIEventHandler(const DesktopWeakPtr& desktop_group):
+  _desktop( desktop_group )
+{
+
+}
+
 //------------------------------------------------------------------------------
-GUIMgr::GUIMgr():
+bool GUIEventHandler::handle( const osgGA::GUIEventAdapter& ea,
+                              osgGA::GUIActionAdapter&,
+                              osg::Object*,
+                              osg::NodeVisitor* )
+{
+  if( ea.getHandled() )
+    return false;
+
+  DesktopPtr desktop = _desktop.lock();
+  return desktop && desktop->handleEvent(ea);
+}
+
+//------------------------------------------------------------------------------
+DesktopGroup::DesktopGroup():
   Group(simgear::canvas::CanvasPtr(), fgGetNode("/sim/gui/canvas", true)),
-  _event_handler( new GUIEventHandler(this) ),
   _cb_mouse_mode( this,
-                  &GUIMgr::handleMouseMode,
+                  &DesktopGroup::handleMouseMode,
                   fgGetNode("/devices/status/mice/mouse[0]/mode") ),
   _handle_events(true),
   _width(_node, "size[0]"),
@@ -109,26 +173,11 @@ GUIMgr::GUIMgr():
   _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( getMatrixTransform() );
 
-  simgear::canvas::Canvas::addPlacementFactory
-  (
-    "window",
-    boost::bind(&GUIMgr::addPlacement, this, _1, _2)
-  );
-
   osg::StateSet* stateSet = _transform->getOrCreateStateSet();
   stateSet->setDataVariance(osg::Object::STATIC);
   stateSet->setRenderBinDetails(1000, "RenderBin");
@@ -143,60 +192,20 @@ GUIMgr::GUIMgr():
   stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
   stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
   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()
-{
-  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()
-{
-  _node->removeChangeListener(this);
+  _width = _height = -1;
 
-  globals->get_renderer()
-         ->getViewer()
-         ->removeEventHandler( _event_handler );
-}
+  // Do not change values on reinit
+  _width.node()->setAttribute(SGPropertyNode::PRESERVE, true);
+  _height.node()->setAttribute(SGPropertyNode::PRESERVE, true);
 
-//------------------------------------------------------------------------------
-void GUIMgr::update(double dt)
-{
-  Group::update(dt);
+  // Do not restore windows on reinit (all windows will need to be recreated,
+  // but hey it's a reset ;-))
+  _node->setAttribute(SGPropertyNode::PRESERVE, true);
 }
 
 //------------------------------------------------------------------------------
-bool GUIMgr::handleEvent(const osgGA::GUIEventAdapter& ea)
+bool DesktopGroup::handleEvent(const osgGA::GUIEventAdapter& ea)
 {
   switch( ea.getEventType() )
   {
@@ -219,34 +228,6 @@ bool GUIMgr::handleEvent(const osgGA::GUIEventAdapter& ea)
   }
 }
 
-//------------------------------------------------------------------------------
-GUIMgr::ElementFactory GUIMgr::getChildFactory(const std::string& type) const
-{
-  if( type == "window" )
-    return &Element::create<canvas::Window>;
-
-  return Group::getChildFactory(type);
-}
-
-//------------------------------------------------------------------------------
-simgear::canvas::Placements
-GUIMgr::addPlacement( SGPropertyNode* node,
-                      simgear::canvas::CanvasPtr canvas )
-{
-  const std::string& id = node->getStringValue("id");
-
-  simgear::canvas::Placements placements;
-  canvas::WindowPtr window = getChild<canvas::Window>(id);
-  if( window )
-  {
-    window->setCanvasContent(canvas);
-    placements.push_back(
-      simgear::canvas::PlacementPtr(new WindowPlacement(node, window, canvas))
-    );
-  }
-  return placements;
-}
-
 /*
 RESIZE AREAS
 ============
@@ -267,7 +248,7 @@ const float resize_margin_neg = 2;
 const float resize_corner = 20;
 
 //------------------------------------------------------------------------------
-bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea)
+bool DesktopGroup::handleMouse(const osgGA::GUIEventAdapter& ea)
 {
   if( !_transform->getNumChildren() || !_handle_events )
     return false;
@@ -298,7 +279,8 @@ bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea)
         _resize_window.reset();
         break;
       case osgGA::GUIEventAdapter::DRAG:
-        _resize_window.lock()->handleResize(_resize, event->delta);
+        _resize_window.lock()->handleResize( _resize,
+                                             event->screen_pos - _drag_start );
         return true;
       default:
         return false;
@@ -314,12 +296,12 @@ bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea)
     assert(element->getUserData());
 
     canvas::WindowPtr window =
-      boost::static_pointer_cast<canvas::Window>
+      boost::dynamic_pointer_cast<canvas::Window>
       (
         static_cast<sc::Element::OSGUserData*>(element->getUserData())->element
       );
 
-    if( !window->isCapturingEvents() || !window->isVisible() )
+    if( !window || !window->isCapturingEvents() || !window->isVisible() )
       continue;
 
     float margin = window->isResizable() ? resize_margin_pos : 0;
@@ -375,9 +357,10 @@ bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea)
       if( ea.getEventType() == osgGA::GUIEventAdapter::PUSH )
       {
         _resize_window = window_at_cursor;
+        _drag_start = event->screen_pos;
+
         window_at_cursor->raise();
-        window_at_cursor->handleResize( _resize | canvas::Window::INIT,
-                                        event->delta );
+        window_at_cursor->handleResize(_resize | canvas::Window::INIT);
       }
 
       return true;
@@ -475,7 +458,7 @@ bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea)
 }
 
 //------------------------------------------------------------------------------
-void GUIMgr::handleResize(int x, int y, int width, int height)
+void DesktopGroup::handleResize(int x, int y, int width, int height)
 {
   if( _width == width && _height == height )
     return;
@@ -493,9 +476,102 @@ void GUIMgr::handleResize(int x, int y, int width, int height)
 }
 
 //------------------------------------------------------------------------------
-void GUIMgr::handleMouseMode(SGPropertyNode* node)
+void DesktopGroup::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");
 }
+
+//------------------------------------------------------------------------------
+GUIMgr::GUIMgr()
+{
+
+}
+
+//------------------------------------------------------------------------------
+canvas::WindowPtr GUIMgr::createWindow(const std::string& name)
+{
+  canvas::WindowPtr window = _desktop->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()
+{
+  DesktopPtr desktop( new DesktopGroup );
+  desktop->handleResize
+  (
+    0,
+    0,
+    fgGetInt("/sim/startup/xsize"),
+    fgGetInt("/sim/startup/ysize")
+  );
+  _desktop = desktop;
+
+  _event_handler = new GUIEventHandler(desktop);
+  globals->get_renderer()
+         ->getViewer()
+         ->getEventHandlers()
+         // GUI is on top of everything so lets install as first event handler
+         .push_front( _event_handler );
+
+  simgear::canvas::Canvas::addPlacementFactory
+  (
+    "window",
+    boost::bind(&GUIMgr::addWindowPlacement, this, _1, _2)
+  );
+
+  _desktop->getProps()->fireCreatedRecursive();
+}
+
+//------------------------------------------------------------------------------
+void GUIMgr::shutdown()
+{
+  _desktop->destroy();
+  _desktop.reset();
+  simgear::canvas::Canvas::removePlacementFactory("window");
+
+  globals->get_renderer()
+         ->getViewer()
+         ->removeEventHandler( _event_handler );
+  _event_handler = 0;
+}
+
+//------------------------------------------------------------------------------
+void GUIMgr::update(double dt)
+{
+  _desktop->update(dt);
+}
+
+//------------------------------------------------------------------------------
+simgear::canvas::GroupPtr GUIMgr::getDesktop()
+{
+  return _desktop;
+}
+
+//------------------------------------------------------------------------------
+simgear::canvas::Placements
+GUIMgr::addWindowPlacement( SGPropertyNode* placement,
+                            simgear::canvas::CanvasPtr canvas )
+{
+  const std::string& id = placement->getStringValue("id");
+
+  simgear::canvas::Placements placements;
+  canvas::WindowPtr window = _desktop->getChild<canvas::Window>(id);
+  if( window )
+  {
+    window->setCanvasContent(canvas);
+    placements.push_back(
+      simgear::canvas::PlacementPtr(
+        new WindowPlacement(placement, window, canvas)
+    ));
+  }
+  return placements;
+}