1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2008 Robert Osfield
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.
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.
14// Code by: Jeremy Moles (cubicool) 2007-2008
16#ifndef OSGWIDGET_WINDOW_MANAGER
17#define OSGWIDGET_WINDOW_MANAGER
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>
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.
34// A private typedef that we use for pickAtXY() below.
35typedef osgUtil::LineSegmentIntersector::Intersections Intersections;
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> {
42 WM_USE_LUA = 0x00000001,
43 WM_USE_PYTHON = 0x00000002,
44 WM_USE_RENDERBINS = 0x00000004,
45 WM_PICK_DEBUG = 0x00000008
48 enum PointerDirection {
51 PD_RIGHT = 0x00000002,
56 enum PointerFocusMode {
57 PFM_FOCUS = 0x00000000,
58 PFM_UNFOCUS = 0x00000001,
59 PFM_SLOPPY = 0x00000002
63 META_Object(osgWidget, WindowManager);
73 WindowManager(const WindowManager&, const osg::CopyOp&);
75 virtual ~WindowManager();
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*);
81 // A static template method that will iterate over a container and return a
82 // properly formed EventInterface*.
84 static EventInterface* getFirstEventInterface(T&, Event&);
86 bool pickAtXY (float, float, WidgetList&);
87 bool setFocused (Window*);
88 void setPointerXY (float, float);
89 void setStyleManager (StyleManager*);
90 void resizeAllWindows (bool = true);
92 XYCoord windowXY (double, double) const;
93 XYCoord localXY (double, double) const;
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);
101 osg::Camera* createParentOrthoCamera();
103 unsigned int getNodeMask() const {
107 point_type getWidth() const {
111 point_type getHeight() const {
115 bool isUsingLua() const {
116 return (_flags & WM_USE_LUA) != 0;
119 bool isUsingPython() const {
120 return (_flags & WM_USE_PYTHON) != 0;
123 bool isUsingRenderBins() const {
124 return (_flags & WM_USE_RENDERBINS) != 0;
127 int getMouseKeysDown() const {
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;
137 ScriptEngine* getLuaEngine() {
141 const ScriptEngine* getLuaEngine() const {
145 ScriptEngine* getPythonEngine() {
146 return _python.get();
149 const ScriptEngine* getPythonEngine() const {
150 return _python.get();
153 StyleManager* getStyleManager() {
154 return _styleManager.get();
157 const StyleManager* getStyleManager() const {
158 return _styleManager.get();
161 PointerDirection getPointerVerticalDirection() const {
162 return _lastVertical;
165 PointerDirection getPointerHorizontalDirection() const {
166 return _lastHorizontal;
169 PointerFocusMode getPointerFocusMode() const {
173 int getPointerDirectionVector() const {
174 return _lastVertical | _lastHorizontal;
177 bool isPointerMovingUp() const {
178 return _lastVertical == PD_UP;
181 bool isPointerMovingDown() const {
182 return _lastVertical == PD_DOWN;
185 bool isPointerMovingLeft() const {
186 return _lastHorizontal == PD_LEFT;
189 bool isPointerMovingRight() const {
190 return _lastHorizontal == PD_RIGHT;
193 bool isPointerMovingVertically() const {
194 return _lastVertical != PD_NONE;
197 bool isPointerMovingHorizontally() const {
198 return _lastHorizontal != PD_NONE;
201 bool isLeftMouseButtonDown() const {
205 bool isMiddleMouseButtonDown() const {
209 bool isRightMouseButtonDown() const {
213 bool isMouseScrollingUp() const {
214 return _scrolling == osgGA::GUIEventAdapter::SCROLL_UP;
217 bool isMouseScrollingDown() const {
218 return _scrolling == osgGA::GUIEventAdapter::SCROLL_DOWN;
221 bool setFocusedByName(const std::string& name) {
222 return setFocused(getByName(name));
225 void setScrollingMotion(osgGA::GUIEventAdapter::ScrollingMotion sm) {
229 void setPointerFocusMode(PointerFocusMode pfm) {
233 void setWidth(point_type w) {
237 void setHeight(point_type h) {
241 void setSize(point_type w, point_type h) {
246 void setWindowSize(point_type w, point_type h) {
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);
258 bool mousePushedMiddle(float x, float y) {
259 return _handleMousePushed(x, y, _middleDown);
262 bool mousePushedRight(float x, float y) {
263 return _handleMousePushed(x, y, _rightDown);
266 bool mouseReleasedLeft(float x, float y) {
267 return _handleMouseReleased(x, y, _leftDown);
270 bool mouseReleasedMiddle(float x, float y) {
271 return _handleMouseReleased(x, y, _middleDown);
274 bool mouseReleasedRight(float x, float y) {
275 return _handleMouseReleased(x, y, _rightDown);
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);
283 osgViewer::View* getView() { return _view; }
284 const osgViewer::View* getView() const { return _view; }
287 // A functor used to sort the Windows by their Z component in descending order.
288 struct WindowZCompare
290 bool operator()(const ptr_type& x, const ptr_type& y) {
291 return x.get()->getZ() > y.get()->getZ();
295 // A functor used to sort the Windows by their BinNum component in descending order.
296 struct WindowBinNumberCompare
298 bool operator()(const ptr_type& x, const ptr_type& y) {
300 x.get()->getOrCreateStateSet()->getBinNumber() >
301 y.get()->getOrCreateStateSet()->getBinNumber()
308 point_type _windowWidth;
309 point_type _windowHeight;
311 unsigned int _nodeMask;
312 osgViewer::View* _view;
315 EventInterface* _lastEvent;
316 EventInterface* _lastPush;
317 PointerDirection _lastVertical;
318 PointerDirection _lastHorizontal;
319 PointerFocusMode _focusMode;
324 osgGA::GUIEventAdapter::ScrollingMotion _scrolling;
326 osg::ref_ptr<ScriptEngine> _lua;
327 osg::ref_ptr<ScriptEngine> _python;
328 osg::ref_ptr<StyleManager> _styleManager;
330 osg::observer_ptr<Widget> _widget;
331 osg::observer_ptr<Window> _focused;
332 osg::observer_ptr<Window> _pickWindow;
334 void childInserted (unsigned int);
335 void childRemoved (unsigned int, unsigned int);
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);
345// We use a template here because the container could be a list or a vector; or something
346// else that supports iteration!
348EventInterface* WindowManager::getFirstEventInterface(T& container, Event& ev) {
349 if(!container.size()) return 0;
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();
355 // If so, set the _widget/_window members and return it.
356 if(widget->getEventMask() & ev.type) {
357 ev._window = widget->getParent();
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;
368 Window* parent = container.back()->getParent();
371 parent->getParentList(windowList);
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();
378 if(window->getEventMask() & ev.type) {