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 "mouse_event.hxx"
21 #include <Canvas/window.hxx>
22 #include <Canvas/canvas.hxx>
24 #include <Main/globals.hxx>
25 #include <Viewer/CameraGroup.hxx>
26 #include <Viewer/renderer.hxx>
28 #include <osgViewer/Viewer>
29 #include <osgGA/GUIEventHandler>
31 #include <boost/bind.hpp>
36 class GUIEventHandler:
37 public osgGA::GUIEventHandler
40 GUIEventHandler(GUIMgr* gui_mgr):
44 bool handle( const osgGA::GUIEventAdapter& ea,
45 osgGA::GUIActionAdapter& aa,
49 return _gui_mgr->handleEvent(ea);
57 * Track a canvas placement on a window
59 class WindowPlacement:
60 public canvas::Placement
63 WindowPlacement( canvas::WindowPtr window,
70 * Remove placement from window
72 virtual ~WindowPlacement()
74 canvas::WindowPtr window = _window.lock();
75 CanvasPtr canvas = _canvas.lock();
77 if( window && canvas && canvas == window->getCanvas().lock() )
78 window->setCanvas( CanvasPtr() );
82 canvas::WindowWeakPtr _window;
83 CanvasWeakPtr _canvas;
86 //------------------------------------------------------------------------------
87 typedef boost::shared_ptr<canvas::Window> WindowPtr;
88 WindowPtr windowFactory(SGPropertyNode* node)
90 return WindowPtr(new canvas::Window(node));
93 //------------------------------------------------------------------------------
95 PropertyBasedMgr("/sim/gui/canvas", "window", &windowFactory),
96 _event_handler( new GUIEventHandler(this) ),
97 _transform( new osg::MatrixTransform ),
98 _geode_windows( new osg::Geode ),
99 _width(_props, "size[0]"),
100 _height(_props, "size[1]"),
103 _width = _height = -1;
105 osg::Camera* camera =
106 flightgear::getGUICamera( flightgear::CameraGroup::getDefault() );
109 osg::Viewport* vp = camera->getViewport();
110 handleResize(vp->x(), vp->y(), vp->width(), vp->height());
112 _transform->addChild(_geode_windows);
113 camera->addChild(_transform);
115 Canvas::addPlacementFactory
118 boost::bind(&GUIMgr::addPlacement, this, _1, _2)
122 //------------------------------------------------------------------------------
125 PropertyBasedMgr::init();
127 globals->get_renderer()
129 ->addEventHandler( _event_handler );
132 //------------------------------------------------------------------------------
133 void GUIMgr::shutdown()
135 PropertyBasedMgr::shutdown();
137 globals->get_renderer()
139 ->removeEventHandler( _event_handler );
142 //------------------------------------------------------------------------------
143 void GUIMgr::elementCreated(PropertyBasedElementPtr element)
145 _geode_windows->addDrawable
147 static_cast<canvas::Window*>(element.get())->getDrawable()
151 //------------------------------------------------------------------------------
152 bool GUIMgr::handleEvent(const osgGA::GUIEventAdapter& ea)
154 switch( ea.getEventType() )
156 case osgGA::GUIEventAdapter::PUSH:
157 case osgGA::GUIEventAdapter::RELEASE:
158 // case osgGA::GUIEventAdapter::DOUBLECLICK:
159 // // DOUBLECLICK doesn't seem to be triggered...
160 case osgGA::GUIEventAdapter::DRAG:
161 case osgGA::GUIEventAdapter::MOVE:
162 case osgGA::GUIEventAdapter::SCROLL:
163 return handleMouse(ea);
164 // case osgGA::GUIEventAdapter::MOVE:
165 // std::cout << "MOVE" << std::endl;
167 case osgGA::GUIEventAdapter::RESIZE:
168 handleResize( ea.getWindowX(),
171 ea.getWindowHeight() );
178 //------------------------------------------------------------------------------
179 canvas::WindowPtr GUIMgr::getWindow(size_t i)
181 return boost::shared_static_cast<canvas::Window>(_elements[i]);
184 //------------------------------------------------------------------------------
185 canvas::Placements GUIMgr::addPlacement( const SGPropertyNode* node,
188 int placement_index = node->getIntValue("index", -1);
190 canvas::Placements placements;
191 for( size_t i = 0; i < _elements.size(); ++i )
193 if( placement_index > 0 && static_cast<int>(i) != placement_index )
196 canvas::WindowPtr window = getWindow(i);
200 window->setCanvas(canvas);
201 placements.push_back(
202 canvas::PlacementPtr(new WindowPlacement(window, canvas))
208 //------------------------------------------------------------------------------
209 bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea)
211 canvas::MouseEvent event( ea.getEventType() );
213 event.x = 0.5 * (ea.getXnormalized() + 1) * _width + 0.5;
214 event.y = 0.5 * (ea.getYnormalized() + 1) * _height + 0.5;
215 if( ea.getMouseYOrientation()
216 != osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS )
217 event.y = _height - event.y;
219 event.button = ea.getButton();
220 event.state = ea.getButtonMask();
221 event.mod = ea.getModKeyMask();
222 event.scroll = ea.getScrollingMotion();
224 int window_at_cursor = -1;
225 for( size_t i = 0; i < _elements.size(); ++i )
228 && getWindow(i)->getRegion().contains(event.x, event.y) )
230 window_at_cursor = i;
235 int target_window = window_at_cursor;
236 switch( ea.getEventType() )
238 case osgGA::GUIEventAdapter::PUSH:
239 _last_push = window_at_cursor;
241 case osgGA::GUIEventAdapter::SCROLL:
242 case osgGA::GUIEventAdapter::MOVE:
245 case osgGA::GUIEventAdapter::RELEASE:
249 target_window = _last_push;
253 case osgGA::GUIEventAdapter::DRAG:
254 target_window = _last_push;
261 if( target_window >= 0 )
263 canvas::WindowPtr window = getWindow(target_window);
265 event.dx = event.x - _last_x;
266 event.dy = event.y - _last_y;
271 // Let the event position be always relative to the top left window corner
272 event.x -= window->getRegion().x();
273 event.y -= window->getRegion().y();
275 return window->handleMouseEvent(event);
281 //------------------------------------------------------------------------------
282 void GUIMgr::handleResize(int x, int y, int width, int height)
284 if( _width == width && _height == height )
290 // Origin should be at top left corner, therefore we need to mirror the y-axis
291 _transform->setMatrix(osg::Matrix(