diff options
author | WBoerenkamps <wrj.boerenkamps@student.avans.nl> | 2024-11-20 18:41:50 +0100 |
---|---|---|
committer | WBoerenkamps <wrj.boerenkamps@student.avans.nl> | 2024-11-20 18:41:50 +0100 |
commit | 9a46acde813e00e574e70439795dedcdc9a8192a (patch) | |
tree | f79b2abc6c87aff3893625d9f69c27b5a06afd86 | |
parent | 5f76ad1dde34fc0cf7b8ea63befa8917da94fe5c (diff) |
dispatch fixed and priority added
-rw-r--r-- | src/crepe/api/EventManager.cpp | 73 | ||||
-rw-r--r-- | src/crepe/api/EventManager.hpp | 95 | ||||
-rw-r--r-- | src/crepe/api/KeyCodes.h | 29 | ||||
-rw-r--r-- | src/test/EventTest.cpp | 142 |
4 files changed, 84 insertions, 255 deletions
diff --git a/src/crepe/api/EventManager.cpp b/src/crepe/api/EventManager.cpp index 27a304f..4f88e97 100644 --- a/src/crepe/api/EventManager.cpp +++ b/src/crepe/api/EventManager.cpp @@ -8,58 +8,37 @@ EventManager & EventManager::get_instance() { } void EventManager::dispatch_events() { - using HandlersMap - = std::unordered_map<int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>; - 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 = (*event_it).event; + int channel = (*event_it).channel; + std::type_index event_type = (*event_it).type; - for (auto event_it = this->events_queue.begin(); event_it != this->events_queue.end();) { - 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; + auto handlers_it = this->subscribers.find(event_type); + if (handlers_it != this->subscribers.end()) { + std::vector<CallbackEntry>& handlers = handlers_it->second; + + std::sort(handlers.begin(), handlers.end(), [](const CallbackEntry& a, const CallbackEntry& b) { + return a.priority > b.priority; + }); - bool event_handled = false; + for (auto handler_it = handlers.begin(); handler_it != handlers.end(); ++handler_it) { + // If callback is executed and returns true, remove the event from the queue + if ((*handler_it).callback->exec(*event)) { + event_it = this->events_queue.erase(event_it); + event_handled = true; + break; + } + } + } - if (channel) { - auto handlers_it = subscribers_by_event_id.find(event_type); - if (handlers_it != subscribers_by_event_id.end()) { - HandlersMap & handlers_map = handlers_it->second; - auto handlers = handlers_map.find(channel); - if (handlers != handlers_map.end()) { - HandlersVec & callbacks = handlers->second; - for (auto handler_it = callbacks.begin(); handler_it != callbacks.end(); - ++handler_it) { - if ((*handler_it)->exec(*event)) { - event_it = events_queue.erase(event_it); - event_handled = true; - break; - } - } - } - } - } else { - // Handle event for all channels - auto handlers_it = this->subscribers.find(event_type); - if (handlers_it != this->subscribers.end()) { - HandlersVec & handlers = handlers_it->second; - for (auto handler_it = handlers.begin(); handler_it != handlers.end(); - ++handler_it) { - // remove event from queue since and continue when callback returns true - if ((*handler_it)->exec(*event)) { - event_it = this->events_queue.erase(event_it); - event_handled = true; - break; - } - } - } - } - - if (!event_handled) { - ++event_it; - } - } + if (!event_handled) { + ++event_it; + } + } } + void EventManager::clear(){ this->subscribers.clear(); this->events_queue.clear(); - this->subscribers_by_event_id.clear(); } diff --git a/src/crepe/api/EventManager.hpp b/src/crepe/api/EventManager.hpp index 3a40336..481017d 100644 --- a/src/crepe/api/EventManager.hpp +++ b/src/crepe/api/EventManager.hpp @@ -4,17 +4,20 @@ namespace crepe { template <typename EventType> void EventManager::subscribe(const EventHandler<EventType> & callback, int channel, int priority) { - using HandlersVec = std::vector<CallbackEntry>; std::type_index event_type = typeid(EventType); std::unique_ptr<EventHandlerWrapper<EventType>> handler = std::make_unique<EventHandlerWrapper<EventType>>(callback); - HandlersVec & handlers = this->subscribers[event_type]; + std::vector<CallbackEntry> & handlers = this->subscribers[event_type]; handlers.emplace_back(CallbackEntry{ .callback = std::move(handler), .channel = channel, .priority = priority, }); + // Sort handlers by priority (highest first) + std::sort(handlers.begin(), handlers.end(), [](const CallbackEntry &a, const CallbackEntry &b) { + return a.priority > b.priority; + }); } template <typename EventType> @@ -36,72 +39,44 @@ void EventManager::queue_event(const EventType & event, int channel,int priority template <typename EventType> void EventManager::trigger_event(const EventType & event, int channel) { - using HandlersMap - = 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); - - if (channel == CHANNEL_ALL) { - HandlersMap & handlers_map = this->subscribers_by_event_id[event_type]; - auto handlers_it = handlers_map.find(channel); + auto handlers_it = this->subscribers.find(event_type); + if (handlers_it != this->subscribers.end()) { + const std::vector<CallbackEntry> &handlers = handlers_it->second; - if (handlers_it != handlers_map.end()) { - HandlersVec & handlers = handlers_it->second; - for (auto it = handlers.begin(); it != handlers.end(); ++it) { - // stops when callback returns true - if ((*it)->exec(event)) { - break; - } - } - } - } else { - HandlersVec & handlers = this->subscribers[event_type]; - for (auto it = handlers.begin(); it != handlers.end(); ++it) { - // stops when callback returns true - if ((*it)->exec(event)) { - break; - } - } - } + for (const CallbackEntry &handler : handlers) { + if (handler.channel != channel && handler.channel != CHANNEL_ALL) { + continue; + } + if (handler.callback->exec(event)) { + break; + } + } + } } + template <typename EventType> void EventManager::unsubscribe(const EventHandler<EventType> & callback, int channel) { - using HandlersMap - = 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::string handler_name = callback.target_type().name(); - std::type_index event_type = typeid(EventType); - std::string handler_name = callback.target_type().name(); + // Find the list of handlers for this event type + auto handlers_it = this->subscribers.find(event_type); + if (handlers_it != this->subscribers.end()) { + std::vector<CallbackEntry> & handlers = handlers_it->second; - if (channel) { - auto subscriber_list = this->subscribers_by_event_id.find(event_type); - if (subscriber_list != this->subscribers_by_event_id.end()) { - HandlersMap & handlers_map = subscriber_list->second; - auto handlers = handlers_map.find(channel); - if (handlers != handlers_map.end()) { - HandlersVec & callbacks = handlers->second; - for (auto it = callbacks.begin(); it != callbacks.end(); ++it) { - if ((*it)->get_type() == handler_name) { - it = callbacks.erase(it); - return; - } - } - } - } - } else { - auto handlers_it = this->subscribers.find(event_type); - if (handlers_it != this->subscribers.end()) { - HandlersVec & handlers = handlers_it->second; - for (auto it = handlers.begin(); it != handlers.end(); ++it) { - if ((*it)->get_type() == handler_name) { - it = handlers.erase(it); - return; - } - } - } - } + for (auto it = handlers.begin(); it != handlers.end(); ) { + // Match based on handler type and channel + if (it->callback->get_type() == handler_name && it->channel == channel) { + it = handlers.erase(it); + return; + } + ++it; + } + } } + } // namespace crepe diff --git a/src/crepe/api/KeyCodes.h b/src/crepe/api/KeyCodes.h index feed0b2..16c2108 100644 --- a/src/crepe/api/KeyCodes.h +++ b/src/crepe/api/KeyCodes.h @@ -1,7 +1,6 @@ #pragma once -//! \enum MouseButton -//! \brief Enumeration for mouse button inputs, including standard and extended buttons. +//! Enumeration for mouse button inputs, including standard and extended buttons. enum class MouseButton { //! No mouse button input. NONE = 0, @@ -18,12 +17,11 @@ enum class MouseButton { //! Scroll wheel upward movement. SCROLL_UP = 6, //! Scroll wheel downward movement. - SCROLL_DOWN = 7 + SCROLL_DOWN = 7, }; -//! \enum Keycode -//! \brief Enumeration for keyboard key inputs, including printable characters, function keys, and keypad keys. -enum class Keycode : int { +//! Enumeration for keyboard key inputs, including printable characters, function keys, and keypad keys. +enum class Keycode { //! No key input. NONE = 0, //! Spacebar. @@ -164,7 +162,10 @@ enum class Keycode : int { PRINT_SCREEN = 283, //! Pause key. PAUSE = 284, - //! Function keys (F1-F25). + /** + * \name Function keys (F1-F25). + * \{ + */ F1 = 290, F2 = 291, F3 = 292, @@ -190,7 +191,11 @@ enum class Keycode : int { F23 = 312, F24 = 313, F25 = 314, - //! Keypad digits and operators. + /// \} + /** + * \name Keypad digits and operators. + * \{ + */ KP0 = 320, KP1 = 321, KP2 = 322, @@ -208,6 +213,11 @@ enum class Keycode : int { KP_ADD = 334, KP_ENTER = 335, KP_EQUAL = 336, + /// \} + /** + * \name Modifier keys. + * \{ + */ //! Modifier keys. LEFT_SHIFT = 340, LEFT_CONTROL = 341, @@ -217,6 +227,7 @@ enum class Keycode : int { RIGHT_CONTROL = 345, RIGHT_ALT = 346, RIGHT_SUPER = 347, + /// \} //! Menu key. - MENU = 348 + MENU = 348, }; diff --git a/src/test/EventTest.cpp b/src/test/EventTest.cpp index 19f6d2e..3a78590 100644 --- a/src/test/EventTest.cpp +++ b/src/test/EventTest.cpp @@ -105,8 +105,8 @@ TEST_F(EventManagerTest, EventManagerTest_priority_order) { // 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); + event_manager.subscribe<MouseClickEvent>(handler_priority_2, CHANNEL_ALL, 2); // Trigger the event event_manager.trigger_event<MouseClickEvent>(MouseClickEvent{ @@ -242,9 +242,9 @@ TEST_F(EventManagerTest, EventManagerTest_dispatch_priority) { 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.subscribe<MouseClickEvent>(mouse_handler1,CHANNEL_ALL,1); + event_manager.subscribe<MouseClickEvent>(mouse_handler3,CHANNEL_ALL,3); event_manager.queue_event<MouseClickEvent>(MouseClickEvent{ .mouse_x = 100, .mouse_y = 200, @@ -278,7 +278,6 @@ TEST_F(EventManagerTest, EventManagerTest_unsubscribe) { 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); @@ -333,138 +332,3 @@ TEST_F(EventManagerTest, EventManagerTest_unsubscribe) { 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 -// } |