aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2020-06-22 01:09:24 +0800
committercrupest <crupest@outlook.com>2020-06-22 01:09:24 +0800
commit4f0a2f32c273780c32cc3937615c2a8bbd993aab (patch)
tree6e1f45447854a40fe2d16ef9bec79f3c0fef030a
parentd86a71f79afe0e4dac768f61d6bff690567aca5b (diff)
downloadcru-4f0a2f32c273780c32cc3937615c2a8bbd993aab.tar.gz
cru-4f0a2f32c273780c32cc3937615c2a8bbd993aab.tar.bz2
cru-4f0a2f32c273780c32cc3937615c2a8bbd993aab.zip
...
-rw-r--r--demos/input_method/main.cpp2
-rw-r--r--include/cru/platform/GraphBase.hpp22
-rw-r--r--include/cru/ui/base.hpp6
-rw-r--r--include/cru/ui/render/BorderRenderObject.hpp8
-rw-r--r--include/cru/ui/render/CanvasRenderObject.hpp2
-rw-r--r--include/cru/ui/render/FlexLayoutRenderObject.hpp2
-rw-r--r--include/cru/ui/render/MeasureRequirement.hpp79
-rw-r--r--include/cru/ui/render/RenderObject.hpp48
-rw-r--r--include/cru/ui/render/ScrollRenderObject.hpp8
-rw-r--r--include/cru/ui/render/StackLayoutRenderObject.hpp2
-rw-r--r--include/cru/ui/render/TextRenderObject.hpp2
-rw-r--r--include/cru/ui/render/WindowRenderObject.hpp2
-rw-r--r--include/cru/win/graph/direct/TextLayout.hpp5
-rw-r--r--src/ui/CMakeLists.txt1
-rw-r--r--src/ui/UiHost.cpp11
-rw-r--r--src/ui/render/BorderRenderObject.cpp117
-rw-r--r--src/ui/render/CanvasRenderObject.cpp5
-rw-r--r--src/ui/render/FlexLayoutRenderObject.cpp180
-rw-r--r--src/ui/render/RenderObject.cpp94
-rw-r--r--src/ui/render/ScrollRenderObject.cpp77
-rw-r--r--src/ui/render/StackLayoutRenderObject.cpp15
-rw-r--r--src/ui/render/TextRenderObject.cpp10
-rw-r--r--src/ui/render/WindowRenderObject.cpp11
23 files changed, 481 insertions, 228 deletions
diff --git a/demos/input_method/main.cpp b/demos/input_method/main.cpp
index 45924c96..b109f5e7 100644
--- a/demos/input_method/main.cpp
+++ b/demos/input_method/main.cpp
@@ -135,7 +135,7 @@ int main() {
});
input_method_context->CompositionEndEvent()->AddHandler(
- [window, &input_method_context, &optional_composition_text](auto) {
+ [window, &optional_composition_text](auto) {
optional_composition_text = std::nullopt;
window->RequestRepaint();
});
diff --git a/include/cru/platform/GraphBase.hpp b/include/cru/platform/GraphBase.hpp
index af61eba3..0d4effd4 100644
--- a/include/cru/platform/GraphBase.hpp
+++ b/include/cru/platform/GraphBase.hpp
@@ -2,13 +2,17 @@
#include "cru/common/Base.hpp"
#include <cstdint>
+#include <limits>
#include <optional>
#include <utility>
namespace cru::platform {
+struct Size;
+
struct Point final {
constexpr Point() = default;
constexpr Point(const float x, const float y) : x(x), y(y) {}
+ explicit constexpr Point(const Size& size);
float x = 0;
float y = 0;
@@ -34,11 +38,20 @@ struct Size final {
constexpr Size() = default;
constexpr Size(const float width, const float height)
: width(width), height(height) {}
+ explicit constexpr Size(const Point& point)
+ : width(point.x), height(point.y) {}
+
+ constexpr static Size Infinate() {
+ return Size{std::numeric_limits<float>::max(),
+ std::numeric_limits<float>::max()};
+ }
float width = 0;
float height = 0;
};
+constexpr Point::Point(const Size& size) : x(size.width), y(size.height) {}
+
constexpr Size operator+(const Size& left, const Size& right) {
return Size(left.width + right.width, left.height + right.height);
}
@@ -88,6 +101,15 @@ struct Thickness final {
float bottom;
};
+constexpr Size operator+(const Size& size, const Thickness& thickness) {
+ return {size.width + thickness.left + thickness.right,
+ size.height + thickness.top + thickness.bottom};
+}
+
+constexpr Size operator+(const Thickness& thickness, const Size& size) {
+ return operator+(size, thickness);
+}
+
constexpr bool operator==(const Thickness& left, const Thickness& right) {
return left.left == right.left && left.top == right.top &&
left.right == right.right && left.bottom == right.bottom;
diff --git a/include/cru/ui/base.hpp b/include/cru/ui/base.hpp
index 97b0dbff..dacf2d6f 100644
--- a/include/cru/ui/base.hpp
+++ b/include/cru/ui/base.hpp
@@ -270,10 +270,8 @@ using FlexMainAlignment = Alignment;
using FlexCrossAlignment = Alignment;
struct FlexChildLayoutData {
- // nullopt stands for looking at my content
- std::optional<float> flex_basis = std::nullopt;
- float flex_grow = 0;
- float flex_shrink = 0;
+ float expand_factor = 0;
+ float shrink_factor = 1;
// nullopt stands for looking at parent's setting
std::optional<FlexCrossAlignment> cross_alignment = std::nullopt;
};
diff --git a/include/cru/ui/render/BorderRenderObject.hpp b/include/cru/ui/render/BorderRenderObject.hpp
index c3031f59..45df89f9 100644
--- a/include/cru/ui/render/BorderRenderObject.hpp
+++ b/include/cru/ui/render/BorderRenderObject.hpp
@@ -67,9 +67,9 @@ class BorderRenderObject : public RenderObject {
RenderObject* HitTest(const Point& point) override;
protected:
- void OnMeasureCore(const Size& available_size) override;
- void OnLayoutCore(const Rect& rect) override;
- Size OnMeasureContent(const Size& available_size) override;
+ Size OnMeasureCore(const MeasureRequirement& requirement) override;
+ void OnLayoutCore(const Size& size) override;
+ Size OnMeasureContent(const MeasureRequirement& requirement) override;
void OnLayoutContent(const Rect& content_rect) override;
void OnAfterLayout() override;
@@ -85,7 +85,7 @@ class BorderRenderObject : public RenderObject {
bool is_border_enabled_ = false;
std::shared_ptr<platform::graph::IBrush> border_brush_;
- platform::Thickness border_thickness_;
+ Thickness border_thickness_;
CornerRadius border_radius_;
std::shared_ptr<platform::graph::IBrush> foreground_brush_;
diff --git a/include/cru/ui/render/CanvasRenderObject.hpp b/include/cru/ui/render/CanvasRenderObject.hpp
index ba50a985..402302cb 100644
--- a/include/cru/ui/render/CanvasRenderObject.hpp
+++ b/include/cru/ui/render/CanvasRenderObject.hpp
@@ -28,7 +28,7 @@ class CanvasRenderObject : public RenderObject {
IEvent<CanvasPaintEventArgs>* PaintEvent() { return &paint_event_; }
protected:
- Size OnMeasureContent(const Size& available_size) override;
+ Size OnMeasureContent(const MeasureRequirement& requirement) override;
void OnLayoutContent(const Rect& content_rect) override;
private:
diff --git a/include/cru/ui/render/FlexLayoutRenderObject.hpp b/include/cru/ui/render/FlexLayoutRenderObject.hpp
index bc43141d..217ca6cb 100644
--- a/include/cru/ui/render/FlexLayoutRenderObject.hpp
+++ b/include/cru/ui/render/FlexLayoutRenderObject.hpp
@@ -31,7 +31,7 @@ class FlexLayoutRenderObject : public LayoutRenderObject<FlexChildLayoutData> {
}
protected:
- Size OnMeasureContent(const Size& available_size) override;
+ Size OnMeasureContent(const MeasureRequirement& requirement) override;
void OnLayoutContent(const Rect& content_rect) override;
private:
diff --git a/include/cru/ui/render/MeasureRequirement.hpp b/include/cru/ui/render/MeasureRequirement.hpp
new file mode 100644
index 00000000..83de255d
--- /dev/null
+++ b/include/cru/ui/render/MeasureRequirement.hpp
@@ -0,0 +1,79 @@
+#pragma once
+#include "Base.hpp"
+
+#include <limits>
+
+namespace cru::ui::render {
+class MeasureLength {
+ public:
+ struct tag_infinate_t {};
+ constexpr static tag_infinate_t tag_infinate{};
+
+ constexpr MeasureLength() : MeasureLength(0) {}
+ constexpr MeasureLength(tag_infinate_t) : length_(-1) {}
+ constexpr MeasureLength(float length) : length_(length) {
+ Expects(length >= 0);
+ }
+
+ MeasureLength(const MeasureLength& other) = default;
+ MeasureLength& operator=(const MeasureLength& other) = default;
+ MeasureLength& operator=(float length) {
+ Expects(length >= 0);
+ length_ = length;
+ return *this;
+ }
+
+ ~MeasureLength() = default;
+
+ constexpr static MeasureLength Infinate() {
+ return MeasureLength{tag_infinate};
+ }
+
+ constexpr bool IsInfinate() const { return length_ < 0; }
+ constexpr float GetLength() const {
+ return length_ < 0 ? std::numeric_limits<float>::max() : length_;
+ }
+
+ constexpr bool operator==(MeasureLength other) const {
+ return (length_ < 0 && other.length_ < 0) || length_ == other.length_;
+ }
+
+ constexpr bool operator!=(MeasureLength other) const {
+ return !operator==(other);
+ }
+
+ private:
+ // -1 for infinate
+ float length_;
+};
+
+struct MeasureRequirement {
+ MeasureLength max_width;
+ MeasureLength max_height;
+
+ constexpr MeasureRequirement() = default;
+ constexpr MeasureRequirement(MeasureLength max_width,
+ MeasureLength max_height)
+ : max_width(max_width), max_height(max_height) {}
+
+ constexpr MeasureRequirement(const Size& max_size)
+ : max_width(max_size.width), max_height(max_size.height) {}
+
+ constexpr bool Satisfy(const Size& size) const {
+ if (!max_width.IsInfinate() && max_width.GetLength() < size.width)
+ return false;
+ if (!max_height.IsInfinate() && max_height.GetLength() < size.height)
+ return false;
+ return true;
+ }
+
+ constexpr Size GetMaxSize() const {
+ return Size{max_width.GetLength(), max_height.GetLength()};
+ }
+
+ constexpr static MeasureRequirement Infinate() {
+ return MeasureRequirement{MeasureLength::Infinate(),
+ MeasureLength::Infinate()};
+ }
+};
+} // namespace cru::ui::render
diff --git a/include/cru/ui/render/RenderObject.hpp b/include/cru/ui/render/RenderObject.hpp
index 7cfa3883..9de2cc27 100644
--- a/include/cru/ui/render/RenderObject.hpp
+++ b/include/cru/ui/render/RenderObject.hpp
@@ -1,12 +1,22 @@
#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;
@@ -41,12 +51,12 @@ class RenderObject : public Object {
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_; }
- void SetOffset(const Point& offset) { offset_ = offset; }
+ Size GetSize() const { return size_; }
Point GetTotalOffset() const;
Point FromRootToContent(const Point& point) const;
- Size GetSize() const { return size_; }
- void SetSize(const Size& size) { size_ = size; }
Thickness GetMargin() const { return margin_; }
void SetMargin(const Thickness& margin) { margin_ = margin; }
@@ -54,16 +64,16 @@ class RenderObject : public Object {
Thickness GetPadding() const { return padding_; }
void SetPadding(const Thickness& padding) { padding_ = padding; }
- Size GetPreferredSize() const { return preferred_size_; }
- void SetPreferredSize(const Size& preferred_size) {
- preferred_size_ = preferred_size;
- }
+ Size GetMeasuredSize() const { return measured_size_; }
- void Measure(const Size& available_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:
@@ -82,9 +92,23 @@ class RenderObject : public Object {
// default is to invalidate both layout and paint
virtual void OnRemoveChild(RenderObject* removed_child, Index position);
- virtual void OnMeasureCore(const Size& available_size);
- virtual void OnLayoutCore(const Rect& rect);
- virtual Size OnMeasureContent(const Size& available_size) = 0;
+ // 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();
@@ -113,6 +137,6 @@ class RenderObject : public Object {
Thickness margin_{};
Thickness padding_{};
- Size preferred_size_{};
+ Size measured_size_{};
};
} // namespace cru::ui::render
diff --git a/include/cru/ui/render/ScrollRenderObject.hpp b/include/cru/ui/render/ScrollRenderObject.hpp
index dcf6dae6..924b8ca6 100644
--- a/include/cru/ui/render/ScrollRenderObject.hpp
+++ b/include/cru/ui/render/ScrollRenderObject.hpp
@@ -21,8 +21,12 @@ class ScrollRenderObject : public RenderObject {
void SetScrollOffset(const Point& offset);
protected:
- void OnAddChild(RenderObject* new_child, Index position) override;
- void OnRemoveChild(RenderObject* removed_child, Index position) override;
+ // Logic:
+ // If available size is bigger than child's preferred size, then child's
+ // preferred size is taken.
+ // If not, all available size is taken while forming a scroll area.
+ Size OnMeasureContent(const MeasureRequirement& requirement) override;
+ void OnLayoutContent(const Rect& content_rect) override;
private:
Point scroll_offset_;
diff --git a/include/cru/ui/render/StackLayoutRenderObject.hpp b/include/cru/ui/render/StackLayoutRenderObject.hpp
index a5bf9335..2320e1ca 100644
--- a/include/cru/ui/render/StackLayoutRenderObject.hpp
+++ b/include/cru/ui/render/StackLayoutRenderObject.hpp
@@ -11,7 +11,7 @@ class StackLayoutRenderObject
~StackLayoutRenderObject() = default;
protected:
- Size OnMeasureContent(const Size& available_size) override;
+ Size OnMeasureContent(const MeasureRequirement& requirement) override;
void OnLayoutContent(const Rect& content_rect) override;
};
} // namespace cru::ui::render
diff --git a/include/cru/ui/render/TextRenderObject.hpp b/include/cru/ui/render/TextRenderObject.hpp
index 7a81ba51..96bb5997 100644
--- a/include/cru/ui/render/TextRenderObject.hpp
+++ b/include/cru/ui/render/TextRenderObject.hpp
@@ -64,7 +64,7 @@ class TextRenderObject : public RenderObject {
RenderObject* HitTest(const Point& point) override;
protected:
- Size OnMeasureContent(const Size& available_size) override;
+ Size OnMeasureContent(const MeasureRequirement& requirement) override;
void OnLayoutContent(const Rect& content_rect) override;
void OnAfterLayout() override;
diff --git a/include/cru/ui/render/WindowRenderObject.hpp b/include/cru/ui/render/WindowRenderObject.hpp
index 00bce29b..d993dc58 100644
--- a/include/cru/ui/render/WindowRenderObject.hpp
+++ b/include/cru/ui/render/WindowRenderObject.hpp
@@ -16,7 +16,7 @@ class WindowRenderObject : public RenderObject {
RenderObject* HitTest(const Point& point) override;
protected:
- Size OnMeasureContent(const Size& available_size) override;
+ Size OnMeasureContent(const MeasureRequirement& requirement) override;
void OnLayoutContent(const Rect& content_rect) override;
private:
diff --git a/include/cru/win/graph/direct/TextLayout.hpp b/include/cru/win/graph/direct/TextLayout.hpp
index 1a378ed4..40c63dbe 100644
--- a/include/cru/win/graph/direct/TextLayout.hpp
+++ b/include/cru/win/graph/direct/TextLayout.hpp
@@ -4,6 +4,7 @@
#include "cru/platform/graph/TextLayout.hpp"
+#include <limits>
#include <memory>
namespace cru::platform::graph::win::direct {
@@ -47,8 +48,8 @@ class DWriteTextLayout : public DirectGraphResource,
std::string text_;
std::wstring w_text_;
std::shared_ptr<DWriteFont> font_;
- float max_width_ = 10000.0f;
- float max_height_ = 10000.0f;
+ float max_width_ = std::numeric_limits<float>::max();
+ float max_height_ = std::numeric_limits<float>::max();
Microsoft::WRL::ComPtr<IDWriteTextLayout> text_layout_;
};
} // namespace cru::platform::graph::win::direct
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt
index f37982e9..68efa903 100644
--- a/src/ui/CMakeLists.txt
+++ b/src/ui/CMakeLists.txt
@@ -54,6 +54,7 @@ target_sources(cru_ui PUBLIC
${CRU_UI_INCLUDE_DIR}/render/FlexLayoutRenderObject.hpp
${CRU_UI_INCLUDE_DIR}/render/LayoutRenderObject.hpp
${CRU_UI_INCLUDE_DIR}/render/LayoutUtility.hpp
+ ${CRU_UI_INCLUDE_DIR}/render/MeasureRequirement.hpp
${CRU_UI_INCLUDE_DIR}/render/RenderObject.hpp
${CRU_UI_INCLUDE_DIR}/render/ScrollRenderObject.hpp
${CRU_UI_INCLUDE_DIR}/render/StackLayoutRenderObject.hpp
diff --git a/src/ui/UiHost.cpp b/src/ui/UiHost.cpp
index 069e68de..7047d43f 100644
--- a/src/ui/UiHost.cpp
+++ b/src/ui/UiHost.cpp
@@ -1,12 +1,12 @@
#include "cru/ui/UiHost.hpp"
+#include "RoutedEventDispatch.hpp"
#include "cru/common/Logger.hpp"
#include "cru/platform/graph/Painter.hpp"
#include "cru/platform/native/UiApplication.hpp"
#include "cru/platform/native/Window.hpp"
-#include "cru/ui/render/WindowRenderObject.hpp"
#include "cru/ui/Window.hpp"
-#include "RoutedEventDispatch.hpp"
+#include "cru/ui/render/WindowRenderObject.hpp"
namespace cru::ui {
using platform::native::INativeWindow;
@@ -28,7 +28,6 @@ CRU_DEFINE_EVENT_NAME(MouseDown)
CRU_DEFINE_EVENT_NAME(MouseUp)
CRU_DEFINE_EVENT_NAME(KeyDown)
CRU_DEFINE_EVENT_NAME(KeyUp)
-CRU_DEFINE_EVENT_NAME(Char)
#undef CRU_DEFINE_EVENT_NAME
} // namespace event_names
@@ -93,10 +92,10 @@ inline void BindNativeEvent(
} // namespace
UiHost::UiHost(Window* window)
- : mouse_hover_control_(nullptr),
+ : window_control_(window),
+ mouse_hover_control_(nullptr),
focus_control_(window),
- mouse_captured_control_(nullptr),
- window_control_(window) {
+ mouse_captured_control_(nullptr) {
native_window_resolver_ =
IUiApplication::GetInstance()->CreateWindow(nullptr);
diff --git a/src/ui/render/BorderRenderObject.cpp b/src/ui/render/BorderRenderObject.cpp
index a656cb99..fbc3c65f 100644
--- a/src/ui/render/BorderRenderObject.cpp
+++ b/src/ui/render/BorderRenderObject.cpp
@@ -73,84 +73,97 @@ RenderObject* BorderRenderObject::HitTest(const Point& point) {
}
}
-void BorderRenderObject::OnMeasureCore(const Size& available_size) {
+Size BorderRenderObject::OnMeasureCore(const MeasureRequirement& requirement) {
+ if (!is_border_enabled_) {
+ return RenderObject::OnMeasureCore(requirement);
+ }
+
const auto margin = GetMargin();
const auto padding = GetPadding();
- Size margin_border_padding_size{
- margin.GetHorizontalTotal() + padding.GetHorizontalTotal(),
- margin.GetVerticalTotal() + padding.GetVerticalTotal()};
-
- if (is_border_enabled_) {
- margin_border_padding_size.width += border_thickness_.GetHorizontalTotal();
- margin_border_padding_size.height += border_thickness_.GetVerticalTotal();
+ const Size space_size{margin.GetHorizontalTotal() +
+ padding.GetHorizontalTotal() +
+ border_thickness_.GetHorizontalTotal(),
+ margin.GetVerticalTotal() + padding.GetVerticalTotal() +
+ border_thickness_.GetVerticalTotal()};
+
+ auto coerced_space_size = space_size;
+
+ MeasureRequirement content_requirement = requirement;
+
+ if (!requirement.max_width.IsInfinate()) {
+ const auto max_width = requirement.max_width.GetLength();
+ if (coerced_space_size.width > max_width) {
+ log::Warn(
+ "Measure: horizontal length of padding and margin is bigger than "
+ "available length.");
+ coerced_space_size.width = max_width;
+ }
+ content_requirement.max_width = max_width - coerced_space_size.width;
}
- auto coerced_margin_border_padding_size = margin_border_padding_size;
- if (coerced_margin_border_padding_size.width > available_size.width) {
- log::Warn(
- "Measure: horizontal length of padding, border and margin is bigger "
- "than available length.");
- coerced_margin_border_padding_size.width = available_size.width;
- }
- if (coerced_margin_border_padding_size.height > available_size.height) {
- log::Warn(
- "Measure: vertical length of padding, border and margin is bigger "
- "than available length.");
- coerced_margin_border_padding_size.height = available_size.height;
+ if (!requirement.max_height.IsInfinate()) {
+ const auto max_height = requirement.max_height.GetLength();
+ if (coerced_space_size.height > max_height) {
+ log::Warn(
+ "Measure: horizontal length of padding and margin is bigger than "
+ "available length.");
+ coerced_space_size.height = max_height;
+ }
+ content_requirement.max_height = max_height - coerced_space_size.height;
}
- const auto coerced_content_available_size =
- available_size - coerced_margin_border_padding_size;
+ const auto content_size = OnMeasureContent(content_requirement);
- const auto actual_content_size =
- OnMeasureContent(coerced_content_available_size);
+ return coerced_space_size + content_size;
+} // namespace cru::ui::render
- SetPreferredSize(coerced_margin_border_padding_size + actual_content_size);
-}
+void BorderRenderObject::OnLayoutCore(const Size& size) {
+ if (!is_border_enabled_) {
+ return RenderObject::OnLayoutCore(size);
+ }
-void BorderRenderObject::OnLayoutCore(const Rect& rect) {
const auto margin = GetMargin();
const auto padding = GetPadding();
- Size margin_border_padding_size{
- margin.GetHorizontalTotal() + padding.GetHorizontalTotal(),
- margin.GetVerticalTotal() + padding.GetVerticalTotal()};
-
- if (is_border_enabled_) {
- margin_border_padding_size.width += border_thickness_.GetHorizontalTotal();
- margin_border_padding_size.height += border_thickness_.GetVerticalTotal();
- }
+ Size space_size{margin.GetHorizontalTotal() + padding.GetHorizontalTotal() +
+ border_thickness_.GetHorizontalTotal(),
+ margin.GetVerticalTotal() + padding.GetVerticalTotal() +
+ border_thickness_.GetVerticalTotal()};
- const auto content_available_size =
- rect.GetSize() - margin_border_padding_size;
- auto coerced_content_available_size = content_available_size;
+ auto content_size = size - space_size;
- if (coerced_content_available_size.width < 0) {
+ if (content_size.width < 0) {
log::Warn(
"Layout: horizontal length of padding, border and margin is bigger "
"than available length.");
- coerced_content_available_size.width = 0;
+ content_size.width = 0;
}
- if (coerced_content_available_size.height < 0) {
+ if (content_size.height < 0) {
log::Warn(
"Layout: vertical length of padding, border and margin is bigger "
"than available length.");
- coerced_content_available_size.height = 0;
+ content_size.height = 0;
+ }
+
+ Point lefttop{margin.left + padding.left + border_thickness_.left,
+ margin.top + padding.top + border_thickness_.top};
+ if (lefttop.x > size.width) {
+ lefttop.x = size.width;
}
+ if (lefttop.y > size.height) {
+ lefttop.y = size.height;
+ }
+
+ const Rect content_rect{lefttop, content_size};
- OnLayoutContent(
- Rect{margin.left + (is_border_enabled_ ? border_thickness_.left : 0) +
- padding.left,
- margin.top + (is_border_enabled_ ? border_thickness_.top : 0) +
- padding.top,
- coerced_content_available_size.width,
- coerced_content_available_size.height});
+ OnLayoutContent(content_rect);
}
-Size BorderRenderObject::OnMeasureContent(const Size& available_size) {
+Size BorderRenderObject::OnMeasureContent(
+ const MeasureRequirement& requirement) {
const auto child = GetChild();
if (child) {
- child->Measure(available_size);
- return child->GetPreferredSize();
+ child->Measure(requirement);
+ return child->GetMeasuredSize();
} else {
return Size{};
}
diff --git a/src/ui/render/CanvasRenderObject.cpp b/src/ui/render/CanvasRenderObject.cpp
index 16ac9239..72eb3570 100644
--- a/src/ui/render/CanvasRenderObject.cpp
+++ b/src/ui/render/CanvasRenderObject.cpp
@@ -18,8 +18,9 @@ RenderObject* CanvasRenderObject::HitTest(const Point& point) {
return padding_rect.IsPointInside(point) ? this : nullptr;
}
-Size CanvasRenderObject::OnMeasureContent(const Size& available_size) {
- return Min(available_size, GetDesiredSize());
+Size CanvasRenderObject::OnMeasureContent(
+ const MeasureRequirement& requirement) {
+ return Min(requirement.GetMaxSize(), GetDesiredSize());
}
void CanvasRenderObject::OnLayoutContent(const Rect& content_rect) {
diff --git a/src/ui/render/FlexLayoutRenderObject.cpp b/src/ui/render/FlexLayoutRenderObject.cpp
index b609fd97..079bc5a9 100644
--- a/src/ui/render/FlexLayoutRenderObject.cpp
+++ b/src/ui/render/FlexLayoutRenderObject.cpp
@@ -6,111 +6,115 @@
#include <functional>
namespace cru::ui::render {
-Size FlexLayoutRenderObject::OnMeasureContent(const Size& available_size) {
- std::vector<int> has_basis_children;
- std::vector<int> no_basis_children;
- std::vector<int> grow_children;
- std::vector<int> shrink_chilren;
- const auto child_count = GetChildCount();
- for (int i = 0; i < child_count; i++) {
- const auto& layout_data = *GetChildLayoutData(i);
- if (layout_data.flex_basis.has_value())
- has_basis_children.push_back(i);
- else
- no_basis_children.push_back(i);
- if (layout_data.flex_grow > 0) grow_children.push_back(i);
- if (layout_data.flex_shrink > 0) shrink_chilren.push_back(i);
- }
+Size FlexLayoutRenderObject::OnMeasureContent(
+ const MeasureRequirement& requirement) {
+ const bool horizontal = (direction_ == FlexDirection::Horizontal ||
+ direction_ == FlexDirection::HorizontalReverse);
+
+ const auto main_max_length =
+ horizontal ? requirement.max_width : requirement.max_height;
+ const auto cross_max_length =
+ horizontal ? requirement.max_height : requirement.max_width;
std::function<float(const Size&)> get_main_length;
std::function<float(const Size&)> get_cross_length;
- std::function<Size(float main, float cross)> create_size;
+ std::function<void(Size&, const Size&)> calculate_result_size;
+ std::function<MeasureRequirement(MeasureLength main, MeasureLength cross)>
+ create_requirement;
- if (direction_ == FlexDirection::Horizontal ||
- direction_ == FlexDirection::HorizontalReverse) {
+ if (horizontal) {
get_main_length = [](const Size& size) { return size.width; };
get_cross_length = [](const Size& size) { return size.height; };
- create_size = [](float main, float cross) { return Size(main, cross); };
+ calculate_result_size = [](Size& result, const Size& child_size) {
+ result.width += child_size.width;
+ result.height = std::max(result.height, child_size.height);
+ };
+ create_requirement = [](MeasureLength main, MeasureLength cross) {
+ return MeasureRequirement{main, cross};
+ };
} else {
get_main_length = [](const Size& size) { return size.height; };
get_cross_length = [](const Size& size) { return size.width; };
- create_size = [](float main, float cross) { return Size(cross, main); };
+ calculate_result_size = [](Size& result, const Size& child_size) {
+ result.height += child_size.height;
+ result.width = std::max(result.width, child_size.width);
+ };
+ create_requirement = [](MeasureLength main, MeasureLength cross) {
+ return MeasureRequirement{cross, main};
+ };
}
const auto& children = GetChildren();
+ Index children_count = children.size();
- float remain_main_length = get_main_length(available_size);
- float max_cross_length = 0;
-
- for (const int i : has_basis_children) {
- const auto child = children[i];
- const float basis = GetChildLayoutData(i)->flex_basis.value();
- child->Measure(create_size(basis, get_cross_length(available_size)));
- remain_main_length -= basis;
- const float child_preferred_cross_length =
- get_cross_length(child->GetPreferredSize());
- child->SetPreferredSize(create_size(basis, child_preferred_cross_length));
- max_cross_length = std::max(max_cross_length, child_preferred_cross_length);
- }
-
- for (const int i : no_basis_children) {
- const auto child = children[i];
- child->Measure(create_size(remain_main_length > 0 ? remain_main_length : 0,
- get_cross_length(available_size)));
- remain_main_length -= get_main_length(child->GetPreferredSize());
- max_cross_length =
- std::max(max_cross_length, get_cross_length(child->GetPreferredSize()));
- }
-
- if (remain_main_length > 0) {
- float total_grow = 0;
- for (const int i : grow_children)
- total_grow += GetChildLayoutData(i)->flex_grow;
+ if (!main_max_length.IsInfinate()) {
+ float remain_main_length = main_max_length.GetLength();
- for (const int i : grow_children) {
- const float distributed_grow_length =
- remain_main_length * (GetChildLayoutData(i)->flex_grow / total_grow);
+ for (Index i = 0; i < children_count; i++) {
const auto child = children[i];
- const float new_main_length =
- get_main_length(child->GetPreferredSize()) + distributed_grow_length;
- child->Measure(
- create_size(new_main_length, get_cross_length(available_size)));
- const float new_child_preferred_cross_length =
- get_cross_length(child->GetPreferredSize());
- child->SetPreferredSize(
- create_size(new_main_length, new_child_preferred_cross_length));
- max_cross_length =
- std::max(max_cross_length, new_child_preferred_cross_length);
+ child->Measure(create_requirement(remain_main_length, cross_max_length));
+ const auto measure_result = child->GetMeasuredSize();
+ remain_main_length -= get_main_length(measure_result);
}
- }
- if (remain_main_length < 0) {
- float total_shrink = 0;
- for (const int i : shrink_chilren)
- total_shrink += GetChildLayoutData(i)->flex_shrink;
+ if (remain_main_length > 0) {
+ std::vector<Index> expand_children;
+ float total_expand_factor = 0;
+
+ for (Index i = 0; i < children_count; i++) {
+ const auto factor = GetChildLayoutData(i)->expand_factor;
+ if (factor > 0) {
+ expand_children.push_back(i);
+ total_expand_factor += factor;
+ }
+ }
- for (const int i : shrink_chilren) {
- const float distributed_shrink_length = // negative
- remain_main_length *
- (GetChildLayoutData(i)->flex_shrink / total_shrink);
+ for (const int i : expand_children) {
+ const float distributed_grow_length =
+ remain_main_length *
+ (GetChildLayoutData(i)->expand_factor / total_expand_factor);
+ const auto child = children[i];
+ const float new_main_length =
+ get_main_length(child->GetMeasuredSize()) +
+ distributed_grow_length;
+ child->Measure(create_requirement(new_main_length, cross_max_length));
+ }
+ } else if (remain_main_length < 0) {
+ std::vector<Index> shrink_children;
+ float total_shrink_factor = 0;
+
+ for (Index i = 0; i < children_count; i++) {
+ const auto factor = GetChildLayoutData(i)->shrink_factor;
+ if (factor > 0) {
+ shrink_children.push_back(i);
+ total_shrink_factor += factor;
+ }
+ }
+
+ for (const int i : shrink_children) {
+ const float distributed_shrink_length = // negative
+ remain_main_length *
+ (GetChildLayoutData(i)->shrink_factor / total_shrink_factor);
+ const auto child = children[i];
+ float new_main_length = get_main_length(child->GetMeasuredSize()) +
+ distributed_shrink_length;
+ new_main_length = new_main_length > 0 ? new_main_length : 0;
+ child->Measure(create_requirement(new_main_length, cross_max_length));
+ }
+ }
+ } else {
+ for (Index i = 0; i < children_count; i++) {
const auto child = children[i];
- float new_main_length = get_main_length(child->GetPreferredSize()) +
- distributed_shrink_length;
- new_main_length = new_main_length > 0 ? new_main_length : 0;
- child->Measure(
- create_size(new_main_length, get_cross_length(available_size)));
- const float new_child_preferred_cross_length =
- get_cross_length(child->GetPreferredSize());
- child->SetPreferredSize(
- create_size(new_main_length, new_child_preferred_cross_length));
- max_cross_length =
- std::max(max_cross_length, new_child_preferred_cross_length);
+ child->Measure(requirement);
}
}
- return create_size(get_main_length(available_size) -
- (remain_main_length > 0 ? remain_main_length : 0),
- max_cross_length);
+ Size result;
+ for (auto child : children) {
+ calculate_result_size(result, child->GetMeasuredSize());
+ }
+
+ return result;
}
void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) {
@@ -125,7 +129,7 @@ void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) {
case internal::align_end:
return start_point + total_length - content_length;
default:
- return 0;
+ return start_point;
}
};
@@ -134,7 +138,7 @@ void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) {
direction_ == FlexDirection::HorizontalReverse) {
float actual_content_width = 0;
for (const auto child : children) {
- actual_content_width += child->GetPreferredSize().width;
+ actual_content_width += child->GetMeasuredSize().width;
}
const float content_anchor_x =
@@ -144,7 +148,7 @@ void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) {
float anchor_x = 0;
for (int i = 0; i < static_cast<int>(children.size()); i++) {
const auto child = children[i];
- const auto size = child->GetPreferredSize();
+ const auto size = child->GetMeasuredSize();
float real_anchor_x = anchor_x + content_anchor_x;
if (direction_ == FlexDirection::Horizontal)
@@ -164,7 +168,7 @@ void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) {
} else {
float actual_content_height = 0;
for (const auto child : children) {
- actual_content_height = child->GetPreferredSize().height;
+ actual_content_height = child->GetMeasuredSize().height;
}
const float content_anchor_y =
@@ -174,7 +178,7 @@ void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) {
float anchor_y = 0;
for (int i = 0; i < static_cast<int>(children.size()); i++) {
const auto child = children[i];
- const auto size = child->GetPreferredSize();
+ const auto size = child->GetMeasuredSize();
float real_anchor_y = anchor_y + content_anchor_y;
if (direction_ == FlexDirection::Vertical) {
diff --git a/src/ui/render/RenderObject.cpp b/src/ui/render/RenderObject.cpp
index 83e306a8..cdc3032f 100644
--- a/src/ui/render/RenderObject.cpp
+++ b/src/ui/render/RenderObject.cpp
@@ -57,14 +57,20 @@ Point RenderObject::FromRootToContent(const Point& point) const {
point.y - (offset.y + rect.top)};
}
-void RenderObject::Measure(const Size& available_size) {
- OnMeasureCore(available_size);
+void RenderObject::Measure(const MeasureRequirement& requirement) {
+ measured_size_ = OnMeasureCore(requirement);
+
+ Ensures(measured_size_.width >= 0);
+ Ensures(measured_size_.height >= 0);
+ Ensures(requirement.Satisfy(measured_size_));
}
void RenderObject::Layout(const Rect& rect) {
- SetOffset(rect.GetLeftTop());
- SetSize(rect.GetSize());
- OnLayoutCore(Rect{Point{}, rect.GetSize()});
+ Expects(rect.width >= 0);
+ Expects(rect.height >= 0);
+ offset_ = rect.GetLeftTop();
+ size_ = rect.GetSize();
+ OnLayoutCore(rect.GetSize());
}
void RenderObject::OnParentChanged(RenderObject* old_parent,
@@ -89,56 +95,72 @@ void RenderObject::OnRemoveChild(RenderObject* removed_child, Index position) {
InvalidatePaint();
}
-void RenderObject::OnMeasureCore(const Size& available_size) {
- Size margin_padding_size{
+Size RenderObject::OnMeasureCore(const MeasureRequirement& requirement) {
+ const Size space_size{
margin_.GetHorizontalTotal() + padding_.GetHorizontalTotal(),
margin_.GetVerticalTotal() + padding_.GetVerticalTotal()};
- auto coerced_margin_padding_size = margin_padding_size;
- if (coerced_margin_padding_size.width > available_size.width) {
- log::Warn(
- "Measure: horizontal length of padding and margin is bigger than "
- "available length.");
- coerced_margin_padding_size.width = available_size.width;
+ auto coerced_space_size = space_size;
+
+ MeasureRequirement content_requirement = requirement;
+
+ if (!requirement.max_width.IsInfinate()) {
+ const auto max_width = requirement.max_width.GetLength();
+ if (coerced_space_size.width > max_width) {
+ log::Warn(
+ "Measure: horizontal length of padding and margin is bigger than "
+ "available length.");
+ coerced_space_size.width = max_width;
+ }
+ content_requirement.max_width = max_width - coerced_space_size.width;
}
- if (coerced_margin_padding_size.height > available_size.height) {
- log::Warn(
- "Measure: vertical length of padding and margin is bigger than "
- "available length.");
- coerced_margin_padding_size.height = available_size.height;
+
+ if (!requirement.max_height.IsInfinate()) {
+ const auto max_height = requirement.max_height.GetLength();
+ if (coerced_space_size.height > max_height) {
+ log::Warn(
+ "Measure: horizontal length of padding and margin is bigger than "
+ "available length.");
+ coerced_space_size.height = max_height;
+ }
+ content_requirement.max_height = max_height - coerced_space_size.height;
}
- const auto coerced_content_available_size =
- available_size - coerced_margin_padding_size;
- const auto actual_content_size =
- OnMeasureContent(coerced_content_available_size);
+ const auto content_size = OnMeasureContent(content_requirement);
- SetPreferredSize(coerced_margin_padding_size + actual_content_size);
+ return coerced_space_size + 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;
+void RenderObject::OnLayoutCore(const Size& size) {
+ Size space_size{margin_.GetHorizontalTotal() + padding_.GetHorizontalTotal(),
+ margin_.GetVerticalTotal() + padding_.GetVerticalTotal()};
- if (coerced_content_available_size.width < 0) {
+ auto content_size = size - space_size;
+
+ if (content_size.width < 0) {
log::Warn(
"Layout: horizontal length of padding and margin is bigger than "
"available length.");
- coerced_content_available_size.width = 0;
+ content_size.width = 0;
}
- if (coerced_content_available_size.height < 0) {
+ if (content_size.height < 0) {
log::Warn(
"Layout: vertical length of padding and margin is bigger than "
"available length.");
- coerced_content_available_size.height = 0;
+ content_size.height = 0;
}
- OnLayoutContent(Rect{margin_.left + padding_.left, margin_.top + padding_.top,
- coerced_content_available_size.width,
- coerced_content_available_size.height});
+ Point lefttop{margin_.left + padding_.left, margin_.top + padding_.top};
+ if (lefttop.x > size.width) {
+ lefttop.x = size.width;
+ }
+ if (lefttop.y > size.height) {
+ lefttop.y = size.height;
+ }
+
+ const Rect content_rect{lefttop, content_size};
+
+ OnLayoutContent(content_rect);
}
void RenderObject::OnAfterLayout() {}
diff --git a/src/ui/render/ScrollRenderObject.cpp b/src/ui/render/ScrollRenderObject.cpp
index 33e9e407..f1df9d8b 100644
--- a/src/ui/render/ScrollRenderObject.cpp
+++ b/src/ui/render/ScrollRenderObject.cpp
@@ -1 +1,78 @@
#include "cru/ui/render/ScrollRenderObject.hpp"
+
+#include "cru/platform/graph/Painter.hpp"
+#include "cru/platform/graph/util/Painter.hpp"
+
+#include <algorithm>
+
+namespace cru::ui::render {
+namespace {
+// This method assumes margin offset is already considered.
+// It promises that it won't return negetive value.
+Point CalculateChildOffsetOfScroll(const Point& scroll_offset,
+ const Size& content_area_size,
+ const Thickness& padding,
+ const Size& child_size) {
+ Point result(scroll_offset);
+
+ Point max_scroll(child_size - content_area_size);
+ max_scroll.x = std::max(max_scroll.x, 0.f);
+ max_scroll.y = std::max(max_scroll.y, 0.f);
+
+ auto coerce = [](float& n, float max) {
+ if (n < 0)
+ n = 0;
+ else if (n > max)
+ n = max;
+ };
+
+ coerce(result.x, scroll_offset.x);
+ coerce(result.y, scroll_offset.y);
+
+ result.x += padding.left;
+ result.y += padding.top;
+
+ return result;
+}
+} // namespace
+
+void ScrollRenderObject::Draw(platform::graph::IPainter* painter) {
+ for (auto child : this->GetChildren()) {
+ painter->PushLayer(this->GetPaddingRect());
+ const auto true_offset =
+ CalculateChildOffsetOfScroll(scroll_offset_, GetContentRect().GetSize(),
+ GetPadding(), child->GetSize());
+ platform::graph::util::WithTransform(
+ painter, Matrix::Translation(true_offset.x, true_offset.y),
+ [child](platform::graph::IPainter* p) { child->Draw(p); });
+ painter->PopLayer();
+ }
+}
+
+RenderObject* ScrollRenderObject::HitTest(const Point& point) {
+ const auto rect = GetPaddingRect();
+ return rect.IsPointInside(point) ? this : nullptr;
+}
+
+void ScrollRenderObject::SetScrollOffset(const Point& offset) {
+ scroll_offset_ = offset;
+ InvalidatePaint();
+}
+
+Size ScrollRenderObject::OnMeasureContent(
+ const MeasureRequirement& requirement) {
+ CRU_UNUSED(requirement);
+ // TODO!
+ // const auto& children = GetChildren();
+ // if (children.empty()) return Size{};
+ // const auto child = children.front();
+ // child->Measure(MeasureRequirement::Infinate());
+ // const auto preferred_size = child->GetMeasuredSize();
+ return Size{};
+} // namespace cru::ui::render
+
+void ScrollRenderObject::OnLayoutContent(const Rect& content_rect) {
+ CRU_UNUSED(content_rect);
+ // TODO!
+}
+} // namespace cru::ui::render
diff --git a/src/ui/render/StackLayoutRenderObject.cpp b/src/ui/render/StackLayoutRenderObject.cpp
index d08e136d..7dce1a83 100644
--- a/src/ui/render/StackLayoutRenderObject.cpp
+++ b/src/ui/render/StackLayoutRenderObject.cpp
@@ -3,13 +3,14 @@
#include <algorithm>
namespace cru::ui::render {
-Size StackLayoutRenderObject::OnMeasureContent(const Size& available_size) {
+Size StackLayoutRenderObject::OnMeasureContent(
+ const MeasureRequirement& requirement) {
auto size = Size{};
for (const auto child : GetChildren()) {
- child->Measure(available_size);
- const auto& preferred_size = child->GetPreferredSize();
- size.width = std::max(size.width, preferred_size.width);
- size.height = std::max(size.height, preferred_size.height);
+ child->Measure(requirement);
+ const auto& measure_result = child->GetMeasuredSize();
+ size.width = std::max(size.width, measure_result.width);
+ size.height = std::max(size.height, measure_result.height);
}
return size;
}
@@ -26,7 +27,7 @@ void StackLayoutRenderObject::OnLayoutContent(const Rect& rect) {
case internal::align_end:
return start_point + total_length - content_length;
default:
- return 0;
+ return start_point;
}
};
@@ -36,7 +37,7 @@ void StackLayoutRenderObject::OnLayoutContent(const Rect& rect) {
for (int i = 0; i < count; i++) {
const auto layout_data = GetChildLayoutData(i);
const auto child = children[i];
- const auto& size = child->GetPreferredSize();
+ const auto& size = child->GetMeasuredSize();
child->Layout(
Rect{calculate_anchor(static_cast<int>(layout_data->horizontal),
rect.left, rect.width, size.width),
diff --git a/src/ui/render/TextRenderObject.cpp b/src/ui/render/TextRenderObject.cpp
index 05acd086..ececfbc2 100644
--- a/src/ui/render/TextRenderObject.cpp
+++ b/src/ui/render/TextRenderObject.cpp
@@ -4,8 +4,10 @@
#include "cru/platform/graph/Factory.hpp"
#include "cru/platform/graph/TextLayout.hpp"
#include "cru/platform/graph/util/Painter.hpp"
+#include "cru/ui/render/LayoutUtility.hpp"
#include <algorithm>
+#include <limits>
namespace cru::ui::render {
TextRenderObject::TextRenderObject(
@@ -158,10 +160,10 @@ RenderObject* TextRenderObject::HitTest(const Point& point) {
return padding_rect.IsPointInside(point) ? this : nullptr;
}
-Size TextRenderObject::OnMeasureContent(const Size& available_size) {
- text_layout_->SetMaxWidth(available_size.width);
- text_layout_->SetMaxHeight(available_size.height);
- return text_layout_->GetTextBounds().GetSize();
+Size TextRenderObject::OnMeasureContent(const MeasureRequirement& requirement) {
+ text_layout_->SetMaxWidth(requirement.max_height.GetLength());
+ text_layout_->SetMaxHeight(requirement.max_height.GetLength());
+ return Min(text_layout_->GetTextBounds().GetSize(), requirement.GetMaxSize());
}
void TextRenderObject::OnLayoutContent(const Rect& content_rect) {
diff --git a/src/ui/render/WindowRenderObject.cpp b/src/ui/render/WindowRenderObject.cpp
index cd1f806f..28afe01d 100644
--- a/src/ui/render/WindowRenderObject.cpp
+++ b/src/ui/render/WindowRenderObject.cpp
@@ -34,9 +34,14 @@ RenderObject* WindowRenderObject::HitTest(const Point& point) {
return Rect{Point{}, GetSize()}.IsPointInside(point) ? this : nullptr;
}
-Size WindowRenderObject::OnMeasureContent(const Size& available_size) {
- if (const auto child = GetChild()) child->Measure(available_size);
- return available_size;
+Size WindowRenderObject::OnMeasureContent(
+ const MeasureRequirement& requirement) {
+ if (const auto child = GetChild()) {
+ child->Measure(requirement);
+ return child->GetMeasuredSize();
+ } else {
+ return Size{};
+ }
}
void WindowRenderObject::OnLayoutContent(const Rect& content_rect) {