So this is how i do it:
On creation, my window object (GlfwWindow * is passed in) creates an EventHandler, which holds a data structure for objects to register themselves and offers virtual methods for the c-style callback functions (code for the cursor callback, not every callback is implemented yet). In EventHandler.h/.cpp:
typedef enum eventType : unsigned int {
MOUSE_MOVE = 0b1,
MOUSE_BUTTON = 0b10,
MOUSE_SCROLL = 0b100,
KEY = 0b1000,
CHAR = 0b10000,
FRAMEBUFFER_RESIZE = 0b100000
} eventType;
std::vector<EventHandler::RegisteredObject> EventHandler::s_registeredObjects {};
EventHandler::EventHandler( GlfwWindow *win ) : m_window { win } {
glfwSetCursorPosCallback( m_window->getWindow(), cursorPosCallback );
...
...
The callback redirects to the virtual method:
// static
void EventHandler::cursorPosCallback( GLFWwindow *w, double x, double y ) {
EventHandler *e = reinterpret_cast<EventHandler *>( glfwGetWindowUserPointer( w ) );
e->onMouseMove( (float)x, (float)y );
}
The virtual method iterates over registered objects and calls their respective overriden methods, that can return a bool if they don't want anybody else to handle the event:
// virtual
bool EventHandler::onMouseMove( float x, float y ) {
bool handled = false;
for( RegisteredObject &obj : s_registeredObjects ) {
if( obj.types & MOUSE_MOVE ) {
//handled = reinterpret_cast<EventHandler *>(obj.object)->onMouseMove( x, y );
handled = obj.object->onMouseMove( x, y );
if( handled )
break;
}
}
return handled;
}
A class that wants to receive user events must inherit from EventHandler and register the events it wants to receive via a method from the eventhandler, via a simple bit field (in the first code snippet):
void EventHandler::registerObject( RegisteredObject &obj ) {
bool found = false;
for( RegisteredObject &r : s_registeredObjects ) {
if( r.object == obj.object ) {
Logbook::getInstance().logMsg( Logbook::WINDOW, Logbook::WARNING,
"Ignoring try to register an already registered object with the event handler." );
found = true;
}
}
if( !found )
s_registeredObjects.push_back( obj );
}
And overrides the inherited virtual method:
// virtual
bool Camera::onMouseMove( float x, float y ) {
bool handled{ false };
... do mouse move stuff ...
return handled;
} // onMouseMove()
It works, for Camera, UI interface and my drawing apps.
What do you think ? It is probably a standard, though i have seen more complicated solutions. Have i missed something ? Could it be done better with the window user pointer, whose function i haven't really understood ?