SleakEngine 1.0.0
C++23 multi-backend game engine
Loading...
Searching...
No Matches
Event.hpp
Go to the documentation of this file.
1#ifndef _EVENT_H_
2#define _EVENT_H_
3
4#include <Core/OSDef.hpp>
5#include <string>
6#include <functional>
7#include <unordered_map>
8#include <vector>
9#include <Events/Delegate.hpp>
10
11
12#define BIND_LAMBDA(fn) [this](auto&&... args) -> decltype(auto) { return this->fn(std::forward<decltype(args)>(args)...); }
13#define BIND_FUNC_0(Function, class_name) std::bind(&class_name::Function, this)
14#define BIND_FUNC_1(Function, class_name) std::bind(&class_name::Function, this, std::placeholders::_1)
15#define BIND_FUNC_2(Function, class_name) std::bind(&class_name::Function, this, std::placeholders::_2)
16#define BIND_FUNC_3(Function, class_name) std::bind(&class_name::Function, this, std::placeholders::_3)
17
18#define GET_DISPATCHER Sleak::EventDispatcher::GetInstance()
19
20namespace Sleak {
21 /// Concrete kind of Event; each Event subclass reports one of these via GetEventType().
22 /// @ingroup events
30
31 /// Bitmask groups an Event can belong to, queried via Event::IsInCategory().
32 /// @ingroup events
33 enum class EventCategory {
34 None = (1 << 0),
35 Application = (1 << 1),
36 Input = (1 << 2),
37 Keyboard = (1 << 3),
38 Mouse = (1 << 4),
39 MouseButton = (1 << 5)
40 };
41
42 #define EVENT_CLASS_TYPE(type) \
43 static EventType GetStaticType() \
44 { \
45 return EventType::type;\
46 }\
47 virtual EventType GetEventType() const override \
48 {\
49 return GetStaticType();\
50 }\
51 virtual const char* GetName() const override \
52 {\
53 return #type;\
54 }
55
56 #define EVENT_CLASS_CATEGORY(category)\
57 virtual int GetCategoryFlags() const override \
58 { return static_cast<int>(category); }
59
60 /// Base for all engine events; carries type/category identity and the
61 /// Handled flag consumers can set to stop further propagation.
62 /// @ingroup events
63 class ENGINE_API Event {
64 public:
65 Event() {}
66
67 virtual ~Event() = default;
68
69 bool Handled = false;
70
71 virtual EventType GetEventType() const = 0;
72 virtual const char* GetName() const = 0;
73 virtual int GetCategoryFlags() const = 0;
74 virtual std::string ToString() const { return GetName(); }
75
77 {
78 return GetCategoryFlags() & (uint16_t)category;
79 }
80 };
81
82 /// Static registry mapping EventType to subscribed handlers; dispatches
83 /// events synchronously to every handler registered for its type.
84 ///
85 /// Everything here is static, so there is no dispatcher instance to
86 /// pass around: subscribe from anywhere, and the window layer's
87 /// keyboard, mouse, and window events reach you. RegisterEventHandler()
88 /// binds a member function and is the form you will use most;
89 /// RegisterEventCallback() takes a std::function for lambdas and free
90 /// functions.
91 ///
92 /// Both return a string id. Keep it and pass it to UnregisterEvent()
93 /// when the subscriber goes away, typically in a scene's OnDeactivate()
94 /// or destructor. Handlers outlive the objects they were bound to
95 /// otherwise, and the next dispatch calls into freed memory.
96 ///
97 /// Dispatch is synchronous and runs in registration order on the
98 /// calling thread. The handler list is copied before iteration, so a
99 /// handler may register or unregister during dispatch safely.
100 ///
101 /// @code{.cpp}
102 /// class WorldScene : public Sleak::Scene {
103 /// public:
104 /// void Begin() override {
105 /// m_keyId = Sleak::EventDispatcher::RegisterEventHandler(
106 /// this, &WorldScene::OnKeyPressed);
107 /// Sleak::Scene::Begin();
108 /// }
109 ///
110 /// void OnDeactivate() override {
111 /// if (!m_keyId.empty()) {
112 /// Sleak::EventDispatcher::UnregisterEvent(
113 /// Sleak::EventType::KeyPressed, m_keyId);
114 /// m_keyId.clear();
115 /// }
116 /// Sleak::Scene::OnDeactivate();
117 /// }
118 ///
119 /// void OnKeyPressed(
120 /// const Sleak::Events::Input::KeyPressedEvent& e) {
121 /// if_key_press(KEY__F) { ToggleFlashlight(); }
122 /// }
123 ///
124 /// private:
125 /// std::string m_keyId;
126 /// };
127 /// @endcode
128 ///
129 /// @see Event, EventType, Events::Input::KeyPressedEvent,
130 /// Events::Input::MouseMovedEvent
131 /// @ingroup events
132 class ENGINE_API EventDispatcher {
133 public:
134 // Register a handler for any event type
135 /// Registers a free-function/lambda callback for EventT, returning an ID for later unregistration.
136 template<typename EventT>
137 static std::string RegisterEventCallback(std::function<void(const EventT&)> callback) {
138 EventType type = EventT::GetStaticType();
139
140 auto delegate = std::make_shared<EventDelegate<EventT>>(callback);
141 eventHandlers[type].push_back(delegate);
142
143 return delegate->GetUUID();
144 }
145
146 // Register a member function handler
147 /// Registers a member-function handler bound to instance, returning an ID for later unregistration.
148 template<typename T, typename EventT>
149 static std::string RegisterEventHandler(T* instance, void (T::*memberFunction)(const EventT&)) {
150 EventType type = EventT::GetStaticType();
151
152 auto callback = [instance, memberFunction](const EventT& event) {
153 (instance->*memberFunction)(event);
154 };
155
156 auto delegate = std::make_shared<EventDelegate<EventT>>(callback);
157 eventHandlers[type].push_back(delegate);
158
159 return delegate->GetID();
160 }
161
162 /// Removes the single handler with matching id from type's handler list.
163 static void UnregisterEvent(EventType type, std::string id) {
164 for(auto it = eventHandlers[type].begin(); it != eventHandlers[type].end(); ++it) {
165 if((*it)->GetID() == id) {
166 eventHandlers[type].erase(it);
167 break;
168 }
169 }
170 }
171
172 /// Drops every handler registered for type.
173 static void UnregisterEvents(EventType type) {
174 eventHandlers[type].clear();
175 }
176
177 /// Drops every handler for every event type.
178 static void UnregisterAllEvents() {
179 eventHandlers.clear();
180 }
181
182 // Dispatch an event to all registered handlers
183 /// Invokes every handler registered for event's type, in registration order.
184 template<typename EventT>
185 static void DispatchEvent(const EventT& event) {
186 EventType type = event.GetEventType();
187
188 if (eventHandlers.find(type) == eventHandlers.end())
189 return;
190
191 // Copy the handler list so that handlers which add/remove entries
192 // during dispatch don't invalidate the iteration.
193 auto handlers = eventHandlers[type];
194 for (auto& handler : handlers) {
195 // Try to cast to the right event delegate type
196 auto typedDelegate = std::dynamic_pointer_cast<EventDelegate<EventT>>(handler);
197 if (typedDelegate) {
198 typedDelegate->SetEvent(event);
199 typedDelegate->Execute();
200 }
201 }
202 }
203
204 /// Drops every handler for every event type; equivalent to UnregisterAllEvents().
205 static void ClearEventHandlers() {
206 eventHandlers.clear();
207 }
208
209 private:
210 static inline std::unordered_map<EventType, std::vector<std::shared_ptr<IDelegate>>> eventHandlers;
211 };
212
213
214 // Helper function for easier event dispatching
215 /// Constructs a T from args and dispatches it through EventDispatcher.
216 template<typename T, typename... Args>
217 void DispatchEvent(Args&&... args) {
218 T event(std::forward<Args>(args)...);
220 }
221
222 inline std::ostream& operator<<(std::ostream& os, const Event& e)
223 {
224 return os << e.ToString();
225 }
226}
227
228#endif
static std::string RegisterEventCallback(std::function< void(const EventT &)> callback)
Registers a free-function/lambda callback for EventT, returning an ID for later unregistration.
Definition Event.hpp:137
static void ClearEventHandlers()
Drops every handler for every event type; equivalent to UnregisterAllEvents().
Definition Event.hpp:205
static void DispatchEvent(const EventT &event)
Invokes every handler registered for event's type, in registration order.
Definition Event.hpp:185
static void UnregisterAllEvents()
Drops every handler for every event type.
Definition Event.hpp:178
static void UnregisterEvent(EventType type, std::string id)
Removes the single handler with matching id from type's handler list.
Definition Event.hpp:163
static std::string RegisterEventHandler(T *instance, void(T::*memberFunction)(const EventT &))
Registers a member-function handler bound to instance, returning an ID for later unregistration.
Definition Event.hpp:149
static void UnregisterEvents(EventType type)
Drops every handler registered for type.
Definition Event.hpp:173
bool Handled
Definition Event.hpp:69
bool IsInCategory(EventCategory category)
Definition Event.hpp:76
virtual ~Event()=default
virtual std::string ToString() const
Definition Event.hpp:74
virtual int GetCategoryFlags() const =0
virtual const char * GetName() const =0
virtual EventType GetEventType() const =0
EventCategory
Definition Event.hpp:33
EventType
Definition Event.hpp:23
Key and mouse-button code enumerations plus their name lookups.
Root namespace for everything the engine exposes.
Definition Camera.hpp:10
void DispatchEvent(Args &&... args)
Constructs a T from args and dispatches it through EventDispatcher.
Definition Event.hpp:217
std::ostream & operator<<(std::ostream &os, const Event &e)
Definition Event.hpp:222