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>
22 #include <Main/fg_props.hxx>
23 #include <Main/globals.hxx>
24 #include <Viewer/CameraGroup.hxx>
25 #include <Viewer/renderer.hxx>
27 #include <simgear/canvas/Canvas.hxx>
28 #include <simgear/canvas/CanvasPlacement.hxx>
30 #include <osg/BlendFunc>
31 #include <osgViewer/Viewer>
32 #include <osgGA/GUIEventHandler>
34 #include <boost/bind.hpp>
39 class GUIEventHandler:
40 public osgGA::GUIEventHandler
43 GUIEventHandler(GUIMgr* gui_mgr):
47 bool handle( const osgGA::GUIEventAdapter& ea,
48 osgGA::GUIActionAdapter& aa,
52 return _gui_mgr->handleEvent(ea);
60 * Track a canvas placement on a window
62 class WindowPlacement:
63 public simgear::canvas::Placement
66 WindowPlacement( SGPropertyNode* node,
67 canvas::WindowPtr window,
68 simgear::canvas::CanvasPtr canvas ):
75 * Remove placement from window
77 virtual ~WindowPlacement()
79 canvas::WindowPtr window = _window.lock();
80 simgear::canvas::CanvasPtr canvas = _canvas.lock();
82 if( window && canvas && canvas == window->getCanvas().lock() )
83 window->setCanvas( simgear::canvas::CanvasPtr() );
87 canvas::WindowWeakPtr _window;
88 simgear::canvas::CanvasWeakPtr _canvas;
92 * Store pointer to window as user data
95 public osg::Referenced
98 canvas::WindowWeakPtr window;
99 WindowUserData(canvas::WindowPtr window):
104 //------------------------------------------------------------------------------
105 typedef boost::shared_ptr<canvas::Window> WindowPtr;
106 WindowPtr windowFactory(SGPropertyNode* node)
108 return WindowPtr(new canvas::Window(node));
111 //------------------------------------------------------------------------------
113 PropertyBasedMgr( fgGetNode("/sim/gui/canvas", true),
116 _event_handler( new GUIEventHandler(this) ),
117 _transform( new osg::MatrixTransform ),
118 _width(_props, "size[0]"),
119 _height(_props, "size[1]")
121 _width = _height = -1;
123 osg::Camera* camera =
124 flightgear::getGUICamera( flightgear::CameraGroup::getDefault() );
126 camera->addChild(_transform);
128 osg::Viewport* vp = camera->getViewport();
129 handleResize(vp->x(), vp->y(), vp->width(), vp->height());
131 simgear::canvas::Canvas::addPlacementFactory
134 boost::bind(&GUIMgr::addPlacement, this, _1, _2)
137 osg::StateSet* stateSet = _transform->getOrCreateStateSet();
138 stateSet->setDataVariance(osg::Object::STATIC);
139 stateSet->setRenderBinDetails(1000, "RenderBin");
141 // speed optimization?
142 stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
143 stateSet->setAttribute(new osg::BlendFunc(
144 osg::BlendFunc::SRC_ALPHA,
145 osg::BlendFunc::ONE_MINUS_SRC_ALPHA)
147 stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
148 stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
149 stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
150 stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
153 //------------------------------------------------------------------------------
156 PropertyBasedMgr::init();
158 globals->get_renderer()
160 ->addEventHandler( _event_handler );
163 //------------------------------------------------------------------------------
164 void GUIMgr::shutdown()
166 PropertyBasedMgr::shutdown();
168 globals->get_renderer()
170 ->removeEventHandler( _event_handler );
173 //------------------------------------------------------------------------------
174 void GUIMgr::elementCreated(simgear::PropertyBasedElementPtr element)
176 canvas::WindowPtr window =
177 boost::static_pointer_cast<canvas::Window>(element);
179 size_t layer_index = std::max(0, window->getProps()->getIntValue("layer", 1));
180 osg::Group *layer = 0;
182 if( layer_index < _transform->getNumChildren() )
184 layer = _transform->getChild(layer_index)->asGroup();
189 while( _transform->getNumChildren() <= layer_index )
191 layer = new osg::Group;
192 _transform->addChild(layer);
195 window->getGroup()->setUserData(new WindowUserData(window));
196 layer->addChild(window->getGroup());
199 //------------------------------------------------------------------------------
200 bool GUIMgr::handleEvent(const osgGA::GUIEventAdapter& ea)
202 switch( ea.getEventType() )
204 case osgGA::GUIEventAdapter::PUSH:
205 case osgGA::GUIEventAdapter::RELEASE:
206 // case osgGA::GUIEventAdapter::DOUBLECLICK:
207 // // DOUBLECLICK doesn't seem to be triggered...
208 case osgGA::GUIEventAdapter::DRAG:
209 case osgGA::GUIEventAdapter::MOVE:
210 case osgGA::GUIEventAdapter::SCROLL:
211 return handleMouse(ea);
212 case osgGA::GUIEventAdapter::RESIZE:
213 handleResize( ea.getWindowX(),
216 ea.getWindowHeight() );
223 //------------------------------------------------------------------------------
224 canvas::WindowPtr GUIMgr::getWindow(size_t i)
226 return boost::static_pointer_cast<canvas::Window>(_elements[i]);
229 //------------------------------------------------------------------------------
230 simgear::canvas::Placements
231 GUIMgr::addPlacement( SGPropertyNode* node,
232 simgear::canvas::CanvasPtr canvas )
234 int placement_index = node->getIntValue("index", -1);
236 simgear::canvas::Placements placements;
237 for( size_t i = 0; i < _elements.size(); ++i )
239 if( placement_index >= 0 && static_cast<int>(i) != placement_index )
242 canvas::WindowPtr window = getWindow(i);
246 window->setCanvas(canvas);
247 placements.push_back(
248 simgear::canvas::PlacementPtr(new WindowPlacement(node, window, canvas))
254 //------------------------------------------------------------------------------
255 bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea)
257 if( !_transform->getNumChildren() )
260 namespace sc = simgear::canvas;
261 sc::MouseEventPtr event(new sc::MouseEvent);
263 event->pos.x() = 0.5 * (ea.getXnormalized() + 1) * _width + 0.5;
264 event->pos.y() = 0.5 * (ea.getYnormalized() + 1) * _height + 0.5;
265 if( ea.getMouseYOrientation()
266 != osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS )
267 event->pos.y() = _height - event->pos.y();
269 event->delta.x() = event->pos.x() - _last_x;
270 event->delta.y() = event->pos.y() - _last_y;
272 _last_x = event->pos.x();
273 _last_y = event->pos.y();
275 event->button = ea.getButton();
276 event->state = ea.getButtonMask();
277 event->mod = ea.getModKeyMask();
278 //event->scroll = ea.getScrollingMotion();
280 canvas::WindowPtr window_at_cursor;
281 for( int i = _transform->getNumChildren() - 1; i >= 0; --i )
283 osg::Group *layer = _transform->getChild(i)->asGroup();
285 if( !layer->getNumChildren() )
288 for( int j = layer->getNumChildren() - 1; j >= 0; --j )
290 assert(layer->getChild(j)->getUserData());
291 canvas::WindowPtr window =
292 static_cast<WindowUserData*>(layer->getChild(j)->getUserData())
294 if( window->getRegion().contains(event->pos.x(), event->pos.y()) )
296 window_at_cursor = window;
301 if( window_at_cursor )
305 canvas::WindowPtr target_window = window_at_cursor;
306 switch( ea.getEventType() )
308 case osgGA::GUIEventAdapter::PUSH:
309 _last_push = window_at_cursor;
310 event->type = sc::Event::MOUSE_DOWN;
312 // case osgGA::GUIEventAdapter::SCROLL:
313 // event->type = sc::Event::SCROLL;
315 case osgGA::GUIEventAdapter::MOVE:
317 canvas::WindowPtr last_mouse_over = _last_mouse_over.lock();
318 if( last_mouse_over != window_at_cursor && last_mouse_over )
320 sc::MouseEventPtr move_event( new sc::MouseEvent(*event) );
321 move_event->type = sc::Event::MOUSE_LEAVE;
323 // Let the event position be always relative to the top left window corner
324 move_event->pos.x() -= last_mouse_over->getRegion().x();
325 move_event->pos.y() -= last_mouse_over->getRegion().y();
327 last_mouse_over->handleMouseEvent(move_event);
329 _last_mouse_over = window_at_cursor;
330 event->type = sc::Event::MOUSE_MOVE;
333 case osgGA::GUIEventAdapter::RELEASE:
334 target_window = _last_push.lock();
336 event->type = sc::Event::MOUSE_UP;
339 // case osgGA::GUIEventAdapter::DRAG:
340 // target_window = _last_push.lock();
349 // Let the event position be always relative to the top left window corner
350 event->pos.x() -= target_window->getRegion().x();
351 event->pos.y() -= target_window->getRegion().y();
353 return target_window->handleMouseEvent(event);
359 //------------------------------------------------------------------------------
360 void GUIMgr::handleResize(int x, int y, int width, int height)
362 if( _width == width && _height == height )
368 // Origin should be at top left corner, therefore we need to mirror the y-axis
369 _transform->setMatrix(osg::Matrix(