#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>
+
+class DesktopGroup;
+typedef boost::shared_ptr<DesktopGroup> DesktopPtr;
+typedef boost::weak_ptr<DesktopGroup> DesktopWeakPtr;
/**
* Event handler
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* )
- {
- if( ea.getHandled() )
- return false;
- return _gui_mgr->handleEvent(ea);
- }
+ osg::NodeVisitor* );
protected:
- GUIMgr *_gui_mgr;
+ DesktopWeakPtr _desktop;
};
/**
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:
};
/**
- * Store pointer to window as user data
+ * Desktop root group
*/
-class WindowUserData:
- public osg::Referenced
+class DesktopGroup:
+ public simgear::canvas::Group
{
public:
- canvas::WindowWeakPtr window;
- WindowUserData(canvas::WindowPtr window):
- window(window)
- {}
+ 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);
+ }
};
//------------------------------------------------------------------------------
-typedef boost::shared_ptr<canvas::Window> WindowPtr;
-WindowPtr windowFactory(SGPropertyNode* node)
+GUIEventHandler::GUIEventHandler(const DesktopWeakPtr& desktop_group):
+ _desktop( desktop_group )
{
- return WindowPtr(new canvas::Window(node));
+
}
//------------------------------------------------------------------------------
-GUIMgr::GUIMgr():
- PropertyBasedMgr( fgGetNode("/sim/gui/canvas", true),
- "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* )
+{
+ 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)
{
- _width = _height = -1;
-
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());
-
- simgear::canvas::Canvas::addPlacementFactory
- (
- "window",
- boost::bind(&GUIMgr::addPlacement, this, _1, _2)
- );
+ camera->addChild( getMatrixTransform() );
osg::StateSet* stateSet = _transform->getOrCreateStateSet();
stateSet->setDataVariance(osg::Object::STATIC);
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()
- ->getEventHandlers()
- // GUI is on top of everything so lets install as first event handler
- .push_front( _event_handler );
-}
-
-//------------------------------------------------------------------------------
-void GUIMgr::shutdown()
-{
- PropertyBasedMgr::shutdown();
-
- globals->get_renderer()
- ->getViewer()
- ->removeEventHandler( _event_handler );
-}
-
-//------------------------------------------------------------------------------
-void GUIMgr::elementCreated(simgear::PropertyBasedElementPtr element)
-{
- canvas::WindowPtr window =
- boost::static_pointer_cast<canvas::Window>(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() )
{
}
}
-//------------------------------------------------------------------------------
-canvas::WindowPtr GUIMgr::getWindow(size_t i)
-{
- return boost::static_pointer_cast<canvas::Window>(_elements[i]);
-}
-
-//------------------------------------------------------------------------------
-simgear::canvas::Placements
-GUIMgr::addPlacement( SGPropertyNode* node,
- simgear::canvas::CanvasPtr canvas )
-{
- int placement_index = node->getIntValue("index", -1);
-
- simgear::canvas::Placements placements;
- for( size_t i = 0; i < _elements.size(); ++i )
- {
- if( placement_index >= 0 && static_cast<int>(i) != placement_index )
- continue;
-
- canvas::WindowPtr window = getWindow(i);
- if( !window )
- continue;
-
- window->setCanvas(canvas);
- placements.push_back(
- simgear::canvas::PlacementPtr(new WindowPlacement(node, window, canvas))
- );
- }
- return placements;
-}
-
/*
RESIZE AREAS
============
const float resize_corner = 20;
//------------------------------------------------------------------------------
-bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea)
+bool DesktopGroup::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;
_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() )
{
_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;
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<canvas::Window>
+ (
+ static_cast<sc::Element::OSGUserData*>(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 ) )
{
- 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
if( ea.getEventType() == osgGA::GUIEventAdapter::PUSH )
{
_resize_window = window_at_cursor;
- window_at_cursor->doRaise();
- window_at_cursor->handleResize( _resize | canvas::Window::INIT,
- event->delta );
+ _drag_start = event->screen_pos;
+
+ window_at_cursor->raise();
+ window_at_cursor->handleResize(_resize | canvas::Window::INIT);
}
return true;
{
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;
break;
}
case osgGA::GUIEventAdapter::RELEASE:
- target_window = _last_push.lock();
- _last_push.reset();
+ {
event->type = sc::Event::MOUSE_UP;
- break;
+ canvas::WindowPtr last_push = _last_push.lock();
+ _last_push.reset();
+
+ 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;
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;
}
//------------------------------------------------------------------------------
-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;
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<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;
+}