X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FCanvas%2Fgui_mgr.cxx;h=453893886ba6ca100590fb8b7135c330242ab758;hb=b0dcb657e77579ecc79798ff365737095f96f9e2;hp=4fa66febd24830533b1c932d5a0145f1b2c5edad;hpb=948d87e561e2f307c6adbd8cb1854f7bd56053ba;p=flightgear.git diff --git a/src/Canvas/gui_mgr.cxx b/src/Canvas/gui_mgr.cxx index 4fa66febd..453893886 100644 --- a/src/Canvas/gui_mgr.cxx +++ b/src/Canvas/gui_mgr.cxx @@ -18,17 +18,27 @@ #include "gui_mgr.hxx" #include -#include +#include
+#include
#include
#include #include +#include +#include +#include + #include #include #include #include +#include + +class DesktopGroup; +typedef boost::shared_ptr DesktopPtr; +typedef boost::weak_ptr DesktopWeakPtr; /** * Event handler @@ -37,31 +47,28 @@ 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& aa, + osgGA::GUIActionAdapter&, osg::Object*, - osg::NodeVisitor* ) - { - return _gui_mgr->handleEvent(ea); - } + osg::NodeVisitor* ); protected: - GUIMgr *_gui_mgr; + DesktopWeakPtr _desktop; }; /** * Track a canvas placement on a window */ class WindowPlacement: - public canvas::Placement + public simgear::canvas::Placement { public: - WindowPlacement( canvas::WindowPtr window, - CanvasPtr canvas ): + WindowPlacement( SGPropertyNode* node, + canvas::WindowPtr window, + simgear::canvas::CanvasPtr canvas ): + Placement(node), _window(window), _canvas(canvas) {} @@ -72,60 +79,104 @@ class WindowPlacement: virtual ~WindowPlacement() { canvas::WindowPtr window = _window.lock(); - CanvasPtr canvas = _canvas.lock(); + simgear::canvas::CanvasPtr canvas = _canvas.lock(); - if( window && canvas && canvas == window->getCanvas().lock() ) - window->setCanvas( CanvasPtr() ); + if( window && canvas && canvas == window->getCanvasContent().lock() ) + window->setCanvasContent( simgear::canvas::CanvasPtr() ); } private: canvas::WindowWeakPtr _window; - CanvasWeakPtr _canvas; + simgear::canvas::CanvasWeakPtr _canvas; }; /** - * Store pointer to window as user data + * Desktop root group */ -class WindowUserData: - public osg::Referenced +class DesktopGroup: + public simgear::canvas::Group { public: - canvas::WindowPtr window; - WindowUserData(canvas::WindowPtr window): - window(window) - {} + DesktopGroup(); + bool handleEvent(const osgGA::GUIEventAdapter& ea); + + protected: + + friend class GUIMgr; + + SGPropertyChangeCallback _cb_mouse_mode; + bool _handle_events; + + simgear::PropertyObject _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; + + return Group::getChildFactory(type); + } }; //------------------------------------------------------------------------------ -typedef boost::shared_ptr WindowPtr; -WindowPtr windowFactory(SGPropertyNode* node) +GUIEventHandler::GUIEventHandler(const DesktopWeakPtr& desktop_group): + _desktop( desktop_group ) { - return WindowPtr(new canvas::Window(node)); + } //------------------------------------------------------------------------------ -GUIMgr::GUIMgr(): - PropertyBasedMgr("/sim/gui/canvas", "window", &windowFactory), - _event_handler( new GUIEventHandler(this) ), - _transform( new osg::MatrixTransform ), - _width(_props, "size[0]"), - _height(_props, "size[1]") +bool GUIEventHandler::handle( const osgGA::GUIEventAdapter& ea, + osgGA::GUIActionAdapter&, + osg::Object*, + osg::NodeVisitor* ) { - _width = _height = -1; + 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)), + _cb_mouse_mode( this, + &DesktopGroup::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) +{ 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()); - - Canvas::addPlacementFactory - ( - "window", - boost::bind(&GUIMgr::addPlacement, this, _1, _2) - ); + camera->addChild( getMatrixTransform() ); osg::StateSet* stateSet = _transform->getOrCreateStateSet(); stateSet->setDataVariance(osg::Object::STATIC); @@ -141,56 +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); -} - -//------------------------------------------------------------------------------ -void GUIMgr::init() -{ - PropertyBasedMgr::init(); - - globals->get_renderer() - ->getViewer() - ->addEventHandler( _event_handler ); -} - -//------------------------------------------------------------------------------ -void GUIMgr::shutdown() -{ - PropertyBasedMgr::shutdown(); - globals->get_renderer() - ->getViewer() - ->removeEventHandler( _event_handler ); -} - -//------------------------------------------------------------------------------ -void GUIMgr::elementCreated(PropertyBasedElementPtr element) -{ - canvas::WindowPtr window = - boost::static_pointer_cast(element); + _width = _height = -1; - size_t layer_index = std::max(0, window->getProps()->getIntValue("layer", 1)); - osg::Group *layer = 0; + // Do not change values on reinit + _width.node()->setAttribute(SGPropertyNode::PRESERVE, true); + _height.node()->setAttribute(SGPropertyNode::PRESERVE, true); - 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()); + // 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() ) { @@ -202,91 +217,161 @@ bool GUIMgr::handleEvent(const osgGA::GUIEventAdapter& ea) case osgGA::GUIEventAdapter::MOVE: case osgGA::GUIEventAdapter::SCROLL: return handleMouse(ea); -// case osgGA::GUIEventAdapter::MOVE: -// std::cout << "MOVE" << std::endl; -// break; case osgGA::GUIEventAdapter::RESIZE: handleResize( ea.getWindowX(), ea.getWindowY(), ea.getWindowWidth(), ea.getWindowHeight() ); - return true; + return false; // Let other event handlers also consume resize events default: return false; } } -//------------------------------------------------------------------------------ -canvas::WindowPtr GUIMgr::getWindow(size_t i) -{ - return boost::static_pointer_cast(_elements[i]); -} +/* +RESIZE AREAS +============ + +| || | _ inside corner region (L-shaped part inside margin) both +|___||_|_ _ _/ directions can be resized (outside only one axis) +| || | | +| || | +| || |_____|__ _ +| || | } margin_neg \ +| ========|== <-- window border |_ area where resize +| | } margin_pos | can be initiated +|____________|__/ _/ +|<- corner ->| +*/ +const float resize_margin_pos = 12; +const float resize_margin_neg = 2; +const float resize_corner = 20; //------------------------------------------------------------------------------ -canvas::Placements GUIMgr::addPlacement( const SGPropertyNode* node, - CanvasPtr canvas ) +bool DesktopGroup::handleMouse(const osgGA::GUIEventAdapter& ea) { - int placement_index = node->getIntValue("index", -1); - - canvas::Placements placements; - for( size_t i = 0; i < _elements.size(); ++i ) - { - if( placement_index > 0 && static_cast(i) != placement_index ) - continue; - - canvas::WindowPtr window = getWindow(i); - if( !window ) - continue; - - window->setCanvas(canvas); - placements.push_back( - canvas::PlacementPtr(new WindowPlacement(window, canvas)) - ); - } - return placements; -} - -//------------------------------------------------------------------------------ -bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea) -{ - if( !_transform->getNumChildren() ) + if( !_transform->getNumChildren() || !_handle_events ) return false; - canvas::MouseEvent event( ea.getEventType() ); + namespace sc = simgear::canvas; + sc::MouseEventPtr event(new sc::MouseEvent(ea)); - event.x = 0.5 * (ea.getXnormalized() + 1) * _width + 0.5; - event.y = 0.5 * (ea.getYnormalized() + 1) * _height + 0.5; + event->screen_pos.x() = 0.5 * (ea.getXnormalized() + 1) * _width + 0.5; + event->screen_pos.y() = 0.5 * (ea.getYnormalized() + 1) * _height + 0.5; if( ea.getMouseYOrientation() != osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS ) - event.y = _height - event.y; + event->screen_pos.y() = _height - event->screen_pos.y(); - event.button = ea.getButton(); - event.state = ea.getButtonMask(); - event.mod = ea.getModKeyMask(); - event.scroll = ea.getScrollingMotion(); + event->delta.x() = event->getScreenX() - _last_x; + event->delta.y() = event->getScreenY() - _last_y; + + _last_x = event->getScreenX(); + _last_y = event->getScreenY(); + + event->local_pos = event->client_pos = event->screen_pos; + + if( !_resize_window.expired() ) + { + switch( ea.getEventType() ) + { + case osgGA::GUIEventAdapter::RELEASE: + _resize_window.lock()->handleResize(canvas::Window::NONE); + _resize_window.reset(); + break; + case osgGA::GUIEventAdapter::DRAG: + _resize_window.lock()->handleResize( _resize, + event->screen_pos - _drag_start ); + return true; + default: + return false; + } + } 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::dynamic_pointer_cast + ( + static_cast(element->getUserData())->element + ); + + if( !window || !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 ) ) + { + window_at_cursor = window; + break; + } + } + + if( window_at_cursor ) + { + const SGRect& reg = window_at_cursor->getScreenRegion(); + + if( window_at_cursor->isResizable() + && ( ea.getEventType() == osgGA::GUIEventAdapter::MOVE + || ea.getEventType() == osgGA::GUIEventAdapter::PUSH + || ea.getEventType() == osgGA::GUIEventAdapter::RELEASE + ) + && !reg.contains( event->getScreenX(), + event->getScreenY(), + -resize_margin_neg ) ) { - assert(layer->getChild(j)->getUserData()); - canvas::WindowPtr window = - static_cast(layer->getChild(j)->getUserData())->window; - if( window->getRegion().contains(event.x, event.y) ) + if( !_last_cursor ) + _last_cursor = fgGetMouseCursor(); + + _resize = 0; + + if( event->getScreenX() <= reg.l() + resize_corner ) + _resize |= canvas::Window::LEFT; + else if( event->getScreenX() >= reg.r() - resize_corner ) + _resize |= canvas::Window::RIGHT; + + if( event->getScreenY() <= reg.t() + resize_corner ) + _resize |= canvas::Window::TOP; + else if( event->getScreenY() >= reg.b() - resize_corner ) + _resize |= canvas::Window::BOTTOM; + + static const int cursor_mapping[] = { - window_at_cursor = window; - break; + 0, MOUSE_CURSOR_LEFTSIDE, MOUSE_CURSOR_RIGHTSIDE, 0, + MOUSE_CURSOR_TOPSIDE, MOUSE_CURSOR_TOPLEFT, MOUSE_CURSOR_TOPRIGHT, 0, + MOUSE_CURSOR_BOTTOMSIDE, MOUSE_CURSOR_BOTTOMLEFT, MOUSE_CURSOR_BOTTOMRIGHT, + }; + + if( !cursor_mapping[_resize] ) + return false; + + fgSetMouseCursor(cursor_mapping[_resize]); + + 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); } + + return true; } + } - if( window_at_cursor ) - break; + if( _last_cursor ) + { + fgSetMouseCursor(_last_cursor); + _last_cursor = 0; + return true; } canvas::WindowPtr target_window = window_at_cursor; @@ -294,21 +379,68 @@ bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea) { case osgGA::GUIEventAdapter::PUSH: _last_push = window_at_cursor; + event->type = sc::Event::MOUSE_DOWN; break; case osgGA::GUIEventAdapter::SCROLL: - case osgGA::GUIEventAdapter::MOVE: + switch( ea.getScrollingMotion() ) + { + case osgGA::GUIEventAdapter::SCROLL_UP: + event->delta.y() = 1; + break; + case osgGA::GUIEventAdapter::SCROLL_DOWN: + event->delta.y() = -1; + break; + default: + return false; + } + + // osg sends two events for every scrolling motion. We don't need + // duplicate events, so lets ignore the second event with the same + // timestamp. + if( _last_scroll_time == ea.getTime() ) + return window_at_cursor ? true : false; + _last_scroll_time = ea.getTime(); + + event->type = sc::Event::WHEEL; break; + case osgGA::GUIEventAdapter::MOVE: + { + canvas::WindowPtr last_mouse_over = _last_mouse_over.lock(); + if( last_mouse_over != window_at_cursor && last_mouse_over ) + { + 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->handleEvent(move_event); + } + _last_mouse_over = window_at_cursor; + event->type = sc::Event::MOUSE_MOVE; + break; + } case osgGA::GUIEventAdapter::RELEASE: - if( !_last_push.expired() ) - return false; + { + event->type = sc::Event::MOUSE_UP; - target_window = _last_push.lock(); + canvas::WindowPtr last_push = _last_push.lock(); _last_push.reset(); - break; + if( last_push && last_push != target_window ) + { + // Leave old window + sc::MouseEventPtr leave_event( new sc::MouseEvent(*event) ); + leave_event->type = sc::Event::MOUSE_LEAVE; + leave_event->client_pos -= toOsg(last_push->getPosition()); + leave_event->local_pos = leave_event->client_pos; + + last_push->handleEvent(leave_event); + } + break; + } case osgGA::GUIEventAdapter::DRAG: target_window = _last_push.lock(); + event->type = sc::Event::DRAG; break; default: @@ -317,24 +449,16 @@ bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea) if( target_window ) { - event.dx = event.x - _last_x; - event.dy = event.y - _last_y; - - _last_x = event.x; - _last_y = event.y; - - // Let the event position be always relative to the top left window corner - event.x -= target_window->getRegion().x(); - event.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; } //------------------------------------------------------------------------------ -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; @@ -350,3 +474,104 @@ void GUIMgr::handleResize(int x, int y, int width, int height) 0, _height, 0, 1 )); } + +//------------------------------------------------------------------------------ +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(name); + if( name.empty() ) + window->set + ( + "id", + boost::lexical_cast(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(id); + if( window ) + { + window->setCanvasContent(canvas); + placements.push_back( + simgear::canvas::PlacementPtr( + new WindowPlacement(placement, window, canvas) + )); + } + return placements; +}