aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/cru/common/ClonablePtr.hpp7
-rw-r--r--include/cru/common/Event.hpp4
-rw-r--r--include/cru/ui/Base.hpp12
-rw-r--r--include/cru/ui/UiManager.hpp5
-rw-r--r--include/cru/ui/controls/Base.hpp22
-rw-r--r--include/cru/ui/controls/Button.hpp5
-rw-r--r--include/cru/ui/controls/Control.hpp5
-rw-r--r--include/cru/ui/controls/TextBox.hpp14
-rw-r--r--include/cru/ui/helper/ClickDetector.hpp2
-rw-r--r--include/cru/ui/render/BorderRenderObject.hpp2
-rw-r--r--include/cru/ui/style/Condition.hpp42
-rw-r--r--include/cru/ui/style/StyleRuleSet.hpp55
-rw-r--r--include/cru/ui/style/Styler.hpp7
-rw-r--r--src/ui/UiManager.cpp91
-rw-r--r--src/ui/controls/Button.cpp19
-rw-r--r--src/ui/controls/Control.cpp7
-rw-r--r--src/ui/controls/TextBox.cpp29
-rw-r--r--src/ui/render/BorderRenderObject.cpp9
-rw-r--r--src/ui/style/Condition.cpp10
-rw-r--r--src/ui/style/StyleRuleSet.cpp58
-rw-r--r--src/win/gui/Window.cpp2
21 files changed, 262 insertions, 145 deletions
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 <typename TClonable>
class ClonablePtr {
+ template <typename T>
+ friend class ClonablePtr;
+
public:
using element_type = typename std::unique_ptr<TClonable>::element_type;
using pointer = typename std::unique_ptr<TClonable>::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<element_type>&& p) noexcept
: ptr_(std::move(p)) {}
template <typename O,
@@ -52,7 +55,7 @@ class ClonablePtr {
}
ClonablePtr& operator=(const ClonablePtr& other) {
if (this != &other) {
- ptr_ = std::unique_ptr<element_type>(other.ptr->Clone());
+ ptr_ = std::unique_ptr<element_type>(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<void()>;
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<TEventArgs> {
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<platform::graphics::IBrush> border_brush;
- Thickness border_thickness;
- CornerRadius border_radius;
- std::shared_ptr<platform::graphics::IBrush> foreground_brush;
- std::shared_ptr<platform::graphics::IBrush> 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 <memory>
#include <string>
@@ -13,8 +14,8 @@ struct ThemeResources {
std::shared_ptr<platform::graphics::IBrush> text_brush;
std::shared_ptr<platform::graphics::IBrush> text_selection_brush;
std::shared_ptr<platform::graphics::IBrush> 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::BorderRenderObject> 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<platform::gui::ICursor> 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<platform::gui::ICursor> cursor_ = nullptr;
+
+ std::unique_ptr<style::StyleRuleSet> 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 <memory>
@@ -7,7 +8,7 @@ namespace cru::ui::controls {
template <typename TControl>
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<render::TextRenderObject*> 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<render::BorderRenderObject> border_render_object_;
std::unique_ptr<render::ScrollRenderObject> scroll_render_object_;
std::unique_ptr<render::TextRenderObject> text_render_object_;
- TextBoxBorderStyle border_style_;
-
std::unique_ptr<TextControlService<TextBox>> 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<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);
@@ -51,6 +66,10 @@ class OrCondition : public CompoundCondition {
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;
@@ -64,8 +83,31 @@ class FocusCondition : public Condition {
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;
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<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);
+
+ const StyleRule& operator[](gsl::index index) const { return rules_[index]; }
+
+ private:
+ void UpdateChangeListener();
+ void UpdateStyle();
+
+ private:
+ controls::Control* control_;
+
+ std::vector<StyleRule> 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 <memory>
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<BorderStyler> Create(ApplyBorderStyleInfo style) {
+ return ClonablePtr<BorderStyler>(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<ISolidColorBrush> 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<platform::graphics::ISolidColorBrush>(
- CreateSolidColorBrush(factory, colors::black));
+ const auto black_brush =
+ std::shared_ptr<platform::graphics::ISolidColorBrush>(
+ 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<platform::gui::ICursor> 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::BorderRenderObject>();
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 <memory>
@@ -15,6 +16,8 @@ using platform::gui::IUiApplication;
using platform::gui::SystemCursorType;
Control::Control() {
+ style_rule_set_ = std::make_unique<style::StyleRuleSet>(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<ICursor> 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<TextRenderObject>(
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<IBaseEvent*> 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 <unordered_set>
+
+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<IBaseEvent*> 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;