aboutsummaryrefslogtreecommitdiff
path: root/src/ui/style/StyleRuleSet.cpp
blob: 24b88af987ab2452240ab293db627e7f42f0b5a7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#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) {
  rules_ = other.rules_;

  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