diff options
Diffstat (limited to 'include/cru/ui/style')
-rw-r--r-- | include/cru/ui/style/ApplyBorderStyleInfo.hpp | 28 | ||||
-rw-r--r-- | include/cru/ui/style/Condition.hpp | 123 | ||||
-rw-r--r-- | include/cru/ui/style/StyleRule.hpp | 45 | ||||
-rw-r--r-- | include/cru/ui/style/StyleRuleSet.hpp | 87 | ||||
-rw-r--r-- | include/cru/ui/style/Styler.hpp | 80 |
5 files changed, 363 insertions, 0 deletions
diff --git a/include/cru/ui/style/ApplyBorderStyleInfo.hpp b/include/cru/ui/style/ApplyBorderStyleInfo.hpp new file mode 100644 index 00000000..5058b51f --- /dev/null +++ b/include/cru/ui/style/ApplyBorderStyleInfo.hpp @@ -0,0 +1,28 @@ +#pragma once +#include <optional> +#include "../Base.hpp" + +namespace cru::ui::style { +struct ApplyBorderStyleInfo { + explicit ApplyBorderStyleInfo( + std::optional<std::shared_ptr<platform::graphics::IBrush>> border_brush = + std::nullopt, + std::optional<Thickness> border_thickness = std::nullopt, + std::optional<CornerRadius> border_radius = std::nullopt, + std::optional<std::shared_ptr<platform::graphics::IBrush>> + foreground_brush = std::nullopt, + std::optional<std::shared_ptr<platform::graphics::IBrush>> + background_brush = std::nullopt) + : border_brush(std::move(border_brush)), + border_thickness(std::move(border_thickness)), + border_radius(std::move(border_radius)), + foreground_brush(std::move(foreground_brush)), + background_brush(std::move(background_brush)) {} + + std::optional<std::shared_ptr<platform::graphics::IBrush>> border_brush; + std::optional<Thickness> border_thickness; + std::optional<CornerRadius> border_radius; + std::optional<std::shared_ptr<platform::graphics::IBrush>> foreground_brush; + std::optional<std::shared_ptr<platform::graphics::IBrush>> background_brush; +}; +} // namespace cru::ui::style diff --git a/include/cru/ui/style/Condition.hpp b/include/cru/ui/style/Condition.hpp new file mode 100644 index 00000000..d5cf16f2 --- /dev/null +++ b/include/cru/ui/style/Condition.hpp @@ -0,0 +1,123 @@ +#pragma once +#include "../Base.hpp" +#include "cru/common/Base.hpp" +#include "cru/common/ClonablePtr.hpp" +#include "cru/common/Event.hpp" +#include "cru/ui/controls/IClickableControl.hpp" +#include "cru/ui/helper/ClickDetector.hpp" + +#include <memory> +#include <type_traits> +#include <utility> +#include <vector> + +namespace cru::ui::style { +class Condition : public Object { + public: + virtual std::vector<IBaseEvent*> ChangeOn( + controls::Control* control) const = 0; + virtual bool Judge(controls::Control* control) const = 0; + + virtual Condition* Clone() const = 0; +}; + +class NoCondition : public Condition { + public: + static ClonablePtr<NoCondition> Create() { + return ClonablePtr<NoCondition>(new NoCondition); + }; + + std::vector<IBaseEvent*> ChangeOn(controls::Control*) const override { + return {}; + } + + bool Judge(controls::Control*) const override { return true; } + + NoCondition* Clone() const override { return new NoCondition; } +}; + +class CompoundCondition : public Condition { + public: + explicit CompoundCondition(std::vector<ClonablePtr<Condition>> conditions); + + std::vector<IBaseEvent*> ChangeOn(controls::Control* control) const override; + + protected: + std::vector<ClonablePtr<Condition>> conditions_; +}; + +class AndCondition : public CompoundCondition { + public: + using CompoundCondition::CompoundCondition; + + bool Judge(controls::Control* control) const override; + + AndCondition* Clone() const override { return new AndCondition(conditions_); } +}; + +class OrCondition : public CompoundCondition { + public: + using CompoundCondition::CompoundCondition; + + bool Judge(controls::Control* control) const override; + + OrCondition* Clone() const override { return new OrCondition(conditions_); } +}; + +class FocusCondition : public Condition { + public: + static ClonablePtr<FocusCondition> Create(bool has_focus) { + return ClonablePtr<FocusCondition>(new FocusCondition(has_focus)); + } + + explicit FocusCondition(bool has_focus); + + std::vector<IBaseEvent*> ChangeOn(controls::Control* control) const override; + bool Judge(controls::Control* control) const override; + + FocusCondition* Clone() const override { + return new FocusCondition(has_focus_); + } + + private: + bool has_focus_; +}; + +class HoverCondition : public Condition { + public: + static ClonablePtr<HoverCondition> Create(bool hover) { + return ClonablePtr<HoverCondition>(new HoverCondition(hover)); + } + + explicit HoverCondition(bool hover) : hover_(hover) {} + + std::vector<IBaseEvent*> ChangeOn(controls::Control* control) const override; + bool Judge(controls::Control* control) const override; + + HoverCondition* Clone() const override { return new HoverCondition(hover_); } + + private: + bool hover_; +}; + +class ClickStateCondition : public Condition { + public: + static ClonablePtr<ClickStateCondition> Create( + helper::ClickState click_state) { + return ClonablePtr<ClickStateCondition>( + new ClickStateCondition(click_state)); + } + + explicit ClickStateCondition(helper::ClickState click_state); + + std::vector<IBaseEvent*> ChangeOn(controls::Control* control) const override; + bool Judge(controls::Control* control) const override; + + ClickStateCondition* Clone() const override { + return new ClickStateCondition(click_state_); + } + + private: + helper::ClickState click_state_; +}; +} // namespace cru::ui::style diff --git a/include/cru/ui/style/StyleRule.hpp b/include/cru/ui/style/StyleRule.hpp new file mode 100644 index 00000000..8ac42cd0 --- /dev/null +++ b/include/cru/ui/style/StyleRule.hpp @@ -0,0 +1,45 @@ +#pragma once +#include "Condition.hpp" +#include "Styler.hpp" +#include "cru/common/Base.hpp" +#include "cru/common/ClonablePtr.hpp" +#include "cru/ui/Base.hpp" + +#include <memory> +#include <string> +#include <vector> + +namespace cru::ui::style { +class StyleRule : public Object { + public: + StyleRule(ClonablePtr<Condition> condition, ClonablePtr<Styler> styler, + std::u16string name = {}); + + CRU_DEFAULT_COPY(StyleRule) + CRU_DEFAULT_MOVE(StyleRule) + + ~StyleRule() override = default; + + public: + const std::u16string& GetName() const { return name_; } + Condition* GetCondition() const { return condition_.get(); } + Styler* GetStyler() const { return styler_.get(); } + + StyleRule WithNewCondition(ClonablePtr<Condition> condition, + std::u16string name = {}) const { + return StyleRule{std::move(condition), styler_, std::move(name)}; + } + + StyleRule WithNewStyler(ClonablePtr<Styler> styler, + std::u16string name = {}) const { + return StyleRule{condition_, std::move(styler), std::move(name)}; + } + + bool CheckAndApply(controls::Control* control) const; + + private: + ClonablePtr<Condition> condition_; + ClonablePtr<Styler> styler_; + std::u16string name_; +}; +} // namespace cru::ui::style diff --git a/include/cru/ui/style/StyleRuleSet.hpp b/include/cru/ui/style/StyleRuleSet.hpp new file mode 100644 index 00000000..e62dd2de --- /dev/null +++ b/include/cru/ui/style/StyleRuleSet.hpp @@ -0,0 +1,87 @@ +#pragma once +#include "StyleRule.hpp" +#include "cru/common/Base.hpp" +#include "cru/common/Event.hpp" + +#include <cstddef> + +namespace cru::ui::style { +class StyleRuleSet : public Object { + public: + StyleRuleSet() = default; + explicit StyleRuleSet(StyleRuleSet* parent); + + CRU_DELETE_COPY(StyleRuleSet) + CRU_DELETE_MOVE(StyleRuleSet) + + ~StyleRuleSet() override = default; + + public: + StyleRuleSet* GetParent() const { return parent_; } + void SetParent(StyleRuleSet* parent); + + gsl::index GetSize() const { return static_cast<gsl::index>(rules_.size()); } + const std::vector<StyleRule>& GetRules() const { return rules_; } + + void AddStyleRule(StyleRule rule) { + AddStyleRule(std::move(rule), GetSize()); + } + + void AddStyleRule(StyleRule rule, gsl::index index); + + template <typename Iter> + void AddStyleRuleRange(Iter start, Iter end, gsl::index index) { + Expects(index >= 0 && index <= GetSize()); + rules_.insert(rules_.cbegin() + index, std::move(start), std::move(end)); + UpdateChangeListener(); + UpdateStyle(); + } + + void RemoveStyleRule(gsl::index index, gsl::index count = 1); + + void Clear() { RemoveStyleRule(0, GetSize()); } + + void Set(const StyleRuleSet& other, bool set_parent = false); + + const StyleRule& operator[](gsl::index index) const { return rules_[index]; } + + // Triggered whenever a change happened to this (rule add or remove, parent + // change ...). Subscribe to this and update style change listeners and style. + IEvent<std::nullptr_t>* ChangeEvent() { return &change_event_; } + + private: + void RaiseChangeEvent() { change_event_.Raise(nullptr); } + + private: + Event<std::nullptr_t> change_event_; + + StyleRuleSet* parent_ = nullptr; + EventRevokerGuard parent_change_event_guard_; + + std::vector<StyleRule> rules_; +}; + +class StyleRuleSetBind { + public: + StyleRuleSetBind(controls::Control* control, StyleRuleSet* ruleset); + + CRU_DELETE_COPY(StyleRuleSetBind) + CRU_DELETE_MOVE(StyleRuleSetBind) + + ~StyleRuleSetBind() = default; + + private: + void UpdateRuleSetChainCache(); + void UpdateChangeListener(); + void UpdateStyle(); + + private: + controls::Control* control_; + StyleRuleSet* ruleset_; + + // child first, parent last. + std::vector<StyleRuleSet*> ruleset_chain_cache_; + + EventRevokerListGuard guard_; +}; +} // namespace cru::ui::style diff --git a/include/cru/ui/style/Styler.hpp b/include/cru/ui/style/Styler.hpp new file mode 100644 index 00000000..865cbbaf --- /dev/null +++ b/include/cru/ui/style/Styler.hpp @@ -0,0 +1,80 @@ +#pragma once +#include "../Base.hpp" +#include "ApplyBorderStyleInfo.hpp" +#include "cru/common/Base.hpp" +#include "cru/common/ClonablePtr.hpp" +#include "cru/platform/gui/Cursor.hpp" +#include "cru/ui/controls/Control.hpp" + +#include <memory> +#include <vector> + +namespace cru::ui::style { +class Styler : public Object { + public: + virtual void Apply(controls::Control* control) const = 0; + + virtual Styler* Clone() const = 0; +}; + +class CompoundStyler : public Styler { + public: + template <typename... S> + static ClonablePtr<CompoundStyler> Create(ClonablePtr<S>... s) { + return ClonablePtr<CompoundStyler>( + new CompoundStyler(std::vector<ClonablePtr<Styler>>{std::move(s)...})); + } + + explicit CompoundStyler(std::vector<ClonablePtr<Styler>> stylers) + : stylers_(std::move(stylers)) {} + + void Apply(controls::Control* control) const override { + for (const auto& styler : stylers_) { + styler->Apply(control); + } + } + + virtual CompoundStyler* Clone() const override { + return new CompoundStyler(stylers_); + } + + private: + std::vector<ClonablePtr<Styler>> stylers_; +}; + +class BorderStyler : public Styler { + public: + static ClonablePtr<BorderStyler> Create(ApplyBorderStyleInfo style) { + return ClonablePtr<BorderStyler>(new BorderStyler(std::move(style))); + } + + explicit BorderStyler(ApplyBorderStyleInfo style); + + void Apply(controls::Control* control) const override; + + BorderStyler* Clone() const override { return new BorderStyler(style_); } + + private: + ApplyBorderStyleInfo style_; +}; + +class CursorStyler : public Styler { + public: + static ClonablePtr<CursorStyler> Create( + std::shared_ptr<platform::gui::ICursor> cursor) { + return ClonablePtr<CursorStyler>(new CursorStyler(std::move(cursor))); + } + + static ClonablePtr<CursorStyler> Create(platform::gui::SystemCursorType type); + + explicit CursorStyler(std::shared_ptr<platform::gui::ICursor> cursor) + : cursor_(std::move(cursor)) {} + + void Apply(controls::Control* control) const override; + + CursorStyler* Clone() const override { return new CursorStyler(cursor_); } + + private: + std::shared_ptr<platform::gui::ICursor> cursor_; +}; +} // namespace cru::ui::style |