openscenegraph
WindowManager
Go to the documentation of this file.
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2008 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version. The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14// Code by: Jeremy Moles (cubicool) 2007-2008
15
16#ifndef OSGWIDGET_WINDOW_MANAGER
17#define OSGWIDGET_WINDOW_MANAGER
18
19#include <osg/Switch>
20#include <osg/Uniform>
21#include <osg/Drawable>
22#include <osgGA/GUIEventAdapter>
23#include <osgUtil/LineSegmentIntersector>
24#include <osgViewer/View>
25#include <osgWidget/ScriptEngine>
26#include <osgWidget/StyleManager>
27#include <osgWidget/Window>
28
29namespace osgWidget {
30
31// TODO: It should be possible to use something other than osgWidget/ViewerEventHandlers
32// to handle all of these events. In fact, I need to create an SDL example showing this.
33
34// A private typedef that we use for pickAtXY() below.
35typedef osgUtil::LineSegmentIntersector::Intersections Intersections;
36
37// A WindowManager performs pointer interaction with the topmost (highest Z) Widget,
38// and performs keyboard input on the currently focused Window->Widget.
39class OSGWIDGET_EXPORT WindowManager: public osg::Switch, public UIObjectParent<Window> {
40 public:
41 enum WmFlags {
42 WM_USE_LUA = 0x00000001,
43 WM_USE_PYTHON = 0x00000002,
44 WM_USE_RENDERBINS = 0x00000004,
45 WM_PICK_DEBUG = 0x00000008
46 };
47
48 enum PointerDirection {
49 PD_NONE = 0x00000000,
50 PD_LEFT = 0x00000001,
51 PD_RIGHT = 0x00000002,
52 PD_UP = 0x00000004,
53 PD_DOWN = 0x00000008
54 };
55
56 enum PointerFocusMode {
57 PFM_FOCUS = 0x00000000,
58 PFM_UNFOCUS = 0x00000001,
59 PFM_SLOPPY = 0x00000002
60 };
61
62 public:
63 META_Object(osgWidget, WindowManager);
64
65 WindowManager(
66 osgViewer::View* = 0,
67 point_type = 0.0f,
68 point_type = 0.0f,
69 unsigned int = 0,
70 unsigned int = 0
71 );
72
73 WindowManager(const WindowManager&, const osg::CopyOp&);
74
75 virtual ~WindowManager();
76
77 // A static method that will set both the _widget and _window data of an Event
78 // reference from a passed-in Interface.
79 static void setEventFromInterface(Event&, EventInterface*);
80
81 // A static template method that will iterate over a container and return a
82 // properly formed EventInterface*.
83 template<typename T>
84 static EventInterface* getFirstEventInterface(T&, Event&);
85
86 bool pickAtXY (float, float, WidgetList&);
87 bool setFocused (Window*);
88 void setPointerXY (float, float);
89 void setStyleManager (StyleManager*);
90 void resizeAllWindows (bool = true);
91
92 XYCoord windowXY (double, double) const;
93 XYCoord localXY (double, double) const;
94
95 // Methods all called by the ViewerEventHandlers::MouseHandler object, or
96 // by some customer caller of your own. Examples of this to come...
97 bool pointerMove (float, float);
98 bool pointerDrag (float, float);
99 bool mouseScroll (float, float);
100
101 osg::Camera* createParentOrthoCamera();
102
103 unsigned int getNodeMask() const {
104 return _nodeMask;
105 }
106
107 point_type getWidth() const {
108 return _width;
109 }
110
111 point_type getHeight() const {
112 return _height;
113 }
114
115 bool isUsingLua() const {
116 return (_flags & WM_USE_LUA) != 0;
117 }
118
119 bool isUsingPython() const {
120 return (_flags & WM_USE_PYTHON) != 0;
121 }
122
123 bool isUsingRenderBins() const {
124 return (_flags & WM_USE_RENDERBINS) != 0;
125 }
126
127 int getMouseKeysDown() const {
128 int flag = 0;
129
130 flag |= _leftDown ? osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON : 0;
131 flag |= _middleDown ? osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON: 0;
132 flag |= _rightDown ? osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON : 0;
133
134 return flag;
135 }
136
137 ScriptEngine* getLuaEngine() {
138 return _lua.get();
139 }
140
141 const ScriptEngine* getLuaEngine() const {
142 return _lua.get();
143 }
144
145 ScriptEngine* getPythonEngine() {
146 return _python.get();
147 }
148
149 const ScriptEngine* getPythonEngine() const {
150 return _python.get();
151 }
152
153 StyleManager* getStyleManager() {
154 return _styleManager.get();
155 }
156
157 const StyleManager* getStyleManager() const {
158 return _styleManager.get();
159 }
160
161 PointerDirection getPointerVerticalDirection() const {
162 return _lastVertical;
163 }
164
165 PointerDirection getPointerHorizontalDirection() const {
166 return _lastHorizontal;
167 }
168
169 PointerFocusMode getPointerFocusMode() const {
170 return _focusMode;
171 }
172
173 int getPointerDirectionVector() const {
174 return _lastVertical | _lastHorizontal;
175 }
176
177 bool isPointerMovingUp() const {
178 return _lastVertical == PD_UP;
179 }
180
181 bool isPointerMovingDown() const {
182 return _lastVertical == PD_DOWN;
183 }
184
185 bool isPointerMovingLeft() const {
186 return _lastHorizontal == PD_LEFT;
187 }
188
189 bool isPointerMovingRight() const {
190 return _lastHorizontal == PD_RIGHT;
191 }
192
193 bool isPointerMovingVertically() const {
194 return _lastVertical != PD_NONE;
195 }
196
197 bool isPointerMovingHorizontally() const {
198 return _lastHorizontal != PD_NONE;
199 }
200
201 bool isLeftMouseButtonDown() const {
202 return _leftDown;
203 }
204
205 bool isMiddleMouseButtonDown() const {
206 return _middleDown;
207 }
208
209 bool isRightMouseButtonDown() const {
210 return _rightDown;
211 }
212
213 bool isMouseScrollingUp() const {
214 return _scrolling == osgGA::GUIEventAdapter::SCROLL_UP;
215 }
216
217 bool isMouseScrollingDown() const {
218 return _scrolling == osgGA::GUIEventAdapter::SCROLL_DOWN;
219 }
220
221 bool setFocusedByName(const std::string& name) {
222 return setFocused(getByName(name));
223 }
224
225 void setScrollingMotion(osgGA::GUIEventAdapter::ScrollingMotion sm) {
226 _scrolling = sm;
227 }
228
229 void setPointerFocusMode(PointerFocusMode pfm) {
230 _focusMode = pfm;
231 }
232
233 void setWidth(point_type w) {
234 _width = w;
235 }
236
237 void setHeight(point_type h) {
238 _height = h;
239 }
240
241 void setSize(point_type w, point_type h) {
242 _width = w;
243 _height = h;
244 }
245
246 void setWindowSize(point_type w, point_type h) {
247 _windowWidth = w;
248 _windowHeight = h;
249 }
250
251 // Wrappers around the real calls. These only pertains to mouse buttons,
252 // particularly 3-button mice, although there are other more generic
253 // "pointer" API methods.
254 bool mousePushedLeft(float x, float y) {
255 return _handleMousePushed(x, y, _leftDown);
256 }
257
258 bool mousePushedMiddle(float x, float y) {
259 return _handleMousePushed(x, y, _middleDown);
260 }
261
262 bool mousePushedRight(float x, float y) {
263 return _handleMousePushed(x, y, _rightDown);
264 }
265
266 bool mouseReleasedLeft(float x, float y) {
267 return _handleMouseReleased(x, y, _leftDown);
268 }
269
270 bool mouseReleasedMiddle(float x, float y) {
271 return _handleMouseReleased(x, y, _middleDown);
272 }
273
274 bool mouseReleasedRight(float x, float y) {
275 return _handleMouseReleased(x, y, _rightDown);
276 }
277
278 // Keyboards wrappers, as above; takes the key and key's mask code, which
279 // can be compared to osgGA::GUIEventAdapter::{KeySymbol,KeyModMask}.
280 bool keyDown (int, int);
281 bool keyUp (int, int);
282
283 osgViewer::View* getView() { return _view; }
284 const osgViewer::View* getView() const { return _view; }
285
286 private:
287 // A functor used to sort the Windows by their Z component in descending order.
288 struct WindowZCompare
289 {
290 bool operator()(const ptr_type& x, const ptr_type& y) {
291 return x.get()->getZ() > y.get()->getZ();
292 }
293 };
294
295 // A functor used to sort the Windows by their BinNum component in descending order.
296 struct WindowBinNumberCompare
297 {
298 bool operator()(const ptr_type& x, const ptr_type& y) {
299 return
300 x.get()->getOrCreateStateSet()->getBinNumber() >
301 y.get()->getOrCreateStateSet()->getBinNumber()
302 ;
303 }
304 };
305
306 point_type _width;
307 point_type _height;
308 point_type _windowWidth;
309 point_type _windowHeight;
310 unsigned int _flags;
311 unsigned int _nodeMask;
312 osgViewer::View* _view;
313 float _lastX;
314 float _lastY;
315 EventInterface* _lastEvent;
316 EventInterface* _lastPush;
317 PointerDirection _lastVertical;
318 PointerDirection _lastHorizontal;
319 PointerFocusMode _focusMode;
320 bool _leftDown;
321 bool _middleDown;
322 bool _rightDown;
323
324 osgGA::GUIEventAdapter::ScrollingMotion _scrolling;
325
326 osg::ref_ptr<ScriptEngine> _lua;
327 osg::ref_ptr<ScriptEngine> _python;
328 osg::ref_ptr<StyleManager> _styleManager;
329
330 osg::observer_ptr<Widget> _widget;
331 osg::observer_ptr<Window> _focused;
332 osg::observer_ptr<Window> _pickWindow;
333
334 void childInserted (unsigned int);
335 void childRemoved (unsigned int, unsigned int);
336
337 bool _handleMousePushed (float, float, bool&);
338 bool _handleMouseReleased (float, float, bool&);
339 bool _handleMouseScrolled (float, float, bool = false);
340 void _getPointerXYDiff (float&, float&);
341 void _updatePickWindow (const WidgetList*, point_type, point_type);
342
343};
344
345// We use a template here because the container could be a list or a vector; or something
346// else that supports iteration!
347template<typename T>
348EventInterface* WindowManager::getFirstEventInterface(T& container, Event& ev) {
349 if(!container.size()) return 0;
350
351 // See if we can find a Widget that responds to this event...
352 for(typename T::iterator i = container.begin(); i != container.end(); i++) {
353 Widget* widget = i->get();
354
355 // If so, set the _widget/_window members and return it.
356 if(widget->getEventMask() & ev.type) {
357 ev._window = widget->getParent();
358 ev._widget = widget;
359
360 return widget;
361 }
362 }
363
364 // If we can't find a Widget that will accept this event, try and recurse all
365 // of the parent Windows and find one that can.
366 WindowList windowList;
367
368 Window* parent = container.back()->getParent();
369
370 if(parent) {
371 parent->getParentList(windowList);
372
373 // A WindowList from getParentList includes the Window the method was called
374 // on, and the entire tree of parentage.
375 for(WindowList::iterator i = windowList.begin(); i != windowList.end(); i++) {
376 Window* window = i->get();
377
378 if(window->getEventMask() & ev.type) {
379 ev._window = window;
380
381 return window;
382 }
383 }
384 }
385
386 return 0;
387}
388
389}
390
391#endif