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/globals.hxx>
24 #include <Viewer/CameraGroup.hxx>
25 #include <Viewer/renderer.hxx>
27 #include <osgViewer/Viewer>
28 #include <osgGA/GUIEventHandler>
30 #include <boost/bind.hpp>
35 class GUIEventHandler:
36 public osgGA::GUIEventHandler
39 GUIEventHandler(GUIMgr* gui_mgr):
43 bool handle( const osgGA::GUIEventAdapter& ea,
44 osgGA::GUIActionAdapter& aa,
48 return _gui_mgr->handleEvent(ea);
56 * Track a canvas placement on a window
58 class WindowPlacement:
59 public canvas::Placement
62 WindowPlacement( canvas::WindowPtr window,
69 * Remove placement from window
71 virtual ~WindowPlacement()
73 canvas::WindowPtr window = _window.lock();
74 CanvasPtr canvas = _canvas.lock();
76 if( window && canvas && canvas == window->getCanvas().lock() )
77 window->setCanvas( CanvasPtr() );
81 canvas::WindowWeakPtr _window;
82 CanvasWeakPtr _canvas;
85 //------------------------------------------------------------------------------
86 typedef boost::shared_ptr<canvas::Window> WindowPtr;
87 WindowPtr windowFactory(SGPropertyNode* node)
89 return WindowPtr(new canvas::Window(node));
92 //------------------------------------------------------------------------------
94 PropertyBasedMgr("/sim/gui/canvas", "window", &windowFactory),
95 _event_handler( new GUIEventHandler(this) ),
96 _transform( new osg::MatrixTransform ),
97 _geode_windows( new osg::Geode ),
98 _width(_props, "size[0]"),
99 _height(_props, "size[1]"),
102 _width = _height = -1;
104 osg::Camera* camera =
105 flightgear::getGUICamera( flightgear::CameraGroup::getDefault() );
108 osg::Viewport* vp = camera->getViewport();
109 handleResize(vp->x(), vp->y(), vp->width(), vp->height());
111 _transform->addChild(_geode_windows);
112 camera->addChild(_transform);
114 Canvas::addPlacementFactory
117 boost::bind(&GUIMgr::addPlacement, this, _1, _2)
121 //------------------------------------------------------------------------------
124 PropertyBasedMgr::init();
126 globals->get_renderer()
128 ->addEventHandler( _event_handler );
131 //------------------------------------------------------------------------------
132 void GUIMgr::shutdown()
134 PropertyBasedMgr::shutdown();
136 globals->get_renderer()
138 ->removeEventHandler( _event_handler );
141 //------------------------------------------------------------------------------
142 void GUIMgr::elementCreated(PropertyBasedElementPtr element)
144 _geode_windows->addDrawable
146 static_cast<canvas::Window*>(element.get())->getDrawable()
150 //------------------------------------------------------------------------------
151 bool GUIMgr::handleEvent(const osgGA::GUIEventAdapter& ea)
153 switch( ea.getEventType() )
155 case osgGA::GUIEventAdapter::PUSH:
156 case osgGA::GUIEventAdapter::RELEASE:
157 // case osgGA::GUIEventAdapter::DOUBLECLICK:
158 // // DOUBLECLICK doesn't seem to be triggered...
159 case osgGA::GUIEventAdapter::DRAG:
160 case osgGA::GUIEventAdapter::MOVE:
161 case osgGA::GUIEventAdapter::SCROLL:
162 return handleMouse(ea);
163 // case osgGA::GUIEventAdapter::MOVE:
164 // std::cout << "MOVE" << std::endl;
166 case osgGA::GUIEventAdapter::RESIZE:
167 handleResize( ea.getWindowX(),
170 ea.getWindowHeight() );
177 //------------------------------------------------------------------------------
178 canvas::WindowPtr GUIMgr::getWindow(size_t i)
180 return boost::shared_static_cast<canvas::Window>(_elements[i]);
183 //------------------------------------------------------------------------------
184 canvas::Placements GUIMgr::addPlacement( const SGPropertyNode* node,
187 int placement_index = node->getIntValue("index", -1);
189 canvas::Placements placements;
190 for( size_t i = 0; i < _elements.size(); ++i )
192 if( placement_index > 0 && static_cast<int>(i) != placement_index )
195 canvas::WindowPtr window = getWindow(i);
199 window->setCanvas(canvas);
200 placements.push_back(
201 canvas::PlacementPtr(new WindowPlacement(window, canvas))
207 //------------------------------------------------------------------------------
208 bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea)
210 canvas::MouseEvent event( ea.getEventType() );
212 event.x = 0.5 * (ea.getXnormalized() + 1) * _width + 0.5;
213 event.y = 0.5 * (ea.getYnormalized() + 1) * _height + 0.5;
214 if( ea.getMouseYOrientation()
215 != osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS )
216 event.y = _height - event.y;
218 event.button = ea.getButton();
219 event.state = ea.getButtonMask();
220 event.mod = ea.getModKeyMask();
221 event.scroll = ea.getScrollingMotion();
223 int window_at_cursor = -1;
224 for( size_t i = 0; i < _elements.size(); ++i )
227 && getWindow(i)->getRegion().contains(event.x, event.y) )
229 window_at_cursor = i;
234 int target_window = window_at_cursor;
235 switch( ea.getEventType() )
237 case osgGA::GUIEventAdapter::PUSH:
238 _last_push = window_at_cursor;
240 case osgGA::GUIEventAdapter::SCROLL:
241 case osgGA::GUIEventAdapter::MOVE:
244 case osgGA::GUIEventAdapter::RELEASE:
248 target_window = _last_push;
252 case osgGA::GUIEventAdapter::DRAG:
253 target_window = _last_push;
260 if( target_window >= 0 )
262 canvas::WindowPtr window = getWindow(target_window);
264 event.dx = event.x - _last_x;
265 event.dy = event.y - _last_y;
270 // Let the event position be always relative to the top left window corner
271 event.x -= window->getRegion().x();
272 event.y -= window->getRegion().y();
274 return window->handleMouseEvent(event);
280 //------------------------------------------------------------------------------
281 void GUIMgr::handleResize(int x, int y, int width, int height)
283 if( _width == width && _height == height )
289 // Origin should be at top left corner, therefore we need to mirror the y-axis
290 _transform->setMatrix(osg::Matrix(