diff options
Diffstat (limited to 'src/ui/style')
-rw-r--r-- | src/ui/style/Condition.cpp | 84 | ||||
-rw-r--r-- | src/ui/style/StyleRule.cpp | 17 | ||||
-rw-r--r-- | src/ui/style/StyleRuleSet.cpp | 97 | ||||
-rw-r--r-- | src/ui/style/Styler.cpp | 29 |
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 |