aboutsummaryrefslogtreecommitdiff
path: root/src/ui/style
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/style')
-rw-r--r--src/ui/style/Condition.cpp84
-rw-r--r--src/ui/style/StyleRule.cpp17
-rw-r--r--src/ui/style/StyleRuleSet.cpp97
-rw-r--r--src/ui/style/Styler.cpp29
4 files changed, 227 insertions, 0 deletions
diff --git a/src/ui/style/Condition.cpp b/src/ui/style/Condition.cpp
new file mode 100644
index 00000000..f4866c04
--- /dev/null
+++ b/src/ui/style/Condition.cpp
@@ -0,0 +1,84 @@
+#include "cru/ui/style/Condition.hpp"
+#include <memory>
+
+#include "cru/common/ClonablePtr.hpp"
+#include "cru/common/Event.hpp"
+#include "cru/ui/controls/Control.hpp"
+#include "cru/ui/controls/IClickableControl.hpp"
+#include "cru/ui/helper/ClickDetector.hpp"
+
+namespace cru::ui::style {
+CompoundCondition::CompoundCondition(
+ std::vector<ClonablePtr<Condition>> conditions)
+ : conditions_(std::move(conditions)) {}
+
+std::vector<IBaseEvent*> CompoundCondition::ChangeOn(
+ controls::Control* control) const {
+ std::vector<IBaseEvent*> result;
+
+ for (auto condition : conditions_) {
+ for (auto e : condition->ChangeOn(control)) {
+ result.push_back(e);
+ }
+ }
+
+ return result;
+}
+
+bool AndCondition::Judge(controls::Control* control) const {
+ for (auto condition : conditions_) {
+ if (!condition->Judge(control)) return false;
+ }
+ return true;
+}
+
+bool OrCondition::Judge(controls::Control* control) const {
+ for (auto condition : conditions_) {
+ if (condition->Judge(control)) return true;
+ }
+ return false;
+}
+
+FocusCondition::FocusCondition(bool has_focus) : has_focus_(has_focus) {}
+
+std::vector<IBaseEvent*> FocusCondition::ChangeOn(
+ controls::Control* control) const {
+ return {control->GainFocusEvent()->Direct(),
+ control->LoseFocusEvent()->Direct()};
+}
+
+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) {}
+
+std::vector<IBaseEvent*> ClickStateCondition::ChangeOn(
+ controls::Control* control) const {
+ auto clickable_control = dynamic_cast<controls::IClickableControl*>(control);
+ if (clickable_control) {
+ return {clickable_control->ClickStateChangeEvent()};
+ } else {
+ return {};
+ }
+}
+
+bool ClickStateCondition::Judge(controls::Control* control) const {
+ auto clickable_control = dynamic_cast<controls::IClickableControl*>(control);
+ if (clickable_control) {
+ return clickable_control->GetClickState() == click_state_;
+ }
+ return false;
+}
+} // namespace cru::ui::style
diff --git a/src/ui/style/StyleRule.cpp b/src/ui/style/StyleRule.cpp
new file mode 100644
index 00000000..1a72a970
--- /dev/null
+++ b/src/ui/style/StyleRule.cpp
@@ -0,0 +1,17 @@
+#include "cru/ui/style/StyleRule.hpp"
+
+namespace cru::ui::style {
+StyleRule::StyleRule(ClonablePtr<Condition> condition,
+ ClonablePtr<Styler> 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) {
+ styler_->Apply(control);
+ }
+ return active;
+}
+} // namespace cru::ui::style
diff --git a/src/ui/style/StyleRuleSet.cpp b/src/ui/style/StyleRuleSet.cpp
new file mode 100644
index 00000000..537d1956
--- /dev/null
+++ b/src/ui/style/StyleRuleSet.cpp
@@ -0,0 +1,97 @@
+#include "cru/ui/style/StyleRuleSet.hpp"
+#include "cru/common/Event.hpp"
+#include "cru/ui/controls/Control.hpp"
+#include "gsl/gsl_assert"
+
+#include <unordered_set>
+
+namespace cru::ui::style {
+StyleRuleSet::StyleRuleSet(StyleRuleSet* parent) { SetParent(parent); }
+
+void StyleRuleSet::SetParent(StyleRuleSet* parent) {
+ if (parent == parent_) return;
+ parent_change_event_guard_.Reset();
+ parent_ = parent;
+ if (parent != nullptr) {
+ parent_change_event_guard_.Reset(parent->ChangeEvent()->AddSpyOnlyHandler(
+ [this] { this->RaiseChangeEvent(); }));
+ }
+ RaiseChangeEvent();
+}
+
+void StyleRuleSet::AddStyleRule(StyleRule rule, gsl::index index) {
+ Expects(index >= 0 && index <= GetSize());
+
+ rules_.insert(rules_.cbegin() + index, std::move(rule));
+
+ RaiseChangeEvent();
+}
+
+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);
+
+ RaiseChangeEvent();
+}
+
+void StyleRuleSet::Set(const StyleRuleSet& other, bool set_parent) {
+ rules_ = other.rules_;
+ if (set_parent) parent_ = other.parent_;
+
+ RaiseChangeEvent();
+}
+
+StyleRuleSetBind::StyleRuleSetBind(controls::Control* control,
+ StyleRuleSet* ruleset)
+ : control_(control), ruleset_(ruleset) {
+ Expects(control);
+ Expects(ruleset);
+
+ ruleset->ChangeEvent()->AddSpyOnlyHandler([this] {
+ UpdateRuleSetChainCache();
+ UpdateChangeListener();
+ UpdateStyle();
+ });
+}
+
+void StyleRuleSetBind::UpdateRuleSetChainCache() {
+ ruleset_chain_cache_.clear();
+ auto parent = ruleset_;
+ while (parent != nullptr) {
+ ruleset_chain_cache_.push_back(parent);
+ parent = parent->GetParent();
+ }
+}
+
+void StyleRuleSetBind::UpdateChangeListener() {
+ guard_.Clear();
+
+ std::unordered_set<IBaseEvent*> events;
+
+ // ruleset order does not matter
+ for (auto ruleset : ruleset_chain_cache_) {
+ for (const auto& rule : ruleset->GetRules()) {
+ auto e = rule.GetCondition()->ChangeOn(control_);
+ events.insert(e.cbegin(), e.cend());
+ }
+ }
+
+ for (auto e : events) {
+ guard_ += e->AddSpyOnlyHandler([this] { this->UpdateStyle(); });
+ }
+}
+
+void StyleRuleSetBind::UpdateStyle() {
+ // cache is parent last, but when calculate style, parent first, so iterate
+ // reverse.
+ for (auto iter = ruleset_chain_cache_.crbegin();
+ iter != ruleset_chain_cache_.crend(); ++iter) {
+ for (const auto& rule : (*iter)->GetRules())
+ if (rule.GetCondition()->Judge(control_)) {
+ rule.GetStyler()->Apply(control_);
+ }
+ }
+}
+} // namespace cru::ui::style
diff --git a/src/ui/style/Styler.cpp b/src/ui/style/Styler.cpp
new file mode 100644
index 00000000..da3a2247
--- /dev/null
+++ b/src/ui/style/Styler.cpp
@@ -0,0 +1,29 @@
+#include "cru/ui/style/Styler.hpp"
+
+#include "../Helper.hpp"
+#include "cru/common/ClonablePtr.hpp"
+#include "cru/platform/gui/Cursor.hpp"
+#include "cru/platform/gui/UiApplication.hpp"
+#include "cru/ui/controls/Control.hpp"
+#include "cru/ui/controls/IBorderControl.hpp"
+#include "cru/ui/style/ApplyBorderStyleInfo.hpp"
+
+namespace cru::ui::style {
+BorderStyler::BorderStyler(ApplyBorderStyleInfo style)
+ : style_(std::move(style)) {}
+
+void BorderStyler::Apply(controls::Control *control) const {
+ if (auto border_control = dynamic_cast<controls::IBorderControl *>(control)) {
+ border_control->ApplyBorderStyle(style_);
+ }
+}
+
+ClonablePtr<CursorStyler> CursorStyler::Create(
+ platform::gui::SystemCursorType type) {
+ return Create(GetUiApplication()->GetCursorManager()->GetSystemCursor(type));
+}
+
+void CursorStyler::Apply(controls::Control *control) const {
+ control->SetCursor(cursor_);
+}
+} // namespace cru::ui::style