| 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_EVENT_INTERFACE |
|---|
| 17 | #define OSGWIDGET_EVENT_INTERFACE |
|---|
| 18 | |
|---|
| 19 | #include <list> |
|---|
| 20 | #include <osg/ref_ptr> |
|---|
| 21 | #include <osg/observer_ptr> |
|---|
| 22 | #include <osg/Referenced> |
|---|
| 23 | |
|---|
| 24 | #include <osgWidget/Export> |
|---|
| 25 | |
|---|
| 26 | namespace osgWidget { |
|---|
| 27 | |
|---|
| 28 | class WindowManager; |
|---|
| 29 | class Window; |
|---|
| 30 | class Widget; |
|---|
| 31 | |
|---|
| 32 | enum EventType |
|---|
| 33 | { |
|---|
| 34 | EVENT_NONE = 0x0000, |
|---|
| 35 | EVENT_FOCUS = 0x0001, |
|---|
| 36 | EVENT_UNFOCUS = 0x0002, |
|---|
| 37 | EVENT_MOUSE_ENTER = 0x0004, |
|---|
| 38 | EVENT_MOUSE_OVER = 0x0008, |
|---|
| 39 | EVENT_MOUSE_LEAVE = 0x0010, |
|---|
| 40 | EVENT_MOUSE_DRAG = 0x0020, |
|---|
| 41 | EVENT_MOUSE_PUSH = 0x0040, |
|---|
| 42 | EVENT_MOUSE_RELEASE = 0x0080, |
|---|
| 43 | EVENT_MOUSE_SCROLL = 0x0100, |
|---|
| 44 | EVENT_KEY_DOWN = 0x0200, |
|---|
| 45 | EVENT_KEY_UP = 0x0400, |
|---|
| 46 | EVENT_ALL = 0xFFFF |
|---|
| 47 | }; |
|---|
| 48 | |
|---|
| 49 | // Helpful wrapper around using the raw types, since it often doesn't make sense to |
|---|
| 50 | // use some without the others. |
|---|
| 51 | enum EventMask |
|---|
| 52 | { |
|---|
| 53 | EVENT_MASK_FOCUS = EVENT_FOCUS | EVENT_UNFOCUS, |
|---|
| 54 | EVENT_MASK_MOUSE_MOVE = EVENT_MOUSE_ENTER | EVENT_MOUSE_OVER | EVENT_MOUSE_LEAVE, |
|---|
| 55 | EVENT_MASK_MOUSE_CLICK = EVENT_MOUSE_PUSH | EVENT_MOUSE_RELEASE, |
|---|
| 56 | EVENT_MASK_MOUSE_DRAG = EVENT_MASK_MOUSE_MOVE | EVENT_MASK_MOUSE_CLICK | EVENT_MOUSE_DRAG, |
|---|
| 57 | EVENT_MASK_KEY = EVENT_KEY_UP | EVENT_KEY_DOWN |
|---|
| 58 | }; |
|---|
| 59 | |
|---|
| 60 | class OSGWIDGET_EXPORT Event |
|---|
| 61 | { |
|---|
| 62 | public: |
|---|
| 63 | EventType type; |
|---|
| 64 | double x; |
|---|
| 65 | double y; |
|---|
| 66 | int key; |
|---|
| 67 | int keyMask; |
|---|
| 68 | |
|---|
| 69 | Event(WindowManager* wm, EventType _type = EVENT_NONE): |
|---|
| 70 | type (_type), |
|---|
| 71 | x (0.0f), |
|---|
| 72 | y (0.0f), |
|---|
| 73 | key (-1), |
|---|
| 74 | keyMask (-1), |
|---|
| 75 | _wm (wm), |
|---|
| 76 | _window (0), |
|---|
| 77 | _widget (0), |
|---|
| 78 | _data (0) { |
|---|
| 79 | } |
|---|
| 80 | |
|---|
| 81 | Event& makeType(EventType _type) { |
|---|
| 82 | if(_type != EVENT_NONE) type = _type; |
|---|
| 83 | |
|---|
| 84 | return *this; |
|---|
| 85 | } |
|---|
| 86 | |
|---|
| 87 | Event& makeMouse(double _x, double _y, EventType _type = EVENT_NONE) { |
|---|
| 88 | x = _x; |
|---|
| 89 | y = _y; |
|---|
| 90 | |
|---|
| 91 | if(_type != EVENT_NONE) type = _type; |
|---|
| 92 | |
|---|
| 93 | return *this; |
|---|
| 94 | } |
|---|
| 95 | |
|---|
| 96 | Event& makeKey(int _key, int _keyMask, EventType _type = EVENT_NONE) { |
|---|
| 97 | key = _key; |
|---|
| 98 | keyMask = _keyMask; |
|---|
| 99 | |
|---|
| 100 | if(_type != EVENT_NONE) type = _type; |
|---|
| 101 | |
|---|
| 102 | return *this; |
|---|
| 103 | } |
|---|
| 104 | |
|---|
| 105 | WindowManager* getWindowManager() { return _wm; } |
|---|
| 106 | |
|---|
| 107 | const WindowManager* getWindowManager() const { |
|---|
| 108 | return _wm; |
|---|
| 109 | } |
|---|
| 110 | |
|---|
| 111 | Window* getWindow() { |
|---|
| 112 | return _window; |
|---|
| 113 | } |
|---|
| 114 | |
|---|
| 115 | const Window* getWindow() const { |
|---|
| 116 | return _window; |
|---|
| 117 | } |
|---|
| 118 | |
|---|
| 119 | Widget* getWidget() { |
|---|
| 120 | return _widget; |
|---|
| 121 | } |
|---|
| 122 | |
|---|
| 123 | const Widget* getWidget() const { |
|---|
| 124 | return _widget; |
|---|
| 125 | } |
|---|
| 126 | |
|---|
| 127 | void* getData() { |
|---|
| 128 | return _data; |
|---|
| 129 | } |
|---|
| 130 | |
|---|
| 131 | const void* getData() const { |
|---|
| 132 | return _data; |
|---|
| 133 | } |
|---|
| 134 | |
|---|
| 135 | void setData(void* data) { |
|---|
| 136 | _data = data; |
|---|
| 137 | } |
|---|
| 138 | |
|---|
| 139 | protected: |
|---|
| 140 | |
|---|
| 141 | friend class WindowManager; |
|---|
| 142 | friend class Window; |
|---|
| 143 | |
|---|
| 144 | WindowManager* _wm; |
|---|
| 145 | Window* _window; |
|---|
| 146 | Widget* _widget; |
|---|
| 147 | void* _data; |
|---|
| 148 | |
|---|
| 149 | }; |
|---|
| 150 | |
|---|
| 151 | // The Callback interface was inspired by the CEGUI project: |
|---|
| 152 | // |
|---|
| 153 | // http://www.cegui.org.uk/wiki/index.php/Main_Page |
|---|
| 154 | // |
|---|
| 155 | // It's a great little way to cleanly implement callbacks for events, although |
|---|
| 156 | // I did change the names a bit to make them more appropriate for OSG. MANY THANKS |
|---|
| 157 | // to the CEGUI project! |
|---|
| 158 | |
|---|
| 159 | // The CallbackInterface, which the highest-level functor keeps a pointer to. |
|---|
| 160 | struct CallbackInterface: public osg::Referenced |
|---|
| 161 | { |
|---|
| 162 | virtual ~CallbackInterface() {} |
|---|
| 163 | |
|---|
| 164 | virtual const char* className() const { return "osgWidget::CallbackInterface"; } |
|---|
| 165 | |
|---|
| 166 | virtual bool operator()(Event&) = 0; |
|---|
| 167 | }; |
|---|
| 168 | |
|---|
| 169 | // The object that facilitates a class method as a callback. |
|---|
| 170 | template<typename T> |
|---|
| 171 | class ObjectCallback: public CallbackInterface |
|---|
| 172 | { |
|---|
| 173 | public: |
|---|
| 174 | typedef bool (T::*ObjectCallbackType)(Event&); |
|---|
| 175 | |
|---|
| 176 | ObjectCallback(ObjectCallbackType callback, T* obj): |
|---|
| 177 | _object (obj), |
|---|
| 178 | _callback (callback) {} |
|---|
| 179 | |
|---|
| 180 | virtual bool operator()(Event& ev) { |
|---|
| 181 | return (_object->*_callback)(ev); |
|---|
| 182 | } |
|---|
| 183 | |
|---|
| 184 | private: |
|---|
| 185 | T* _object; |
|---|
| 186 | ObjectCallbackType _callback; |
|---|
| 187 | }; |
|---|
| 188 | |
|---|
| 189 | // The object that facilitates general functions as callbacks. |
|---|
| 190 | template<typename T> |
|---|
| 191 | class FunctionCallback: public CallbackInterface |
|---|
| 192 | { |
|---|
| 193 | public: |
|---|
| 194 | FunctionCallback(T* callback): |
|---|
| 195 | _callback(callback) { |
|---|
| 196 | } |
|---|
| 197 | |
|---|
| 198 | virtual bool operator()(Event& ev) { |
|---|
| 199 | return (*_callback)(ev); |
|---|
| 200 | } |
|---|
| 201 | protected: |
|---|
| 202 | T* _callback; |
|---|
| 203 | }; |
|---|
| 204 | |
|---|
| 205 | // The highlevel functor. |
|---|
| 206 | class OSGWIDGET_EXPORT Callback: public osg::Referenced |
|---|
| 207 | { |
|---|
| 208 | public: |
|---|
| 209 | Callback(): _type(EVENT_NONE), _data(0), _callback(0) {} |
|---|
| 210 | Callback(const Callback& rhs): osg::Referenced(rhs), _type(rhs._type), _data(rhs._data), _callback(rhs._callback) {} |
|---|
| 211 | |
|---|
| 212 | virtual const char* className() const { return "osgWidget::Callback"; } |
|---|
| 213 | |
|---|
| 214 | // The more traditional style of OSG Callbacks. |
|---|
| 215 | Callback(EventType type, void* data=0): |
|---|
| 216 | _type (type), |
|---|
| 217 | _data (data), |
|---|
| 218 | _callback (0) { |
|---|
| 219 | } |
|---|
| 220 | |
|---|
| 221 | // Creates a Callback that is bound to a member function. |
|---|
| 222 | template<typename T> |
|---|
| 223 | Callback(bool (T::*function)(Event&), T* obj, EventType type, void* data=0): |
|---|
| 224 | _type (type), |
|---|
| 225 | _data (data), |
|---|
| 226 | _callback (new ObjectCallback<T>(function, obj)) { |
|---|
| 227 | } |
|---|
| 228 | |
|---|
| 229 | // Creates a Callback that is bound to a functor pointer. |
|---|
| 230 | template<typename T> |
|---|
| 231 | Callback(T* functor, EventType type, void* data=0): |
|---|
| 232 | _type (type), |
|---|
| 233 | _data (data), |
|---|
| 234 | _callback (new FunctionCallback<T>(functor)) { |
|---|
| 235 | } |
|---|
| 236 | |
|---|
| 237 | virtual ~Callback() {} |
|---|
| 238 | |
|---|
| 239 | virtual bool operator()(Event& ev) { |
|---|
| 240 | if(!_callback) return false; |
|---|
| 241 | |
|---|
| 242 | return (*_callback)(ev); |
|---|
| 243 | } |
|---|
| 244 | |
|---|
| 245 | EventType getType() const { |
|---|
| 246 | return _type; |
|---|
| 247 | } |
|---|
| 248 | |
|---|
| 249 | void* getData() { |
|---|
| 250 | return _data; |
|---|
| 251 | } |
|---|
| 252 | |
|---|
| 253 | const void* getData() const { |
|---|
| 254 | return _data; |
|---|
| 255 | } |
|---|
| 256 | |
|---|
| 257 | protected: |
|---|
| 258 | EventType _type; |
|---|
| 259 | void* _data; |
|---|
| 260 | |
|---|
| 261 | // We use a ref_ptr here so that we don't have to worry about memory. |
|---|
| 262 | osg::ref_ptr<CallbackInterface> _callback; |
|---|
| 263 | |
|---|
| 264 | }; |
|---|
| 265 | |
|---|
| 266 | |
|---|
| 267 | class OSGWIDGET_EXPORT EventInterface |
|---|
| 268 | { |
|---|
| 269 | public: |
|---|
| 270 | EventInterface(): _eventMask(EVENT_NONE) {} |
|---|
| 271 | |
|---|
| 272 | EventInterface(const EventInterface& ei): |
|---|
| 273 | _eventMask (ei._eventMask), |
|---|
| 274 | _callbacks (ei._callbacks) {} |
|---|
| 275 | |
|---|
| 276 | virtual ~EventInterface() {} |
|---|
| 277 | |
|---|
| 278 | // These functions take as their final argument the WindowManager which issued the |
|---|
| 279 | // request. This is sometimes useful to get information about key state, etc. |
|---|
| 280 | |
|---|
| 281 | // Notify the EventInterface object that is has been focused or unfocused; since |
|---|
| 282 | // this isn't always bound to a mouse event (i.e., if you want to be able to use |
|---|
| 283 | // the TAB key to focus), we need seperate events here. |
|---|
| 284 | virtual bool focus (const WindowManager*) { return false; } |
|---|
| 285 | virtual bool unfocus (const WindowManager*) { return false; } |
|---|
| 286 | |
|---|
| 287 | // Mouse events, pretty self-explanatory. |
|---|
| 288 | virtual bool mouseEnter (double, double, const WindowManager*) { return false; } |
|---|
| 289 | virtual bool mouseOver (double, double, const WindowManager*) { return false; } |
|---|
| 290 | virtual bool mouseLeave (double, double, const WindowManager*) { return false; } |
|---|
| 291 | virtual bool mouseDrag (double, double, const WindowManager*) { return false; } |
|---|
| 292 | virtual bool mousePush (double, double, const WindowManager*) { return false; } |
|---|
| 293 | virtual bool mouseRelease (double, double, const WindowManager*) { return false; } |
|---|
| 294 | virtual bool mouseScroll (double, double, const WindowManager*) { return false; } |
|---|
| 295 | |
|---|
| 296 | // These functions pass the osgGA::GUIEventAdapter::KeySymbol and KeyModMask and, |
|---|
| 297 | // as above, the WindowManager. |
|---|
| 298 | virtual bool keyDown (int, int, const WindowManager*) { return false; } |
|---|
| 299 | virtual bool keyUp (int, int, const WindowManager*) { return false; } |
|---|
| 300 | |
|---|
| 301 | void setEventMask(unsigned int mask) { |
|---|
| 302 | _eventMask = mask; |
|---|
| 303 | } |
|---|
| 304 | |
|---|
| 305 | void addEventMask(unsigned int mask) { |
|---|
| 306 | _eventMask |= mask; |
|---|
| 307 | } |
|---|
| 308 | |
|---|
| 309 | void removeEventMask(unsigned int mask) { |
|---|
| 310 | _eventMask ^= mask; |
|---|
| 311 | } |
|---|
| 312 | |
|---|
| 313 | unsigned int getEventMask() const { |
|---|
| 314 | return _eventMask; |
|---|
| 315 | } |
|---|
| 316 | |
|---|
| 317 | void addCallback(Callback* cb) { |
|---|
| 318 | _callbacks.push_back(cb); |
|---|
| 319 | } |
|---|
| 320 | |
|---|
| 321 | bool callCallbacks(Event& ev) { |
|---|
| 322 | if(ev.type == EVENT_NONE || !(_eventMask & ev.type)) return false; |
|---|
| 323 | |
|---|
| 324 | for(CallbackList::iterator i = _callbacks.begin(); i != _callbacks.end(); i++) { |
|---|
| 325 | // This is the OLD method; testing a new method below. |
|---|
| 326 | // if(i->getType() == ev.type && (*i)(ev)) return true; |
|---|
| 327 | |
|---|
| 328 | if(i->get()->getType() & ev.type) { |
|---|
| 329 | ev.setData(i->get()->getData()); |
|---|
| 330 | |
|---|
| 331 | if((*i->get())(ev)) return true; |
|---|
| 332 | } |
|---|
| 333 | } |
|---|
| 334 | |
|---|
| 335 | return false; |
|---|
| 336 | } |
|---|
| 337 | |
|---|
| 338 | bool callMethodAndCallbacks(Event& ev) { |
|---|
| 339 | if(ev.type == EVENT_NONE || !(_eventMask & ev.type)) return false; |
|---|
| 340 | |
|---|
| 341 | bool handled = false; |
|---|
| 342 | |
|---|
| 343 | if(ev.type == EVENT_FOCUS) handled = focus(ev.getWindowManager()); |
|---|
| 344 | |
|---|
| 345 | else if(ev.type == EVENT_UNFOCUS) handled = unfocus(ev.getWindowManager()); |
|---|
| 346 | |
|---|
| 347 | else if(ev.type == EVENT_MOUSE_ENTER) |
|---|
| 348 | handled = mouseEnter(ev.x, ev.y, ev.getWindowManager()) |
|---|
| 349 | ; |
|---|
| 350 | |
|---|
| 351 | else if(ev.type == EVENT_MOUSE_OVER) |
|---|
| 352 | handled = mouseOver(ev.x, ev.y, ev.getWindowManager()) |
|---|
| 353 | ; |
|---|
| 354 | |
|---|
| 355 | else if(ev.type == EVENT_MOUSE_LEAVE) |
|---|
| 356 | handled = mouseLeave(ev.x, ev.y, ev.getWindowManager()) |
|---|
| 357 | ; |
|---|
| 358 | |
|---|
| 359 | else if(ev.type == EVENT_MOUSE_DRAG) |
|---|
| 360 | handled = mouseDrag(ev.x, ev.y, ev.getWindowManager()) |
|---|
| 361 | ; |
|---|
| 362 | |
|---|
| 363 | else if(ev.type == EVENT_MOUSE_PUSH) |
|---|
| 364 | handled = mousePush(ev.x, ev.y, ev.getWindowManager()) |
|---|
| 365 | ; |
|---|
| 366 | |
|---|
| 367 | else if(ev.type == EVENT_MOUSE_RELEASE) |
|---|
| 368 | handled = mouseRelease(ev.x, ev.y, ev.getWindowManager()) |
|---|
| 369 | ; |
|---|
| 370 | |
|---|
| 371 | else if(ev.type == EVENT_MOUSE_SCROLL) |
|---|
| 372 | handled = mouseScroll(ev.x, ev.y, ev.getWindowManager()) |
|---|
| 373 | ; |
|---|
| 374 | |
|---|
| 375 | else if(ev.type == EVENT_KEY_DOWN) |
|---|
| 376 | handled = keyDown(ev.key, ev.keyMask, ev.getWindowManager()) |
|---|
| 377 | ; |
|---|
| 378 | |
|---|
| 379 | else if(ev.type == EVENT_KEY_UP) |
|---|
| 380 | handled = keyUp(ev.key, ev.keyMask, ev.getWindowManager()) |
|---|
| 381 | ; |
|---|
| 382 | |
|---|
| 383 | else return false; |
|---|
| 384 | |
|---|
| 385 | return callCallbacks(ev) || handled; |
|---|
| 386 | } |
|---|
| 387 | |
|---|
| 388 | bool canFocus () const { return (_eventMask & EVENT_FOCUS) != 0; } |
|---|
| 389 | bool canUnfocus () const { return (_eventMask & EVENT_UNFOCUS) != 0; } |
|---|
| 390 | |
|---|
| 391 | bool canMouseEnter () const { return (_eventMask & EVENT_MOUSE_ENTER) != 0; } |
|---|
| 392 | bool canMouseOver () const { return (_eventMask & EVENT_MOUSE_OVER) != 0; } |
|---|
| 393 | bool canMouseLeave () const { return (_eventMask & EVENT_MOUSE_LEAVE) != 0; } |
|---|
| 394 | bool canMouseDrag () const { return (_eventMask & EVENT_MOUSE_DRAG) != 0; } |
|---|
| 395 | bool canMousePush () const { return (_eventMask & EVENT_MOUSE_PUSH) != 0; } |
|---|
| 396 | bool canMouseRelease () const { return (_eventMask & EVENT_MOUSE_RELEASE) != 0; } |
|---|
| 397 | bool canMouseScroll () const { return (_eventMask & EVENT_MOUSE_SCROLL) != 0; } |
|---|
| 398 | |
|---|
| 399 | bool canKeyDown () const { return (_eventMask & EVENT_KEY_DOWN) != 0; } |
|---|
| 400 | bool canKeyUp () const { return (_eventMask & EVENT_KEY_UP) != 0; } |
|---|
| 401 | |
|---|
| 402 | private: |
|---|
| 403 | typedef std::list<osg::observer_ptr<Callback> > CallbackList; |
|---|
| 404 | |
|---|
| 405 | unsigned int _eventMask; |
|---|
| 406 | CallbackList _callbacks; |
|---|
| 407 | |
|---|
| 408 | }; |
|---|
| 409 | |
|---|
| 410 | } |
|---|
| 411 | |
|---|
| 412 | #endif |
|---|