aboutsummaryrefslogtreecommitdiff
path: root/src/ui/render/render_object.cpp
blob: 0035d1bee39af8668b05950e80059286c17db05f (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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include "render_object.hpp"

#include "cru_debug.hpp"

namespace cru::ui::render {
void RenderObject::SetRenderHost(IRenderHost* new_render_host) {
  if (new_render_host == render_host_) return;

  const auto old = render_host_;
  render_host_ = new_render_host;
  OnRenderHostChanged(old, new_render_host);
}

void RenderObject::AddChild(RenderObject* render_object, const int position) {
  if (render_object->GetParent() != nullptr)
    throw std::invalid_argument("Render object already has a parent.");

  if (position < 0)
    throw std::invalid_argument("Position index is less than 0.");

  if (static_cast<std::vector<RenderObject*>::size_type>(position) >
      children_.size())
    throw std::invalid_argument("Position index is out of bound.");

  children_.insert(children_.cbegin() + position, render_object);
  render_object->SetParent(this);
  OnAddChild(render_object, position);
}

void RenderObject::RemoveChild(const int position) {
  if (position < 0)
    throw std::invalid_argument("Position index is less than 0.");

  if (static_cast<std::vector<RenderObject*>::size_type>(position) >=
      children_.size())
    throw std::invalid_argument("Position index is out of bound.");

  const auto i = children_.cbegin() + position;
  const auto removed_child = *i;
  children_.erase(i);
  removed_child->SetParent(nullptr);
  OnRemoveChild(removed_child, position);
}

void RenderObject::Measure(const Size& available_size) {
  OnMeasureCore(available_size);
}

void RenderObject::Layout(const Rect& rect) {
  SetOffset(rect.GetLeftTop());
  SetSize(rect.GetSize());
  OnLayoutCore(Rect{Point::Zero(), rect.GetSize()});
}

void RenderObject::OnRenderHostChanged(IRenderHost* old_render_host,
                                       IRenderHost* new_render_host) {}

void RenderObject::InvalidateRenderHostPaint() const {
  if (render_host_ != nullptr) render_host_->InvalidatePaint();
}

void RenderObject::InvalidateRenderHostLayout() const {
  if (render_host_ != nullptr) render_host_->InvalidateLayout();
}

void RenderObject::OnParentChanged(RenderObject* old_parent,
                                   RenderObject* new_parent) {}

void RenderObject::OnAddChild(RenderObject* new_child, int position) {}

void RenderObject::OnRemoveChild(RenderObject* removed_child, int position) {}

void RenderObject::SetParent(RenderObject* new_parent) {
  const auto old_parent = parent_;
  parent_ = new_parent;
  OnParentChanged(old_parent, new_parent);
}

void RenderObject::OnMeasureCore(const Size& available_size) {
  Size margin_padding_size{
      margin_.GetHorizontalTotal() + padding_.GetHorizontalTotal(),
      margin_.GetVerticalTotal() + padding_.GetVerticalTotal()};
  const auto content_available_size = available_size - margin_padding_size;
  auto coerced_content_available_size = content_available_size;

  if (coerced_content_available_size.width < 0) {
    debug::DebugMessage(
        L"Measure: horizontal length of padding and margin is bigger than "
        L"available length.");
    coerced_content_available_size.width = 0;
  }
  if (coerced_content_available_size.height < 0) {
    debug::DebugMessage(
        L"Measure: vertical length of padding and margin is bigger than "
        L"available length.");
    coerced_content_available_size.height = 0;
  }

  const auto actual_content_size =
      OnMeasureContent(coerced_content_available_size);

  SetPreferredSize(margin_padding_size + content_available_size +
                   actual_content_size);
}

void RenderObject::OnLayoutCore(const Rect& rect) {
  Size margin_padding_size{
      margin_.GetHorizontalTotal() + padding_.GetHorizontalTotal(),
      margin_.GetVerticalTotal() + padding_.GetVerticalTotal()};
  const auto content_available_size = rect.GetSize() - margin_padding_size;
  auto coerced_content_available_size = content_available_size;

  if (coerced_content_available_size.width < 0) {
    debug::DebugMessage(
        L"Layout: horizontal length of padding and margin is bigger than "
        L"available length.");
    coerced_content_available_size.width = 0;
  }
  if (coerced_content_available_size.height < 0) {
    debug::DebugMessage(
        L"Layout: vertical length of padding and margin is bigger than "
        L"available length.");
    coerced_content_available_size.height = 0;
  }

  OnLayoutContent(Rect{margin_.left + padding_.left, margin_.top + padding_.top,
                       coerced_content_available_size.width,
                       coerced_content_available_size.height});
}
}  // namespace cru::ui::render