From 948d87e561e2f307c6adbd8cb1854f7bd56053ba Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Sat, 11 Aug 2012 23:35:33 +0200 Subject: [PATCH] Canvas: Basic support for window stacking --- src/Canvas/gui_mgr.cxx | 89 ++++++++++++++++++++------- src/Canvas/gui_mgr.hxx | 6 +- src/Canvas/property_based_element.cxx | 12 ++++ src/Canvas/property_based_element.hxx | 3 + src/Canvas/window.cxx | 23 ++++++- src/Canvas/window.hxx | 2 + 6 files changed, 108 insertions(+), 27 deletions(-) diff --git a/src/Canvas/gui_mgr.cxx b/src/Canvas/gui_mgr.cxx index 7d581e6c9..4fa66febd 100644 --- a/src/Canvas/gui_mgr.cxx +++ b/src/Canvas/gui_mgr.cxx @@ -83,6 +83,19 @@ class WindowPlacement: CanvasWeakPtr _canvas; }; +/** + * Store pointer to window as user data + */ +class WindowUserData: + public osg::Referenced +{ + public: + canvas::WindowPtr window; + WindowUserData(canvas::WindowPtr window): + window(window) + {} +}; + //------------------------------------------------------------------------------ typedef boost::shared_ptr WindowPtr; WindowPtr windowFactory(SGPropertyNode* node) @@ -96,8 +109,7 @@ GUIMgr::GUIMgr(): _event_handler( new GUIEventHandler(this) ), _transform( new osg::MatrixTransform ), _width(_props, "size[0]"), - _height(_props, "size[1]"), - _last_push(-1) + _height(_props, "size[1]") { _width = _height = -1; @@ -154,10 +166,27 @@ void GUIMgr::shutdown() //------------------------------------------------------------------------------ void GUIMgr::elementCreated(PropertyBasedElementPtr element) { - _transform->addChild - ( - static_cast(element.get())->getGroup() - ); + canvas::WindowPtr window = + boost::static_pointer_cast(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()); } //------------------------------------------------------------------------------ @@ -220,6 +249,9 @@ canvas::Placements GUIMgr::addPlacement( const SGPropertyNode* node, //------------------------------------------------------------------------------ bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea) { + if( !_transform->getNumChildren() ) + return false; + canvas::MouseEvent event( ea.getEventType() ); event.x = 0.5 * (ea.getXnormalized() + 1) * _width + 0.5; @@ -233,18 +265,31 @@ bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea) event.mod = ea.getModKeyMask(); event.scroll = ea.getScrollingMotion(); - int window_at_cursor = -1; - for( size_t i = 0; i < _elements.size(); ++i ) + canvas::WindowPtr window_at_cursor; + for( int i = _transform->getNumChildren() - 1; i >= 0; --i ) { - if( _elements[i] - && getWindow(i)->getRegion().contains(event.x, event.y) ) + osg::Group *layer = _transform->getChild(i)->asGroup(); + assert(layer); + if( !layer->getNumChildren() ) + continue; + + for( int j = layer->getNumChildren() - 1; j >= 0; --j ) { - window_at_cursor = i; - break; + assert(layer->getChild(j)->getUserData()); + canvas::WindowPtr window = + static_cast(layer->getChild(j)->getUserData())->window; + if( window->getRegion().contains(event.x, event.y) ) + { + window_at_cursor = window; + break; + } } + + if( window_at_cursor ) + break; } - int target_window = window_at_cursor; + canvas::WindowPtr target_window = window_at_cursor; switch( ea.getEventType() ) { case osgGA::GUIEventAdapter::PUSH: @@ -255,25 +300,23 @@ bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea) break; case osgGA::GUIEventAdapter::RELEASE: - if( _last_push < 0 ) + if( !_last_push.expired() ) return false; - target_window = _last_push; - _last_push = -1; + target_window = _last_push.lock(); + _last_push.reset(); break; case osgGA::GUIEventAdapter::DRAG: - target_window = _last_push; + target_window = _last_push.lock(); break; default: return false; } - if( target_window >= 0 ) + if( target_window ) { - canvas::WindowPtr window = getWindow(target_window); - event.dx = event.x - _last_x; event.dy = event.y - _last_y; @@ -281,10 +324,10 @@ bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea) _last_y = event.y; // Let the event position be always relative to the top left window corner - event.x -= window->getRegion().x(); - event.y -= window->getRegion().y(); + event.x -= target_window->getRegion().x(); + event.y -= target_window->getRegion().y(); - return window->handleMouseEvent(event); + return target_window->handleMouseEvent(event); } else return false; diff --git a/src/Canvas/gui_mgr.hxx b/src/Canvas/gui_mgr.hxx index 76722ec7d..8a1ccf786 100644 --- a/src/Canvas/gui_mgr.hxx +++ b/src/Canvas/gui_mgr.hxx @@ -55,9 +55,9 @@ class GUIMgr: simgear::PropertyObject _width, _height; - int _last_push, - _last_x, - _last_y; + canvas::WindowWeakPtr _last_push; + float _last_x, + _last_y; canvas::WindowPtr getWindow(size_t i); canvas::Placements addPlacement( const SGPropertyNode*, diff --git a/src/Canvas/property_based_element.cxx b/src/Canvas/property_based_element.cxx index 3b801a7c1..8672539c0 100644 --- a/src/Canvas/property_based_element.cxx +++ b/src/Canvas/property_based_element.cxx @@ -30,3 +30,15 @@ PropertyBasedElement::~PropertyBasedElement() { _node->removeChangeListener(this); } + +//------------------------------------------------------------------------------ +SGConstPropertyNode_ptr PropertyBasedElement::getProps() const +{ + return _node; +} + +//------------------------------------------------------------------------------ +SGPropertyNode_ptr PropertyBasedElement::getProps() +{ + return _node; +} diff --git a/src/Canvas/property_based_element.hxx b/src/Canvas/property_based_element.hxx index 358ae7d0c..a41914df9 100644 --- a/src/Canvas/property_based_element.hxx +++ b/src/Canvas/property_based_element.hxx @@ -34,6 +34,9 @@ class PropertyBasedElement: virtual void update(double delta_time_sec) = 0; + SGConstPropertyNode_ptr getProps() const; + SGPropertyNode_ptr getProps(); + protected: friend class PropertyBasedMgr; diff --git a/src/Canvas/window.cxx b/src/Canvas/window.cxx index 43c9a1654..e6db4c30a 100644 --- a/src/Canvas/window.cxx +++ b/src/Canvas/window.cxx @@ -59,7 +59,10 @@ namespace canvas //---------------------------------------------------------------------------- void Window::valueChanged(SGPropertyNode * node) { - _image.valueChanged(node); + if( node->getParent() == _node && node->getNameString() == "raise-top" ) + doRaise(node); + else + _image.valueChanged(node); } //---------------------------------------------------------------------------- @@ -95,4 +98,22 @@ namespace canvas return false; } + //---------------------------------------------------------------------------- + void Window::doRaise(SGPropertyNode* node_raise) + { + if( !node_raise->getBoolValue() ) + return; + + BOOST_FOREACH(osg::Group* parent, getGroup()->getParents()) + { + // Remove window... + parent->removeChild(getGroup()); + + // ...and add again as topmost window + parent->addChild(getGroup()); + } + + node_raise->setBoolValue(false); + } + } // namespace canvas diff --git a/src/Canvas/window.hxx b/src/Canvas/window.hxx index 3a94f4c8e..cce5b1aa9 100644 --- a/src/Canvas/window.hxx +++ b/src/Canvas/window.hxx @@ -51,6 +51,8 @@ namespace canvas protected: Image _image; + + void doRaise(SGPropertyNode* node_raise); }; } // namespace canvas