aboutsummaryrefslogtreecommitdiff
path: root/include/cru/ui/style
diff options
context:
space:
mode:
Diffstat (limited to 'include/cru/ui/style')
-rw-r--r--include/cru/ui/style/ApplyBorderStyleInfo.hpp28
-rw-r--r--include/cru/ui/style/Condition.hpp123
-rw-r--r--include/cru/ui/style/StyleRule.hpp45
-rw-r--r--include/cru/ui/style/StyleRuleSet.hpp87
-rw-r--r--include/cru/ui/style/Styler.hpp80
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