aboutsummaryrefslogtreecommitdiff
path: root/include/cru/ui/render/LayoutRenderObject.hpp
blob: b46ba0d09aec909d29de48be6aed6c5daf168e42 (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
#pragma once
#include "RenderObject.hpp"

#include "cru/platform/graph/util/Painter.hpp"

namespace cru::ui::render {
template <typename TChildLayoutData>
class LayoutRenderObject : public RenderObject {
 public:
  using ChildLayoutData = TChildLayoutData;

 protected:
  LayoutRenderObject() : RenderObject(ChildMode::Multiple) {}

 public:
  CRU_DELETE_COPY(LayoutRenderObject)
  CRU_DELETE_MOVE(LayoutRenderObject)

  ~LayoutRenderObject() override = default;

  const std::vector<ChildLayoutData>& GetChildLayoutDataList() const {
    return this->child_layout_data_;
  }

  void SetChildLayoutData(Index position, ChildLayoutData data) {
    Expects(position >= 0 &&
            position < static_cast<Index>(this->child_layout_data_.size()));
    this->child_layout_data_[position] = std::move(data);
    this->InvalidateLayout();
  }

  const ChildLayoutData& GetChildLayoutData(Index position) const {
    Expects(position >= 0 &&
            position < static_cast<Index>(this->child_layout_data_.size()));
    return this->child_layout_data_[position];
  }

  RenderObject* HitTest(const Point& point) override;

 protected:
  void OnAddChild(RenderObject* new_child, Index position) override;
  void OnRemoveChild(RenderObject* removed_child, Index position) override;

 private:
  std::vector<ChildLayoutData> child_layout_data_{};
};

template <typename TChildLayoutData>
RenderObject* LayoutRenderObject<TChildLayoutData>::HitTest(
    const Point& point) {
  const auto& children = GetChildren();
  for (auto i = children.crbegin(); i != children.crend(); ++i) {
    auto offset = (*i)->GetOffset();
    Point p{point.x - offset.x, point.y - offset.y};
    const auto result = (*i)->HitTest(p);
    if (result != nullptr) {
      return result;
    }
  }

  const auto margin = GetMargin();
  const auto size = GetSize();
  return Rect{margin.left, margin.top,
              std::max(size.width - margin.GetHorizontalTotal(), 0.0f),
              std::max(size.height - margin.GetVerticalTotal(), 0.0f)}
                 .IsPointInside(point)
             ? this
             : nullptr;
}  // namespace cru::ui::render

template <typename TChildLayoutData>
void LayoutRenderObject<TChildLayoutData>::OnAddChild(RenderObject* new_child,
                                                      const Index position) {
  CRU_UNUSED(new_child)

  child_layout_data_.emplace(child_layout_data_.cbegin() + position);
}

template <typename TChildLayoutData>
void LayoutRenderObject<TChildLayoutData>::OnRemoveChild(
    RenderObject* removed_child, const Index position) {
  CRU_UNUSED(removed_child)

  child_layout_data_.erase(child_layout_data_.cbegin() + position);
}
}  // namespace cru::ui::render