aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2020-12-02 19:19:22 +0800
committercrupest <crupest@outlook.com>2020-12-02 19:19:22 +0800
commit145cfd5b82d76e0c937eceda707aa22427899943 (patch)
treeab98708eea0e0ba7b965e20927303e49a8d9ae23 /include
parent0fb7a0e0b2b9e04ca414b1e47c69cc854c79831b (diff)
downloadcru-145cfd5b82d76e0c937eceda707aa22427899943.tar.gz
cru-145cfd5b82d76e0c937eceda707aa22427899943.tar.bz2
cru-145cfd5b82d76e0c937eceda707aa22427899943.zip
...
Diffstat (limited to 'include')
-rw-r--r--include/cru/common/Event.hpp72
-rw-r--r--include/cru/common/SelfResolvable.hpp24
-rw-r--r--include/cru/ui/style/Condition.hpp69
-rw-r--r--include/cru/ui/style/Trigger.hpp75
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