event: Support C++11 lambdas as event handlers

It's unfortunate that we now have three maps on EventHandler for three different types of functions.  I'd love to unify them all under std::function, but the fact that it doesn't support comparison means the behavior would be different.

Perhaps in the future we can create a new interface or deprecate the existing behaviors and unify everything under std::function.
This commit is contained in:
rdb 2021-11-29 14:48:06 +01:00
parent 4af5bc9e6d
commit 653cc3e091
4 changed files with 94 additions and 0 deletions

View File

@ -104,6 +104,20 @@ dispatch_event(const Event *event) {
}
}
// now for lambda hooks
LambdaHooks::const_iterator lhi;
lhi = _lambdahooks.find(event->get_name());
if (lhi != _lambdahooks.end()) {
// found one
const LambdaFunctions &functions = (*lhi).second;
size_t num_functions = functions.size();
for (size_t i = 0; i < num_functions; ++i) {
functions[i](event);
}
}
// Finally, check for futures that need to be triggered.
Futures::iterator fi;
fi = _futures.find(event->get_name());
@ -189,6 +203,19 @@ add_hook(const string &event_name, EventCallbackFunction *function,
return _cbhooks[event_name].insert(CallbackFunction(function, data)).second;
}
/**
* Adds the indicated function to the list of those that will be called when
* the named event is thrown. Returns true if the function was successfully
* added, false if it was already defined on the indicated event name. This
* version stores an arbitrary C++ lambda.
*/
void EventHandler::
add_hook(const string &event_name, EventLambda function) {
assert(!event_name.empty());
assert(function);
_lambdahooks[event_name].push_back(function);
}
/**
* Returns true if there is any hook added on the indicated event name, false
* otherwise.
@ -212,6 +239,14 @@ has_hook(const string &event_name) const {
}
}
LambdaHooks::const_iterator lhi;
lhi = _lambdahooks.find(event_name);
if (lhi != _lambdahooks.end()) {
if (!(*lhi).second.empty()) {
return true;
}
}
return false;
}
@ -306,6 +341,14 @@ remove_hooks(const string &event_name) {
_cbhooks.erase(chi);
}
LambdaHooks::iterator lhi = _lambdahooks.find(event_name);
if (lhi != _lambdahooks.end()) {
if (!(*lhi).second.empty()) {
any_removed = true;
}
_lambdahooks.erase(lhi);
}
return any_removed;
}
@ -344,6 +387,7 @@ void EventHandler::
remove_all_hooks() {
_hooks.clear();
_cbhooks.clear();
_lambdahooks.clear();
}
/**

View File

@ -23,6 +23,10 @@
#include "pset.h"
#include "pmap.h"
#ifndef CPPPARSER
#include <functional>
#endif
class EventQueue;
/**
@ -40,6 +44,12 @@ public:
typedef void EventFunction(const Event *);
typedef void EventCallbackFunction(const Event *, void *);
#ifdef CPPPARSER
typedef EventFunction EventLambda;
#else
typedef std::function<void (const Event *)> EventLambda;
#endif
PUBLISHED:
explicit EventHandler(EventQueue *ev_queue);
~EventHandler() {}
@ -58,6 +68,7 @@ public:
bool add_hook(const std::string &event_name, EventFunction *function);
bool add_hook(const std::string &event_name, EventCallbackFunction *function,
void *data);
void add_hook(const std::string &event_name, EventLambda function);
bool has_hook(const std::string &event_name) const;
bool has_hook(const std::string &event_name, EventFunction *function) const;
bool has_hook(const std::string &event_name, EventCallbackFunction *function,
@ -78,10 +89,13 @@ protected:
typedef std::pair<EventCallbackFunction*, void*> CallbackFunction;
typedef pset<CallbackFunction> CallbackFunctions;
typedef pmap<std::string, CallbackFunctions> CallbackHooks;
typedef pvector<EventLambda> LambdaFunctions;
typedef pmap<std::string, LambdaFunctions> LambdaHooks;
typedef pmap<std::string, PT(AsyncFuture)> Futures;
Hooks _hooks;
CallbackHooks _cbhooks;
LambdaHooks _lambdahooks;
Futures _futures;
EventQueue &_queue;

View File

@ -310,6 +310,39 @@ define_key(const string &event_name, const string &description,
}
}
/**
* Sets up a handler for the indicated key. When the key is pressed in a
* window, the given callback will be called. The description is a one-line
* description of the function of the key, for display to the user.
*/
void PandaFramework::
define_key(const string &event_name, const string &description,
EventHandler::EventLambda function) {
if (_event_handler.has_hook(event_name)) {
// If there is already a hook for the indicated keyname, we're most likely
// replacing a previous definition of a key. Search for the old
// definition and remove it.
KeyDefinitions::iterator di;
di = _key_definitions.begin();
while (di != _key_definitions.end() && (*di)._event_name != event_name) {
++di;
}
if (di != _key_definitions.end()) {
_key_definitions.erase(di);
}
}
// Now add a new hook for the keyname, and also add the new description.
_event_handler.add_hook(event_name, function);
if (!description.empty()) {
KeyDefinition keydef;
keydef._event_name = event_name;
keydef._description = description;
_key_definitions.push_back(keydef);
}
}
/**
* Fills in the indicated window properties structure according to the normal
* window properties for this application.

View File

@ -56,6 +56,9 @@ public:
const std::string &description,
EventHandler::EventCallbackFunction *function,
void *data);
void define_key(const std::string &event_name,
const std::string &description,
EventHandler::EventLambda function);
INLINE void set_window_title(const std::string &title);
virtual void get_default_window_props(WindowProperties &props);