aboutsummaryrefslogtreecommitdiff
path: root/include/cru/ui/render/RenderObject.hpp
blob: 9de2cc27932c4cadffedda11ff13dfe4e5f88aa9 (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
131
132
133
134
135
136
137
138
139
140
141
142
#pragma once
#include "Base.hpp"

#include "MeasureRequirement.hpp"
#include "cru/common/Event.hpp"

namespace cru::ui::render {

// Render object will not destroy its children when destroyed. Control must
// manage lifecycle of its render objects. Since control will destroy its
// children when destroyed, render objects will be destroyed along with it.
//
// To write a custom RenderObject, override following methods:
// public:
//  void Draw(platform::graph::IPainter* painter) override;
//  RenderObject* HitTest(const Point& point) override;
// protected:
//  Size OnMeasureContent(const MeasureRequirement& requirement) override;
//  void OnLayoutContent(const Rect& content_rect) override;
class RenderObject : public Object {
  friend WindowRenderObject;

 protected:
  enum class ChildMode {
    None,
    Single,
    Multiple,
  };

  RenderObject() = default;
  RenderObject(ChildMode child_mode) : RenderObject() {
    SetChildMode(child_mode);
  }

 public:
  RenderObject(const RenderObject& other) = delete;
  RenderObject(RenderObject&& other) = delete;
  RenderObject& operator=(const RenderObject& other) = delete;
  RenderObject& operator=(RenderObject&& other) = delete;
  ~RenderObject() override = default;

  Control* GetAttachedControl() const { return control_; }
  void SetAttachedControl(Control* new_control) { control_ = new_control; }

  UiHost* GetUiHost() const { return ui_host_; }

  RenderObject* GetParent() const { return parent_; }

  const std::vector<RenderObject*>& GetChildren() const { return children_; }
  Index GetChildCount() const { return static_cast<Index>(children_.size()); }
  void AddChild(RenderObject* render_object, Index position);
  void RemoveChild(Index position);

  // Offset from parent's lefttop to lefttop of this render object. Margin is
  // accounted for.
  Point GetOffset() const { return offset_; }
  Size GetSize() const { return size_; }
  Point GetTotalOffset() const;
  Point FromRootToContent(const Point& point) const;

  Thickness GetMargin() const { return margin_; }
  void SetMargin(const Thickness& margin) { margin_ = margin; }

  Thickness GetPadding() const { return padding_; }
  void SetPadding(const Thickness& padding) { padding_ = padding; }

  Size GetMeasuredSize() const { return measured_size_; }

  void Measure(const MeasureRequirement& requirement);
  // Size of rect must not be negative.
  void Layout(const Rect& rect);

  virtual void Draw(platform::graph::IPainter* painter) = 0;

  // Param point must be relative the lefttop of render object including margin.
  // Add offset before pass point to children.
  virtual RenderObject* HitTest(const Point& point) = 0;

 public:
  void InvalidateLayout();
  void InvalidatePaint();

 protected:
  void SetChildMode(ChildMode mode) { child_mode_ = mode; }

 protected:
  virtual void OnParentChanged(RenderObject* old_parent,
                               RenderObject* new_parent);

  // default is to invalidate both layout and paint
  virtual void OnAddChild(RenderObject* new_child, Index position);
  // default is to invalidate both layout and paint
  virtual void OnRemoveChild(RenderObject* removed_child, Index position);

  // Size measure including margin and padding. Please reduce margin and padding
  // or other custom things and pass the result content measure requirement to
  // OnMeasureContent.
  // Return value must not be negative and not bigger than requirement.
  virtual Size OnMeasureCore(const MeasureRequirement& requirement);

  // Size including margin and padding. Please reduce margin and padding or
  // other custom things and pass the result content rect to OnLayoutContent.
  // Parameter size are never negative.
  virtual void OnLayoutCore(const Size& size);

  // Do not consider margin or padding in this method because they are already
  // considered in OnMeasureCore. Returned size should never be bigger than
  // requirement.
  virtual Size OnMeasureContent(const MeasureRequirement& requirement) = 0;

  // Lefttop of content_rect should be added when calculated children's offset.
  virtual void OnLayoutContent(const Rect& content_rect) = 0;

  virtual void OnAfterLayout();
  static void NotifyAfterLayoutRecursive(RenderObject* render_object);

  Rect GetPaddingRect() const;
  Rect GetContentRect() const;

 private:
  void SetParent(RenderObject* new_parent);

  void SetRenderHostRecursive(UiHost* host);

 private:
  Control* control_ = nullptr;
  UiHost* ui_host_ = nullptr;

  RenderObject* parent_ = nullptr;
  std::vector<RenderObject*> children_{};

  ChildMode child_mode_ = ChildMode::None;

  Point offset_{};
  Size size_{};

  Thickness margin_{};
  Thickness padding_{};

  Size measured_size_{};
};
}  // namespace cru::ui::render