// ===================================================================================================================== // Copyright 2024 Medusa Slockbower // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ===================================================================================================================== #ifndef ENGINE_EVENTSYSTEM_H #define ENGINE_EVENTSYSTEM_H #include #include #include #include #define MAX_EVENT_TYPES 256 namespace ocu = open_cpp_utils; namespace OpenShaderDesigner { /** * \brief Base Event class for sending events to the Engine. */ struct Event { template static uint8_t TypeOf() { return static_cast(ocu::unique_id()); } /** * \brief Get the Event's type ID. * \return A pointer to the Event type ID. */ virtual inline uint8_t GetID() const = 0; }; /** * \brief Base EventHandler for abstraction. */ class _ImplEventHandler { virtual bool _HandleEvent(const Event* event) = 0; friend class EventSystem; }; /** * \brief EventHandler interface for creating custom EventHandlers * \tparam EventType The ComponentType of Event handled by the EventHandler */ template class EventHandler : private _ImplEventHandler { public: using HandledType = EventType; //!< The type handled by the EventHandler /** * \brief Virtual function for custom EventHandler implementations. * \param event The Event being handled. */ virtual bool HandleEvent(const HandledType* event) = 0; private: /** * \brief Override for abstraction. * \param event The Event being handled. */ bool _HandleEvent(const Event* event) override; }; /** * \brief EventSystem for posting Events to be handled. */ class EventSystem { public: /** * \brief Post an Event to be Handled. */ static void PostEvent(const Event*); /** * \brief Register an EventHandler with the EventSystem. * \tparam T ComponentType of Event handled by the EventHandler. */ template static void RegisterHandler(EventHandler*); /** * \brief Unregister an EventHandler with the EventSystem. * \tparam T ComponentType of Event handled by the EventHandler. */ template static void UnregisterHandler(EventHandler*); private: inline static std::list<_ImplEventHandler*> HandlerMap[MAX_EVENT_TYPES]; inline static std::mutex Lock; EventSystem(const EventSystem&) = delete; EventSystem(EventSystem&&) = delete; }; template void EventSystem::UnregisterHandler(EventHandler* handler) { // Thread safe std::lock_guard guard(Lock); const uint8_t index = T::ID; std::erase(HandlerMap[index], reinterpret_cast<_ImplEventHandler*>(handler)); } template void EventSystem::RegisterHandler(EventHandler* handler) { // Thread safe std::lock_guard guard(Lock); const uint8_t index = T::ID; HandlerMap[index].push_back(reinterpret_cast<_ImplEventHandler*>(handler)); } template bool EventHandler::_HandleEvent(const Event *event) { if(EventType::ID != event->GetID()) return false; return HandleEvent(reinterpret_cast(event)); } } #define BeginEvent(EVENT) struct EVENT : OpenShaderDesigner::Event \ { \ static inline const uint8_t ID = Event::TypeOf(); \ inline uint8_t GetID() const override { return ID; } #define EndEvent }; #endif //ENGINE_EVENTSYSTEM_H