1 // Canvas gui/dialog manager
3 // Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License as
7 // published by the Free Software Foundation; either version 2 of the
8 // License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 #include "gui_mgr.hxx"
20 #include <Canvas/window.hxx>
21 #include <Canvas/canvas.hxx>
23 #include <Main/fg_props.hxx>
24 #include <Main/globals.hxx>
25 #include <Viewer/CameraGroup.hxx>
26 #include <Viewer/renderer.hxx>
28 #include <osg/BlendFunc>
29 #include <osgViewer/Viewer>
30 #include <osgGA/GUIEventHandler>
32 #include <boost/bind.hpp>
37 class GUIEventHandler:
38 public osgGA::GUIEventHandler
41 GUIEventHandler(GUIMgr* gui_mgr):
45 bool handle( const osgGA::GUIEventAdapter& ea,
46 osgGA::GUIActionAdapter& aa,
50 return _gui_mgr->handleEvent(ea);
58 * Track a canvas placement on a window
60 class WindowPlacement:
61 public canvas::Placement
64 WindowPlacement( canvas::WindowPtr window,
71 * Remove placement from window
73 virtual ~WindowPlacement()
75 canvas::WindowPtr window = _window.lock();
76 CanvasPtr canvas = _canvas.lock();
78 if( window && canvas && canvas == window->getCanvas().lock() )
79 window->setCanvas( CanvasPtr() );
83 canvas::WindowWeakPtr _window;
84 CanvasWeakPtr _canvas;
88 * Store pointer to window as user data
91 public osg::Referenced
94 canvas::WindowWeakPtr window;
95 WindowUserData(canvas::WindowPtr window):
100 //------------------------------------------------------------------------------
101 typedef boost::shared_ptr<canvas::Window> WindowPtr;
102 WindowPtr windowFactory(SGPropertyNode* node)
104 return WindowPtr(new canvas::Window(node));
107 //------------------------------------------------------------------------------
109 PropertyBasedMgr( fgGetNode("/sim/gui/canvas", true),
112 _event_handler( new GUIEventHandler(this) ),
113 _transform( new osg::MatrixTransform ),
114 _width(_props, "size[0]"),
115 _height(_props, "size[1]")
117 _width = _height = -1;
119 osg::Camera* camera =
120 flightgear::getGUICamera( flightgear::CameraGroup::getDefault() );
122 camera->addChild(_transform);
124 osg::Viewport* vp = camera->getViewport();
125 handleResize(vp->x(), vp->y(), vp->width(), vp->height());
127 Canvas::addPlacementFactory
130 boost::bind(&GUIMgr::addPlacement, this, _1, _2)
133 osg::StateSet* stateSet = _transform->getOrCreateStateSet();
134 stateSet->setDataVariance(osg::Object::STATIC);
135 stateSet->setRenderBinDetails(1000, "RenderBin");
137 // speed optimization?
138 stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
139 stateSet->setAttribute(new osg::BlendFunc(
140 osg::BlendFunc::SRC_ALPHA,
141 osg::BlendFunc::ONE_MINUS_SRC_ALPHA)
143 stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
144 stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
145 stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
146 stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
149 //------------------------------------------------------------------------------
152 PropertyBasedMgr::init();
154 globals->get_renderer()
156 ->addEventHandler( _event_handler );
159 //------------------------------------------------------------------------------
160 void GUIMgr::shutdown()
162 PropertyBasedMgr::shutdown();
164 globals->get_renderer()
166 ->removeEventHandler( _event_handler );
169 //------------------------------------------------------------------------------
170 void GUIMgr::elementCreated(simgear::PropertyBasedElementPtr element)
172 canvas::WindowPtr window =
173 boost::static_pointer_cast<canvas::Window>(element);
175 size_t layer_index = std::max(0, window->getProps()->getIntValue("layer", 1));
176 osg::Group *layer = 0;
178 if( layer_index < _transform->getNumChildren() )
180 layer = _transform->getChild(layer_index)->asGroup();
185 while( _transform->getNumChildren() <= layer_index )
187 layer = new osg::Group;
188 _transform->addChild(layer);
191 window->getGroup()->setUserData(new WindowUserData(window));
192 layer->addChild(window->getGroup());
195 //------------------------------------------------------------------------------
196 bool GUIMgr::handleEvent(const osgGA::GUIEventAdapter& ea)
198 switch( ea.getEventType() )
200 case osgGA::GUIEventAdapter::PUSH:
201 case osgGA::GUIEventAdapter::RELEASE:
202 // case osgGA::GUIEventAdapter::DOUBLECLICK:
203 // // DOUBLECLICK doesn't seem to be triggered...
204 case osgGA::GUIEventAdapter::DRAG:
205 case osgGA::GUIEventAdapter::MOVE:
206 case osgGA::GUIEventAdapter::SCROLL:
207 return handleMouse(ea);
208 // case osgGA::GUIEventAdapter::MOVE:
209 // std::cout << "MOVE" << std::endl;
211 case osgGA::GUIEventAdapter::RESIZE:
212 handleResize( ea.getWindowX(),
215 ea.getWindowHeight() );
222 //------------------------------------------------------------------------------
223 canvas::WindowPtr GUIMgr::getWindow(size_t i)
225 return boost::static_pointer_cast<canvas::Window>(_elements[i]);
228 //------------------------------------------------------------------------------
229 canvas::Placements GUIMgr::addPlacement( const SGPropertyNode* node,
232 int placement_index = node->getIntValue("index", -1);
234 canvas::Placements placements;
235 for( size_t i = 0; i < _elements.size(); ++i )
237 if( placement_index >= 0 && static_cast<int>(i) != placement_index )
240 canvas::WindowPtr window = getWindow(i);
244 window->setCanvas(canvas);
245 placements.push_back(
246 canvas::PlacementPtr(new WindowPlacement(window, canvas))
252 //------------------------------------------------------------------------------
253 bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea)
255 if( !_transform->getNumChildren() )
258 canvas::MouseEvent event( ea.getEventType() );
260 event.x = 0.5 * (ea.getXnormalized() + 1) * _width + 0.5;
261 event.y = 0.5 * (ea.getYnormalized() + 1) * _height + 0.5;
262 if( ea.getMouseYOrientation()
263 != osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS )
264 event.y = _height - event.y;
266 event.button = ea.getButton();
267 event.state = ea.getButtonMask();
268 event.mod = ea.getModKeyMask();
269 event.scroll = ea.getScrollingMotion();
271 canvas::WindowPtr window_at_cursor;
272 for( int i = _transform->getNumChildren() - 1; i >= 0; --i )
274 osg::Group *layer = _transform->getChild(i)->asGroup();
276 if( !layer->getNumChildren() )
279 for( int j = layer->getNumChildren() - 1; j >= 0; --j )
281 assert(layer->getChild(j)->getUserData());
282 canvas::WindowPtr window =
283 static_cast<WindowUserData*>(layer->getChild(j)->getUserData())
285 if( window->getRegion().contains(event.x, event.y) )
287 window_at_cursor = window;
292 if( window_at_cursor )
296 canvas::WindowPtr target_window = window_at_cursor;
297 switch( ea.getEventType() )
299 case osgGA::GUIEventAdapter::PUSH:
300 _last_push = window_at_cursor;
302 case osgGA::GUIEventAdapter::SCROLL:
303 case osgGA::GUIEventAdapter::MOVE:
306 case osgGA::GUIEventAdapter::RELEASE:
307 target_window = _last_push.lock();
311 case osgGA::GUIEventAdapter::DRAG:
312 target_window = _last_push.lock();
321 event.dx = event.x - _last_x;
322 event.dy = event.y - _last_y;
327 // Let the event position be always relative to the top left window corner
328 event.x -= target_window->getRegion().x();
329 event.y -= target_window->getRegion().y();
331 return target_window->handleMouseEvent(event);
337 //------------------------------------------------------------------------------
338 void GUIMgr::handleResize(int x, int y, int width, int height)
340 if( _width == width && _height == height )
346 // Origin should be at top left corner, therefore we need to mirror the y-axis
347 _transform->setMatrix(osg::Matrix(