From 145cfd5b82d76e0c937eceda707aa22427899943 Mon Sep 17 00:00:00 2001 From: crupest Date: Wed, 2 Dec 2020 19:19:22 +0800 Subject: ... --- include/cru/ui/style/Condition.hpp | 69 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 include/cru/ui/style/Condition.hpp (limited to 'include/cru/ui/style/Condition.hpp') 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 +#include +#include + +namespace cru::ui::style { +class Condition { + public: + virtual ~Condition() = default; + + virtual std::vector ChangeOn( + controls::Control* control) const = 0; + virtual bool Judge(controls::Control* control) const = 0; +}; + +class CompoundCondition : public Condition { + public: + explicit CompoundCondition(std::vector conditions); + + const std::vector& GetConditions() const { return conditions_; } + + std::vector ChangeOn(controls::Control* control) const override; + + private: + std::vector 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 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 ChangeOn(controls::Control* control) const override; + bool Judge(controls::Control* control) const override; + + private: + helper::ClickState click_state_; +}; +} // namespace cru::ui::style -- cgit v1.2.3 From d7dca1be0dd0814e30fa63924a20af3d924e974c Mon Sep 17 00:00:00 2001 From: crupest Date: Wed, 2 Dec 2020 19:38:25 +0800 Subject: ... --- include/cru/ui/controls/Button.hpp | 8 +++++++- include/cru/ui/controls/IBorderControl.hpp | 10 ++++++++++ include/cru/ui/render/BorderRenderObject.hpp | 4 ++++ include/cru/ui/style/ApplyBorderStyleInfo.hpp | 12 ++++++++++++ include/cru/ui/style/Condition.hpp | 4 +--- include/cru/ui/style/Styler.hpp | 13 +++++++++++++ src/ui/CMakeLists.txt | 5 +++++ src/ui/controls/Button.cpp | 4 ++++ src/ui/render/BorderRenderObject.cpp | 18 +++++++++++++++--- 9 files changed, 71 insertions(+), 7 deletions(-) create mode 100644 include/cru/ui/controls/IBorderControl.hpp create mode 100644 include/cru/ui/style/ApplyBorderStyleInfo.hpp (limited to 'include/cru/ui/style/Condition.hpp') diff --git a/include/cru/ui/controls/Button.hpp b/include/cru/ui/controls/Button.hpp index 0d2f4898..7299c146 100644 --- a/include/cru/ui/controls/Button.hpp +++ b/include/cru/ui/controls/Button.hpp @@ -2,11 +2,15 @@ #include "ContentControl.hpp" #include "../helper/ClickDetector.hpp" +#include "IBorderControl.hpp" #include "IClickableControl.hpp" #include "cru/common/Event.hpp" +#include "cru/ui/style/ApplyBorderStyleInfo.hpp" namespace cru::ui::controls { -class Button : public ContentControl, public virtual IClickableControl { +class Button : public ContentControl, + public virtual IClickableControl, + public virtual IBorderControl { public: static constexpr std::u16string_view control_type = u"Button"; @@ -35,6 +39,8 @@ class Button : public ContentControl, public virtual IClickableControl { return click_detector_.StateChangeEvent(); } + void ApplyBorderStyle(const style::ApplyBorderStyleInfo& style) override; + const ButtonStyle& GetStyle() const { return style_; } void SetStyle(ButtonStyle style); diff --git a/include/cru/ui/controls/IBorderControl.hpp b/include/cru/ui/controls/IBorderControl.hpp new file mode 100644 index 00000000..817305ef --- /dev/null +++ b/include/cru/ui/controls/IBorderControl.hpp @@ -0,0 +1,10 @@ +#pragma once +#include "../style/ApplyBorderStyleInfo.hpp" +#include "Base.hpp" +#include "cru/common/Base.hpp" + +namespace cru::ui::controls { +struct IBorderControl : virtual Interface { + virtual void ApplyBorderStyle(const style::ApplyBorderStyleInfo& style) = 0; +}; +} // namespace cru::ui::controls diff --git a/include/cru/ui/render/BorderRenderObject.hpp b/include/cru/ui/render/BorderRenderObject.hpp index f1b957cf..ec0bd52b 100644 --- a/include/cru/ui/render/BorderRenderObject.hpp +++ b/include/cru/ui/render/BorderRenderObject.hpp @@ -1,5 +1,7 @@ #pragma once +#include "../style/ApplyBorderStyleInfo.hpp" #include "RenderObject.hpp" +#include "cru/ui/Base.hpp" namespace cru::ui::render { class BorderRenderObject : public RenderObject { @@ -64,6 +66,8 @@ class BorderRenderObject : public RenderObject { void SetBorderStyle(const BorderStyle& style); + void ApplyBorderStyle(const style::ApplyBorderStyleInfo& style); + RenderObject* HitTest(const Point& point) override; protected: diff --git a/include/cru/ui/style/ApplyBorderStyleInfo.hpp b/include/cru/ui/style/ApplyBorderStyleInfo.hpp new file mode 100644 index 00000000..e9c4ca44 --- /dev/null +++ b/include/cru/ui/style/ApplyBorderStyleInfo.hpp @@ -0,0 +1,12 @@ +#pragma once +#include "../Base.hpp" + +namespace cru::ui::style { +struct ApplyBorderStyleInfo { + std::shared_ptr border_brush; + std::optional border_thickness; + std::optional border_radius; + std::shared_ptr foreground_brush; + std::shared_ptr background_brush; +}; +} // namespace cru::ui::style diff --git a/include/cru/ui/style/Condition.hpp b/include/cru/ui/style/Condition.hpp index b88a338f..97d29287 100644 --- a/include/cru/ui/style/Condition.hpp +++ b/include/cru/ui/style/Condition.hpp @@ -10,10 +10,8 @@ #include namespace cru::ui::style { -class Condition { +class Condition : public Object { public: - virtual ~Condition() = default; - virtual std::vector ChangeOn( controls::Control* control) const = 0; virtual bool Judge(controls::Control* control) const = 0; diff --git a/include/cru/ui/style/Styler.hpp b/include/cru/ui/style/Styler.hpp index e69de29b..0b48f1ce 100644 --- a/include/cru/ui/style/Styler.hpp +++ b/include/cru/ui/style/Styler.hpp @@ -0,0 +1,13 @@ +#pragma once +#include "../Base.hpp" +#include "cru/common/Base.hpp" + +#include + +namespace cru::ui::style { +class Styler : public Object { + public: + virtual void Apply(controls::Control* control) const; +}; + +} // namespace cru::ui::style diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 85c87f5e..03297988 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -35,6 +35,7 @@ add_library(cru_ui STATIC render/StackLayoutRenderObject.cpp render/TextRenderObject.cpp style/Condition.cpp + style/Styler.cpp ) target_sources(cru_ui PUBLIC ${CRU_UI_INCLUDE_DIR}/Base.hpp @@ -46,6 +47,8 @@ target_sources(cru_ui PUBLIC ${CRU_UI_INCLUDE_DIR}/controls/ContentControl.hpp ${CRU_UI_INCLUDE_DIR}/controls/Control.hpp ${CRU_UI_INCLUDE_DIR}/controls/FlexLayout.hpp + ${CRU_UI_INCLUDE_DIR}/controls/IBorderControl.hpp + ${CRU_UI_INCLUDE_DIR}/controls/IClickableControl.hpp ${CRU_UI_INCLUDE_DIR}/controls/LayoutControl.hpp ${CRU_UI_INCLUDE_DIR}/controls/NoChildControl.hpp ${CRU_UI_INCLUDE_DIR}/controls/Popup.hpp @@ -71,6 +74,8 @@ target_sources(cru_ui PUBLIC ${CRU_UI_INCLUDE_DIR}/render/ScrollRenderObject.hpp ${CRU_UI_INCLUDE_DIR}/render/StackLayoutRenderObject.hpp ${CRU_UI_INCLUDE_DIR}/render/TextRenderObject.hpp + ${CRU_UI_INCLUDE_DIR}/style/ApplyBorderStyleInfo.hpp ${CRU_UI_INCLUDE_DIR}/style/Condition.hpp + ${CRU_UI_INCLUDE_DIR}/style/Styler.hpp ) target_link_libraries(cru_ui PUBLIC cru_platform_gui) diff --git a/src/ui/controls/Button.cpp b/src/ui/controls/Button.cpp index 39c4b961..6f19e6b9 100644 --- a/src/ui/controls/Button.cpp +++ b/src/ui/controls/Button.cpp @@ -64,4 +64,8 @@ Button::~Button() = default; render::RenderObject* Button::GetRenderObject() const { return render_object_.get(); } + +void Button::ApplyBorderStyle(const style::ApplyBorderStyleInfo& style) { + render_object_->ApplyBorderStyle(style); +} } // namespace cru::ui::controls diff --git a/src/ui/render/BorderRenderObject.cpp b/src/ui/render/BorderRenderObject.cpp index 8e16d8cb..5abc7832 100644 --- a/src/ui/render/BorderRenderObject.cpp +++ b/src/ui/render/BorderRenderObject.cpp @@ -5,6 +5,7 @@ #include "cru/platform/graphics/Factory.hpp" #include "cru/platform/graphics/Geometry.hpp" #include "cru/platform/graphics/util/Painter.hpp" +#include "cru/ui/style/ApplyBorderStyleInfo.hpp" #include @@ -25,6 +26,16 @@ void BorderRenderObject::SetBorderStyle(const BorderStyle& style) { InvalidateLayout(); } +void BorderRenderObject::ApplyBorderStyle( + const style::ApplyBorderStyleInfo& style) { + if (style.border_brush != nullptr) border_brush_ = style.border_brush; + if (style.border_thickness) border_thickness_ = *style.border_thickness; + if (style.border_radius) border_radius_ = *style.border_radius; + if (style.foreground_brush) foreground_brush_ = style.foreground_brush; + if (style.background_brush) background_brush_ = style.background_brush; + InvalidateLayout(); +} + RenderObject* BorderRenderObject::HitTest(const Point& point) { if (const auto child = GetSingleChild()) { auto offset = child->GetOffset(); @@ -109,9 +120,10 @@ Size BorderRenderObject::OnMeasureCore(const MeasureRequirement& requirement, if (!requirement.max.height.IsNotSpecified()) { const auto max_height = requirement.max.height.GetLengthOrMax(); if (coerced_space_size.height > max_height) { - log::TagWarn(log_tag, - u"(Measure) Vertical length of padding, border and margin is " - u"bigger than required max length."); + log::TagWarn( + log_tag, + u"(Measure) Vertical length of padding, border and margin is " + u"bigger than required max length."); coerced_space_size.height = max_height; } content_requirement.max.height = max_height - coerced_space_size.height; -- cgit v1.2.3 From c6baeb6432a4db7433aab4fc8f89cc235473f11a Mon Sep 17 00:00:00 2001 From: crupest Date: Wed, 2 Dec 2020 20:50:26 +0800 Subject: ... --- include/cru/ui/style/Condition.hpp | 31 +++++++++++++++++++-- include/cru/ui/style/StyleRule.hpp | 57 ++++++++++++++++++++++++++++++++++++++ include/cru/ui/style/Styler.hpp | 8 ++++++ src/ui/CMakeLists.txt | 2 ++ src/ui/style/Condition.cpp | 17 ++++++++++-- src/ui/style/StyleRule.cpp | 11 ++++++++ 6 files changed, 121 insertions(+), 5 deletions(-) create mode 100644 include/cru/ui/style/StyleRule.hpp create mode 100644 src/ui/style/StyleRule.cpp (limited to 'include/cru/ui/style/Condition.hpp') diff --git a/include/cru/ui/style/Condition.hpp b/include/cru/ui/style/Condition.hpp index 97d29287..c4fd2106 100644 --- a/include/cru/ui/style/Condition.hpp +++ b/include/cru/ui/style/Condition.hpp @@ -5,6 +5,7 @@ #include "cru/ui/controls/IClickableControl.hpp" #include "cru/ui/helper/ClickDetector.hpp" +#include #include #include #include @@ -15,18 +16,26 @@ class Condition : public Object { virtual std::vector ChangeOn( controls::Control* control) const = 0; virtual bool Judge(controls::Control* control) const = 0; + + virtual std::unique_ptr Clone() const = 0; }; class CompoundCondition : public Condition { public: - explicit CompoundCondition(std::vector conditions); + explicit CompoundCondition( + std::vector> conditions); + + const std::vector& GetConditions() const { + return readonly_conditions_; + } - const std::vector& GetConditions() const { return conditions_; } + std::vector> CloneConditions() const; std::vector ChangeOn(controls::Control* control) const override; private: - std::vector conditions_; + std::vector> conditions_; + std::vector readonly_conditions_; }; class AndCondition : public CompoundCondition { @@ -34,6 +43,10 @@ class AndCondition : public CompoundCondition { using CompoundCondition::CompoundCondition; bool Judge(controls::Control* control) const override; + + std::unique_ptr Clone() const override { + return std::make_unique(CloneConditions()); + } }; class OrCondition : public CompoundCondition { @@ -41,6 +54,10 @@ class OrCondition : public CompoundCondition { using CompoundCondition::CompoundCondition; bool Judge(controls::Control* control) const override; + + std::unique_ptr Clone() const override { + return std::make_unique(CloneConditions()); + } }; class FocusCondition : public Condition { @@ -50,6 +67,10 @@ class FocusCondition : public Condition { std::vector ChangeOn(controls::Control* control) const override; bool Judge(controls::Control* control) const override; + std::unique_ptr Clone() const override { + return std::make_unique(has_focus_); + } + private: bool has_focus_; }; @@ -61,6 +82,10 @@ class ClickStateCondition : public Condition { std::vector ChangeOn(controls::Control* control) const override; bool Judge(controls::Control* control) const override; + std::unique_ptr Clone() const override { + return std::make_unique(click_state_); + } + private: helper::ClickState click_state_; }; diff --git a/include/cru/ui/style/StyleRule.hpp b/include/cru/ui/style/StyleRule.hpp new file mode 100644 index 00000000..f1283e24 --- /dev/null +++ b/include/cru/ui/style/StyleRule.hpp @@ -0,0 +1,57 @@ +#pragma once +#include "Condition.hpp" +#include "Styler.hpp" +#include "cru/common/Base.hpp" +#include "cru/ui/Base.hpp" + +#include +#include +#include + +namespace cru::ui::style { +class StyleRule : public Object { + public: + StyleRule(std::unique_ptr condition, + std::unique_ptr styler, std::u16string name = {}); + + StyleRule(const StyleRule& other) + : condition_(other.condition_->Clone()), + styler_(other.styler_->Clone()), + name_(other.name_) {} + + StyleRule& operator=(const StyleRule& other) { + if (this != &other) { + condition_ = other.condition_->Clone(); + styler_ = other.styler_->Clone(); + name_ = other.name_; + } + return *this; + } + + 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(std::unique_ptr condition, + std::u16string name = {}) const { + return StyleRule{std::move(condition), styler_->Clone(), std::move(name)}; + } + + StyleRule WithNewStyler(std::unique_ptr styler, + std::u16string name = {}) const { + return StyleRule{condition_->Clone(), std::move(styler), std::move(name)}; + } + + bool CheckAndApply(controls::Control* control) const; + + private: + std::unique_ptr condition_; + std::unique_ptr styler_; + std::u16string name_; +}; +} // namespace cru::ui::style diff --git a/include/cru/ui/style/Styler.hpp b/include/cru/ui/style/Styler.hpp index 89731033..4f4b18ba 100644 --- a/include/cru/ui/style/Styler.hpp +++ b/include/cru/ui/style/Styler.hpp @@ -3,10 +3,14 @@ #include "ApplyBorderStyleInfo.hpp" #include "cru/common/Base.hpp" +#include + namespace cru::ui::style { class Styler : public Object { public: virtual void Apply(controls::Control* control) const; + + virtual std::unique_ptr Clone() const = 0; }; class BorderStyler : public Styler { @@ -15,6 +19,10 @@ class BorderStyler : public Styler { void Apply(controls::Control* control) const override; + std::unique_ptr Clone() const override { + return std::make_unique(style_); + } + private: ApplyBorderStyleInfo style_; }; diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 03297988..e61ed7de 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -36,6 +36,7 @@ add_library(cru_ui STATIC render/TextRenderObject.cpp style/Condition.cpp style/Styler.cpp + style/StyleRule.cpp ) target_sources(cru_ui PUBLIC ${CRU_UI_INCLUDE_DIR}/Base.hpp @@ -77,5 +78,6 @@ target_sources(cru_ui PUBLIC ${CRU_UI_INCLUDE_DIR}/style/ApplyBorderStyleInfo.hpp ${CRU_UI_INCLUDE_DIR}/style/Condition.hpp ${CRU_UI_INCLUDE_DIR}/style/Styler.hpp + ${CRU_UI_INCLUDE_DIR}/style/StyleRule.hpp ) target_link_libraries(cru_ui PUBLIC cru_platform_gui) diff --git a/src/ui/style/Condition.cpp b/src/ui/style/Condition.cpp index bc24e265..2b51bde3 100644 --- a/src/ui/style/Condition.cpp +++ b/src/ui/style/Condition.cpp @@ -1,4 +1,5 @@ #include "cru/ui/style/Condition.hpp" +#include #include "cru/common/Event.hpp" #include "cru/ui/controls/Control.hpp" @@ -6,8 +7,11 @@ #include "cru/ui/helper/ClickDetector.hpp" namespace cru::ui::style { -CompoundCondition::CompoundCondition(std::vector conditions) - : conditions_(std::move(conditions)) {} +CompoundCondition::CompoundCondition( + std::vector> conditions) + : conditions_(std::move(conditions)) { + for (const auto& p : conditions_) readonly_conditions_.push_back(p.get()); +} std::vector CompoundCondition::ChangeOn( controls::Control* control) const { @@ -22,6 +26,15 @@ std::vector CompoundCondition::ChangeOn( return result; } +std::vector> CompoundCondition::CloneConditions() + const { + std::vector> result; + for (auto condition : GetConditions()) { + result.push_back(condition->Clone()); + } + return result; +} + bool AndCondition::Judge(controls::Control* control) const { for (auto condition : GetConditions()) { if (!condition->Judge(control)) return false; diff --git a/src/ui/style/StyleRule.cpp b/src/ui/style/StyleRule.cpp new file mode 100644 index 00000000..4a5ecf7e --- /dev/null +++ b/src/ui/style/StyleRule.cpp @@ -0,0 +1,11 @@ +#include "cru/ui/style/StyleRule.hpp" + +namespace cru::ui::style { +bool StyleRule::CheckAndApply(controls::Control *control) const { + auto active = condition_->Judge(control); + if (active) { + styler_->Apply(control); + } + return active; +} +} // namespace cru::ui::style -- cgit v1.2.3 From 93a8bf8b967817031cd2798cdaedfa73f867dead Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 3 Dec 2020 20:51:53 +0800 Subject: ... --- include/cru/common/ClonablePtr.hpp | 201 ++++++++++++++++++++++++++++++++++ include/cru/ui/style/Condition.hpp | 33 ++---- include/cru/ui/style/StyleRule.hpp | 32 ++---- include/cru/ui/style/StyleRuleSet.hpp | 0 include/cru/ui/style/Styler.hpp | 6 +- src/ui/CMakeLists.txt | 2 + src/ui/style/Condition.cpp | 22 +--- src/ui/style/StyleRule.cpp | 6 + src/ui/style/StyleRuleSet.cpp | 0 9 files changed, 238 insertions(+), 64 deletions(-) create mode 100644 include/cru/common/ClonablePtr.hpp create mode 100644 include/cru/ui/style/StyleRuleSet.hpp create mode 100644 src/ui/style/StyleRuleSet.cpp (limited to 'include/cru/ui/style/Condition.hpp') diff --git a/include/cru/common/ClonablePtr.hpp b/include/cru/common/ClonablePtr.hpp new file mode 100644 index 00000000..47a1d3bd --- /dev/null +++ b/include/cru/common/ClonablePtr.hpp @@ -0,0 +1,201 @@ +#pragma once + +#include +#include +#include +#include + +namespace cru { +template +class ClonablePtr { + public: + using element_type = typename std::unique_ptr::element_type; + using pointer = typename std::unique_ptr::pointer; + + ClonablePtr() = default; + ClonablePtr(std::nullptr_t) noexcept : ptr_(nullptr) {} + ClonablePtr(pointer p) noexcept : ptr_(p) {} + ClonablePtr(std::unique_ptr&& p) noexcept + : ptr_(std::move(p)) {} + template ::pointer, pointer>, + int> = 0> + ClonablePtr(std::unique_ptr&& p) : ptr_(std::move(p)) {} + ClonablePtr(const ClonablePtr& other) : ptr_(other.ptr_->Clone()) {} + ClonablePtr(ClonablePtr&& other) = default; + template ::pointer, pointer>, + int> = 0> + ClonablePtr(const ClonablePtr& other) : ptr_(other.ptr_->Clone()) {} + template ::pointer, pointer>, + int> = 0> + ClonablePtr(ClonablePtr&& other) noexcept : ptr_(std::move(other.ptr_)) {} + ClonablePtr& operator=(std::nullptr_t) noexcept { + ptr_ = nullptr; + return *this; + } + ClonablePtr& operator=(std::unique_ptr&& other) noexcept { + ptr_ = std::move(other); + return *this; + } + template ::pointer, pointer>, + int> = 0> + ClonablePtr& operator=(std::unique_ptr&& p) noexcept { + ptr_ = std::move(p); + return *this; + } + ClonablePtr& operator=(const ClonablePtr& other) { + if (this != &other) { + ptr_ = std::unique_ptr(other.ptr->Clone()); + } + return *this; + } + ClonablePtr& operator=(ClonablePtr&& other) = default; + template ::pointer, pointer>, + int> = 0> + ClonablePtr& operator=(const ClonablePtr& other) noexcept { + if (this != &other) { + ptr_ = std::unique_ptr(other.ptr_->Clone()); + } + return *this; + } + template ::pointer, pointer>, + int> = 0> + ClonablePtr& operator=(ClonablePtr&& other) noexcept { + ptr_ = std::move(other.ptr_); + } + + ~ClonablePtr() = default; + + public: + pointer release() noexcept { return ptr_.release(); } + void reset(pointer p = pointer()) noexcept { ptr_.reset(p); } + void swap(ClonablePtr& other) noexcept { ptr_.swap(other.ptr_); } + + public: + pointer get() const noexcept { return ptr_.get(); } + + operator bool() const noexcept { return ptr_; } + + element_type& operator*() const noexcept { return *ptr_; } + pointer operator->() const noexcept { return ptr_.get(); } + + private: + std::unique_ptr ptr_; +}; + +template +void swap(ClonablePtr& left, ClonablePtr& right) noexcept { + left.swap(right); +} + +template +bool operator==(const ClonablePtr& left, const ClonablePtr& right) { + return left.get() == right.get(); +} + +template +bool operator!=(const ClonablePtr& left, const ClonablePtr& right) { + return left.get() != right.get(); +} + +template +bool operator<(const ClonablePtr& left, const ClonablePtr& right) { + return left.get() < right.get(); +} + +template +bool operator<=(const ClonablePtr& left, const ClonablePtr& right) { + return left.get() <= right.get(); +} + +template +bool operator>(const ClonablePtr& left, const ClonablePtr& right) { + return left.get() > right.get(); +} + +template +bool operator>=(const ClonablePtr& left, const ClonablePtr& right) { + return left.get() >= right.get(); +} + +template +bool operator==(const ClonablePtr& left, std::nullptr_t) { + return left.get() == nullptr; +} + +template +bool operator!=(const ClonablePtr& left, std::nullptr_t) { + return left.get() != nullptr; +} + +template +bool operator<(const ClonablePtr& left, std::nullptr_t) { + return left.get() < nullptr; +} + +template +bool operator<=(const ClonablePtr& left, std::nullptr_t) { + return left.get() <= nullptr; +} + +template +bool operator>(const ClonablePtr& left, std::nullptr_t) { + return left.get() > nullptr; +} + +template +bool operator>=(const ClonablePtr& left, std::nullptr_t) { + return left.get() >= nullptr; +} + +template +bool operator==(std::nullptr_t, const ClonablePtr& right) { + return nullptr == right.get(); +} + +template +bool operator!=(std::nullptr_t, const ClonablePtr& right) { + return nullptr != right.get(); +} + +template +bool operator<(std::nullptr_t, const ClonablePtr& right) { + return nullptr < right.get(); +} + +template +bool operator<=(std::nullptr_t, const ClonablePtr& right) { + return nullptr <= right.get(); +} + +template +bool operator>(std::nullptr_t, const ClonablePtr& right) { + return nullptr > right.get(); +} + +template +bool operator>=(std::nullptr_t, const ClonablePtr& right) { + return nullptr >= right.get(); +} + +} // namespace cru + +namespace std { +template +struct hash> { + std::size_t operator()(const cru::ClonablePtr& p) const { + return std::hash::pointer>(p.get()); + } +}; +} // namespace std diff --git a/include/cru/ui/style/Condition.hpp b/include/cru/ui/style/Condition.hpp index c4fd2106..13ab7764 100644 --- a/include/cru/ui/style/Condition.hpp +++ b/include/cru/ui/style/Condition.hpp @@ -1,6 +1,7 @@ #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" @@ -17,25 +18,17 @@ class Condition : public Object { controls::Control* control) const = 0; virtual bool Judge(controls::Control* control) const = 0; - virtual std::unique_ptr Clone() const = 0; + virtual Condition* Clone() const = 0; }; class CompoundCondition : public Condition { public: - explicit CompoundCondition( - std::vector> conditions); - - const std::vector& GetConditions() const { - return readonly_conditions_; - } - - std::vector> CloneConditions() const; + explicit CompoundCondition(std::vector> conditions); std::vector ChangeOn(controls::Control* control) const override; - private: - std::vector> conditions_; - std::vector readonly_conditions_; + protected: + std::vector> conditions_; }; class AndCondition : public CompoundCondition { @@ -44,9 +37,7 @@ class AndCondition : public CompoundCondition { bool Judge(controls::Control* control) const override; - std::unique_ptr Clone() const override { - return std::make_unique(CloneConditions()); - } + AndCondition* Clone() const override { return new AndCondition(conditions_); } }; class OrCondition : public CompoundCondition { @@ -55,9 +46,7 @@ class OrCondition : public CompoundCondition { bool Judge(controls::Control* control) const override; - std::unique_ptr Clone() const override { - return std::make_unique(CloneConditions()); - } + OrCondition* Clone() const override { return new OrCondition(conditions_); } }; class FocusCondition : public Condition { @@ -67,8 +56,8 @@ class FocusCondition : public Condition { std::vector ChangeOn(controls::Control* control) const override; bool Judge(controls::Control* control) const override; - std::unique_ptr Clone() const override { - return std::make_unique(has_focus_); + FocusCondition* Clone() const override { + return new FocusCondition(has_focus_); } private: @@ -82,8 +71,8 @@ class ClickStateCondition : public Condition { std::vector ChangeOn(controls::Control* control) const override; bool Judge(controls::Control* control) const override; - std::unique_ptr Clone() const override { - return std::make_unique(click_state_); + ClickStateCondition* Clone() const override { + return new ClickStateCondition(click_state_); } private: diff --git a/include/cru/ui/style/StyleRule.hpp b/include/cru/ui/style/StyleRule.hpp index f1283e24..8ac42cd0 100644 --- a/include/cru/ui/style/StyleRule.hpp +++ b/include/cru/ui/style/StyleRule.hpp @@ -2,6 +2,7 @@ #include "Condition.hpp" #include "Styler.hpp" #include "cru/common/Base.hpp" +#include "cru/common/ClonablePtr.hpp" #include "cru/ui/Base.hpp" #include @@ -11,23 +12,10 @@ namespace cru::ui::style { class StyleRule : public Object { public: - StyleRule(std::unique_ptr condition, - std::unique_ptr styler, std::u16string name = {}); - - StyleRule(const StyleRule& other) - : condition_(other.condition_->Clone()), - styler_(other.styler_->Clone()), - name_(other.name_) {} - - StyleRule& operator=(const StyleRule& other) { - if (this != &other) { - condition_ = other.condition_->Clone(); - styler_ = other.styler_->Clone(); - name_ = other.name_; - } - return *this; - } + StyleRule(ClonablePtr condition, ClonablePtr styler, + std::u16string name = {}); + CRU_DEFAULT_COPY(StyleRule) CRU_DEFAULT_MOVE(StyleRule) ~StyleRule() override = default; @@ -37,21 +25,21 @@ class StyleRule : public Object { Condition* GetCondition() const { return condition_.get(); } Styler* GetStyler() const { return styler_.get(); } - StyleRule WithNewCondition(std::unique_ptr condition, + StyleRule WithNewCondition(ClonablePtr condition, std::u16string name = {}) const { - return StyleRule{std::move(condition), styler_->Clone(), std::move(name)}; + return StyleRule{std::move(condition), styler_, std::move(name)}; } - StyleRule WithNewStyler(std::unique_ptr styler, + StyleRule WithNewStyler(ClonablePtr styler, std::u16string name = {}) const { - return StyleRule{condition_->Clone(), std::move(styler), std::move(name)}; + return StyleRule{condition_, std::move(styler), std::move(name)}; } bool CheckAndApply(controls::Control* control) const; private: - std::unique_ptr condition_; - std::unique_ptr styler_; + ClonablePtr condition_; + ClonablePtr 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..e69de29b diff --git a/include/cru/ui/style/Styler.hpp b/include/cru/ui/style/Styler.hpp index 4f4b18ba..2aece114 100644 --- a/include/cru/ui/style/Styler.hpp +++ b/include/cru/ui/style/Styler.hpp @@ -10,7 +10,7 @@ class Styler : public Object { public: virtual void Apply(controls::Control* control) const; - virtual std::unique_ptr Clone() const = 0; + virtual Styler* Clone() const = 0; }; class BorderStyler : public Styler { @@ -19,9 +19,7 @@ class BorderStyler : public Styler { void Apply(controls::Control* control) const override; - std::unique_ptr Clone() const override { - return std::make_unique(style_); - } + BorderStyler* Clone() const override { return new BorderStyler(style_); } private: ApplyBorderStyleInfo style_; diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index e61ed7de..4964a1ae 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -37,6 +37,7 @@ add_library(cru_ui STATIC style/Condition.cpp style/Styler.cpp style/StyleRule.cpp + style/StyleRuleSet.cpp ) target_sources(cru_ui PUBLIC ${CRU_UI_INCLUDE_DIR}/Base.hpp @@ -79,5 +80,6 @@ target_sources(cru_ui PUBLIC ${CRU_UI_INCLUDE_DIR}/style/Condition.hpp ${CRU_UI_INCLUDE_DIR}/style/Styler.hpp ${CRU_UI_INCLUDE_DIR}/style/StyleRule.hpp + ${CRU_UI_INCLUDE_DIR}/style/StyleRuleSet.hpp ) target_link_libraries(cru_ui PUBLIC cru_platform_gui) diff --git a/src/ui/style/Condition.cpp b/src/ui/style/Condition.cpp index 2b51bde3..891eb062 100644 --- a/src/ui/style/Condition.cpp +++ b/src/ui/style/Condition.cpp @@ -1,6 +1,7 @@ #include "cru/ui/style/Condition.hpp" #include +#include "cru/common/ClonablePtr.hpp" #include "cru/common/Event.hpp" #include "cru/ui/controls/Control.hpp" #include "cru/ui/controls/IClickableControl.hpp" @@ -8,16 +9,14 @@ namespace cru::ui::style { CompoundCondition::CompoundCondition( - std::vector> conditions) - : conditions_(std::move(conditions)) { - for (const auto& p : conditions_) readonly_conditions_.push_back(p.get()); -} + std::vector> conditions) + : conditions_(std::move(conditions)) {} std::vector CompoundCondition::ChangeOn( controls::Control* control) const { std::vector result; - for (auto condition : GetConditions()) { + for (auto condition : conditions_) { for (auto e : condition->ChangeOn(control)) { result.push_back(e); } @@ -26,24 +25,15 @@ std::vector CompoundCondition::ChangeOn( return result; } -std::vector> CompoundCondition::CloneConditions() - const { - std::vector> result; - for (auto condition : GetConditions()) { - result.push_back(condition->Clone()); - } - return result; -} - bool AndCondition::Judge(controls::Control* control) const { - for (auto condition : GetConditions()) { + for (auto condition : conditions_) { if (!condition->Judge(control)) return false; } return true; } bool OrCondition::Judge(controls::Control* control) const { - for (auto condition : GetConditions()) { + for (auto condition : conditions_) { if (condition->Judge(control)) return true; } return false; diff --git a/src/ui/style/StyleRule.cpp b/src/ui/style/StyleRule.cpp index 4a5ecf7e..1a72a970 100644 --- a/src/ui/style/StyleRule.cpp +++ b/src/ui/style/StyleRule.cpp @@ -1,6 +1,12 @@ #include "cru/ui/style/StyleRule.hpp" namespace cru::ui::style { +StyleRule::StyleRule(ClonablePtr condition, + ClonablePtr styler, std::u16string name) + : condition_(std::move(condition)), + styler_(std::move(styler)), + name_(std::move(name)) {} + bool StyleRule::CheckAndApply(controls::Control *control) const { auto active = condition_->Judge(control); if (active) { diff --git a/src/ui/style/StyleRuleSet.cpp b/src/ui/style/StyleRuleSet.cpp new file mode 100644 index 00000000..e69de29b -- cgit v1.2.3 From b29fb11be2f043a3438a50d8942b4ad7d2af0034 Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 3 Dec 2020 22:44:57 +0800 Subject: ... --- include/cru/common/ClonablePtr.hpp | 7 ++- include/cru/common/Event.hpp | 4 +- include/cru/ui/Base.hpp | 12 ++-- include/cru/ui/UiManager.hpp | 5 +- include/cru/ui/controls/Base.hpp | 22 +------ include/cru/ui/controls/Button.hpp | 5 -- include/cru/ui/controls/Control.hpp | 5 ++ include/cru/ui/controls/TextBox.hpp | 14 +---- include/cru/ui/helper/ClickDetector.hpp | 2 +- include/cru/ui/render/BorderRenderObject.hpp | 2 - include/cru/ui/style/Condition.hpp | 42 +++++++++++++ include/cru/ui/style/StyleRuleSet.hpp | 55 +++++++++++++++++ include/cru/ui/style/Styler.hpp | 7 ++- src/ui/UiManager.cpp | 91 ++++++++++++++++------------ src/ui/controls/Button.cpp | 19 +----- src/ui/controls/Control.cpp | 7 +++ src/ui/controls/TextBox.cpp | 29 +-------- src/ui/render/BorderRenderObject.cpp | 9 --- src/ui/style/Condition.cpp | 10 +++ src/ui/style/StyleRuleSet.cpp | 58 ++++++++++++++++++ src/win/gui/Window.cpp | 2 +- 21 files changed, 262 insertions(+), 145 deletions(-) (limited to 'include/cru/ui/style/Condition.hpp') diff --git a/include/cru/common/ClonablePtr.hpp b/include/cru/common/ClonablePtr.hpp index 47a1d3bd..5e4b80c9 100644 --- a/include/cru/common/ClonablePtr.hpp +++ b/include/cru/common/ClonablePtr.hpp @@ -8,13 +8,16 @@ namespace cru { template class ClonablePtr { + template + friend class ClonablePtr; + public: using element_type = typename std::unique_ptr::element_type; using pointer = typename std::unique_ptr::pointer; ClonablePtr() = default; ClonablePtr(std::nullptr_t) noexcept : ptr_(nullptr) {} - ClonablePtr(pointer p) noexcept : ptr_(p) {} + explicit ClonablePtr(pointer p) noexcept : ptr_(p) {} ClonablePtr(std::unique_ptr&& p) noexcept : ptr_(std::move(p)) {} template (other.ptr->Clone()); + ptr_ = std::unique_ptr(other.ptr_->Clone()); } return *this; } diff --git a/include/cru/common/Event.hpp b/include/cru/common/Event.hpp index 59502527..7f7b4dd4 100644 --- a/include/cru/common/Event.hpp +++ b/include/cru/common/Event.hpp @@ -98,7 +98,7 @@ struct IBaseEvent { using SpyOnlyHandler = std::function; public: - virtual EventRevoker AddHandler(SpyOnlyHandler handler) = 0; + virtual EventRevoker AddSpyOnlyHandler(SpyOnlyHandler handler) = 0; }; // Provides an interface of event. @@ -147,7 +147,7 @@ class Event : public details::EventBase, public IEvent { CRU_DEFAULT_MOVE(Event) ~Event() = default; - EventRevoker AddHandler(SpyOnlyHandler handler) override { + EventRevoker AddSpyOnlyHandler(SpyOnlyHandler handler) override { const auto token = current_token_++; this->handler_data_list_.emplace_back(token, std::move(handler)); return CreateRevoker(token); diff --git a/include/cru/ui/Base.hpp b/include/cru/ui/Base.hpp index 8595258d..57beb723 100644 --- a/include/cru/ui/Base.hpp +++ b/include/cru/ui/Base.hpp @@ -40,6 +40,10 @@ namespace render { class RenderObject; } +namespace style { +class StyleRuleSet; +} + //-------------------- region: basic types -------------------- namespace internal { constexpr int align_start = 0; @@ -87,14 +91,6 @@ inline bool operator!=(const CornerRadius& left, const CornerRadius& right) { return !(left == right); } -struct BorderStyle { - std::shared_ptr border_brush; - Thickness border_thickness; - CornerRadius border_radius; - std::shared_ptr foreground_brush; - std::shared_ptr background_brush; -}; - class CanvasPaintEventArgs { public: CanvasPaintEventArgs(platform::graphics::IPainter* painter, diff --git a/include/cru/ui/UiManager.hpp b/include/cru/ui/UiManager.hpp index 64599d99..e747fcd2 100644 --- a/include/cru/ui/UiManager.hpp +++ b/include/cru/ui/UiManager.hpp @@ -2,6 +2,7 @@ #include "Base.hpp" #include "controls/Base.hpp" +#include "style/StyleRuleSet.hpp" #include #include @@ -13,8 +14,8 @@ struct ThemeResources { std::shared_ptr text_brush; std::shared_ptr text_selection_brush; std::shared_ptr caret_brush; - controls::ButtonStyle button_style; - controls::TextBoxBorderStyle text_box_border_style; + style::StyleRuleSet button_style; + style::StyleRuleSet text_box_style; }; class UiManager : public Object { diff --git a/include/cru/ui/controls/Base.hpp b/include/cru/ui/controls/Base.hpp index 82c31d1e..7c85cdb2 100644 --- a/include/cru/ui/controls/Base.hpp +++ b/include/cru/ui/controls/Base.hpp @@ -1,24 +1,4 @@ #pragma once #include "../Base.hpp" -namespace cru::ui::controls { -using ButtonStateStyle = ui::BorderStyle; - -struct ButtonStyle { - // corresponds to ClickState::None - ButtonStateStyle normal; - // corresponds to ClickState::Hover - ButtonStateStyle hover; - // corresponds to ClickState::Press - ButtonStateStyle press; - // corresponds to ClickState::PressInactive - ButtonStateStyle press_cancel; -}; - -struct TextBoxBorderStyle { - ui::BorderStyle normal; - ui::BorderStyle hover; - ui::BorderStyle focus; - ui::BorderStyle focus_hover; -}; -} // namespace cru::ui::controls +namespace cru::ui::controls {} // namespace cru::ui::controls diff --git a/include/cru/ui/controls/Button.hpp b/include/cru/ui/controls/Button.hpp index 7299c146..1c9b1216 100644 --- a/include/cru/ui/controls/Button.hpp +++ b/include/cru/ui/controls/Button.hpp @@ -41,14 +41,9 @@ class Button : public ContentControl, void ApplyBorderStyle(const style::ApplyBorderStyleInfo& style) override; - const ButtonStyle& GetStyle() const { return style_; } - void SetStyle(ButtonStyle style); - private: std::unique_ptr render_object_{}; - ButtonStyle style_; - helper::ClickDetector click_detector_; }; } // namespace cru::ui::controls diff --git a/include/cru/ui/controls/Control.hpp b/include/cru/ui/controls/Control.hpp index 96aad2bd..0d34bc63 100644 --- a/include/cru/ui/controls/Control.hpp +++ b/include/cru/ui/controls/Control.hpp @@ -66,6 +66,9 @@ class Control : public Object { // null to unset void SetCursor(std::shared_ptr cursor); + public: + style::StyleRuleSet* GetStyleRuleSet(); + //*************** region: events *************** public: // Raised when mouse enter the control. Even when the control itself captures @@ -147,5 +150,7 @@ class Control : public Object { bool is_mouse_over_ = false; std::shared_ptr cursor_ = nullptr; + + std::unique_ptr style_rule_set_; }; } // namespace cru::ui::controls diff --git a/include/cru/ui/controls/TextBox.hpp b/include/cru/ui/controls/TextBox.hpp index 91d38c61..75e7cb65 100644 --- a/include/cru/ui/controls/TextBox.hpp +++ b/include/cru/ui/controls/TextBox.hpp @@ -1,5 +1,6 @@ #pragma once #include "NoChildControl.hpp" +#include "IBorderControl.hpp" #include @@ -7,7 +8,7 @@ namespace cru::ui::controls { template class TextControlService; -class TextBox : public NoChildControl { +class TextBox : public NoChildControl, public IBorderControl { public: static constexpr std::u16string_view control_type = u"TextBox"; @@ -29,22 +30,13 @@ class TextBox : public NoChildControl { gsl::not_null GetTextRenderObject(); render::ScrollRenderObject* GetScrollRenderObject(); - const TextBoxBorderStyle& GetBorderStyle(); - void SetBorderStyle(TextBoxBorderStyle border_style); - - protected: - void OnMouseHoverChange(bool newHover) override; - - private: - void UpdateBorderStyle(); + void ApplyBorderStyle(const style::ApplyBorderStyleInfo& style) override; private: std::unique_ptr border_render_object_; std::unique_ptr scroll_render_object_; std::unique_ptr text_render_object_; - TextBoxBorderStyle border_style_; - std::unique_ptr> service_; }; } // namespace cru::ui::controls diff --git a/include/cru/ui/helper/ClickDetector.hpp b/include/cru/ui/helper/ClickDetector.hpp index 0df77c60..b58297b1 100644 --- a/include/cru/ui/helper/ClickDetector.hpp +++ b/include/cru/ui/helper/ClickDetector.hpp @@ -71,7 +71,7 @@ class ClickDetector : public Object { private: controls::Control* control_; - ClickState state_; + ClickState state_ = ClickState::None; bool enable_ = true; MouseButton trigger_button_ = mouse_buttons::left | mouse_buttons::right; diff --git a/include/cru/ui/render/BorderRenderObject.hpp b/include/cru/ui/render/BorderRenderObject.hpp index ec0bd52b..3d4f4dad 100644 --- a/include/cru/ui/render/BorderRenderObject.hpp +++ b/include/cru/ui/render/BorderRenderObject.hpp @@ -64,8 +64,6 @@ class BorderRenderObject : public RenderObject { InvalidatePaint(); } - void SetBorderStyle(const BorderStyle& style); - void ApplyBorderStyle(const style::ApplyBorderStyleInfo& style); RenderObject* HitTest(const Point& point) override; diff --git a/include/cru/ui/style/Condition.hpp b/include/cru/ui/style/Condition.hpp index 13ab7764..d5cf16f2 100644 --- a/include/cru/ui/style/Condition.hpp +++ b/include/cru/ui/style/Condition.hpp @@ -21,6 +21,21 @@ class Condition : public Object { virtual Condition* Clone() const = 0; }; +class NoCondition : public Condition { + public: + static ClonablePtr Create() { + return ClonablePtr(new NoCondition); + }; + + std::vector 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> conditions); @@ -51,6 +66,10 @@ class OrCondition : public CompoundCondition { class FocusCondition : public Condition { public: + static ClonablePtr Create(bool has_focus) { + return ClonablePtr(new FocusCondition(has_focus)); + } + explicit FocusCondition(bool has_focus); std::vector ChangeOn(controls::Control* control) const override; @@ -64,8 +83,31 @@ class FocusCondition : public Condition { bool has_focus_; }; +class HoverCondition : public Condition { + public: + static ClonablePtr Create(bool hover) { + return ClonablePtr(new HoverCondition(hover)); + } + + explicit HoverCondition(bool hover) : hover_(hover) {} + + std::vector 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 Create( + helper::ClickState click_state) { + return ClonablePtr( + new ClickStateCondition(click_state)); + } + explicit ClickStateCondition(helper::ClickState click_state); std::vector ChangeOn(controls::Control* control) const override; diff --git a/include/cru/ui/style/StyleRuleSet.hpp b/include/cru/ui/style/StyleRuleSet.hpp index e69de29b..3ec71730 100644 --- a/include/cru/ui/style/StyleRuleSet.hpp +++ b/include/cru/ui/style/StyleRuleSet.hpp @@ -0,0 +1,55 @@ +#pragma once +#include "StyleRule.hpp" +#include "cru/common/Base.hpp" +#include "cru/common/Event.hpp" +#include "gsl/gsl_assert" + +namespace cru::ui::style { +class StyleRuleSet : public Object { + public: + StyleRuleSet() : control_(nullptr) {} + explicit StyleRuleSet(controls::Control* control) : control_(control) {} + + CRU_DELETE_COPY(StyleRuleSet) + CRU_DELETE_MOVE(StyleRuleSet) + + ~StyleRuleSet() override = default; + + public: + gsl::index GetSize() const { return static_cast(rules_.size()); } + const std::vector& GetRules() const { return rules_; } + + void AddStyleRule(StyleRule rule) { + AddStyleRule(std::move(rule), GetSize()); + } + + void AddStyleRule(StyleRule rule, gsl::index index); + + template + 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); + + const StyleRule& operator[](gsl::index index) const { return rules_[index]; } + + private: + void UpdateChangeListener(); + void UpdateStyle(); + + private: + controls::Control* control_; + + std::vector rules_; + + EventRevokerListGuard guard_; +}; +} // namespace cru::ui::style diff --git a/include/cru/ui/style/Styler.hpp b/include/cru/ui/style/Styler.hpp index 2aece114..10b169b1 100644 --- a/include/cru/ui/style/Styler.hpp +++ b/include/cru/ui/style/Styler.hpp @@ -2,19 +2,24 @@ #include "../Base.hpp" #include "ApplyBorderStyleInfo.hpp" #include "cru/common/Base.hpp" +#include "cru/common/ClonablePtr.hpp" #include namespace cru::ui::style { class Styler : public Object { public: - virtual void Apply(controls::Control* control) const; + virtual void Apply(controls::Control* control) const = 0; virtual Styler* Clone() const = 0; }; class BorderStyler : public Styler { public: + static ClonablePtr Create(ApplyBorderStyleInfo style) { + return ClonablePtr(new BorderStyler(std::move(style))); + } + explicit BorderStyler(ApplyBorderStyleInfo style); void Apply(controls::Control* control) const override; diff --git a/src/ui/UiManager.cpp b/src/ui/UiManager.cpp index 62995f86..bb7f5841 100644 --- a/src/ui/UiManager.cpp +++ b/src/ui/UiManager.cpp @@ -5,9 +5,14 @@ #include "cru/platform/graphics/Factory.hpp" #include "cru/platform/graphics/Font.hpp" #include "cru/platform/gui/UiApplication.hpp" +#include "cru/ui/style/ApplyBorderStyleInfo.hpp" +#include "cru/ui/style/Condition.hpp" +#include "cru/ui/style/Styler.hpp" namespace cru::ui { using namespace cru::platform::graphics; +using namespace cru::ui::style; +using namespace cru::ui::helper; namespace { std::unique_ptr CreateSolidColorBrush(IGraphFactory* factory, @@ -35,49 +40,59 @@ UiManager::UiManager() { theme_resource_.default_font = factory->CreateFont(theme_resource_.default_font_family, 24.0f); - const auto black_brush = std::shared_ptr( - CreateSolidColorBrush(factory, colors::black)); + const auto black_brush = + std::shared_ptr( + CreateSolidColorBrush(factory, colors::black)); theme_resource_.text_brush = black_brush; theme_resource_.text_selection_brush = CreateSolidColorBrush(factory, colors::skyblue); theme_resource_.caret_brush = black_brush; - theme_resource_.button_style.normal.border_brush = - CreateSolidColorBrush(factory, Color::FromHex(0x00bfff)); - theme_resource_.button_style.hover.border_brush = - CreateSolidColorBrush(factory, Color::FromHex(0x47d1ff)); - theme_resource_.button_style.press.border_brush = - CreateSolidColorBrush(factory, Color::FromHex(0x91e4ff)); - theme_resource_.button_style.press_cancel.border_brush = - CreateSolidColorBrush(factory, Color::FromHex(0x91e4ff)); - - theme_resource_.button_style.normal.border_thickness = - theme_resource_.button_style.hover.border_thickness = - theme_resource_.button_style.press.border_thickness = - theme_resource_.button_style.press_cancel.border_thickness = - Thickness(3); - - theme_resource_.button_style.normal.border_radius = - theme_resource_.button_style.hover.border_radius = - theme_resource_.button_style.press.border_radius = - theme_resource_.button_style.press_cancel.border_radius = - CornerRadius({5, 5}); - - theme_resource_.text_box_border_style.normal.border_brush = - CreateSolidColorBrush(factory, Color::FromHex(0xced4da)); - theme_resource_.text_box_border_style.normal.border_radius = CornerRadius(5); - theme_resource_.text_box_border_style.normal.border_thickness = Thickness(1); - - theme_resource_.text_box_border_style.hover = - theme_resource_.text_box_border_style.normal; - - theme_resource_.text_box_border_style.focus.border_brush = - CreateSolidColorBrush(factory, Color::FromHex(0x495057)); - theme_resource_.text_box_border_style.focus.border_radius = CornerRadius(5); - theme_resource_.text_box_border_style.focus.border_thickness = Thickness(1); - - theme_resource_.text_box_border_style.focus_hover = - theme_resource_.text_box_border_style.focus; + theme_resource_.button_style.AddStyleRule( + {ClickStateCondition::Create(ClickState::None), + BorderStyler::Create(ApplyBorderStyleInfo{ + CreateSolidColorBrush(factory, Color::FromHex(0x00bfff)), + Thickness(3), CornerRadius(5), nullptr, nullptr}), + u"DefaultButtonNormal"}); + theme_resource_.button_style.AddStyleRule( + {ClickStateCondition::Create(ClickState::Hover), + BorderStyler::Create(ApplyBorderStyleInfo{ + CreateSolidColorBrush(factory, Color::FromHex(0x47d1ff)), + Thickness(3), CornerRadius(5), nullptr, nullptr}), + u"DefaultButtonHover"}); + theme_resource_.button_style.AddStyleRule( + {ClickStateCondition::Create(ClickState::Press), + BorderStyler::Create(ApplyBorderStyleInfo{ + CreateSolidColorBrush(factory, Color::FromHex(0x91e4ff)), + Thickness(3), CornerRadius(5), nullptr, nullptr}), + u"DefaultButtonPress"}); + theme_resource_.button_style.AddStyleRule( + {ClickStateCondition::Create(ClickState::PressInactive), + BorderStyler::Create(ApplyBorderStyleInfo{ + CreateSolidColorBrush(factory, Color::FromHex(0x91e4ff)), + Thickness(3), CornerRadius(5), nullptr, nullptr}), + u"DefaultButtonPressInactive"}); + + theme_resource_.text_box_style.AddStyleRule( + {HoverCondition::Create(false), + BorderStyler::Create(ApplyBorderStyleInfo{ + CreateSolidColorBrush(factory, Color::FromHex(0xced4da)), + Thickness(1), CornerRadius(5), nullptr, nullptr}), + u"DefaultTextBoxNormal"}); + + theme_resource_.text_box_style.AddStyleRule( + {HoverCondition::Create(true), + BorderStyler::Create(ApplyBorderStyleInfo{ + CreateSolidColorBrush(factory, Color::FromHex(0xced4da)), + Thickness(1), CornerRadius(5), nullptr, nullptr}), + u"DefaultTextBoxHover"}); + + theme_resource_.text_box_style.AddStyleRule( + {FocusCondition::Create(true), + BorderStyler::Create(ApplyBorderStyleInfo{ + CreateSolidColorBrush(factory, Color::FromHex(0x495057)), + Thickness(1), CornerRadius(5), nullptr, nullptr}), + u"DefaultTextBoxHover"}); } UiManager::~UiManager() = default; diff --git a/src/ui/controls/Button.cpp b/src/ui/controls/Button.cpp index 6f19e6b9..7858eadb 100644 --- a/src/ui/controls/Button.cpp +++ b/src/ui/controls/Button.cpp @@ -13,50 +13,37 @@ namespace cru::ui::controls { using cru::platform::gui::SystemCursorType; namespace { -void Set(render::BorderRenderObject* o, const ButtonStateStyle& s) { - o->SetBorderBrush(s.border_brush); - o->SetBorderThickness(s.border_thickness); - o->SetBorderRadius(s.border_radius); - o->SetForegroundBrush(s.foreground_brush); - o->SetBackgroundBrush(s.background_brush); -} - std::shared_ptr GetSystemCursor(SystemCursorType type) { return GetUiApplication()->GetCursorManager()->GetSystemCursor(type); } } // namespace Button::Button() : click_detector_(this) { - style_ = UiManager::GetInstance()->GetThemeResources()->button_style; - render_object_ = std::make_unique(); render_object_->SetAttachedControl(this); SetContainerRenderObject(render_object_.get()); - - Set(render_object_.get(), style_.normal); render_object_->SetBorderEnabled(true); click_detector_.StateChangeEvent()->AddHandler( [this](const helper::ClickState& state) { switch (state) { case helper::ClickState::None: - Set(render_object_.get(), style_.normal); SetCursor(GetSystemCursor(SystemCursorType::Arrow)); break; case helper::ClickState::Hover: - Set(render_object_.get(), style_.hover); SetCursor(GetSystemCursor(SystemCursorType::Hand)); break; case helper::ClickState::Press: - Set(render_object_.get(), style_.press); SetCursor(GetSystemCursor(SystemCursorType::Hand)); break; case helper::ClickState::PressInactive: - Set(render_object_.get(), style_.press_cancel); SetCursor(GetSystemCursor(SystemCursorType::Arrow)); break; } }); + + GetStyleRuleSet()->Set( + UiManager::GetInstance()->GetThemeResources()->button_style); } Button::~Button() = default; diff --git a/src/ui/controls/Control.cpp b/src/ui/controls/Control.cpp index c1316a62..1c4ffe51 100644 --- a/src/ui/controls/Control.cpp +++ b/src/ui/controls/Control.cpp @@ -6,6 +6,7 @@ #include "cru/ui/Base.hpp" #include "cru/ui/host/WindowHost.hpp" #include "cru/ui/render/RenderObject.hpp" +#include "cru/ui/style/StyleRuleSet.hpp" #include @@ -15,6 +16,8 @@ using platform::gui::IUiApplication; using platform::gui::SystemCursorType; Control::Control() { + style_rule_set_ = std::make_unique(this); + MouseEnterEvent()->Direct()->AddHandler([this](event::MouseEventArgs&) { this->is_mouse_over_ = true; this->OnMouseHoverChange(true); @@ -94,6 +97,10 @@ void Control::SetCursor(std::shared_ptr cursor) { } } +style::StyleRuleSet* Control::GetStyleRuleSet() { + return style_rule_set_.get(); +} + void Control::AddChild(Control* control, const Index position) { Expects(control->GetParent() == nullptr); // The control already has a parent. diff --git a/src/ui/controls/TextBox.cpp b/src/ui/controls/TextBox.cpp index 6ba6ecb2..031894c0 100644 --- a/src/ui/controls/TextBox.cpp +++ b/src/ui/controls/TextBox.cpp @@ -18,8 +18,6 @@ TextBox::TextBox() scroll_render_object_(new ScrollRenderObject()) { const auto theme_resources = UiManager::GetInstance()->GetThemeResources(); - border_style_ = theme_resources->text_box_border_style; - text_render_object_ = std::make_unique( theme_resources->text_brush, theme_resources->default_font, theme_resources->text_selection_brush, theme_resources->caret_brush); @@ -38,17 +36,8 @@ TextBox::TextBox() service_->SetEditable(true); border_render_object_->SetBorderEnabled(true); - border_render_object_->SetBorderStyle(border_style_.normal); - - GainFocusEvent()->Direct()->AddHandler([this](event::FocusChangeEventArgs&) { - this->service_->SetCaretVisible(true); - this->UpdateBorderStyle(); - }); - LoseFocusEvent()->Direct()->AddHandler([this](event::FocusChangeEventArgs&) { - this->service_->SetCaretVisible(false); - this->UpdateBorderStyle(); - }); + GetStyleRuleSet()->Set(theme_resources->text_box_style); } TextBox::~TextBox() {} @@ -65,19 +54,7 @@ render::ScrollRenderObject* TextBox::GetScrollRenderObject() { return scroll_render_object_.get(); } -const TextBoxBorderStyle& TextBox::GetBorderStyle() { return border_style_; } - -void TextBox::SetBorderStyle(TextBoxBorderStyle border_style) { - border_style_ = std::move(border_style); -} - -void TextBox::OnMouseHoverChange(bool) { UpdateBorderStyle(); } - -void TextBox::UpdateBorderStyle() { - const auto focus = HasFocus(); - const auto hover = IsMouseOver(); - border_render_object_->SetBorderStyle( - focus ? (hover ? border_style_.focus_hover : border_style_.focus) - : (hover ? border_style_.hover : border_style_.normal)); +void TextBox::ApplyBorderStyle(const style::ApplyBorderStyleInfo& style) { + border_render_object_->ApplyBorderStyle(style); } } // namespace cru::ui::controls diff --git a/src/ui/render/BorderRenderObject.cpp b/src/ui/render/BorderRenderObject.cpp index 5abc7832..c176e760 100644 --- a/src/ui/render/BorderRenderObject.cpp +++ b/src/ui/render/BorderRenderObject.cpp @@ -17,15 +17,6 @@ BorderRenderObject::BorderRenderObject() { BorderRenderObject::~BorderRenderObject() {} -void BorderRenderObject::SetBorderStyle(const BorderStyle& style) { - border_brush_ = style.border_brush; - border_thickness_ = style.border_thickness; - border_radius_ = style.border_radius; - foreground_brush_ = style.foreground_brush; - background_brush_ = style.background_brush; - InvalidateLayout(); -} - void BorderRenderObject::ApplyBorderStyle( const style::ApplyBorderStyleInfo& style) { if (style.border_brush != nullptr) border_brush_ = style.border_brush; diff --git a/src/ui/style/Condition.cpp b/src/ui/style/Condition.cpp index 891eb062..f4866c04 100644 --- a/src/ui/style/Condition.cpp +++ b/src/ui/style/Condition.cpp @@ -51,6 +51,16 @@ bool FocusCondition::Judge(controls::Control* control) const { return control->HasFocus() == has_focus_; } +std::vector HoverCondition::ChangeOn( + controls::Control* control) const { + return {control->MouseEnterEvent()->Direct(), + control->MouseLeaveEvent()->Direct()}; +} + +bool HoverCondition::Judge(controls::Control* control) const { + return control->IsMouseOver() == hover_; +} + ClickStateCondition::ClickStateCondition(helper::ClickState click_state) : click_state_(click_state) {} diff --git a/src/ui/style/StyleRuleSet.cpp b/src/ui/style/StyleRuleSet.cpp index e69de29b..403fe114 100644 --- a/src/ui/style/StyleRuleSet.cpp +++ b/src/ui/style/StyleRuleSet.cpp @@ -0,0 +1,58 @@ +#include "cru/ui/style/StyleRuleSet.hpp" +#include "cru/common/Event.hpp" +#include "gsl/gsl_assert" + +#include + +namespace cru::ui::style { +void StyleRuleSet::AddStyleRule(StyleRule rule, gsl::index index) { + Expects(index >= 0 && index <= GetSize()); + + rules_.insert(rules_.cbegin() + index, std::move(rule)); + + UpdateChangeListener(); + UpdateStyle(); +} + +void StyleRuleSet::RemoveStyleRule(gsl::index index, gsl::index count) { + Expects(index >= 0); + Expects(count >= 0 && index + count <= GetSize()); + + rules_.erase(rules_.cbegin() + index, rules_.cbegin() + index + count); + + UpdateChangeListener(); + UpdateStyle(); +} + +void StyleRuleSet::Set(const StyleRuleSet& other) { + rules_ = other.rules_; + UpdateChangeListener(); + UpdateStyle(); +} + +void StyleRuleSet::UpdateChangeListener() { + if (control_ == nullptr) return; + + guard_.Clear(); + + std::unordered_set events; + for (const auto& rule : rules_) { + auto e = rule.GetCondition()->ChangeOn(control_); + events.insert(e.cbegin(), e.cend()); + } + + for (auto e : events) { + guard_ += e->AddSpyOnlyHandler([this] { this->UpdateStyle(); }); + } +} + +void StyleRuleSet::UpdateStyle() { + if (control_ == nullptr) return; + + for (const auto& rule : rules_) { + if (rule.GetCondition()->Judge(control_)) { + rule.GetStyler()->Apply(control_); + } + } +} +} // namespace cru::ui::style diff --git a/src/win/gui/Window.cpp b/src/win/gui/Window.cpp index 174b8931..efd3bfcc 100644 --- a/src/win/gui/Window.cpp +++ b/src/win/gui/Window.cpp @@ -367,9 +367,9 @@ RECT WinNativeWindow::GetClientRectPixel() { } void WinNativeWindow::OnDestroyInternal() { + destroy_event_.Raise(nullptr); application_->GetWindowManager()->UnregisterWindow(hwnd_); hwnd_ = nullptr; - destroy_event_.Raise(nullptr); if (!sync_flag_) { sync_flag_ = true; delete this; -- cgit v1.2.3