aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/crepe/api/Event.h12
-rw-r--r--src/crepe/api/EventHandler.cpp3
-rw-r--r--src/crepe/api/EventHandler.h6
-rw-r--r--src/crepe/api/EventHandler.hpp8
-rw-r--r--src/crepe/api/EventManager.cpp11
-rw-r--r--src/crepe/api/EventManager.h32
-rw-r--r--src/crepe/api/EventManager.hpp24
-rw-r--r--src/crepe/api/IKeyListener.cpp35
-rw-r--r--src/crepe/api/IKeyListener.h21
-rw-r--r--src/crepe/api/IMouseListener.cpp34
-rw-r--r--src/crepe/api/IMouseListener.h22
-rw-r--r--src/crepe/facade/SDLContext.cpp1
-rw-r--r--src/example/events.cpp74
-rw-r--r--src/test/CMakeLists.txt1
-rw-r--r--src/test/EventTest.cpp470
15 files changed, 584 insertions, 170 deletions
diff --git a/src/crepe/api/Event.h b/src/crepe/api/Event.h
index d5ddf0a..33f3add 100644
--- a/src/crepe/api/Event.h
+++ b/src/crepe/api/Event.h
@@ -7,17 +7,15 @@
/**
* \brief Base class for all event types in the system.
*/
-class Event {
-public:
-};
+class Event {};
/**
* \brief Event triggered when a key is pressed.
*/
class KeyPressEvent : public Event {
public:
- //! Number of times the key press is repeated (e.g., for long presses).
- int repeat = 0;
+ //! false if first time press, true if key is repeated
+ bool repeat = false;
//! The key that was pressed.
Keycode key = Keycode::NONE;
@@ -110,6 +108,4 @@ public:
/**
* \brief Event triggered to indicate the application is shutting down.
*/
-class ShutDownEvent : public Event {
-public:
-};
+class ShutDownEvent : public Event {};
diff --git a/src/crepe/api/EventHandler.cpp b/src/crepe/api/EventHandler.cpp
index 186ec9c..4dc232f 100644
--- a/src/crepe/api/EventHandler.cpp
+++ b/src/crepe/api/EventHandler.cpp
@@ -2,5 +2,4 @@
using namespace crepe;
-// Implementation of IEventHandlerWrapper::exec
-bool IEventHandlerWrapper::exec(const Event & e) { return call(e); }
+bool IEventHandlerWrapper::exec(const Event & e) { return this->call(e); }
diff --git a/src/crepe/api/EventHandler.h b/src/crepe/api/EventHandler.h
index db51d04..90886aa 100644
--- a/src/crepe/api/EventHandler.h
+++ b/src/crepe/api/EventHandler.h
@@ -13,6 +13,8 @@ namespace crepe {
* indicating whether the event is handled.
*
* \tparam EventType The type of event this handler will handle.
+ *
+ * Returning \c false from an event handler results in the event being propogated to other listeners for the same event type, while returning \c true stops propogation altogether.
*/
template <typename EventType>
using EventHandler = std::function<bool(const EventType & e)>;
@@ -105,9 +107,9 @@ private:
std::string get_type() const override;
//! The event handler function.
- EventHandler<EventType> m_handler;
+ EventHandler<EventType> handler;
//! The type name of the handler function.
- const std::string m_handler_type;
+ const std::string handler_type;
};
} // namespace crepe
diff --git a/src/crepe/api/EventHandler.hpp b/src/crepe/api/EventHandler.hpp
index 9c47da2..a1e774d 100644
--- a/src/crepe/api/EventHandler.hpp
+++ b/src/crepe/api/EventHandler.hpp
@@ -8,19 +8,19 @@ namespace crepe {
// Implementation of EventHandlerWrapper constructor
template <typename EventType>
EventHandlerWrapper<EventType>::EventHandlerWrapper(const EventHandler<EventType> & handler)
- : m_handler(handler),
- m_handler_type(m_handler.target_type().name()) {}
+ : handler(handler),
+ handler_type(handler.target_type().name()) {}
// Implementation of EventHandlerWrapper::call
template <typename EventType>
bool EventHandlerWrapper<EventType>::call(const Event & e) {
- return m_handler(static_cast<const EventType &>(e));
+ return this->handler(static_cast<const EventType &>(e));
}
// Implementation of EventHandlerWrapper::get_type
template <typename EventType>
std::string EventHandlerWrapper<EventType>::get_type() const {
- return m_handler_type;
+ return this->handler_type;
}
} //namespace crepe
diff --git a/src/crepe/api/EventManager.cpp b/src/crepe/api/EventManager.cpp
index b465e89..27a304f 100644
--- a/src/crepe/api/EventManager.cpp
+++ b/src/crepe/api/EventManager.cpp
@@ -13,9 +13,9 @@ void EventManager::dispatch_events() {
using HandlersVec = std::vector<std::unique_ptr<IEventHandlerWrapper>>;
for (auto event_it = this->events_queue.begin(); event_it != this->events_queue.end();) {
- std::unique_ptr<Event> & event = std::get<0>(*event_it);
- int channel = std::get<1>(*event_it);
- std::type_index event_type = std::get<2>(*event_it);
+ std::unique_ptr<Event> & event = (*event_it).event;
+ int channel = (*event_it).channel;
+ std::type_index event_type = (*event_it).type;
bool event_handled = false;
@@ -58,3 +58,8 @@ void EventManager::dispatch_events() {
}
}
}
+void EventManager::clear(){
+ this->subscribers.clear();
+ this->events_queue.clear();
+ this->subscribers_by_event_id.clear();
+}
diff --git a/src/crepe/api/EventManager.h b/src/crepe/api/EventManager.h
index 92273df..8fd22f4 100644
--- a/src/crepe/api/EventManager.h
+++ b/src/crepe/api/EventManager.h
@@ -11,7 +11,7 @@
#include "EventHandler.h"
namespace crepe {
-
+static constexpr int CHANNEL_ALL = -1;
/**
* \class EventManager
* \brief The EventManager class is responsible for managing the subscription, triggering,
@@ -19,6 +19,7 @@ namespace crepe {
*/
class EventManager {
public:
+
/**
* \brief Get the singleton instance of the EventManager.
*
@@ -38,7 +39,7 @@ public:
* \param channel The channel number to subscribe to (default is 0).
*/
template <typename EventType>
- void subscribe(EventHandler<EventType> && callback, int channel = 0);
+ void subscribe(const EventHandler<EventType> & callback, int channel = CHANNEL_ALL, int priority = 0);
/**
* \brief Unsubscribe from an event.
@@ -50,7 +51,7 @@ public:
* \param channel The event ID to unsubscribe from.
*/
template <typename EventType>
- void unsubscribe(const EventHandler<EventType> &, int channel = 0);
+ void unsubscribe(const EventHandler<EventType> &, int channel = CHANNEL_ALL);
/**
* \brief Trigger an event.
@@ -62,7 +63,7 @@ public:
* \param channel The channel from which to trigger the event (default is 0).
*/
template <typename EventType>
- void trigger_event(const EventType & event, int channel = 0);
+ void trigger_event(const EventType & event, int channel = CHANNEL_ALL);
/**
* \brief Queue an event for later processing.
@@ -75,7 +76,7 @@ public:
* \param channel The channel number for the event (default is 0).
*/
template <typename EventType>
- void queue_event(EventType && event, int channel = 0);
+ void queue_event(const EventType & event, int channel = CHANNEL_ALL,int priority = 0);
/**
* \brief Dispatch all queued events.
@@ -84,8 +85,24 @@ public:
* callbacks for each event.
*/
void dispatch_events();
-
+ /**
+ * \brief clears all subscribers
+ *
+ */
+ void clear();
private:
+ struct QueueEntry {
+ std::unique_ptr<Event> event;
+ int channel = 0;
+ std::type_index type;
+ int priority = 0;
+ };
+ struct CallbackEntry {
+ std::unique_ptr<IEventHandlerWrapper> callback;
+ int channel = 0;
+ std::type_index type;
+ int priority = 0;
+ };
/**
* \brief Default constructor for the EventManager.
*
@@ -94,7 +111,7 @@ private:
EventManager() = default;
//! The queue of events to be processed.
- std::vector<std::tuple<std::unique_ptr<Event>, int, std::type_index>> events_queue;
+ std::vector<QueueEntry> events_queue;
//! Registered event handlers.
std::unordered_map<std::type_index, std::vector<std::unique_ptr<IEventHandlerWrapper>>>
subscribers;
@@ -103,6 +120,7 @@ private:
std::type_index,
std::unordered_map<int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>>
subscribers_by_event_id;
+
};
} // namespace crepe
diff --git a/src/crepe/api/EventManager.hpp b/src/crepe/api/EventManager.hpp
index b20b88f..9090a3f 100644
--- a/src/crepe/api/EventManager.hpp
+++ b/src/crepe/api/EventManager.hpp
@@ -3,7 +3,7 @@
namespace crepe {
template <typename EventType>
-void EventManager::subscribe(EventHandler<EventType> && callback, int channel) {
+void EventManager::subscribe(const EventHandler<EventType> & callback, int channel, int priority) {
using HandlersMap
= std::unordered_map<int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>;
using HandlersVec = std::vector<std::unique_ptr<IEventHandlerWrapper>>;
@@ -27,14 +27,20 @@ void EventManager::subscribe(EventHandler<EventType> && callback, int channel) {
}
template <typename EventType>
-void EventManager::queue_event(EventType && event, int channel) {
- std::type_index event_type = std::type_index(typeid(EventType));
+void EventManager::queue_event(const EventType & event, int channel,int priority) {
+ static_assert(std::is_base_of<Event, EventType>::value, "EventType must derive from Event");
+ std::type_index event_type = typeid(EventType);
- auto event_ptr = std::make_unique<EventType>(std::forward<EventType>(event));
+ auto event_ptr = std::make_unique<EventType>(event);
- std::tuple<std::unique_ptr<Event>, int, std::type_index> tuple(std::move(event_ptr),
- channel, event_type);
- this->events_queue.push_back(std::move(tuple));
+
+ this->events_queue.push_back(
+ QueueEntry{
+ .event = std::move(event_ptr),
+ .channel = channel,
+ .type = event_type
+ }
+ );
}
template <typename EventType>
@@ -43,7 +49,7 @@ void EventManager::trigger_event(const EventType & event, int channel) {
= std::unordered_map<int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>;
using HandlersVec = std::vector<std::unique_ptr<IEventHandlerWrapper>>;
- std::type_index event_type = std::type_index(typeid(EventType));
+ std::type_index event_type = typeid(EventType);
if (channel > 0) {
HandlersMap & handlers_map = this->subscribers_by_event_id[event_type];
@@ -75,7 +81,7 @@ void EventManager::unsubscribe(const EventHandler<EventType> & callback, int cha
= std::unordered_map<int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>;
using HandlersVec = std::vector<std::unique_ptr<IEventHandlerWrapper>>;
- std::type_index event_type(typeid(EventType));
+ std::type_index event_type = typeid(EventType);
std::string handler_name = callback.target_type().name();
if (channel) {
diff --git a/src/crepe/api/IKeyListener.cpp b/src/crepe/api/IKeyListener.cpp
index f5426be..5e7d9bb 100644
--- a/src/crepe/api/IKeyListener.cpp
+++ b/src/crepe/api/IKeyListener.cpp
@@ -2,13 +2,6 @@
using namespace crepe;
-// Constructor with default channel
-IKeyListener::IKeyListener()
- : channel(0),
- active(true),
- event_manager(EventManager::get_instance()) {
- this->subscribe_events();
-}
// Constructor with specified channel
IKeyListener::IKeyListener(int channel)
@@ -28,9 +21,9 @@ void IKeyListener::subscribe_events() {
key_released_handler
= [this](const KeyReleaseEvent & event) { return this->on_key_released(event); };
- event_manager.subscribe<KeyPressEvent>(std::move(this->key_pressed_handler),
+ event_manager.subscribe<KeyPressEvent>(this->key_pressed_handler,
this->channel);
- event_manager.subscribe<KeyReleaseEvent>(std::move(this->key_released_handler),
+ event_manager.subscribe<KeyReleaseEvent>(this->key_released_handler,
this->channel);
}
@@ -40,27 +33,3 @@ void IKeyListener::unsubscribe_events() {
event_manager.unsubscribe<KeyReleaseEvent>(this->key_released_handler, this->channel);
}
-// Activate key listening
-void IKeyListener::activate_keys() {
- if (this->active) {
- return;
- }
- this->active = true;
- this->subscribe_events();
-}
-
-// Deactivate key listening
-void IKeyListener::deactivate_keys() {
- if (!this->active) {
- return;
- }
- this->active = false;
- this->unsubscribe_events();
-}
-
-// Set a new channel for key events
-void IKeyListener::set_channel(int channel) {
- this->unsubscribe_events();
- this->channel = channel;
- this->subscribe_events();
-}
diff --git a/src/crepe/api/IKeyListener.h b/src/crepe/api/IKeyListener.h
index d492387..70243b4 100644
--- a/src/crepe/api/IKeyListener.h
+++ b/src/crepe/api/IKeyListener.h
@@ -16,11 +16,11 @@ public:
* \brief Constructs an IKeyListener with a specified channel.
* \param channel The channel ID for event handling.
*/
- IKeyListener(int channel);
- IKeyListener();
+ IKeyListener(int channel = CHANNEL_ALL);
virtual ~IKeyListener();
IKeyListener(const IKeyListener &) = delete;
IKeyListener & operator=(const IKeyListener &) = delete;
+ IKeyListener & operator=(IKeyListener &&) = delete;
IKeyListener(IKeyListener &&) = delete;
/**
@@ -36,23 +36,6 @@ public:
* \return True if the event was handled, false otherwise.
*/
virtual bool on_key_released(const KeyReleaseEvent & event) = 0;
-
- /**
- * \brief Activates key listening.
- */
- void activate_keys();
-
- /**
- * \brief Deactivates key listening.
- */
- void deactivate_keys();
-
- /**
- * \brief Sets the channel ID for event handling.
- * \param channel The channel ID to set.
- */
- void set_channel(int channel);
-
protected:
/**
* \brief Subscribes to key events.
diff --git a/src/crepe/api/IMouseListener.cpp b/src/crepe/api/IMouseListener.cpp
index 5ee2814..6fd6c4b 100644
--- a/src/crepe/api/IMouseListener.cpp
+++ b/src/crepe/api/IMouseListener.cpp
@@ -8,10 +8,6 @@ IMouseListener::IMouseListener(int channel)
this->subscribe_events();
}
-IMouseListener::IMouseListener() : event_manager(EventManager::get_instance()) {
- this->subscribe_events();
-}
-
IMouseListener::~IMouseListener() { this->unsubscribe_events(); }
void IMouseListener::subscribe_events() {
@@ -26,11 +22,11 @@ void IMouseListener::subscribe_events() {
= [this](const MouseMoveEvent & event) { return this->on_mouse_moved(event); };
// Subscribe event handlers (no need for std::move)
- event_manager.subscribe<MouseClickEvent>(std::move(mouse_click_handler), this->channel);
- event_manager.subscribe<MousePressEvent>(std::move(mouse_press_handler), this->channel);
- event_manager.subscribe<MouseReleaseEvent>(std::move(mouse_release_handler),
+ event_manager.subscribe<MouseClickEvent>(mouse_click_handler, this->channel);
+ event_manager.subscribe<MousePressEvent>(mouse_press_handler, this->channel);
+ event_manager.subscribe<MouseReleaseEvent>(mouse_release_handler,
this->channel);
- event_manager.subscribe<MouseMoveEvent>(std::move(mouse_move_handler), this->channel);
+ event_manager.subscribe<MouseMoveEvent>(mouse_move_handler, this->channel);
}
void IMouseListener::unsubscribe_events() {
@@ -40,25 +36,3 @@ void IMouseListener::unsubscribe_events() {
event_manager.unsubscribe<MouseReleaseEvent>(mouse_release_handler, this->channel);
event_manager.unsubscribe<MouseMoveEvent>(mouse_move_handler, this->channel);
}
-
-void IMouseListener::activate_mouse() {
- if (this->active) {
- return;
- }
- this->subscribe_events();
- this->active = true;
-}
-
-void IMouseListener::deactivate_mouse() {
- if (!this->active) {
- return;
- }
- this->unsubscribe_events();
- this->active = false;
-}
-
-void IMouseListener::set_channel(int channel) {
- this->unsubscribe_events();
- this->channel = channel;
- this->subscribe_events();
-}
diff --git a/src/crepe/api/IMouseListener.h b/src/crepe/api/IMouseListener.h
index 921a760..1195a4e 100644
--- a/src/crepe/api/IMouseListener.h
+++ b/src/crepe/api/IMouseListener.h
@@ -12,16 +12,15 @@ namespace crepe {
*/
class IMouseListener {
public:
- IMouseListener();
/**
* \brief Constructs an IMouseListener with a specified channel.
* \param channel The channel ID for event handling.
*/
- IMouseListener(int channel);
+ IMouseListener(int channel = CHANNEL_ALL);
virtual ~IMouseListener();
IMouseListener & operator=(const IMouseListener &) = delete;
IMouseListener(const IMouseListener &) = delete;
- IMouseListener && operator=(const IMouseListener &&) = delete;
+ IMouseListener & operator=(const IMouseListener &&) = delete;
IMouseListener(IMouseListener &&) = delete;
/**
@@ -56,23 +55,6 @@ public:
* \return True if the event was handled, false otherwise.
*/
virtual bool on_mouse_moved(const MouseMoveEvent & event) = 0;
-
- /**
- * \brief Activates mouse listening.
- */
- void activate_mouse();
-
- /**
- * \brief Deactivates mouse listening.
- */
- void deactivate_mouse();
-
- /**
- * \brief Sets the channel ID for event handling.
- * \param channel The channel ID to set.
- */
- void set_channel(int channel);
-
protected:
/**
* \brief Subscribes to mouse events on the specified channel.
diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp
index 83e91f8..9464c31 100644
--- a/src/crepe/facade/SDLContext.cpp
+++ b/src/crepe/facade/SDLContext.cpp
@@ -78,7 +78,6 @@ SDLContext::~SDLContext() {
IMG_Quit();
SDL_Quit();
}
-
void SDLContext::handle_events(bool & running) {
//TODO: wouter i need events
/*
diff --git a/src/example/events.cpp b/src/example/events.cpp
index 6431c67..402a857 100644
--- a/src/example/events.cpp
+++ b/src/example/events.cpp
@@ -2,7 +2,6 @@
#include <crepe/ComponentManager.h>
#include <crepe/system/ScriptSystem.h>
-#include <crepe/util/log.h>
#include <crepe/api/BehaviorScript.h>
#include <crepe/api/Config.h>
@@ -27,7 +26,6 @@ class MyScript : public Script, public IKeyListener, public IMouseListener {
bool on_key_pressed(const KeyPressEvent & event) override {
std::cout << "KeyPressed function" << std::endl;
- this->deactivate_keys();
return false;
}
bool on_key_released(const KeyReleaseEvent & event) override {
@@ -65,48 +63,60 @@ public:
}
};
int main() {
- // two events to trigger
- KeyPressEvent key_press;
- key_press.key = Keycode::A;
- key_press.repeat = 0;
- MouseClickEvent click_event;
- click_event.button = MouseButton::LEFT_MOUSE;
- click_event.mouse_x = 100;
- click_event.mouse_y = 200;
- // queue events to test queue
- EventManager::get_instance().queue_event<KeyPressEvent>(std::move(key_press), 0);
- EventManager::get_instance().queue_event<MouseClickEvent>(std::move(click_event), 0);
+
{
+ // two events to trigger
+ KeyPressEvent key_press;
+ key_press.key = Keycode::A;
+ key_press.repeat = 0;
+ MouseClickEvent click_event;
+ click_event.button = MouseButton::LEFT_MOUSE;
+ click_event.mouse_x = 100;
+ click_event.mouse_y = 200;
+ // queue events to test queue
+ EventManager::get_instance().queue_event<KeyPressEvent>(key_press);
+ EventManager::get_instance().queue_event<MouseClickEvent>(click_event);
TestKeyListener test_listener;
- test_listener.set_channel(1);
- auto obj = GameObject(0, "name", "tag", Vector2{1.2, 3.4}, 0, 1);
- obj.add_component<BehaviorScript>().set_script<MyScript>();
+ //auto obj = GameObject(0, "name", "tag", Vector2{1.2, 3.4}, 0, 1);
+ //obj.add_component<BehaviorScript>().set_script<MyScript>();
- ScriptSystem sys;
- sys.update();
+ //ScriptSystem sys;
+ //sys.update();
// Trigger the events while `testListener` is in scope
- EventManager::get_instance().trigger_event<KeyPressEvent>(key_press, 1);
- EventManager::get_instance().trigger_event(
- MouseClickEvent{
- .mouse_x = 100,
- .mouse_y = 100,
- .button = MouseButton::LEFT_MOUSE,
- },
- 1);
+ //EventManager::get_instance().trigger_event<KeyPressEvent>(key_press, 1);
+ // EventManager::get_instance().trigger_event(
+ // MouseClickEvent{
+ // .mouse_x = 100,
+ // .mouse_y = 100,
+ // .button = MouseButton::LEFT_MOUSE,
+ // },
+ // 1);
+ //EventManager::get_instance().trigger_event<MouseClickEvent>(click_event, 0);
}
// custom lambda event handler
EventHandler<KeyPressEvent> event_handler = [](const KeyPressEvent & e) {
- std::cout << "lambda test" << std::endl;
+ std::cout << "key lambda test" << std::endl;
+ return true;
+ };
+ EventHandler<MouseClickEvent> event_handler2 = [](const MouseClickEvent & e) {
+ std::cout << "mouse lambda test" << std::endl;
return false;
};
- EventManager::get_instance().subscribe<KeyPressEvent>(std::move(event_handler), 0);
+ EventManager::get_instance().subscribe<KeyPressEvent>(event_handler, CHANNEL_ALL);
+ EventManager::get_instance().subscribe<KeyPressEvent>(event_handler, CHANNEL_ALL);
+ EventManager::get_instance().subscribe<MouseClickEvent>(event_handler2, CHANNEL_ALL);
+ EventManager::get_instance().trigger_event<KeyPressEvent>(KeyPressEvent{
+ .repeat = false,
+ .key = Keycode::A
+ });
+ //EventManager::get_instance().unsubscribe<KeyPressEvent>(event_handler, 0);
// testing trigger with testListener not in scope (unsubscribed)
- EventManager::get_instance().trigger_event<KeyPressEvent>(key_press, 0);
- EventManager::get_instance().trigger_event<MouseClickEvent>(click_event, 0);
+ // EventManager::get_instance().trigger_event<KeyPressEvent>(key_press, 0);
+ // EventManager::get_instance().trigger_event<MouseClickEvent>(click_event, 0);
// dispatching queued events
- EventManager::get_instance().dispatch_events();
+ //EventManager::get_instance().dispatch_events();
- EventManager::get_instance().unsubscribe<KeyPressEvent>(event_handler, 0);
+ EventManager::get_instance().unsubscribe<KeyPressEvent>(event_handler);
return EXIT_SUCCESS;
}
diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt
index 49c8151..6f6ad79 100644
--- a/src/test/CMakeLists.txt
+++ b/src/test/CMakeLists.txt
@@ -3,5 +3,6 @@ target_sources(test_main PUBLIC
PhysicsTest.cpp
ScriptTest.cpp
ParticleTest.cpp
+ EventTest.cpp
)
diff --git a/src/test/EventTest.cpp b/src/test/EventTest.cpp
new file mode 100644
index 0000000..19f6d2e
--- /dev/null
+++ b/src/test/EventTest.cpp
@@ -0,0 +1,470 @@
+
+#include "api/EventManager.h"
+#include "api/Event.h"
+#include "api/IKeyListener.h"
+#include "api/IMouseListener.h"
+#include <gtest/gtest.h>
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+using namespace std;
+using namespace std::chrono_literals;
+using namespace crepe;
+
+
+class EventManagerTest : public ::testing::Test {
+protected:
+ void SetUp() override {
+ // Clear any existing subscriptions or events before each test
+ EventManager::get_instance().clear();
+ }
+
+ void TearDown() override {
+ // Ensure cleanup after each test
+ EventManager::get_instance().clear();
+ }
+};
+class MockKeyListener : public IKeyListener {
+public:
+ MOCK_METHOD(bool, on_key_pressed, (const KeyPressEvent& event), (override));
+ MOCK_METHOD(bool, on_key_released, (const KeyReleaseEvent& event), (override));
+};
+
+class MockMouseListener : public IMouseListener {
+public:
+ MOCK_METHOD(bool, on_mouse_clicked, (const MouseClickEvent& event), (override));
+ MOCK_METHOD(bool, on_mouse_pressed, (const MousePressEvent& event), (override));
+ MOCK_METHOD(bool, on_mouse_released, (const MouseReleaseEvent& event), (override));
+ MOCK_METHOD(bool, on_mouse_moved, (const MouseMoveEvent& event), (override));
+};
+TEST_F(EventManagerTest, EventSubscription) {
+ EventHandler<KeyPressEvent> key_handler = [](const KeyPressEvent& e) {
+ std::cout << "Key Event Triggered" << std::endl;
+ return true;
+ };
+
+ // Subscribe to KeyPressEvent
+ EventManager::get_instance().subscribe<KeyPressEvent>(key_handler, 1);
+
+ // Verify subscription (not directly verifiable; test by triggering event)
+
+ EventManager::get_instance().trigger_event<KeyPressEvent>(KeyPressEvent{
+ .repeat = true,
+ .key = Keycode::A,
+ }, 1);
+ EventManager::get_instance().trigger_event<KeyPressEvent>(KeyPressEvent{
+ .repeat = true,
+ .key = Keycode::A,
+
+ }, CHANNEL_ALL);
+
+}
+TEST_F(EventManagerTest, EventManagerTest_trigger_all_channels) {
+ bool triggered = false;
+
+ EventHandler<MouseClickEvent> mouse_handler = [&](const MouseClickEvent& e) {
+ triggered = true;
+ std::cout << "mouse handled" <<std::endl;
+ EXPECT_EQ(e.mouse_x, 100);
+ EXPECT_EQ(e.mouse_y, 200);
+ EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);
+ return false;
+ };
+ EventManager::get_instance().subscribe<MouseClickEvent>(mouse_handler, CHANNEL_ALL);
+
+ MouseClickEvent click_event{
+ .mouse_x = 100,
+ .mouse_y = 200,
+ .button = MouseButton::LEFT_MOUSE
+ };
+ EventManager::get_instance().trigger_event<MouseClickEvent>(click_event, CHANNEL_ALL);
+
+ EXPECT_TRUE(triggered);
+}
+
+TEST_F(EventManagerTest, EventManagerTest_priority_order) {
+ EventManager& event_manager = EventManager::get_instance();
+
+ // Vector to track call order
+ std::vector<int> call_order;
+
+ // Handlers with different priorities
+ EventHandler<MouseClickEvent> handler_priority_3 = [&](const MouseClickEvent& e) {
+ call_order.push_back(3);
+ return false; // Allow propagation
+ };
+
+ EventHandler<MouseClickEvent> handler_priority_1 = [&](const MouseClickEvent& e) {
+ call_order.push_back(1);
+ return false; // Allow propagation
+ };
+
+ EventHandler<MouseClickEvent> handler_priority_2 = [&](const MouseClickEvent& e) {
+ call_order.push_back(2);
+ return false; // Allow propagation
+ };
+
+ // Subscribe handlers with different priorities
+ event_manager.subscribe<MouseClickEvent>(handler_priority_1, CHANNEL_ALL, 1);
+ event_manager.subscribe<MouseClickEvent>(handler_priority_2, CHANNEL_ALL, 2);
+ event_manager.subscribe<MouseClickEvent>(handler_priority_3, CHANNEL_ALL, 3);
+
+ // Trigger the event
+ event_manager.trigger_event<MouseClickEvent>(MouseClickEvent{
+ .mouse_x = 100,
+ .mouse_y = 200,
+ .button = MouseButton::LEFT_MOUSE
+ }, CHANNEL_ALL);
+
+ // Check the call order matches the expected priority order
+ std::vector<int> expected_order = {3, 2, 1};
+ EXPECT_EQ(call_order, expected_order);
+
+}
+
+TEST_F(EventManagerTest, EventManagerTest_callback_propagation) {
+ EventManager& event_manager = EventManager::get_instance();
+
+ // Flags to track handler calls
+ bool triggered_true = false;
+ bool triggered_false = false;
+
+ // Handlers
+ EventHandler<MouseClickEvent> mouse_handler_true = [&](const MouseClickEvent& e) {
+ triggered_true = true;
+ EXPECT_EQ(e.mouse_x, 100);
+ EXPECT_EQ(e.mouse_y, 200);
+ EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);
+ return true; // Stops propagation
+ };
+
+ EventHandler<MouseClickEvent> mouse_handler_false = [&](const MouseClickEvent& e) {
+ triggered_false = true;
+ EXPECT_EQ(e.mouse_x, 100);
+ EXPECT_EQ(e.mouse_y, 200);
+ EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);
+ return false; // Allows propagation
+ };
+
+ // Test event
+ MouseClickEvent click_event{
+ .mouse_x = 100,
+ .mouse_y = 200,
+ .button = MouseButton::LEFT_MOUSE
+ };
+
+ // First Scenario: True handler has higher priority
+ event_manager.subscribe<MouseClickEvent>(mouse_handler_true, CHANNEL_ALL, 1);
+ event_manager.subscribe<MouseClickEvent>(mouse_handler_false, CHANNEL_ALL, 0);
+
+ // Trigger event
+ event_manager.trigger_event<MouseClickEvent>(click_event, CHANNEL_ALL);
+
+ // Check that only the true handler was triggered
+ EXPECT_TRUE(triggered_true);
+ EXPECT_FALSE(triggered_false);
+
+ // Reset and clear
+ triggered_true = false;
+ triggered_false = false;
+ event_manager.clear();
+
+ // Second Scenario: False handler has higher priority
+ event_manager.subscribe<MouseClickEvent>(mouse_handler_true, CHANNEL_ALL, 0);
+ event_manager.subscribe<MouseClickEvent>(mouse_handler_false, CHANNEL_ALL, 1);
+
+ // Trigger event again
+ event_manager.trigger_event<MouseClickEvent>(click_event, CHANNEL_ALL);
+
+ // Check that both handlers were triggered
+ EXPECT_TRUE(triggered_true);
+ EXPECT_TRUE(triggered_false);
+}
+
+TEST_F(EventManagerTest, EventManagerTest_queue_dispatch) {
+ EventManager& event_manager = EventManager::get_instance();
+ bool triggered1 = false;
+ bool triggered2 = false;
+ int test_channel = 1;
+ EventHandler<MouseClickEvent> mouse_handler1 = [&](const MouseClickEvent& e) {
+ triggered1 = true;
+ EXPECT_EQ(e.mouse_x, 100);
+ EXPECT_EQ(e.mouse_y, 200);
+ EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);
+ return false; // Allows propagation
+ };
+ EventHandler<MouseClickEvent> mouse_handler2 = [&](const MouseClickEvent& e) {
+ triggered2 = true;
+ EXPECT_EQ(e.mouse_x, 100);
+ EXPECT_EQ(e.mouse_y, 200);
+ EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);
+ return false; // Allows propagation
+ };
+ event_manager.subscribe<MouseClickEvent>(mouse_handler1);
+ event_manager.subscribe<MouseClickEvent>(mouse_handler2,test_channel);
+
+ event_manager.queue_event<MouseClickEvent>(MouseClickEvent{
+ .mouse_x = 100,
+ .mouse_y = 200,
+ .button = MouseButton::LEFT_MOUSE
+ });
+ event_manager.queue_event<MouseClickEvent>(MouseClickEvent{
+ .mouse_x = 100,
+ .mouse_y = 200,
+ .button = MouseButton::LEFT_MOUSE
+ },test_channel);
+ event_manager.dispatch_events();
+ EXPECT_TRUE(triggered1);
+ EXPECT_TRUE(triggered2);
+}
+
+TEST_F(EventManagerTest, EventManagerTest_dispatch_priority) {
+ EventManager& event_manager = EventManager::get_instance();
+ std::vector<int> call_order;
+ int test_channel = 1;
+ EventHandler<MouseClickEvent> mouse_handler1 = [&](const MouseClickEvent& e) {
+ call_order.push_back(1);
+ EXPECT_EQ(e.mouse_x, 100);
+ EXPECT_EQ(e.mouse_y, 200);
+ EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);
+ return false; // Allows propagation
+ };
+ EventHandler<MouseClickEvent> mouse_handler2 = [&](const MouseClickEvent& e) {
+ call_order.push_back(2);
+ EXPECT_EQ(e.mouse_x, 100);
+ EXPECT_EQ(e.mouse_y, 200);
+ EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);
+ return false; // Allows propagation
+ };
+ EventHandler<MouseClickEvent> mouse_handler3 = [&](const MouseClickEvent& e) {
+ call_order.push_back(3);
+ EXPECT_EQ(e.mouse_x, 100);
+ EXPECT_EQ(e.mouse_y, 200);
+ EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);
+ return false; // Allows propagation
+ };
+ event_manager.subscribe<MouseClickEvent>(mouse_handler1,CHANNEL_ALL,1);
+ event_manager.subscribe<MouseClickEvent>(mouse_handler2,CHANNEL_ALL,2);
+ event_manager.subscribe<MouseClickEvent>(mouse_handler2,CHANNEL_ALL,3);
+ event_manager.queue_event<MouseClickEvent>(MouseClickEvent{
+ .mouse_x = 100,
+ .mouse_y = 200,
+ .button = MouseButton::LEFT_MOUSE
+ });
+ event_manager.dispatch_events();
+ std::vector<int> expected_order = {3, 2, 1};
+ EXPECT_EQ(call_order, expected_order);
+}
+
+TEST_F(EventManagerTest, EventManagerTest_unsubscribe) {
+ EventManager& event_manager = EventManager::get_instance();
+
+ // Flags to track if handlers are triggered
+ bool triggered1 = false;
+ bool triggered2 = false;
+
+ // Define EventHandlers
+ EventHandler<MouseClickEvent> mouse_handler1 = [&](const MouseClickEvent& e) {
+ triggered1 = true;
+ EXPECT_EQ(e.mouse_x, 100);
+ EXPECT_EQ(e.mouse_y, 200);
+ EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);
+ return false; // Allows propagation
+ };
+
+ EventHandler<MouseClickEvent> mouse_handler2 = [&](const MouseClickEvent& e) {
+ triggered2 = true;
+ EXPECT_EQ(e.mouse_x, 100);
+ EXPECT_EQ(e.mouse_y, 200);
+ EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);
+ return false; // Allows propagation
+ };
+
+ // Subscribe handlers
+ event_manager.subscribe<MouseClickEvent>(mouse_handler1);
+ event_manager.subscribe<MouseClickEvent>(mouse_handler2);
+
+ // Queue events
+ event_manager.queue_event<MouseClickEvent>(MouseClickEvent{
+ .mouse_x = 100,
+ .mouse_y = 200,
+ .button = MouseButton::LEFT_MOUSE
+ });
+
+ // Dispatch events - both handlers should be triggered
+ event_manager.dispatch_events();
+ EXPECT_TRUE(triggered1); // Handler 1 should be triggered
+ EXPECT_TRUE(triggered2); // Handler 2 should be triggered
+
+ // Reset flags
+ triggered1 = false;
+ triggered2 = false;
+
+ // Unsubscribe handler1
+ event_manager.unsubscribe<MouseClickEvent>(mouse_handler1);
+
+ // Queue the same event again
+ event_manager.queue_event<MouseClickEvent>(MouseClickEvent{
+ .mouse_x = 100,
+ .mouse_y = 200,
+ .button = MouseButton::LEFT_MOUSE
+ });
+
+ // Dispatch events - only handler 2 should be triggered, handler 1 should NOT
+ event_manager.dispatch_events();
+ EXPECT_FALSE(triggered1); // Handler 1 should NOT be triggered
+ EXPECT_TRUE(triggered2); // Handler 2 should be triggered
+
+ // Reset flags
+ triggered2 = false;
+
+ // Unsubscribe handler2
+ event_manager.unsubscribe<MouseClickEvent>(mouse_handler2);
+
+ // Queue the event again
+ event_manager.queue_event<MouseClickEvent>(MouseClickEvent{
+ .mouse_x = 100,
+ .mouse_y = 200,
+ .button = MouseButton::LEFT_MOUSE
+ });
+
+ // Dispatch events - no handler should be triggered
+ event_manager.dispatch_events();
+ EXPECT_FALSE(triggered1); // Handler 1 should NOT be triggered
+ EXPECT_FALSE(triggered2); // Handler 2 should NOT be triggered
+}
+
+// TEST_F(EventManagerTest, OnKeyPressedTest) {
+// MockKeyListener mock_key_listener;
+// EventManager& event_manager = EventManager::get_instance();
+
+// // Create the KeyPressEvent object
+// KeyPressEvent key_event = KeyPressEvent{
+// .key = Keycode::A,
+// .repeat = false
+// };
+
+// // Set up the mock expectation with direct object passing
+// EXPECT_CALL(mock_key_listener, on_key_pressed(key_event))
+// .Times(1) // Expect it to be called exactly once
+// .WillOnce(::testing::Return(true)); // Return value (can be true/false)
+
+
+// // Queue the event
+// event_manager.queue_event<KeyPressEvent>(key_event);
+
+// // Dispatch the event to trigger the mock
+// event_manager.dispatch_events(); // Trigger event dispatch
+
+// // The mock will ensure the on_key_pressed method is called
+// }
+
+
+
+// TEST_F(EventManagerTest, OnKeyReleaseTest) {
+// MockKeyListener mock_key_listener;
+// EventManager& event_manager = EventManager::get_instance();
+
+// // Create the KeyPressEvent object
+// KeyReleaseEvent key_event = KeyReleaseEvent{
+// .key = Keycode::A,
+// };
+
+// // Set up the mock expectation with direct object passing
+// EXPECT_CALL(mock_key_listener, on_key_released(key_event))
+// .Times(1) // Expect it to be called exactly once
+// .WillOnce(::testing::Return(true)); // Return value (can be true/false)
+
+
+// // Queue the event
+// event_manager.queue_event<KeyReleaseEvent>(key_event);
+
+// // Dispatch the event to trigger the mock
+// event_manager.dispatch_events(); // Trigger event dispatch
+
+// // The mock will ensure the on_key_pressed method is called
+// }
+
+// TEST_F(EventManagerTest, UnsubscribeEventsTest) {
+// EventManager& event_manager = EventManager::get_instance();
+// KeyPressEvent key_event{
+// .key = Keycode::A,
+// .repeat = false
+// };
+
+// // Create the mock listener
+// MockKeyListener mock_key_listener;
+
+// // Set up the mock expectation that on_key_pressed will be called once initially
+// EXPECT_CALL(mock_key_listener, on_key_pressed(key_event))
+// .Times(1) // Expect it to be called exactly once
+// .WillOnce(::testing::Return(true)); // Return value (can be true/false)
+
+// event_manager.queue_event<KeyPressEvent>(key_event);
+// event_manager.dispatch_events(); // Should trigger on_key_pressed once
+
+// // Now unsubscribe the listener
+// event_manager.unsubscribe<KeyPressEvent>(std::bind(&MockKeyListener::on_key_pressed, &mock_key_listener, std::placeholders::_1));
+
+// // Set up the expectation that on_key_pressed will NOT be called after unsubscribing
+// EXPECT_CALL(mock_key_listener, on_key_pressed(key_event))
+// .Times(0); // Should not be called after unsubscribe
+
+// // Queue and dispatch the event again (after unsubscribe)
+// event_manager.queue_event<KeyPressEvent>(key_event);
+// event_manager.dispatch_events(); // Should NOT trigger on_key_pressed after unsubscribe
+// }
+
+// TEST_F(EventManagerTest, OnMouseButtonPressedTest) {
+// MockMouseListener mock_mouse_listener;
+// EventManager& event_manager = EventManager::get_instance();
+
+// // Create the MouseButtonPressEvent object
+// MousePressEvent mouse_event{
+// .mouse_x = 100,
+// .mouse_y = 150,
+// .button = MouseButton::LEFT_MOUSE
+// };
+
+// // Set up the mock expectation with direct object passing
+// EXPECT_CALL(mock_mouse_listener, on_mouse_pressed(mouse_event))
+// .Times(1) // Expect it to be called exactly once
+// .WillOnce(::testing::Return(true)); // Return value (can be true/false)
+
+// // Queue the event
+// event_manager.queue_event<MousePressEvent>(mouse_event);
+
+// // Dispatch the event to trigger the mock
+// event_manager.dispatch_events(); // Should trigger on_mouse_button_pressed once
+// }
+
+// TEST_F(EventManagerTest, UnsubscribeMouseEventsTest) {
+// EventManager& event_manager = EventManager::get_instance();
+// MousePressEvent mouse_event{
+// .mouse_x = 100,
+// .mouse_y = 150,
+// .button = MouseButton::LEFT_MOUSE
+// };
+
+// // Create the mock listener
+// MockMouseListener mock_mouse_listener;
+
+// // Set up the mock expectation that on_mouse_button_pressed will be called once initially
+// EXPECT_CALL(mock_mouse_listener, on_mouse_pressed(mouse_event))
+// .Times(1) // Expect it to be called exactly once
+// .WillOnce(::testing::Return(true)); // Return value (can be true/false)
+
+// // Queue and dispatch the event (should trigger on_mouse_button_pressed)
+// event_manager.queue_event<MousePressEvent>(mouse_event);
+// event_manager.dispatch_events(); // Should trigger on_mouse_button_pressed once
+
+// // Now unsubscribe the listener
+// event_manager.unsubscribe<MousePressEvent>(std::bind(&MockMouseListener::on_mouse_pressed, &mock_mouse_listener, std::placeholders::_1));
+
+// // Set up the expectation that on_mouse_button_pressed will NOT be called after unsubscribing
+// EXPECT_CALL(mock_mouse_listener, on_mouse_pressed(mouse_event))
+// .Times(0); // Should not be called after unsubscribe
+
+// // Queue and dispatch the event again (after unsubscribe)
+// event_manager.queue_event<MousePressEvent>(mouse_event);
+// event_manager.dispatch_events(); // Should NOT trigger on_mouse_button_pressed after unsubscribe
+// }