// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 // $Id: EventInterface 64 2008-06-30 21:32:00Z cubicool $ #ifndef OSGWIDGET_EVENT_INTERFACE #define OSGWIDGET_EVENT_INTERFACE #include #include #include #include namespace osgWidget { class WindowManager; class Window; class Widget; enum EVENT_TYPE { EVENT_NONE = 0x0000, EVENT_FOCUS = 0x0001, EVENT_UNFOCUS = 0x0002, EVENT_MOUSE_ENTER = 0x0004, EVENT_MOUSE_OVER = 0x0008, EVENT_MOUSE_LEAVE = 0x0010, EVENT_MOUSE_DRAG = 0x0020, EVENT_MOUSE_PUSH = 0x0040, EVENT_MOUSE_RELEASE = 0x0080, EVENT_MOUSE_SCROLL = 0x0100, EVENT_KEY_DOWN = 0x0200, EVENT_KEY_UP = 0x0400, EVENT_ALL = 0xFFFF }; // Helpful wrapper around using the raw types, since it often doesn't make sense to // use some without the others. enum EVENT_MASK { EVENT_MASK_FOCUS = EVENT_FOCUS | EVENT_UNFOCUS, EVENT_MASK_MOUSE_MOVE = EVENT_MOUSE_ENTER | EVENT_MOUSE_OVER | EVENT_MOUSE_LEAVE, EVENT_MASK_MOUSE_CLICK = EVENT_MOUSE_PUSH | EVENT_MOUSE_RELEASE, EVENT_MASK_MOUSE_DRAG = EVENT_MASK_MOUSE_MOVE | EVENT_MASK_MOUSE_CLICK | EVENT_MOUSE_DRAG, EVENT_MASK_KEY = EVENT_KEY_UP | EVENT_KEY_DOWN }; class OSGWIDGET_EXPORT Event { friend class WindowManager; friend class Window; WindowManager* _wm; Window* _window; Widget* _widget; void* _data; public: EVENT_TYPE type; double x; double y; int key; int keyMask; Event(WindowManager* wm, EVENT_TYPE _type = EVENT_NONE): _wm (wm), _window (0), _widget (0), _data (0), type (_type), x (0.0f), y (0.0f), key (-1), keyMask (-1) { } Event& makeType(EVENT_TYPE _type) { if(_type != EVENT_NONE) type = _type; return *this; } Event& makeMouse(double _x, double _y, EVENT_TYPE _type = EVENT_NONE) { x = _x; y = _y; if(_type != EVENT_NONE) type = _type; return *this; } Event& makeKey(int _key, int _keyMask, EVENT_TYPE _type = EVENT_NONE) { key = _key; keyMask = _keyMask; if(_type != EVENT_NONE) type = _type; return *this; } WindowManager* getWindowManager() { return _wm; } const WindowManager* getWindowManager() const { return _wm; } Window* getWindow() { return _window; } const Window* getWindow() const { return _window; } Widget* getWidget() { return _widget; } const Widget* getWidget() const { return _widget; } void* getData() { return _data; } const void* getData() const { return _data; } void setData(void* data) { _data = data; } }; // The Callback interface was inspired by the CEGUI project: // // http://www.cegui.org.uk/wiki/index.php/Main_Page // // It's a great little way to cleanly implement callbacks for events, although // I did change the names a bit to make them more appropriate for OSG. MANY THANKS // to the CEGUI project! // The CallbackInterface, which the highest-level functor keeps a pointer to. struct CallbackInterface: public osg::Referenced { virtual ~CallbackInterface() { } virtual bool operator()(Event&) = 0; }; // The object that facilitates a class method as a callback. template class ObjectCallback: public CallbackInterface { public: typedef bool (T::*ObjectCallbackType)(Event&); private: ObjectCallbackType _callback; T* _object; public: ObjectCallback(ObjectCallbackType callback, T* obj): _callback (callback), _object (obj) { } virtual bool operator()(Event& ev) { return (_object->*_callback)(ev); } }; // The object that facilitates general functions as callbacks. template class FunctionCallback: public CallbackInterface { T* _callback; public: FunctionCallback(T* callback): _callback(callback) { } virtual bool operator()(Event& ev) { return (*_callback)(ev); } }; // The highlevel functor. class OSGWIDGET_EXPORT Callback { EVENT_TYPE _type; void* _data; // We use a ref_ptr here so that we don't have to worry about memory. osg::ref_ptr _callback; public: // Creates a Callback that is bound to a member function. template Callback(bool (T::*function)(Event&), T* obj, EVENT_TYPE type, void* data=0): _type (type), _data (data), _callback (new ObjectCallback(function, obj)) { } // Creates a Callback that is bound to a functor pointer. template Callback(T* functor, EVENT_TYPE type, void* data=0): _type (type), _data (data), _callback (new FunctionCallback(functor)) { } bool operator()(Event& ev) { return (*_callback)(ev); } EVENT_TYPE getType() const { return _type; } void* getData() { return _data; } const void* getData() const { return _data; } }; class OSGWIDGET_EXPORT EventInterface { private: typedef std::list CallbackList; unsigned int _eventMask; CallbackList _callbacks; public: EventInterface(): _eventMask(EVENT_NONE) { } EventInterface(const EventInterface& ei): _eventMask (ei._eventMask), _callbacks (ei._callbacks) { } virtual ~EventInterface() { } // These functions take as their final argument the WindowManager which issued the // request. This is sometimes useful to get information about key state, etc. // Notify the EventInterface object that is has been focused or unfocused; since // this isn't always bound to a mouse event (i.e., if you want to be able to use // the TAB key to focus), we need seperate events here. virtual bool focus (WindowManager*) { return false; } virtual bool unfocus (WindowManager*) { return false; } // Mouse events, pretty self-explanatory. virtual bool mouseEnter (double, double, WindowManager*) { return false; } virtual bool mouseOver (double, double, WindowManager*) { return false; } virtual bool mouseLeave (double, double, WindowManager*) { return false; } virtual bool mouseDrag (double, double, WindowManager*) { return false; } virtual bool mousePush (double, double, WindowManager*) { return false; } virtual bool mouseRelease (double, double, WindowManager*) { return false; } virtual bool mouseScroll (double, double, WindowManager*) { return false; } // These functions pass the osgGA::GUIEventAdapter::KeySymbol and KeyModMask and, // as above, the WindowManager. virtual bool keyDown (int, int, WindowManager*) { return false; } virtual bool keyUp (int, int, WindowManager*) { return false; } void setEventMask(unsigned int mask) { _eventMask = mask; } void addEventMask(unsigned int mask) { _eventMask |= mask; } void removeEventMask(unsigned int mask) { _eventMask ^= mask; } unsigned int getEventMask() const { return _eventMask; } void addCallback(const Callback& cb) { _callbacks.push_back(cb); } bool callCallbacks(Event& ev) { if(ev.type == EVENT_NONE || !(_eventMask & ev.type)) return false; for(CallbackList::iterator i = _callbacks.begin(); i != _callbacks.end(); i++) { // This is the OLD method; testing a new method below. // if(i->getType() == ev.type && (*i)(ev)) return true; if(i->getType() == ev.type) { ev.setData(i->getData()); if((*i)(ev)) return true; } } return false; } bool callMethodAndCallbacks(Event& ev) { if(ev.type == EVENT_NONE || !(_eventMask & ev.type)) return false; bool handled = false; if(ev.type == EVENT_FOCUS) handled = focus(ev.getWindowManager()); else if(ev.type == EVENT_UNFOCUS) handled = unfocus(ev.getWindowManager()); else if(ev.type == EVENT_MOUSE_ENTER) handled = mouseEnter(ev.x, ev.y, ev.getWindowManager()) ; else if(ev.type == EVENT_MOUSE_OVER) handled = mouseOver(ev.x, ev.y, ev.getWindowManager()) ; else if(ev.type == EVENT_MOUSE_LEAVE) handled = mouseLeave(ev.x, ev.y, ev.getWindowManager()) ; else if(ev.type == EVENT_MOUSE_DRAG) handled = mouseDrag(ev.x, ev.y, ev.getWindowManager()) ; else if(ev.type == EVENT_MOUSE_PUSH) handled = mousePush(ev.x, ev.y, ev.getWindowManager()) ; else if(ev.type == EVENT_MOUSE_RELEASE) handled = mouseRelease(ev.x, ev.y, ev.getWindowManager()) ; else if(ev.type == EVENT_MOUSE_SCROLL) handled = mouseScroll(ev.x, ev.y, ev.getWindowManager()) ; else if(ev.type == EVENT_KEY_DOWN) handled = keyDown(ev.key, ev.keyMask, ev.getWindowManager()) ; else if(ev.type == EVENT_KEY_UP) handled = keyUp(ev.key, ev.keyMask, ev.getWindowManager()) ; else return false; return callCallbacks(ev) || handled; } bool canFocus () const { return (_eventMask & EVENT_FOCUS) != 0; } bool canUnfocus () const { return (_eventMask & EVENT_UNFOCUS) != 0; } bool canMouseEnter () const { return (_eventMask & EVENT_MOUSE_ENTER) != 0; } bool canMouseOver () const { return (_eventMask & EVENT_MOUSE_OVER) != 0; } bool canMouseLeave () const { return (_eventMask & EVENT_MOUSE_LEAVE) != 0; } bool canMouseDrag () const { return (_eventMask & EVENT_MOUSE_DRAG) != 0; } bool canMousePush () const { return (_eventMask & EVENT_MOUSE_PUSH) != 0; } bool canMouseRelease () const { return (_eventMask & EVENT_MOUSE_RELEASE) != 0; } bool canMouseScroll () const { return (_eventMask & EVENT_MOUSE_SCROLL) != 0; } bool canKeyDown () const { return (_eventMask & EVENT_KEY_DOWN) != 0; } bool canKeyUp () const { return (_eventMask & EVENT_KEY_UP) != 0; } }; } #endif