diff options
author | crupest <crupest@outlook.com> | 2020-12-02 19:19:22 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2020-12-02 19:19:22 +0800 |
commit | 145cfd5b82d76e0c937eceda707aa22427899943 (patch) | |
tree | ab98708eea0e0ba7b965e20927303e49a8d9ae23 /include/cru | |
parent | 0fb7a0e0b2b9e04ca414b1e47c69cc854c79831b (diff) | |
download | cru-145cfd5b82d76e0c937eceda707aa22427899943.tar.gz cru-145cfd5b82d76e0c937eceda707aa22427899943.tar.bz2 cru-145cfd5b82d76e0c937eceda707aa22427899943.zip |
...
Diffstat (limited to 'include/cru')
-rw-r--r-- | include/cru/common/Event.hpp | 72 | ||||
-rw-r--r-- | include/cru/common/SelfResolvable.hpp | 24 | ||||
-rw-r--r-- | include/cru/ui/style/Condition.hpp | 69 | ||||
-rw-r--r-- | include/cru/ui/style/Trigger.hpp | 75 |
4 files changed, 140 insertions, 100 deletions
diff --git a/include/cru/common/Event.hpp b/include/cru/common/Event.hpp index 93ab9b7a..59502527 100644 --- a/include/cru/common/Event.hpp +++ b/include/cru/common/Event.hpp @@ -8,12 +8,16 @@ #include <initializer_list> #include <memory> #include <utility> +#include <variant> #include <vector> namespace cru { class EventRevoker; namespace details { +template <class> +inline constexpr bool always_false_v = false; + // Base class of all Event<T...>. // It erases event args types and provides a // unified form to create event revoker and @@ -25,10 +29,8 @@ class EventBase : public SelfResolvable<EventBase> { using EventHandlerToken = long; EventBase() {} - EventBase(const EventBase& other) = delete; - EventBase(EventBase&& other) = delete; - EventBase& operator=(const EventBase& other) = delete; - EventBase& operator=(EventBase&& other) = delete; + CRU_DELETE_COPY(EventBase) + CRU_DEFAULT_MOVE(EventBase) virtual ~EventBase() = default; // Remove the handler with the given token. If the token @@ -85,59 +87,73 @@ using DeducedEventArgs = std::conditional_t< std::is_lvalue_reference_v<TRaw>, TRaw, std::conditional_t<std::is_scalar_v<TRaw>, TRaw, const TRaw&>>; +struct IBaseEvent { + protected: + IBaseEvent() = default; + CRU_DELETE_COPY(IBaseEvent) + CRU_DEFAULT_MOVE(IBaseEvent) + ~IBaseEvent() = default; // Note that user can't destroy a Event via IEvent. + // So destructor should be protected. + + using SpyOnlyHandler = std::function<void()>; + + public: + virtual EventRevoker AddHandler(SpyOnlyHandler handler) = 0; +}; + // Provides an interface of event. // IEvent only allow to add handler but not to raise the event. You may // want to create an Event object and expose IEvent only so users won't // be able to emit the event. template <typename TEventArgs> -struct IEvent { +struct IEvent : virtual IBaseEvent { public: using EventArgs = DeducedEventArgs<TEventArgs>; using EventHandler = std::function<void(EventArgs)>; + using HandlerVariant = std::variant<SpyOnlyHandler, EventHandler>; protected: IEvent() = default; - IEvent(const IEvent& other) = delete; - IEvent(IEvent&& other) = delete; - IEvent& operator=(const IEvent& other) = delete; - IEvent& operator=(IEvent&& other) = delete; + CRU_DELETE_COPY(IEvent) + CRU_DEFAULT_MOVE(IEvent) ~IEvent() = default; // Note that user can't destroy a Event via IEvent. So // destructor should be protected. public: - virtual EventRevoker AddHandler(const EventHandler& handler) = 0; - virtual EventRevoker AddHandler(EventHandler&& handler) = 0; + virtual EventRevoker AddHandler(EventHandler handler) = 0; }; // A non-copyable non-movable Event class. // It stores a list of event handlers. template <typename TEventArgs> class Event : public details::EventBase, public IEvent<TEventArgs> { + using typename IBaseEvent::SpyOnlyHandler; using typename IEvent<TEventArgs>::EventHandler; + using typename IEvent<TEventArgs>::HandlerVariant; private: struct HandlerData { HandlerData(EventHandlerToken token, EventHandler handler) : token(token), handler(handler) {} + HandlerData(EventHandlerToken token, SpyOnlyHandler handler) + : token(token), handler(handler) {} EventHandlerToken token; - EventHandler handler; + HandlerVariant handler; }; public: Event() = default; - Event(const Event&) = delete; - Event& operator=(const Event&) = delete; - Event(Event&&) = delete; - Event& operator=(Event&&) = delete; + CRU_DELETE_COPY(Event) + CRU_DEFAULT_MOVE(Event) ~Event() = default; - EventRevoker AddHandler(const EventHandler& handler) override { + EventRevoker AddHandler(SpyOnlyHandler handler) override { const auto token = current_token_++; - this->handler_data_list_.emplace_back(token, handler); + this->handler_data_list_.emplace_back(token, std::move(handler)); return CreateRevoker(token); } - EventRevoker AddHandler(EventHandler&& handler) override { + EventRevoker AddHandler(EventHandler handler) override { const auto token = current_token_++; this->handler_data_list_.emplace_back(token, std::move(handler)); return CreateRevoker(token); @@ -150,13 +166,25 @@ class Event : public details::EventBase, public IEvent<TEventArgs> { // is called, so even if you delete a handler during this period, all handlers // in the snapshot will be executed. void Raise(typename IEvent<TEventArgs>::EventArgs args) { - std::vector<EventHandler> handlers; + std::vector<HandlerVariant> handlers; handlers.reserve(this->handler_data_list_.size()); for (const auto& data : this->handler_data_list_) { handlers.push_back(data.handler); } - for (const auto& handler : handlers) { - handler(args); + for (const auto& handler_variant : handlers) { + std::visit( + [&args](auto&& handler) { + using T = std::decay_t<decltype(handler)>; + if constexpr (std::is_same_v<T, SpyOnlyHandler>) { + handler(); + } else if constexpr (std::is_same_v<T, EventHandler>) { + handler(args); + } else { + static_assert(details::always_false_v<T>, + "non-exhaustive visitor!"); + } + }, + handler_variant); } } diff --git a/include/cru/common/SelfResolvable.hpp b/include/cru/common/SelfResolvable.hpp index 94f3ae87..eaa4ce34 100644 --- a/include/cru/common/SelfResolvable.hpp +++ b/include/cru/common/SelfResolvable.hpp @@ -39,9 +39,27 @@ class SelfResolvable { SelfResolvable() : resolver_(new T*(static_cast<T*>(this))) {} SelfResolvable(const SelfResolvable&) = delete; SelfResolvable& operator=(const SelfResolvable&) = delete; - SelfResolvable(SelfResolvable&&) = delete; - SelfResolvable& operator=(SelfResolvable&&) = delete; - virtual ~SelfResolvable() { (*resolver_) = nullptr; } + + // Resolvers to old object will resolve to new object. + SelfResolvable(SelfResolvable&& other) + : resolver_(std::move(other.resolver_)) { + (*resolver_) = static_cast<T*>(this); + } + + // Old resolvers for this object will resolve to nullptr. + // Other's resolvers will now resolve to this. + SelfResolvable& operator=(SelfResolvable&& other) { + if (this != &other) { + (*resolver_) = nullptr; + resolver_ = std::move(other.resolver_); + (*resolver_) = static_cast<T*>(this); + } + return *this; + } + + virtual ~SelfResolvable() { + if (resolver_ != nullptr) (*resolver_) = nullptr; + } ObjectResolver<T> CreateResolver() { return ObjectResolver<T>(resolver_); } diff --git a/include/cru/ui/style/Condition.hpp b/include/cru/ui/style/Condition.hpp new file mode 100644 index 00000000..b88a338f --- /dev/null +++ b/include/cru/ui/style/Condition.hpp @@ -0,0 +1,69 @@ +#pragma once +#include "../Base.hpp" +#include "cru/common/Base.hpp" +#include "cru/common/Event.hpp" +#include "cru/ui/controls/IClickableControl.hpp" +#include "cru/ui/helper/ClickDetector.hpp" + +#include <type_traits> +#include <utility> +#include <vector> + +namespace cru::ui::style { +class Condition { + public: + virtual ~Condition() = default; + + virtual std::vector<IBaseEvent*> ChangeOn( + controls::Control* control) const = 0; + virtual bool Judge(controls::Control* control) const = 0; +}; + +class CompoundCondition : public Condition { + public: + explicit CompoundCondition(std::vector<Condition*> conditions); + + const std::vector<Condition*>& GetConditions() const { return conditions_; } + + std::vector<IBaseEvent*> ChangeOn(controls::Control* control) const override; + + private: + std::vector<Condition*> conditions_; +}; + +class AndCondition : public CompoundCondition { + public: + using CompoundCondition::CompoundCondition; + + bool Judge(controls::Control* control) const override; +}; + +class OrCondition : public CompoundCondition { + public: + using CompoundCondition::CompoundCondition; + + bool Judge(controls::Control* control) const override; +}; + +class FocusCondition : public Condition { + public: + explicit FocusCondition(bool has_focus); + + std::vector<IBaseEvent*> ChangeOn(controls::Control* control) const override; + bool Judge(controls::Control* control) const override; + + private: + bool has_focus_; +}; + +class ClickStateCondition : public Condition { + public: + explicit ClickStateCondition(helper::ClickState click_state); + + std::vector<IBaseEvent*> ChangeOn(controls::Control* control) const override; + bool Judge(controls::Control* control) const override; + + private: + helper::ClickState click_state_; +}; +} // namespace cru::ui::style diff --git a/include/cru/ui/style/Trigger.hpp b/include/cru/ui/style/Trigger.hpp deleted file mode 100644 index ab012a3e..00000000 --- a/include/cru/ui/style/Trigger.hpp +++ /dev/null @@ -1,75 +0,0 @@ -#pragma once -#include "../Base.hpp" -#include "cru/common/Base.hpp" -#include "cru/common/Event.hpp" -#include "cru/ui/controls/IClickableControl.hpp" -#include "cru/ui/helper/ClickDetector.hpp" - -#include <utility> -#include <vector> - -namespace cru::ui::style { -class Trigger { - public: - virtual ~Trigger() = default; - - bool GetState() const { return current_; } - IEvent<bool>* ChangeEvent() { return &change_event_; } - - protected: - void Raise(bool value); - - private: - bool current_ = false; - Event<bool> change_event_; - - protected: - EventRevokerListGuard guard_; -}; - -class CompoundTrigger : public Trigger { - public: - explicit CompoundTrigger(std::vector<Trigger*> triggers); - - const std::vector<Trigger*>& GetTriggers() const { return triggers_; } - - protected: - virtual bool CalculateState(const std::vector<Trigger*>& triggers) const = 0; - - private: - std::vector<Trigger*> triggers_; -}; - -class AndTrigger : public CompoundTrigger { - public: - using CompoundTrigger::CompoundTrigger; - - protected: - bool CalculateState(const std::vector<Trigger*>& triggers) const override; -}; - -class OrTrigger : public CompoundTrigger { - public: - using CompoundTrigger::CompoundTrigger; - - protected: - bool CalculateState(const std::vector<Trigger*>& triggers) const override; -}; - -class FocusTrigger : public Trigger { - public: - FocusTrigger(controls::Control* control, bool has_focus); - - private: - bool has_focus_; -}; - -class ClickStateTrigger : public Trigger { - public: - ClickStateTrigger(controls::IClickableControl* control, - helper::ClickState click_state); - - private: - helper::ClickState click_state_; -}; -} // namespace cru::ui::style |