diff options
m--------- | lib/sdl2 | 0 | ||||
m--------- | lib/sdl_image | 0 | ||||
m--------- | lib/sdl_ttf | 0 | ||||
-rw-r--r-- | mwe/events/include/event.h | 2 | ||||
-rw-r--r-- | src/crepe/api/CMakeLists.txt | 4 | ||||
-rw-r--r-- | src/crepe/api/Event.h | 57 | ||||
-rw-r--r-- | src/crepe/api/EventHandler.cpp | 2 | ||||
-rw-r--r-- | src/crepe/api/EventHandler.h | 111 | ||||
-rw-r--r-- | src/crepe/api/EventManager.cpp | 78 | ||||
-rw-r--r-- | src/crepe/api/EventManager.h | 256 | ||||
-rw-r--r-- | src/crepe/api/IKeyListener.cpp | 49 | ||||
-rw-r--r-- | src/crepe/api/IKeyListener.h | 78 | ||||
-rw-r--r-- | src/crepe/api/IMouseListener.cpp | 56 | ||||
-rw-r--r-- | src/crepe/api/IMouseListener.h | 117 | ||||
-rw-r--r-- | src/crepe/api/KeyCodes.h | 147 | ||||
-rw-r--r-- | src/example/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/example/events.cpp | 110 |
17 files changed, 1063 insertions, 5 deletions
diff --git a/lib/sdl2 b/lib/sdl2 -Subproject 9519b9916cd29a14587af0507292f2bd31dd575 +Subproject c98c4fbff6d8f3016a3ce6685bf8f43433c3efc diff --git a/lib/sdl_image b/lib/sdl_image -Subproject abcf63aa71b4e3ac32120fa9870a6500ddcdcc8 +Subproject 56560190a6c5b5740e5afdce747e2a2bfbf16db diff --git a/lib/sdl_ttf b/lib/sdl_ttf -Subproject 4a318f8dfaa1bb6f10e0c5e54052e25d3c7f344 +Subproject a3d0895c1b60c41ff9e85d9203ddd7485c014da diff --git a/mwe/events/include/event.h b/mwe/events/include/event.h index 16c75bf..3e70201 100644 --- a/mwe/events/include/event.h +++ b/mwe/events/include/event.h @@ -152,7 +152,7 @@ private: }; class ShutDownEvent : public Event { public: - ShutDownEvent() : Event("ShutDownEvent") {}; + ShutDownEvent() : Event("ShutDownEvent"){}; REGISTER_EVENT_TYPE(ShutDownEvent) diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt index 85696c4..87cbb09 100644 --- a/src/crepe/api/CMakeLists.txt +++ b/src/crepe/api/CMakeLists.txt @@ -18,8 +18,6 @@ target_sources(crepe PUBLIC Vector2.cpp Camera.cpp Animator.cpp - LoopManager.cpp - LoopTimer.cpp ) target_sources(crepe PUBLIC FILE_SET HEADERS FILES @@ -44,6 +42,4 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES SceneManager.hpp Camera.h Animator.h - LoopManager.h - LoopTimer.h ) diff --git a/src/crepe/api/Event.h b/src/crepe/api/Event.h new file mode 100644 index 0000000..cffa5da --- /dev/null +++ b/src/crepe/api/Event.h @@ -0,0 +1,57 @@ +#pragma once +#include "KeyCodes.h" +#include <iostream> +#include <string> +#include <typeindex> + +class Event { +public: + bool handled = false; +}; + +class KeyPressEvent : public Event { +public: + int repeat = 0; + Keycode key = Keycode::None; +}; + +class KeyReleaseEvent : public Event { +public: + Keycode key = Keycode::None; +}; + +class MousePressEvent : public Event { +public: + int mouse_x = 0; + int mouse_y = 0; + MouseButton button; +}; + +class MouseClickEvent : public Event { +public: + int mouse_x = 0; + int mouse_y = 0; + MouseButton button; +}; +class MouseReleaseEvent : public Event { +public: + int mouse_x = 0; + int mouse_y = 0; + MouseButton button = MouseButton::None; +}; +class MouseMoveEvent : public Event { +public: + int mouse_x = 0; + int mouse_y = 0; +}; +class CollisionEvent : public Event { +public: + //Collision collisionData; +}; +class TextSubmitEvent : public Event { +public: + std::string text; +}; +class ShutDownEvent : public Event { +public: +}; diff --git a/src/crepe/api/EventHandler.cpp b/src/crepe/api/EventHandler.cpp new file mode 100644 index 0000000..93a116a --- /dev/null +++ b/src/crepe/api/EventHandler.cpp @@ -0,0 +1,2 @@ +#include "EventHandler.h" +bool IEventHandlerWrapper::exec(const Event & e) { return call(e); } diff --git a/src/crepe/api/EventHandler.h b/src/crepe/api/EventHandler.h new file mode 100644 index 0000000..46c6c7b --- /dev/null +++ b/src/crepe/api/EventHandler.h @@ -0,0 +1,111 @@ +#pragma once +#include "Event.h" +#include <functional> +#include <iostream> +#include <typeindex> + +/** + * \brief A type alias for an event handler function. + * + * The EventHandler is a std::function that takes an EventType reference and returns a boolean value + * indicating whether the event is handled. + * + * \tparam EventType The type of event this handler will handle. + */ +template <typename EventType> +using EventHandler = std::function<bool(const EventType & e)>; + +/** + * \class IEventHandlerWrapper + * \brief An abstract base class for event handler wrappers. + * + * This class provides the interface for handling events. Derived classes must implement the + * `call()` method to process events and the `get_type()` method to return the handler's type. + */ +class IEventHandlerWrapper { +public: + /** + * \brief Virtual destructor for IEventHandlerWrapper. + */ + virtual ~IEventHandlerWrapper() = default; + + /** + * \brief Executes the handler with the given event. + * + * This method calls the `call()` method of the derived class, passing the event to the handler. + * + * \param e The event to be processed. + * \return A boolean value indicating whether the event is handled. + */ + bool exec(const Event & e); + + /** + * \brief Get the type of the event handler. + * + * This method returns the type of the event handler as a string. + * + * \return A string representing the handler's type. + */ + virtual std::string get_type() const = 0; + +private: + /** + * \brief The method responsible for handling the event. + * + * This method is implemented by derived classes to process the event. + * + * \param e The event to be processed. + * \return A boolean value indicating whether the event is handled. + */ + virtual bool call(const Event & e) = 0; +}; + +/** + * \class EventHandlerWrapper + * \brief A wrapper for event handler functions. + * + * This class wraps an event handler function of a specific event type. It implements the + * `call()` and `get_type()` methods to allow the handler to be executed and its type to be + * queried. + * + * \tparam EventType The type of event this handler will handle. + */ +template <typename EventType> +class EventHandlerWrapper : public IEventHandlerWrapper { +public: + /** + * \brief Constructs an EventHandlerWrapper with a given handler. + * + * The constructor takes an event handler function and stores it in the wrapper. + * + * \param handler The event handler function. + */ + explicit EventHandlerWrapper(const EventHandler<EventType> & handler) + : m_handler(handler), m_handler_type(m_handler.target_type().name()) {} + +private: + /** + * \brief Calls the stored event handler with the event. + * + * This method casts the event to the appropriate type and calls the handler. + * + * \param e The event to be handled. + * \return A boolean value indicating whether the event is handled. + */ + bool call(const Event & e) override { + return m_handler(static_cast<const EventType &>(e)); + } + + /** + * \brief Returns the type of the handler. + * + * This method returns a string representing the type of the event handler. + * + * \return The handler type as a string. + */ + std::string get_type() const override { return m_handler_type; } + //! The event handler function. + EventHandler<EventType> m_handler; + //! The type name of the handler function. + const std::string m_handler_type; +}; diff --git a/src/crepe/api/EventManager.cpp b/src/crepe/api/EventManager.cpp new file mode 100644 index 0000000..72cfd74 --- /dev/null +++ b/src/crepe/api/EventManager.cpp @@ -0,0 +1,78 @@ +#include "EventManager.h" + +EventManager & EventManager::get_instance() { + static EventManager instance; + return instance; +} + +void EventManager::dispatch_events() { + for (std::vector<std::tuple<std::unique_ptr<Event>, int, + std::type_index>>::iterator 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); + + bool event_handled = false; + + if (channel) { + std::unordered_map< + std::type_index, + std::unordered_map< + int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>>:: + iterator handlers_it + = subscribers_by_event_id.find(event_type); + if (handlers_it != subscribers_by_event_id.end()) { + std::unordered_map< + int, std::vector<std::unique_ptr<IEventHandlerWrapper>>> & + handlers_map + = handlers_it->second; + std::unordered_map< + int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>:: + iterator handlers + = handlers_map.find(channel); + if (handlers != handlers_map.end()) { + std::vector<std::unique_ptr<IEventHandlerWrapper>> & + callbacks + = handlers->second; + for (std::vector<std::unique_ptr<IEventHandlerWrapper>>:: + iterator 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 + std::unordered_map< + std::type_index, + std::vector<std::unique_ptr<IEventHandlerWrapper>>>::iterator + handlers_it + = this->subscribers.find(event_type); + if (handlers_it != this->subscribers.end()) { + std::vector<std::unique_ptr<IEventHandlerWrapper>> & handlers + = handlers_it->second; + for (std::vector<std::unique_ptr<IEventHandlerWrapper>>:: + iterator handler_it + = handlers.begin(); + handler_it != handlers.end(); ++handler_it) { + if ((*handler_it)->exec(*event)) { + event_it = this->events_queue.erase(event_it); + event_handled = true; + break; + } + } + } + } + + if (!event_handled) { + ++event_it; + } + } +} diff --git a/src/crepe/api/EventManager.h b/src/crepe/api/EventManager.h new file mode 100644 index 0000000..e2665bd --- /dev/null +++ b/src/crepe/api/EventManager.h @@ -0,0 +1,256 @@ +#pragma once + +#include <functional> +#include <memory> +#include <type_traits> +#include <typeindex> +#include <unordered_map> +#include <vector> + +#include "Event.h" +#include "EventHandler.h" + +/** + * \class EventManager + * \brief The EventManager class is responsible for managing the subscription, triggering, + * and queueing of events. It handles events and dispatches them to appropriate subscribers. + */ +class EventManager { +public: + /** + * \brief Deleted copy constructor to prevent copying of the EventManager instance. + */ + EventManager(const EventManager &) = delete; + + /** + * \brief Deleted copy assignment operator to prevent assignment of the EventManager instance. + */ + const EventManager & operator=(const EventManager &) = delete; + + /** + * \brief Get the singleton instance of the EventManager. + * + * This method returns the unique instance of the EventManager, creating it on the first call. + * + * \return Reference to the EventManager instance. + */ + static EventManager & get_instance(); + + /** + * \brief Subscribe to an event. + * + * This method allows the registration of a callback for a specific event type and channel. + * + * \tparam EventType The type of the event to subscribe to. + * \param callback The callback function to invoke when the event is triggered. + * \param channel The channel number to subscribe to (default is 0). + */ + template <typename EventType> + void subscribe(EventHandler<EventType> && callback, int channel = 0); + + /** + * \brief Unsubscribe from an event. + * + * This method removes a previously registered callback from an event. + * + * \tparam EventType The type of the event to unsubscribe from. + * \param callback The callback function to remove from the subscription list. + * \param channel The event ID to unsubscribe from. + */ + template <typename EventType> + void unsubscribe(const EventHandler<EventType> &, int channel); + + /** + * \brief Trigger an event. + * + * This method invokes the appropriate callback(s) for the specified event. + * + * \tparam EventType The type of the event to trigger. + * \param event The event data to pass to the callback. + * \param channel The channel from which to trigger the event (default is 0). + */ + template <typename EventType> + void trigger_event(const EventType & event, int channel); + + /** + * \brief Queue an event for later processing. + * + * This method adds an event to the event queue, which will be processed in the + * dispatch_events function. + * + * \tparam EventType The type of the event to queue. + * \param event The event to queue. + * \param channel The channel number for the event (default is 0). + */ + template <typename EventType> + void queue_event(EventType && event, int channel); + + /** + * \brief Dispatch all queued events. + * + * This method processes all events in the event queue and triggers the corresponding + * callbacks for each event. + */ + void dispatch_events(); + +private: + /** + * \brief Default constructor for the EventManager. + * + * This constructor is private to enforce the singleton pattern. + */ + EventManager() = default; + + //! The queue of events to be processed. + std::vector<std::tuple<std::unique_ptr<Event>, int, std::type_index>> + events_queue; + //! Registered event handlers. + std::unordered_map<std::type_index, + std::vector<std::unique_ptr<IEventHandlerWrapper>>> + subscribers; + //! Event handlers indexed by event ID. + std::unordered_map< + std::type_index, + std::unordered_map<int, + std::vector<std::unique_ptr<IEventHandlerWrapper>>>> + subscribers_by_event_id; +}; +template <typename EventType> +void EventManager::subscribe(EventHandler<EventType> && callback, int channel) { + std::type_index event_type = typeid(EventType); + std::unique_ptr<EventHandlerWrapper<EventType>> handler + = std::make_unique<EventHandlerWrapper<EventType>>(callback); + + if (channel) { + std::unordered_map<int, + std::vector<std::unique_ptr<IEventHandlerWrapper>>> & + handlers_map + = this->subscribers_by_event_id[event_type]; + std::unordered_map< + int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>::iterator + handlers + = handlers_map.find(channel); + if (handlers != handlers_map.end()) { + handlers->second.emplace_back(std::move(handler)); + } else { + handlers_map[channel].emplace_back(std::move(handler)); + } + } else { + std::vector<std::unique_ptr<IEventHandlerWrapper>> & handlers + = this->subscribers[event_type]; + handlers.emplace_back(std::move(handler)); + } +} + +template <typename EventType> +void EventManager::queue_event(EventType && event, int channel) { + std::type_index event_type = std::type_index(typeid(EventType)); + + std::unique_ptr<EventType> event_ptr + = std::make_unique<EventType>(std::forward<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)); +} + +template <typename EventType> +void EventManager::trigger_event(const EventType & event, int channel) { + std::type_index event_type = std::type_index(typeid(EventType)); + + if (channel > 0) { + std::unordered_map<int, + std::vector<std::unique_ptr<IEventHandlerWrapper>>> & + handlers_map + = this->subscribers_by_event_id[event_type]; + std::unordered_map< + int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>::iterator + handlers_it + = handlers_map.find(channel); + + if (handlers_it != handlers_map.end()) { + std::vector<std::unique_ptr<IEventHandlerWrapper>> & handlers + = handlers_it->second; + for (std::vector<std::unique_ptr<IEventHandlerWrapper>>::iterator it + = handlers.begin(); + it != handlers.end();) { + // erases callback if callback function returns true + if ((*it)->exec(event)) { + it = handlers.erase(it); + } else { + ++it; + } + } + } + } else { + std::vector<std::unique_ptr<IEventHandlerWrapper>> & handlers + = this->subscribers[event_type]; + for (std::vector<std::unique_ptr<IEventHandlerWrapper>>::iterator it + = handlers.begin(); + it != handlers.end();) { + // erases callback if callback function returns true + if ((*it)->exec(event)) { + it = handlers.erase(it); + } else { + ++it; + } + } + } +} + +template <typename EventType> +void EventManager::unsubscribe(const EventHandler<EventType> & callback, + int channel) { + std::type_index event_type(typeid(EventType)); + std::string handler_name = callback.target_type().name(); + + if (channel) { + std::unordered_map< + std::type_index, + std::unordered_map< + int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>>:: + iterator subscriber_list + = this->subscribers_by_event_id.find(event_type); + if (subscriber_list != this->subscribers_by_event_id.end()) { + std::unordered_map< + int, std::vector<std::unique_ptr<IEventHandlerWrapper>>> & + handlers_map + = subscriber_list->second; + std::unordered_map< + int, + std::vector<std::unique_ptr<IEventHandlerWrapper>>>::iterator + handlers + = handlers_map.find(channel); + if (handlers != handlers_map.end()) { + std::vector<std::unique_ptr<IEventHandlerWrapper>> & callbacks + = handlers->second; + for (std::vector< + std::unique_ptr<IEventHandlerWrapper>>::iterator it + = callbacks.begin(); + it != callbacks.end(); ++it) { + if ((*it)->get_type() == handler_name) { + it = callbacks.erase(it); + return; + } + } + } + } + } else { + std::unordered_map<std::type_index, + std::vector<std::unique_ptr<IEventHandlerWrapper>>>:: + iterator handlers_it + = this->subscribers.find(event_type); + if (handlers_it != this->subscribers.end()) { + std::vector<std::unique_ptr<IEventHandlerWrapper>> & handlers + = handlers_it->second; + for (std::vector<std::unique_ptr<IEventHandlerWrapper>>::iterator it + = handlers.begin(); + it != handlers.end(); ++it) { + if ((*it)->get_type() == handler_name) { + it = handlers.erase(it); + return; + } + } + } + } +} diff --git a/src/crepe/api/IKeyListener.cpp b/src/crepe/api/IKeyListener.cpp new file mode 100644 index 0000000..eb8f9af --- /dev/null +++ b/src/crepe/api/IKeyListener.cpp @@ -0,0 +1,49 @@ +#include "IKeyListener.h" +#include <iostream> +IKeyListener::IKeyListener() { + this->channel = channel; + this->subscribe_events(); +} +IKeyListener::IKeyListener(int channel) { + this->channel = channel; + this->subscribe_events(); +} +IKeyListener::~IKeyListener() { this->unsubscribe_events(); } + +void IKeyListener::subscribe_events() { + key_pressed_handler = [this](const KeyPressEvent & event) { + return this->on_key_pressed(event); + }; + key_released_handler = [this](const KeyReleaseEvent & event) { + return this->on_key_released(event); + }; + EventManager::get_instance().subscribe<KeyPressEvent>( + std::move(this->key_pressed_handler), this->channel); + EventManager::get_instance().subscribe<KeyReleaseEvent>( + std::move(this->key_released_handler), this->channel); +} + +void IKeyListener::unsubscribe_events() { + EventManager::get_instance().unsubscribe<KeyPressEvent>( + this->key_pressed_handler, channel); + EventManager::get_instance().unsubscribe<KeyReleaseEvent>( + this->key_released_handler, channel); + std::cout << std::endl; +} +void IKeyListener::activate_keys() { + if (this->active) { + return; + } + this->subscribe_events(); +} +void IKeyListener::deactivate_keys() { + if (!this->active) { + return; + } + this->unsubscribe_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 new file mode 100644 index 0000000..839acbf --- /dev/null +++ b/src/crepe/api/IKeyListener.h @@ -0,0 +1,78 @@ +#pragma once +#include "Event.h" +#include "EventHandler.h" +#include "EventManager.h" + +/** + * \class IKeyListener + * \brief Interface for keyboard event handling in the application. + */ +class IKeyListener { +public: + /** + * \brief Constructs an IKeyListener with a specified channel. + * \param channel The channel ID for event handling. + */ + IKeyListener(int channel); + + /** + * \brief Default constructor for IKeyListener. + */ + IKeyListener(); + + /** + * \brief Destructor. + */ + virtual ~IKeyListener(); + + /** + * \brief Pure virtual function to handle key press events. + * \param event The key press event to handle. + * \return True if the event was handled, false otherwise. + */ + virtual bool on_key_pressed(const KeyPressEvent & event) = 0; + + /** + * \brief Pure virtual function to handle key release events. + * \param event The key release event to handle. + * \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. + */ + void subscribe_events(); + + /** + * \brief Unsubscribes from key events. + */ + void unsubscribe_events(); + +private: + //! Indicates whether key listening is active. + bool active = true; + //! Channel ID for event handling. + int channel = 0; + //! Key press event handler. + EventHandler<KeyPressEvent> key_pressed_handler; + //!< Key release event handler. + EventHandler<KeyReleaseEvent> key_released_handler; +}; diff --git a/src/crepe/api/IMouseListener.cpp b/src/crepe/api/IMouseListener.cpp new file mode 100644 index 0000000..683632c --- /dev/null +++ b/src/crepe/api/IMouseListener.cpp @@ -0,0 +1,56 @@ +#include "IMouseListener.h" +IMouseListener::IMouseListener(int channel) { this->channel = channel; } +IMouseListener::IMouseListener() { this->subscribe_events(); } +IMouseListener::~IMouseListener() { this->unsubscribe_events(); } + +void IMouseListener::subscribe_events() { + // Define handler lambdas and subscribe them + mouse_click_handler = [this](const MouseClickEvent & event) { + return this->on_mouse_clicked(event); + }; + mouse_press_handler = [this](const MousePressEvent & event) { + return this->on_mouse_pressed(event); + }; + mouse_release_handler = [this](const MouseReleaseEvent & event) { + return this->on_mouse_released(event); + }; + mouse_move_handler = [this](const MouseMoveEvent & event) { + return this->on_mouse_moved(event); + }; + EventManager::get_instance().subscribe<MouseClickEvent>( + std::move(this->mouse_click_handler), this->channel); + EventManager::get_instance().subscribe<MousePressEvent>( + std::move(this->mouse_press_handler), this->channel); + EventManager::get_instance().subscribe<MouseReleaseEvent>( + std::move(this->mouse_release_handler), this->channel); + EventManager::get_instance().subscribe<MouseMoveEvent>( + std::move(this->mouse_move_handler), this->channel); +} + +void IMouseListener::unsubscribe_events() { + EventManager::get_instance().unsubscribe<MouseClickEvent>( + this->mouse_click_handler, this->channel); + EventManager::get_instance().unsubscribe<MousePressEvent>( + this->mouse_press_handler, this->channel); + EventManager::get_instance().unsubscribe<MouseReleaseEvent>( + this->mouse_release_handler, this->channel); + EventManager::get_instance().unsubscribe<MouseMoveEvent>( + this->mouse_move_handler, this->channel); +} +void IMouseListener::activate_mouse() { + if (this->active) { + return; + } + this->subscribe_events(); +} +void IMouseListener::deactivate_mouse() { + if (!this->active) { + return; + } + this->unsubscribe_events(); +} +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 new file mode 100644 index 0000000..7e92956 --- /dev/null +++ b/src/crepe/api/IMouseListener.h @@ -0,0 +1,117 @@ +#pragma once + +#include "Event.h" +#include "EventHandler.h" +#include "EventManager.h" + +/** + * \class IMouseListener + * \brief Interface for mouse event handling in the application. + */ +class IMouseListener { +public: + /** + * \brief Default constructor. + */ + IMouseListener(); + + /** + * \brief Constructs an IMouseListener with a specified channel. + * \param channel The channel ID for event handling. + */ + IMouseListener(int channel); + + /** + * \brief Destructor. + */ + virtual ~IMouseListener(); + + /** + * \brief Copy constructor (deleted). + */ + IMouseListener(const IMouseListener &) = delete; + + /** + * \brief Copy assignment operator (deleted). + */ + IMouseListener & operator=(const IMouseListener &) = delete; + + /** + * \brief Move constructor (deleted). + */ + IMouseListener(IMouseListener &&) = delete; + + /** + * \brief Move assignment operator (deleted). + */ + IMouseListener & operator=(IMouseListener &&) = delete; + + /** + * \brief Handles a mouse click event. + * \param event The mouse click event to handle. + * \return True if the event was handled, false otherwise. + */ + virtual bool on_mouse_clicked(const MouseClickEvent & event) = 0; + + /** + * \brief Handles a mouse press event. + * \param event The mouse press event to handle. + * \return True if the event was handled, false otherwise. + */ + virtual bool on_mouse_pressed(const MousePressEvent & event) = 0; + + /** + * \brief Handles a mouse release event. + * \param event The mouse release event to handle. + * \return True if the event was handled, false otherwise. + */ + virtual bool on_mouse_released(const MouseReleaseEvent & event) = 0; + + /** + * \brief Handles a mouse move event. + * \param event The mouse move event to handle. + * \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. + */ + void subscribe_events(); + + /** + * \brief Unsubscribes from mouse events on the specified channel. + */ + void unsubscribe_events(); + +private: + //! Indicates whether mouse listening is active. + bool active = true; + //! Channel ID for event handling. + int channel = 0; + //! Mouse click event handler. + EventHandler<MouseClickEvent> mouse_click_handler; + //! Mouse press event handler. + EventHandler<MousePressEvent> mouse_press_handler; + //! Mouse release event handler. + EventHandler<MouseReleaseEvent> mouse_release_handler; + //! Mouse move event handler. + EventHandler<MouseMoveEvent> mouse_move_handler; +}; diff --git a/src/crepe/api/KeyCodes.h b/src/crepe/api/KeyCodes.h new file mode 100644 index 0000000..1cb1a8a --- /dev/null +++ b/src/crepe/api/KeyCodes.h @@ -0,0 +1,147 @@ +#pragma once + +enum class MouseButton { + NONE = 0, + LEFT_MOUSE = 1, + RIGHT_MOUSE = 2, + MIDDLE_MOUSE = 3, + X1_MOUSE = 4, + X2_MOUSE = 5, + SCROLL_UP = 6, + SCROLL_DOWN = 7, +}; + +enum class Keycode : int { + // From glfw3.h + NONE = 0, + SPACE = 32, + APOSTROPHE = 39, /* ' */ + COMMA = 44, /* , */ + MINUS = 45, /* - */ + PERIOD = 46, /* . */ + SLASH = 47, /* / */ + + D0 = 48, /* 0 */ + D1 = 49, /* 1 */ + D2 = 50, /* 2 */ + D3 = 51, /* 3 */ + D4 = 52, /* 4 */ + D5 = 53, /* 5 */ + D6 = 54, /* 6 */ + D7 = 55, /* 7 */ + D8 = 56, /* 8 */ + D9 = 57, /* 9 */ + + SEMICOLON = 59, /* ; */ + EQUAL = 61, /* = */ + + A = 65, + B = 66, + C = 67, + D = 68, + E = 69, + F = 70, + G = 71, + H = 72, + I = 73, + J = 74, + K = 75, + L = 76, + M = 77, + N = 78, + O = 79, + P = 80, + Q = 81, + R = 82, + S = 83, + T = 84, + U = 85, + V = 86, + W = 87, + X = 88, + Y = 89, + Z = 90, + + LEFT_BRACKET = 91, /* [ */ + BACKSLASH = 92, /* \ */ + RIGHT_BRACKET = 93, /* ] */ + GRAVE_ACCENT = 96, /* ` */ + + WORLD1 = 161, /* non-US #1 */ + WORLD2 = 162, /* non-US #2 */ + + /* Function keys */ + ESCAPE = 256, + ENTER = 257, + TAB = 258, + BACKSPACE = 259, + INSERT = 260, + DELETE = 261, + RIGHT = 262, + LEFT = 263, + DOWN = 264, + UP = 265, + PAGE_UP = 266, + PAGE_DOWN = 267, + HOME = 268, + END = 269, + CAPS_LOCK = 280, + SCROLL_LOCK = 281, + NUM_LOCK = 282, + PRINT_SCREEN = 283, + PAUSE = 284, + F1 = 290, + F2 = 291, + F3 = 292, + F4 = 293, + F5 = 294, + F6 = 295, + F7 = 296, + F8 = 297, + F9 = 298, + F10 = 299, + F11 = 300, + F12 = 301, + F13 = 302, + F14 = 303, + F15 = 304, + F16 = 305, + F17 = 306, + F18 = 307, + F19 = 308, + F20 = 309, + F21 = 310, + F22 = 311, + F23 = 312, + F24 = 313, + F25 = 314, + + /* Keypad */ + KP0 = 320, + KP1 = 321, + KP2 = 322, + KP3 = 323, + KP4 = 324, + KP5 = 325, + KP6 = 326, + KP7 = 327, + KP8 = 328, + KP9 = 329, + KP_DECIMAL = 330, + KP_DIVIDE = 331, + KP_MULTIPLY = 332, + KP_SUBTRACT = 333, + KP_ADD = 334, + KP_ENTER = 335, + KP_EQUAL = 336, + + LEFT_SHIFT = 340, + LEFT_CONTROL = 341, + LEFT_ALT = 342, + LEFT_SUPER = 343, + RIGHT_SHIFT = 344, + RIGHT_CONTROL = 345, + RIGHT_ALT = 346, + RIGHT_SUPER = 347, + MENU = 348 +}; diff --git a/src/example/CMakeLists.txt b/src/example/CMakeLists.txt index 3a5b543..ddb0262 100644 --- a/src/example/CMakeLists.txt +++ b/src/example/CMakeLists.txt @@ -28,6 +28,7 @@ add_example(proxy) add_example(db) add_example(ecs) add_example(scene_manager) +add_example(events) add_example(particles) add_example(gameloop) diff --git a/src/example/events.cpp b/src/example/events.cpp new file mode 100644 index 0000000..51c9a37 --- /dev/null +++ b/src/example/events.cpp @@ -0,0 +1,110 @@ +#include <iostream> + +#include <crepe/ComponentManager.h> +#include <crepe/system/ScriptSystem.h> +#include <crepe/util/log.h> + +#include <crepe/api/BehaviorScript.h> +#include <crepe/api/Config.h> +#include <crepe/api/Event.h> +#include <crepe/api/EventManager.h> +#include <crepe/api/GameObject.h> +#include <crepe/api/IKeyListener.h> +#include <crepe/api/IMouseListener.h> +#include <crepe/api/KeyCodes.h> +#include <crepe/api/Script.h> +#include <crepe/api/Transform.h> + +using namespace crepe; +using namespace std; + +class MyScript : public Script, public IKeyListener, public IMouseListener { + void update() { + // Retrieve component from the same GameObject this script is on + Transform & test = get_component<Transform>(); + dbg_logf("Transform(%.2f, %.2f)", test.position.x, test.position.y); + } + + 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 { + std::cout << "KeyRelease function" << std::endl; + return false; + } + bool on_mouse_clicked(const MouseClickEvent & event) override { + std::cout << "MouseClick function" << std::endl; + return false; + } + bool on_mouse_pressed(const MousePressEvent & event) override { + std::cout << "MousePress function" << std::endl; + return false; + } + bool on_mouse_released(const MouseReleaseEvent & event) override { + std::cout << "MouseRelease function" << std::endl; + return false; + } + bool on_mouse_moved(const MouseMoveEvent & event) override { + std::cout << "MouseMove function" << std::endl; + return false; + } +}; +class TestKeyListener : public IKeyListener { +public: + bool on_key_pressed(const KeyPressEvent & event) override { + std::cout << "TestKeyListener: Key Pressed - Code: " + << static_cast<int>(event.key) << std::endl; + return true; // Return true if the listener should remain active + } + bool on_key_released(const KeyReleaseEvent & event) override { + std::cout << "TestKeyListener: Key Released - Code: " + << static_cast<int>(event.key) << std::endl; + return true; + } +}; +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); + { + 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>(); + + 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>(click_event, + 1); + } + // custom lambda event handler + EventHandler<KeyPressEvent> event_handler = [](const KeyPressEvent & e) { + std::cout << "lambda test" << std::endl; + return false; + }; + EventManager::get_instance().subscribe<KeyPressEvent>( + std::move(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); + // dispatching queued events + EventManager::get_instance().dispatch_events(); + + EventManager::get_instance().unsubscribe<KeyPressEvent>(event_handler, 0); + return EXIT_SUCCESS; +} |