aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/cru/base/StringUtil.h1
-rw-r--r--include/cru/platform/GraphicsBase.h14
-rw-r--r--include/cru/ui/controls/Control.h8
-rw-r--r--include/cru/ui/render/BorderRenderObject.h3
-rw-r--r--include/cru/ui/render/CanvasRenderObject.h26
-rw-r--r--include/cru/ui/render/FlexLayoutRenderObject.h3
-rw-r--r--include/cru/ui/render/GeometryRenderObject.h3
-rw-r--r--include/cru/ui/render/MeasureRequirement.h273
-rw-r--r--include/cru/ui/render/RenderObject.h19
-rw-r--r--include/cru/ui/render/ScrollRenderObject.h3
-rw-r--r--include/cru/ui/render/StackLayoutRenderObject.h3
-rw-r--r--include/cru/ui/render/TextRenderObject.h4
-rw-r--r--include/cru/ui/render/TreeRenderObject.h3
-rw-r--r--include/cru/ui/style/Styler.h2
-rw-r--r--src/ThemeBuilder/components/StyleRuleSetEditor.cpp2
-rw-r--r--src/ThemeBuilder/components/conditions/CompoundConditionEditor.cpp2
-rw-r--r--src/ThemeBuilder/components/properties/MeasureLengthPropertyEditor.cpp9
-rw-r--r--src/ThemeBuilder/components/stylers/CompoundStylerEditor.cpp2
-rw-r--r--src/ThemeBuilder/components/stylers/PreferredSizeStylerEditor.cpp4
-rw-r--r--src/ui/controls/ControlHost.cpp15
-rw-r--r--src/ui/render/BorderRenderObject.cpp14
-rw-r--r--src/ui/render/CanvasRenderObject.cpp9
-rw-r--r--src/ui/render/FlexLayoutRenderObject.cpp79
-rw-r--r--src/ui/render/GeometryRenderObject.cpp13
-rw-r--r--src/ui/render/RenderObject.cpp95
-rw-r--r--src/ui/render/ScrollBar.cpp16
-rw-r--r--src/ui/render/ScrollRenderObject.cpp31
-rw-r--r--src/ui/render/StackLayoutRenderObject.cpp27
-rw-r--r--src/ui/render/TextRenderObject.cpp31
-rw-r--r--src/ui/render/TreeRenderObject.cpp20
-rw-r--r--src/ui/style/Styler.cpp2
31 files changed, 345 insertions, 391 deletions
diff --git a/include/cru/base/StringUtil.h b/include/cru/base/StringUtil.h
index dbc748d7..363493a1 100644
--- a/include/cru/base/StringUtil.h
+++ b/include/cru/base/StringUtil.h
@@ -1,7 +1,6 @@
#pragma once
#include "Base.h"
#include "Bitmask.h"
-#include "cru/base/StringUtil.h"
#include <algorithm>
#include <cctype>
diff --git a/include/cru/platform/GraphicsBase.h b/include/cru/platform/GraphicsBase.h
index 43c36494..89d3df77 100644
--- a/include/cru/platform/GraphicsBase.h
+++ b/include/cru/platform/GraphicsBase.h
@@ -56,6 +56,16 @@ struct Size final {
std::numeric_limits<float>::max()};
}
+ constexpr Size Min(const Size& other) const {
+ return {std::min(width, other.width), std::min(height, other.height)};
+ }
+
+ constexpr Size Max(const Size& other) const {
+ return {std::max(width, other.width), std::max(height, other.height)};
+ }
+
+ constexpr Size AtLeast0() const { return Max(kZero); }
+
std::string ToString() const {
return std::format("Size(width: {}, height: {})", width, height);
}
@@ -93,6 +103,10 @@ struct Thickness final {
constexpr float GetVerticalTotal() const { return top + bottom; }
+ constexpr Size GetTotalSize() const {
+ return {GetHorizontalTotal(), GetVerticalTotal()};
+ }
+
void SetLeftRight(const float value) { left = right = value; }
void SetTopBottom(const float value) { top = bottom = value; }
diff --git a/include/cru/ui/controls/Control.h b/include/cru/ui/controls/Control.h
index 544d33e6..c82956b5 100644
--- a/include/cru/ui/controls/Control.h
+++ b/include/cru/ui/controls/Control.h
@@ -71,11 +71,11 @@ class CRU_UI_API Control : public Object,
public:
virtual render::RenderObject* GetRenderObject() = 0;
- virtual render::MeasureSize GetPreferredSize() {
- return GetRenderObject()->GetPreferredSize();
+ virtual render::MeasureSize GetSuggestSize() {
+ return GetRenderObject()->GetSuggestSize();
}
- virtual void SetPreferredSize(const render::MeasureSize& size) {
- GetRenderObject()->SetPreferredSize(size);
+ virtual void SetSuggestSize(const render::MeasureSize& size) {
+ GetRenderObject()->SetSuggestSize(size);
}
virtual Thickness GetMargin() { return GetRenderObject()->GetMargin(); }
diff --git a/include/cru/ui/render/BorderRenderObject.h b/include/cru/ui/render/BorderRenderObject.h
index 6060dc4c..8b8f3816 100644
--- a/include/cru/ui/render/BorderRenderObject.h
+++ b/include/cru/ui/render/BorderRenderObject.h
@@ -50,8 +50,7 @@ class CRU_UI_API BorderRenderObject : public SingleChildRenderObject {
Rect GetContentRect() override;
protected:
- Size OnMeasureContent(const MeasureRequirement& requirement,
- const MeasureSize& preferred_size) override;
+ Size OnMeasureContent(const MeasureRequirement& requirement) override;
void OnLayoutContent(const Rect& content_rect) override;
void OnResize(const Size& new_size) override;
diff --git a/include/cru/ui/render/CanvasRenderObject.h b/include/cru/ui/render/CanvasRenderObject.h
index 63da9cd9..2e44fcc2 100644
--- a/include/cru/ui/render/CanvasRenderObject.h
+++ b/include/cru/ui/render/CanvasRenderObject.h
@@ -9,9 +9,6 @@ class CanvasPaintEventArgs {
CanvasPaintEventArgs(platform::graphics::IPainter* painter,
const Size& paint_size)
: painter_(painter), paint_size_(paint_size) {}
- CRU_DEFAULT_COPY(CanvasPaintEventArgs)
- CRU_DEFAULT_MOVE(CanvasPaintEventArgs)
- ~CanvasPaintEventArgs() = default;
platform::graphics::IPainter* GetPainter() const { return painter_; }
Size GetPaintSize() const { return paint_size_; }
@@ -21,9 +18,12 @@ class CanvasPaintEventArgs {
Size paint_size_;
};
-// Layout logic:
-// If no preferred size is set. Then (100, 100) is used and then coerced to
-// required range.
+/**
+ * Layout logic:
+ * Preferred
+ * If no preferred size is set. Then (100, 100) is used and then coerced to
+ * required range.
+ */
class CRU_UI_API CanvasRenderObject : public RenderObject {
public:
static constexpr auto kRenderObjectName = "CanvasRenderObject";
@@ -33,20 +33,12 @@ class CRU_UI_API CanvasRenderObject : public RenderObject {
public:
RenderObject* HitTest(const Point& point) override;
- Size GetDesiredSize() { return desired_size_; }
-
- IEvent<CanvasPaintEventArgs>* PaintEvent() { return &paint_event_; }
-
void Draw(platform::graphics::IPainter* painter) override;
+ CRU_DEFINE_EVENT(Paint, const CanvasPaintEventArgs&)
+
protected:
- Size OnMeasureContent(const MeasureRequirement& requirement,
- const MeasureSize& preferred_size) override;
+ Size OnMeasureContent(const MeasureRequirement& requirement) override;
void OnLayoutContent(const Rect& content_rect) override;
-
- private:
- Size desired_size_{};
-
- Event<CanvasPaintEventArgs> paint_event_;
};
} // namespace cru::ui::render
diff --git a/include/cru/ui/render/FlexLayoutRenderObject.h b/include/cru/ui/render/FlexLayoutRenderObject.h
index 82ac6639..9fdecd28 100644
--- a/include/cru/ui/render/FlexLayoutRenderObject.h
+++ b/include/cru/ui/render/FlexLayoutRenderObject.h
@@ -119,8 +119,7 @@ class CRU_UI_API FlexLayoutRenderObject
}
protected:
- Size OnMeasureContent(const MeasureRequirement& requirement,
- const MeasureSize& preferred_size) override;
+ Size OnMeasureContent(const MeasureRequirement& requirement) override;
void OnLayoutContent(const Rect& content_rect) override;
private:
diff --git a/include/cru/ui/render/GeometryRenderObject.h b/include/cru/ui/render/GeometryRenderObject.h
index 2320b71b..1994daf3 100644
--- a/include/cru/ui/render/GeometryRenderObject.h
+++ b/include/cru/ui/render/GeometryRenderObject.h
@@ -35,8 +35,7 @@ class GeometryRenderObject : public RenderObject {
void SetStrokeWidth(float width);
protected:
- Size OnMeasureContent(const MeasureRequirement& requirement,
- const MeasureSize& preferred_size) override;
+ Size OnMeasureContent(const MeasureRequirement& requirement) override;
void OnLayoutContent(const Rect& content_rect) override;
private:
diff --git a/include/cru/ui/render/MeasureRequirement.h b/include/cru/ui/render/MeasureRequirement.h
index 43bd3326..5ea22952 100644
--- a/include/cru/ui/render/MeasureRequirement.h
+++ b/include/cru/ui/render/MeasureRequirement.h
@@ -7,16 +7,6 @@
#include <string>
namespace cru::ui::render {
-constexpr Size Min(const Size& left, const Size& right) {
- return Size{std::min(left.width, right.width),
- std::min(left.height, right.height)};
-}
-
-constexpr Size Max(const Size& left, const Size& right) {
- return Size{std::max(left.width, right.width),
- std::max(left.height, right.height)};
-}
-
class MeasureLength final {
public:
struct tag_not_specify_t {};
@@ -24,32 +14,31 @@ class MeasureLength final {
constexpr MeasureLength() : MeasureLength(tag_not_specify) {}
constexpr MeasureLength(tag_not_specify_t) : length_(-1) {}
- constexpr MeasureLength(float length) : length_(length) {}
-
- MeasureLength(const MeasureLength& other) = default;
- constexpr MeasureLength& operator=(const MeasureLength& other) = default;
+ constexpr MeasureLength(float length) : length_(length) {
+ if (length < 0.0f) {
+ throw Exception("Measure length must not be positive.");
+ }
+ }
constexpr MeasureLength& operator=(float length) {
+ if (length < 0.0f) {
+ throw Exception("Measure length must not be positive.");
+ }
length_ = length;
return *this;
}
- ~MeasureLength() = default;
-
constexpr static MeasureLength NotSpecified() {
- return MeasureLength{tag_not_specify};
+ return MeasureLength(tag_not_specify);
}
constexpr bool IsSpecified() const { return length_ >= 0.0f; }
- // What not specified means depends on situation.
- constexpr bool IsNotSpecified() const { return length_ < 0.0f; }
-
constexpr float GetLengthOr(float value) const {
return length_ < 0 ? value : length_;
}
// If not specify max value of float is returned.
- constexpr float GetLengthOrMax() const {
+ constexpr float GetLengthOrMaxFloat() const {
return GetLengthOr(std::numeric_limits<float>::max());
}
@@ -59,15 +48,27 @@ class MeasureLength final {
// If not specify, return value is undefined.
constexpr float GetLengthOrUndefined() const { return length_; }
- // Not operator overload because this semantics is not very clear.
+ constexpr MeasureLength Or(MeasureLength value) const {
+ return IsSpecified() ? *this : value;
+ }
+
+ constexpr MeasureLength OverrideBy(MeasureLength value) const {
+ return value.IsSpecified() ? value : *this;
+ }
+
+ /**
+ * If specified, given length is added and negative value is coerced to 0.
+ */
constexpr MeasureLength Plus(float length) const {
if (IsSpecified())
- return length_ + length;
+ return std::max(length_ + length, 0.f);
else
return NotSpecified();
}
- // Not operator overload because this semantics is not very clear.
+ /**
+ * If specified, given length is minused and negative value is coerced to 0.
+ */
constexpr MeasureLength Minus(float length) const {
if (IsSpecified())
return std::max(length_ - length, 0.f);
@@ -75,52 +76,67 @@ class MeasureLength final {
return NotSpecified();
}
- constexpr bool operator==(MeasureLength other) const {
- return (length_ < 0 && other.length_ < 0) || length_ == other.length_;
+ /**
+ * 1. Both unspecified => unspecified.
+ * 2. One is specified and the other is not => the specified one.
+ * 3. Both specified => smaller one.
+ */
+ constexpr MeasureLength Min(MeasureLength other) const {
+ if (IsSpecified()) {
+ return other.IsSpecified() ? std::min(length_, other.length_) : *this;
+ } else {
+ return other;
+ }
}
- constexpr bool operator!=(MeasureLength other) const {
- return !operator==(other);
+ /**
+ * 1. This is unspecified => other.
+ * 2. This is specified => smaller one.
+ */
+ constexpr float Min(float other) const {
+ return IsSpecified() ? std::min(length_, other) : other;
}
- constexpr static MeasureLength Min(MeasureLength left, MeasureLength right) {
- if (left.IsNotSpecified()) {
- if (right.IsNotSpecified())
- return NotSpecified();
- else
- return right;
+ /**
+ * 1. Both unspecified => unspecified.
+ * 2. One is specified and the other is not => the specified one.
+ * 3. Both specified => bigger one.
+ */
+ constexpr MeasureLength Max(MeasureLength other) const {
+ if (IsSpecified()) {
+ return other.IsSpecified() ? std::max(length_, other.length_) : *this;
} else {
- if (right.IsNotSpecified())
- return left;
- else
- return std::min(left.length_, right.length_);
+ return other;
}
}
- constexpr static MeasureLength Max(MeasureLength left, MeasureLength right) {
- if (left.IsNotSpecified()) {
- if (right.IsNotSpecified())
- return NotSpecified();
- else
- return right;
- } else {
- if (left.IsNotSpecified())
- return left;
- else
- return std::max(left.length_, right.length_);
- }
+ /**
+ * 1. This is unspecified => other.
+ * 2. This is specified => bigger one.
+ */
+ constexpr float Max(float other) const {
+ return IsSpecified() ? std::max(length_, other) : other;
}
- std::string ToDebugString() const {
+ std::string ToString() const {
return IsSpecified() ? std::to_string(GetLengthOrUndefined())
- : "UNSPECIFIED";
+ : "unspecified";
}
+ constexpr bool operator==(const MeasureLength& other) const = default;
+
private:
// -1 for not specify
float length_;
};
+} // namespace cru::ui::render
+
+template <>
+struct std::formatter<cru::ui::render::MeasureLength, char>
+ : cru::string::ImplementFormatterByToString<
+ cru::ui::render::MeasureLength> {};
+namespace cru::ui::render {
struct MeasureSize {
MeasureLength width;
MeasureLength height;
@@ -130,120 +146,149 @@ struct MeasureSize {
: width(width), height(height) {}
constexpr MeasureSize(const Size& size)
: width(size.width), height(size.height) {}
- constexpr MeasureSize(const MeasureSize& other) = default;
- MeasureSize& operator=(const MeasureSize& other) = default;
constexpr MeasureSize& operator=(const Size& other) {
width = other.width;
height = other.height;
return *this;
}
- constexpr Size GetSizeOrMax() const {
- return Size{width.GetLengthOrMax(), height.GetLengthOrMax()};
+ constexpr static MeasureSize NotSpecified() {
+ return {MeasureLength::NotSpecified(), MeasureLength::NotSpecified()};
+ }
+
+ constexpr Size GetSizeOrMaxFloat() const {
+ return {width.GetLengthOrMaxFloat(), height.GetLengthOrMaxFloat()};
}
constexpr Size GetSizeOr0() const {
- return Size{width.GetLengthOr0(), height.GetLengthOr0()};
+ return {width.GetLengthOr0(), height.GetLengthOr0()};
+ }
+
+ constexpr Size GetSizeOr(const Size& other) const {
+ return {width.GetLengthOr(other.width), height.GetLengthOr(other.height)};
+ }
+
+ constexpr MeasureSize Or(const MeasureSize& other) const {
+ return {width.Or(other.width), height.Or(other.height)};
+ }
+
+ constexpr MeasureSize OverrideBy(const MeasureSize& other) const {
+ return {width.OverrideBy(other.width), height.OverrideBy(other.height)};
}
constexpr MeasureSize Plus(const Size& size) const {
- return MeasureSize{width.Plus(size.width), height.Plus(size.height)};
+ return {width.Plus(size.width), height.Plus(size.height)};
}
constexpr MeasureSize Minus(const Size& size) const {
- return MeasureSize{width.Minus(size.width), height.Minus(size.height)};
+ return {width.Minus(size.width), height.Minus(size.height)};
}
- constexpr MeasureSize OverrideBy(const MeasureSize& size) const {
- return MeasureSize{
- size.width.IsSpecified() ? size.width.GetLengthOrUndefined()
- : this->width,
- size.height.IsSpecified() ? size.height.GetLengthOrUndefined()
- : this->height,
- };
+ constexpr MeasureSize Min(const MeasureSize& other) const {
+ return {width.Min(other.width), height.Min(other.height)};
}
- std::string ToDebugString() const {
- return std::format("({}, {})", width.ToDebugString(),
- height.ToDebugString());
+ constexpr Size Min(const Size& other) const {
+ return {width.Min(other.width), height.Min(other.height)};
}
- constexpr static MeasureSize NotSpecified() {
- return MeasureSize{MeasureLength::NotSpecified(),
- MeasureLength::NotSpecified()};
+ constexpr MeasureSize Max(const MeasureSize& other) const {
+ return {width.Max(other.width), height.Max(other.height)};
}
- constexpr static MeasureSize Min(const MeasureSize& left,
- const MeasureSize& right) {
- return MeasureSize{MeasureLength::Min(left.width, right.width),
- MeasureLength::Min(left.height, right.height)};
+ constexpr Size Max(const Size& other) const {
+ return {width.Max(other.width), height.Max(other.height)};
}
- constexpr static MeasureSize Max(const MeasureSize& left,
- const MeasureSize& right) {
- return MeasureSize{MeasureLength::Max(left.width, right.width),
- MeasureLength::Max(left.height, right.height)};
- }
+ std::string ToString() const { return std::format("{}x{}", width, height); }
+
+ constexpr bool operator==(const MeasureSize& other) const = default;
+};
+} // namespace cru::ui::render
+
+template <>
+struct std::formatter<cru::ui::render::MeasureSize, char>
+ : cru::string::ImplementFormatterByToString<cru::ui::render::MeasureSize> {
};
+namespace cru::ui::render {
struct MeasureRequirement {
MeasureSize max;
MeasureSize min;
+ MeasureSize suggest;
constexpr MeasureRequirement() = default;
- constexpr MeasureRequirement(const MeasureSize& max, const MeasureSize& min)
- : max(max), min(min) {}
+ constexpr MeasureRequirement(const MeasureSize& max, const MeasureSize& min,
+ const MeasureSize& suggest,
+ bool allow_coerce_suggest = true)
+ : max(max), min(min), suggest(Coerce(suggest)) {
+ if (max.width.GetLengthOrMaxFloat() < min.width.GetLengthOr0()) {
+ throw Exception(
+ "Measure requirement's max width is smaller than min width.");
+ }
- constexpr bool Satisfy(const Size& size) const {
- auto normalized = Normalize();
- return normalized.max.width.GetLengthOrMax() >= size.width &&
- normalized.max.height.GetLengthOrMax() >= size.height &&
- normalized.min.width.GetLengthOr0() <= size.width &&
- normalized.min.height.GetLengthOr0() <= size.height;
- }
+ if (max.height.GetLengthOrMaxFloat() < min.height.GetLengthOr0()) {
+ throw Exception(
+ "Measure requirement's max height is smaller than min height.");
+ }
- constexpr MeasureRequirement Normalize() const {
- MeasureRequirement result = *this;
- if (result.min.width.GetLengthOr0() > result.max.width.GetLengthOrMax())
- result.min.width = result.max.width;
+ if (!allow_coerce_suggest && this->suggest != suggest) {
+ throw Exception(
+ "Measure requirement's suggest size is in invalid range.");
+ }
+ }
- if (result.min.height.GetLengthOr0() > result.max.height.GetLengthOrMax())
- result.min.height = result.max.height;
- return result;
+ constexpr bool Satisfy(const Size& size) const {
+ return max.width.GetLengthOrMaxFloat() >= size.width &&
+ max.height.GetLengthOrMaxFloat() >= size.height &&
+ min.width.GetLengthOr0() <= size.width &&
+ min.height.GetLengthOr0() <= size.height;
}
constexpr Size Coerce(const Size& size) const {
- // This order guarentees result is the same as normalized.
- return Min(Max(size, min.GetSizeOr0()), max.GetSizeOrMax());
+ return max.Min(min.Max(size));
+ }
+
+ constexpr Size ExpandToSuggestAndCoerce(const Size& size) const {
+ return max.Min(min.Max(suggest.Max(size)));
}
constexpr MeasureSize Coerce(const MeasureSize& size) const {
MeasureSize result = size;
if (result.width.IsSpecified())
- // This order guarentees result is the same as normalized.
- result.width = std::min(std::max(min.width.GetLengthOr0(),
- result.width.GetLengthOrUndefined()),
- max.width.GetLengthOrMax());
+ result.width =
+ max.width.Min(min.width.Max(result.width.GetLengthOrUndefined()));
if (result.height.IsSpecified())
- // This order guarentees result is the same as normalized.
- result.height = std::min(std::max(min.height.GetLengthOr0(),
- result.height.GetLengthOrUndefined()),
- max.height.GetLengthOrMax());
+ result.height =
+ max.height.Min(min.height.Max(result.height.GetLengthOrUndefined()));
return result;
}
- std::string ToDebugString() const {
- return std::format("{{min: {}, max: {}}}", min.ToDebugString(),
- max.ToDebugString());
+ constexpr MeasureRequirement Minus(const Size& size) const {
+ return {max.Minus(size), min.Minus(size), suggest.Minus(size)};
+ }
+
+ /**
+ * Suggest size will use the other's one if this doesn't specify one but the
+ * other does.
+ */
+ constexpr MeasureRequirement Merge(const MeasureRequirement& other) const {
+ return {max.Min(other.max), min.Max(other.min),
+ suggest.OverrideBy(other.suggest)};
}
- constexpr static MeasureRequirement Merge(const MeasureRequirement& left,
- const MeasureRequirement& right) {
- return MeasureRequirement{MeasureSize::Min(left.max, right.max),
- MeasureSize::Max(left.min, right.min)};
+ std::string ToString() const {
+ return std::format("(min: {}, max: {}, suggest: {})", min, max, suggest);
}
+
+ constexpr bool operator==(const MeasureRequirement& other) const = default;
};
} // namespace cru::ui::render
+
+template <>
+struct std::formatter<cru::ui::render::MeasureRequirement, char>
+ : cru::string::ImplementFormatterByToString<
+ cru::ui::render::MeasureRequirement> {};
diff --git a/include/cru/ui/render/RenderObject.h b/include/cru/ui/render/RenderObject.h
index ce788ca6..05fee5df 100644
--- a/include/cru/ui/render/RenderObject.h
+++ b/include/cru/ui/render/RenderObject.h
@@ -82,7 +82,7 @@ class CRU_UI_API RenderObject : public Object {
Point GetTotalOffset();
Point FromRootToContent(const Point& point);
- Size GetDesiredSize() { return desired_size_; }
+ Size GetMeasureResultSize() { return measure_result_size_; }
Thickness GetMargin() { return margin_; }
void SetMargin(const Thickness& margin);
@@ -90,8 +90,8 @@ class CRU_UI_API RenderObject : public Object {
Thickness GetPadding() { return padding_; }
void SetPadding(const Thickness& padding);
- MeasureSize GetPreferredSize() { return preferred_size_; }
- void SetPreferredSize(const MeasureSize& preferred_size);
+ MeasureSize GetSuggestSize() { return custom_measure_requirement_.suggest; }
+ void SetSuggestSize(const MeasureSize& suggest_size);
MeasureSize GetMinSize() { return custom_measure_requirement_.min; }
void SetMinSize(const MeasureSize& min_size);
@@ -110,8 +110,7 @@ class CRU_UI_API RenderObject : public Object {
// OnMeasureCore and use the return value of it to set the size of this render
// object. This can be called multiple times on children during measure to
// adjust for better size.
- void Measure(const MeasureRequirement& requirement,
- const MeasureSize& preferred_size);
+ void Measure(const MeasureRequirement& requirement);
// This will set offset of this render object and call OnLayoutCore.
void Layout(const Point& offset);
@@ -145,8 +144,7 @@ class CRU_UI_API RenderObject : public Object {
// must obey requirement.
// Note: Implementation should coerce the preferred size into the requirement
// when pass them to OnMeasureContent.
- virtual Size OnMeasureCore(const MeasureRequirement& requirement,
- const MeasureSize& preferred_size);
+ virtual Size OnMeasureCore(const MeasureRequirement& requirement);
// Please reduce margin and padding or other custom things and pass the result
// content rect to OnLayoutContent.
@@ -156,8 +154,7 @@ class CRU_UI_API RenderObject : public Object {
// them). Do not consider margin or padding in this method because they are
// already considered in OnMeasureCore. Returned size must obey requirement.
// Caller should guarantee preferred_size is corerced into required range.
- virtual Size OnMeasureContent(const MeasureRequirement& requirement,
- const MeasureSize& preferred_size) = 0;
+ virtual Size OnMeasureContent(const MeasureRequirement& requirement) = 0;
// Layout all content and children(Call Layout on them).
// Lefttop of content_rect should be added when calculated children's offset.
@@ -176,12 +173,10 @@ class CRU_UI_API RenderObject : public Object {
Point offset_;
Size size_;
- Size desired_size_;
-
Thickness margin_;
Thickness padding_;
- MeasureSize preferred_size_;
+ Size measure_result_size_;
MeasureRequirement custom_measure_requirement_;
};
} // namespace cru::ui::render
diff --git a/include/cru/ui/render/ScrollRenderObject.h b/include/cru/ui/render/ScrollRenderObject.h
index 417ebf1c..ae11f361 100644
--- a/include/cru/ui/render/ScrollRenderObject.h
+++ b/include/cru/ui/render/ScrollRenderObject.h
@@ -69,8 +69,7 @@ class CRU_UI_API ScrollRenderObject : public SingleChildRenderObject {
// 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,
- const MeasureSize& preferred_size) override;
+ Size OnMeasureContent(const MeasureRequirement& requirement) override;
void OnLayoutContent(const Rect& content_rect) override;
void OnAttachedControlChanged(controls::Control* old_control,
diff --git a/include/cru/ui/render/StackLayoutRenderObject.h b/include/cru/ui/render/StackLayoutRenderObject.h
index bd08fffc..caddf5c5 100644
--- a/include/cru/ui/render/StackLayoutRenderObject.h
+++ b/include/cru/ui/render/StackLayoutRenderObject.h
@@ -45,8 +45,7 @@ class CRU_UI_API StackLayoutRenderObject
void SetDefaultVerticalAlignment(Alignment alignment);
protected:
- Size OnMeasureContent(const MeasureRequirement& requirement,
- const MeasureSize& preferred_size) override;
+ Size OnMeasureContent(const MeasureRequirement& requirement) override;
void OnLayoutContent(const Rect& content_rect) override;
private:
diff --git a/include/cru/ui/render/TextRenderObject.h b/include/cru/ui/render/TextRenderObject.h
index 28d674aa..e976f86d 100644
--- a/include/cru/ui/render/TextRenderObject.h
+++ b/include/cru/ui/render/TextRenderObject.h
@@ -91,9 +91,7 @@ class CRU_UI_API TextRenderObject : public RenderObject {
protected:
// See remarks of this class.
- Size OnMeasureContent(const MeasureRequirement& requirement,
- const MeasureSize& preferred_size) override;
-
+ Size OnMeasureContent(const MeasureRequirement& requirement) override;
void OnLayoutContent(const Rect& content_rect) override;
private:
diff --git a/include/cru/ui/render/TreeRenderObject.h b/include/cru/ui/render/TreeRenderObject.h
index 90c35747..090fe545 100644
--- a/include/cru/ui/render/TreeRenderObject.h
+++ b/include/cru/ui/render/TreeRenderObject.h
@@ -64,8 +64,7 @@ class CRU_UI_API TreeRenderObject : public RenderObject {
void Draw(platform::graphics::IPainter* painter) override;
protected:
- Size OnMeasureContent(const MeasureRequirement& requirement,
- const MeasureSize& preferred_size) override;
+ Size OnMeasureContent(const MeasureRequirement& requirement) override;
void OnLayoutContent(const Rect& content_rect) override;
private:
diff --git a/include/cru/ui/style/Styler.h b/include/cru/ui/style/Styler.h
index 0e21945d..64226166 100644
--- a/include/cru/ui/style/Styler.h
+++ b/include/cru/ui/style/Styler.h
@@ -113,7 +113,7 @@ class CRU_UI_API PreferredSizeStyler : public Styler {
return new PreferredSizeStyler(size_);
}
- render::MeasureSize GetPreferredSize() const { return size_; }
+ render::MeasureSize GetSuggestSize() const { return size_; }
private:
render::MeasureSize size_;
diff --git a/src/ThemeBuilder/components/StyleRuleSetEditor.cpp b/src/ThemeBuilder/components/StyleRuleSetEditor.cpp
index 9159e966..f077d31a 100644
--- a/src/ThemeBuilder/components/StyleRuleSetEditor.cpp
+++ b/src/ThemeBuilder/components/StyleRuleSetEditor.cpp
@@ -24,7 +24,7 @@ StyleRuleSetEditor::StyleRuleSetEditor() {
"cru.theme_builder.icon-button.style"));
add_button_.SetIconWithSvgPathDataStringResourceKey("icon.plus",
{0, 0, 16, 16});
- add_button_.SetPreferredSize({24, 24});
+ add_button_.SetSuggestSize({24, 24});
add_button_.SetPadding(ui::Thickness(2));
add_button_.SetIconFillColor(ui::colors::green);
diff --git a/src/ThemeBuilder/components/conditions/CompoundConditionEditor.cpp b/src/ThemeBuilder/components/conditions/CompoundConditionEditor.cpp
index 8501d7cd..d84f05e2 100644
--- a/src/ThemeBuilder/components/conditions/CompoundConditionEditor.cpp
+++ b/src/ThemeBuilder/components/conditions/CompoundConditionEditor.cpp
@@ -30,7 +30,7 @@ CompoundConditionEditor::CompoundConditionEditor() {
"cru.theme_builder.icon-button.style"));
add_child_button_.GetButton()->SetIconWithSvgPathDataStringResourceKey(
"icon.plus", {0, 0, 16, 16});
- add_child_button_.GetButton()->SetPreferredSize({24, 24});
+ add_child_button_.GetButton()->SetSuggestSize({24, 24});
add_child_button_.GetButton()->SetPadding(ui::Thickness(2));
add_child_button_.GetButton()->SetIconFillColor(ui::colors::green);
add_child_button_.SetMenuItems({"And Condition", "Or Condition",
diff --git a/src/ThemeBuilder/components/properties/MeasureLengthPropertyEditor.cpp b/src/ThemeBuilder/components/properties/MeasureLengthPropertyEditor.cpp
index 001665ae..32723a6d 100644
--- a/src/ThemeBuilder/components/properties/MeasureLengthPropertyEditor.cpp
+++ b/src/ThemeBuilder/components/properties/MeasureLengthPropertyEditor.cpp
@@ -14,8 +14,7 @@ MeasureLengthPropertyEditor::MeasureLengthPropertyEditor() {
auto measure_length_mapper = ui::mapper::MapperRegistry::GetInstance()
->GetMapper<ui::render::MeasureLength>();
try {
- auto measure_length =
- measure_length_mapper->MapFromString(text);
+ auto measure_length = measure_length_mapper->MapFromString(text);
measure_length_ = measure_length;
is_text_valid_ = true;
RaiseChangeEvent();
@@ -31,8 +30,8 @@ MeasureLengthPropertyEditor::~MeasureLengthPropertyEditor() {}
void MeasureLengthPropertyEditor::SetValue(
const ui::render::MeasureLength& value, bool trigger_change) {
if (!trigger_change) SuppressNextChangeEvent();
- text_.SetText(measure_length_.IsNotSpecified()
- ? "unspecified"
- : std::to_string(measure_length_.GetLengthOrUndefined()));
+ text_.SetText(measure_length_.IsSpecified()
+ ? std::to_string(measure_length_.GetLengthOrUndefined())
+ : "unspecified");
}
} // namespace cru::theme_builder::components::properties
diff --git a/src/ThemeBuilder/components/stylers/CompoundStylerEditor.cpp b/src/ThemeBuilder/components/stylers/CompoundStylerEditor.cpp
index 698cc699..fb144e60 100644
--- a/src/ThemeBuilder/components/stylers/CompoundStylerEditor.cpp
+++ b/src/ThemeBuilder/components/stylers/CompoundStylerEditor.cpp
@@ -25,7 +25,7 @@ CompoundStylerEditor::CompoundStylerEditor() {
"cru.theme_builder.icon-button.style"));
add_child_button_.GetButton()->SetIconWithSvgPathDataStringResourceKey(
"icon.plus", {0, 0, 16, 16});
- add_child_button_.GetButton()->SetPreferredSize({24, 24});
+ add_child_button_.GetButton()->SetSuggestSize({24, 24});
add_child_button_.GetButton()->SetPadding(ui::Thickness(2));
add_child_button_.GetButton()->SetIconFillColor(ui::colors::green);
add_child_button_.SetMenuItems({"Compound Styler", "Border Styler",
diff --git a/src/ThemeBuilder/components/stylers/PreferredSizeStylerEditor.cpp b/src/ThemeBuilder/components/stylers/PreferredSizeStylerEditor.cpp
index 8c7c751f..d230e09c 100644
--- a/src/ThemeBuilder/components/stylers/PreferredSizeStylerEditor.cpp
+++ b/src/ThemeBuilder/components/stylers/PreferredSizeStylerEditor.cpp
@@ -24,8 +24,8 @@ PreferredSizeStylerEditor::GetValue() {
void PreferredSizeStylerEditor::SetValue(ui::style::PreferredSizeStyler* styler,
bool trigger_change) {
- width_editor_.SetValue(styler->GetPreferredSize().width, false);
- height_editor_.SetValue(styler->GetPreferredSize().height, false);
+ width_editor_.SetValue(styler->GetSuggestSize().width, false);
+ height_editor_.SetValue(styler->GetSuggestSize().height, false);
if (trigger_change) {
RaiseChangeEvent();
diff --git a/src/ui/controls/ControlHost.cpp b/src/ui/controls/ControlHost.cpp
index f83aa1a2..caa907da 100644
--- a/src/ui/controls/ControlHost.cpp
+++ b/src/ui/controls/ControlHost.cpp
@@ -156,16 +156,15 @@ void ControlHost::Relayout() {
void ControlHost::RelayoutWithSize(const Size& available_size,
bool set_window_size_to_fit_content) {
auto render_object = root_control_->GetRenderObject();
- render_object->Measure(
- render::MeasureRequirement{
- available_size,
- !set_window_size_to_fit_content && IsLayoutPreferToFillWindow()
- ? render::MeasureSize(available_size)
- : render::MeasureSize::NotSpecified()},
- render::MeasureSize::NotSpecified());
+ render_object->Measure(render::MeasureRequirement{
+ available_size,
+ !set_window_size_to_fit_content && IsLayoutPreferToFillWindow()
+ ? render::MeasureSize(available_size)
+ : render::MeasureSize::NotSpecified(),
+ render::MeasureSize::NotSpecified()});
if (set_window_size_to_fit_content) {
- native_window_->SetClientSize(render_object->GetDesiredSize());
+ native_window_->SetClientSize(render_object->GetMeasureResultSize());
}
render_object->Layout(Point{});
diff --git a/src/ui/render/BorderRenderObject.cpp b/src/ui/render/BorderRenderObject.cpp
index 23405aac..18fc6475 100644
--- a/src/ui/render/BorderRenderObject.cpp
+++ b/src/ui/render/BorderRenderObject.cpp
@@ -114,13 +114,13 @@ void BorderRenderObject::Draw(platform::graphics::IPainter* painter) {
foreground_brush_.get());
}
-Size BorderRenderObject::OnMeasureContent(const MeasureRequirement& requirement,
- const MeasureSize& preferred_size) {
+Size BorderRenderObject::OnMeasureContent(
+ const MeasureRequirement& requirement) {
if (auto child = GetChild()) {
- child->Measure(requirement, preferred_size);
- return child->GetDesiredSize();
+ child->Measure(requirement);
+ return child->GetMeasureResultSize();
} else {
- return preferred_size.GetSizeOr0();
+ return requirement.suggest.GetSizeOr0();
}
}
@@ -157,7 +157,7 @@ Rect BorderRenderObject::GetPaddingRect() {
}
Rect BorderRenderObject::GetContentRect() {
- const auto size = GetDesiredSize();
+ const auto size = GetMeasureResultSize();
Rect rect{Point{}, size};
rect = rect.Shrink(GetMargin());
if (is_border_enabled_) rect = rect.Shrink(border_thickness_);
@@ -212,7 +212,7 @@ void BorderRenderObject::RecreateGeometry() {
builder->CloseFigure(true);
};
- const auto size = GetDesiredSize();
+ const auto size = GetMeasureResultSize();
const auto margin = GetMargin();
const Rect outer_rect{margin.left, margin.top,
size.width - margin.GetHorizontalTotal(),
diff --git a/src/ui/render/CanvasRenderObject.cpp b/src/ui/render/CanvasRenderObject.cpp
index b68f9afd..0c5ca3ed 100644
--- a/src/ui/render/CanvasRenderObject.cpp
+++ b/src/ui/render/CanvasRenderObject.cpp
@@ -12,13 +12,12 @@ RenderObject* CanvasRenderObject::HitTest(const Point& point) {
void CanvasRenderObject::Draw(platform::graphics::IPainter* painter) {
const auto rect = GetContentRect();
CanvasPaintEventArgs args{painter, rect.GetSize()};
- paint_event_.Raise(args);
+ PaintEvent_.Raise(args);
}
-Size CanvasRenderObject::OnMeasureContent(const MeasureRequirement& requirement,
- const MeasureSize& preferred_size) {
- return requirement.Coerce(Size{preferred_size.width.GetLengthOr(100),
- preferred_size.height.GetLengthOr(100)});
+Size CanvasRenderObject::OnMeasureContent(
+ const MeasureRequirement& requirement) {
+ return requirement.Coerce(requirement.suggest.GetSizeOr({100, 100}));
}
void CanvasRenderObject::OnLayoutContent(const Rect& content_rect) {
diff --git a/src/ui/render/FlexLayoutRenderObject.cpp b/src/ui/render/FlexLayoutRenderObject.cpp
index 8cbc0295..124f7e70 100644
--- a/src/ui/render/FlexLayoutRenderObject.cpp
+++ b/src/ui/render/FlexLayoutRenderObject.cpp
@@ -10,6 +10,7 @@ namespace cru::ui::render {
FlexLayoutRenderObject::FlexLayoutRenderObject()
: LayoutRenderObject<FlexChildLayoutData>(kRenderObjectName) {}
+namespace {
struct tag_horizontal_t {};
struct tag_vertical_t {};
@@ -69,7 +70,6 @@ constexpr TSize CreateTSize(decltype(std::declval<TSize>().width) main,
enum class FlexLayoutAdjustType { None, Expand, Shrink };
-namespace {
void Remove(std::vector<Index>& v, const std::vector<Index>& to_remove_v) {
Index current = 0;
for (auto to_remove : to_remove_v) {
@@ -106,16 +106,15 @@ Size FlexLayoutMeasureContentImpl(
// step 1.
for (Index i = 0; i < child_count; i++) {
const auto child = children[i];
- child->Measure(MeasureRequirement{CreateTSize<MeasureSize>(
- MeasureLength::NotSpecified(),
- max_cross_length, direction_tag),
- MeasureSize::NotSpecified()},
- MeasureSize::NotSpecified());
+ child->Measure(MeasureRequirement{
+ CreateTSize<MeasureSize>(MeasureLength::NotSpecified(),
+ max_cross_length, direction_tag),
+ MeasureSize::NotSpecified(), MeasureSize::NotSpecified()});
}
float total_length = 0.f;
for (auto child : children) {
- total_length += GetMain(child->GetDesiredSize(), direction_tag);
+ total_length += GetMain(child->GetMeasureResultSize(), direction_tag);
}
// step 2.
@@ -188,7 +187,8 @@ Size FlexLayoutMeasureContentImpl(
const float shrink_length = layout_data[i].shrink_factor /
total_shrink_factor * total_shrink_length;
float new_measure_length =
- GetMain(child->GetDesiredSize(), direction_tag) - shrink_length;
+ GetMain(child->GetMeasureResultSize(), direction_tag) -
+ shrink_length;
MeasureLength child_min_main_length =
GetMain(child->GetMinSize(), direction_tag);
@@ -200,15 +200,15 @@ Size FlexLayoutMeasureContentImpl(
new_measure_length = 0.f;
}
- child->Measure(MeasureRequirement{CreateTSize<MeasureSize>(
- new_measure_length,
- max_cross_length, direction_tag),
- MeasureSize::NotSpecified()},
- CreateTSize<MeasureSize>(new_measure_length,
- MeasureLength::NotSpecified(),
- direction_tag));
+ child->Measure(MeasureRequirement{
+ CreateTSize<MeasureSize>(new_measure_length, max_cross_length,
+ direction_tag),
+ MeasureSize::NotSpecified(),
+ CreateTSize<MeasureSize>(new_measure_length,
+ MeasureLength::NotSpecified(),
+ direction_tag)});
- const Size new_size = child->GetDesiredSize();
+ const Size new_size = child->GetMeasureResultSize();
const float new_main_length = GetMain(new_size, direction_tag);
if (new_main_length >= new_measure_length) {
to_remove.push_back(i);
@@ -217,7 +217,7 @@ Size FlexLayoutMeasureContentImpl(
total_length = 0.f;
for (auto child : children) {
- total_length += GetMain(child->GetDesiredSize(), direction_tag);
+ total_length += GetMain(child->GetMeasureResultSize(), direction_tag);
}
if (total_length <= target_length) break;
@@ -248,7 +248,8 @@ Size FlexLayoutMeasureContentImpl(
const float expand_length = layout_data[i].expand_factor /
total_expand_factor * total_expand_length;
float new_measure_length =
- GetMain(child->GetDesiredSize(), direction_tag) + expand_length;
+ GetMain(child->GetMeasureResultSize(), direction_tag) +
+ expand_length;
MeasureLength child_max_main_length =
GetMain(child->GetMaxSize(), direction_tag);
@@ -258,18 +259,17 @@ Size FlexLayoutMeasureContentImpl(
new_measure_length = child_max_main_length.GetLengthOrUndefined();
}
- child->Measure(
- MeasureRequirement{
- CreateTSize<MeasureSize>(MeasureLength::NotSpecified(),
- max_cross_length, direction_tag),
- CreateTSize<MeasureSize>(new_measure_length,
- MeasureLength::NotSpecified(),
- direction_tag)},
+ child->Measure(MeasureRequirement{
+ CreateTSize<MeasureSize>(MeasureLength::NotSpecified(),
+ max_cross_length, direction_tag),
+ CreateTSize<MeasureSize>(new_measure_length,
+ MeasureLength::NotSpecified(),
+ direction_tag),
CreateTSize<MeasureSize>(new_measure_length,
MeasureLength::NotSpecified(),
- direction_tag));
+ direction_tag)});
- const Size new_size = child->GetDesiredSize();
+ const Size new_size = child->GetMeasureResultSize();
const float new_main_length = GetMain(new_size, direction_tag);
if (new_main_length <= new_measure_length) {
to_remove.push_back(i);
@@ -278,7 +278,7 @@ Size FlexLayoutMeasureContentImpl(
total_length = 0.f;
for (auto child : children) {
- total_length += GetMain(child->GetDesiredSize(), direction_tag);
+ total_length += GetMain(child->GetMeasureResultSize(), direction_tag);
}
if (total_length >= target_length) break;
@@ -290,7 +290,8 @@ Size FlexLayoutMeasureContentImpl(
float child_max_cross_length = 0.f;
for (auto child : children) {
- const float cross_length = GetCross(child->GetDesiredSize(), direction_tag);
+ const float cross_length =
+ GetCross(child->GetMeasureResultSize(), direction_tag);
if (cross_length > child_max_cross_length) {
child_max_cross_length = cross_length;
}
@@ -311,16 +312,16 @@ Size FlexLayoutMeasureContentImpl(
child_max_cross_length =
std::max(min_cross_length.GetLengthOr0(), child_max_cross_length);
child_max_cross_length =
- std::min(max_cross_length.GetLengthOrMax(), child_max_cross_length);
+ std::min(max_cross_length.GetLengthOrMaxFloat(), child_max_cross_length);
for (Index i = 0; i < child_count; i++) {
auto child_layout_data = layout_data[i];
auto child = children[i];
if (child_layout_data.cross_alignment.value_or(item_cross_align) ==
Alignment::Stretch) {
- auto size = child->GetDesiredSize();
+ auto size = child->GetMeasureResultSize();
GetCross(size, direction_tag) = child_max_cross_length;
- child->Measure({size, size}, MeasureSize::NotSpecified());
+ child->Measure({size, size, MeasureSize::NotSpecified()});
}
}
@@ -329,7 +330,7 @@ Size FlexLayoutMeasureContentImpl(
} // namespace
Size FlexLayoutRenderObject::OnMeasureContent(
- const MeasureRequirement& requirement, const MeasureSize& preferred_size) {
+ const MeasureRequirement& requirement) {
const bool horizontal = (direction_ == FlexDirection::Horizontal ||
direction_ == FlexDirection::HorizontalReverse);
std::vector<RenderObject*> children;
@@ -341,11 +342,11 @@ Size FlexLayoutRenderObject::OnMeasureContent(
if (horizontal) {
return FlexLayoutMeasureContentImpl<tag_horizontal_t>(
- requirement, preferred_size, children, layout_data_list,
+ requirement, requirement.suggest, children, layout_data_list,
item_cross_align_, kLogTag);
} else {
return FlexLayoutMeasureContentImpl<tag_vertical_t>(
- requirement, preferred_size, children, layout_data_list,
+ requirement, requirement.suggest, children, layout_data_list,
item_cross_align_, kLogTag);
}
}
@@ -363,7 +364,7 @@ void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) {
float current_main_offset = 0;
for (Index i = 0; i < child_count; i++) {
const auto child = children[i];
- const auto size = child->GetDesiredSize();
+ const auto size = child->GetMeasureResultSize();
const auto cross_align =
layout_data_list[i].cross_alignment.value_or(GetItemCrossAlign());
child->Layout(
@@ -377,7 +378,7 @@ void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) {
float current_main_offset = 0;
for (Index i = 0; i < child_count; i++) {
const auto child = children[i];
- const auto size = child->GetDesiredSize();
+ const auto size = child->GetMeasureResultSize();
const auto cross_align =
layout_data_list[i].cross_alignment.value_or(GetItemCrossAlign());
child->Layout(
@@ -390,7 +391,7 @@ void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) {
float current_main_offset = 0;
for (Index i = 0; i < child_count; i++) {
const auto child = children[i];
- const auto size = child->GetDesiredSize();
+ const auto size = child->GetMeasureResultSize();
const auto cross_align =
layout_data_list[i].cross_alignment.value_or(GetItemCrossAlign());
child->Layout(Point{
@@ -404,7 +405,7 @@ void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) {
float current_main_offset = 0;
for (Index i = 0; i < child_count; i++) {
const auto child = children[i];
- const auto size = child->GetDesiredSize();
+ const auto size = child->GetMeasureResultSize();
const auto cross_align =
layout_data_list[i].cross_alignment.value_or(GetItemCrossAlign());
child->Layout(
diff --git a/src/ui/render/GeometryRenderObject.cpp b/src/ui/render/GeometryRenderObject.cpp
index 9b4eb572..84379b39 100644
--- a/src/ui/render/GeometryRenderObject.cpp
+++ b/src/ui/render/GeometryRenderObject.cpp
@@ -91,18 +91,9 @@ RenderObject* GeometryRenderObject::HitTest(const Point& point) {
}
Size GeometryRenderObject::OnMeasureContent(
- const MeasureRequirement& requirement, const MeasureSize& preferred_size) {
+ const MeasureRequirement& requirement) {
Size result = GetViewPort().GetSize();
-
- if (preferred_size.width.IsSpecified()) {
- result.width = preferred_size.width.GetLengthOrUndefined();
- }
-
- if (preferred_size.height.IsSpecified()) {
- result.height = preferred_size.height.GetLengthOrUndefined();
- }
-
- return requirement.Coerce(result);
+ return requirement.ExpandToSuggestAndCoerce(result);
}
void GeometryRenderObject::OnLayoutContent(const Rect& content_rect) {}
diff --git a/src/ui/render/RenderObject.cpp b/src/ui/render/RenderObject.cpp
index 9081d553..59dc6d6a 100644
--- a/src/ui/render/RenderObject.cpp
+++ b/src/ui/render/RenderObject.cpp
@@ -1,8 +1,8 @@
#include "cru/ui/render/RenderObject.h"
+#include "cru/base/Base.h"
#include "cru/base/log/Logger.h"
#include "cru/platform/GraphicsBase.h"
-#include "cru/ui/DebugFlags.h"
#include "cru/ui/controls/Control.h"
#include "cru/ui/controls/ControlHost.h"
@@ -63,8 +63,8 @@ void RenderObject::SetPadding(const Thickness& padding) {
InvalidateLayout();
}
-void RenderObject::SetPreferredSize(const MeasureSize& preferred_size) {
- preferred_size_ = preferred_size;
+void RenderObject::SetSuggestSize(const MeasureSize& suggest_size) {
+ custom_measure_requirement_.suggest = suggest_size;
InvalidateLayout();
}
@@ -78,93 +78,56 @@ void RenderObject::SetMaxSize(const MeasureSize& max_size) {
InvalidateLayout();
}
-void RenderObject::Measure(const MeasureRequirement& requirement,
- const MeasureSize& preferred_size) {
- MeasureRequirement merged_requirement =
- MeasureRequirement::Merge(requirement, custom_measure_requirement_)
- .Normalize();
- MeasureSize merged_preferred_size =
- preferred_size.OverrideBy(preferred_size_);
+void RenderObject::Measure(const MeasureRequirement& requirement) {
+ CRU_LOG_TAG_DEBUG("{} Measure begins, requirement {}.",
+ this->GetDebugPathInTree(), requirement);
- if constexpr (cru::ui::debug_flags::layout) {
- CRU_LOG_TAG_DEBUG(
- "{} Measure begins :\nrequirement: {}\npreferred size: {}",
- this->GetDebugPathInTree(), requirement.ToDebugString(),
- preferred_size.ToDebugString());
+ measure_result_size_ = OnMeasureCore(requirement);
+ if (measure_result_size_.width < 0 || measure_result_size_.height < 0) {
+ throw Exception("Measure result size is invalid.");
}
- desired_size_ = OnMeasureCore(merged_requirement, merged_preferred_size);
-
- if constexpr (cru::ui::debug_flags::layout) {
- CRU_LOG_TAG_DEBUG("{} Measure ends :\nresult size: {}",
- this->GetDebugPathInTree(), desired_size_);
- }
-
- Ensures(desired_size_.width >= 0);
- Ensures(desired_size_.height >= 0);
+ CRU_LOG_TAG_DEBUG("{} Measure ends, result size: {}.",
+ this->GetDebugPathInTree(), measure_result_size_);
}
void RenderObject::Layout(const Point& offset) {
- if constexpr (cru::ui::debug_flags::layout) {
- CRU_LOG_TAG_DEBUG("{} Layout :\noffset: {} size: {}",
- this->GetDebugPathInTree(), offset, desired_size_);
- }
+ CRU_LOG_TAG_DEBUG("{} Layout begins, offset: {}, size: {}.",
+ this->GetDebugPathInTree(), offset, measure_result_size_);
+
offset_ = offset;
- size_ = desired_size_;
+ size_ = measure_result_size_;
OnResize(size_);
OnLayoutCore();
+
+ CRU_LOG_TAG_DEBUG("{} Layout ends.", this->GetDebugPathInTree());
}
Thickness RenderObject::GetTotalSpaceThickness() { return margin_ + padding_; }
Thickness RenderObject::GetInnerSpaceThickness() { return padding_; }
-Size RenderObject::OnMeasureCore(const MeasureRequirement& requirement,
- const MeasureSize& preferred_size) {
- const Thickness outer_space = GetTotalSpaceThickness();
- const Size space_size{outer_space.GetHorizontalTotal(),
- outer_space.GetVerticalTotal()};
-
- MeasureRequirement content_requirement = requirement;
+Size RenderObject::OnMeasureCore(const MeasureRequirement& requirement) {
+ auto space_size = GetTotalSpaceThickness().GetTotalSize();
- content_requirement.max = content_requirement.max.Minus(space_size);
- content_requirement.min = content_requirement.min.Minus(space_size);
+ auto content_requirement =
+ requirement.Merge(custom_measure_requirement_).Minus(space_size);
- auto inner_space = GetInnerSpaceThickness();
- MeasureSize content_preferred_size =
- content_requirement.Coerce(preferred_size.Minus(
- {inner_space.GetHorizontalTotal(), inner_space.GetVerticalTotal()}));
-
- const auto content_size =
- OnMeasureContent(content_requirement, content_preferred_size);
+ auto content_size = OnMeasureContent(content_requirement);
return space_size + content_size;
}
void RenderObject::OnLayoutCore() {
- Size total_size = GetDesiredSize();
- const Thickness outer_space = GetTotalSpaceThickness();
- const Size space_size{outer_space.GetHorizontalTotal(),
- outer_space.GetVerticalTotal()};
-
- auto content_size = total_size - space_size;
-
- if (content_size.width < 0) {
- content_size.width = 0;
- }
- if (content_size.height < 0) {
- content_size.height = 0;
- }
+ auto total_size = GetMeasureResultSize();
+ auto outer_space = GetTotalSpaceThickness();
+ auto content_size = (total_size - outer_space.GetTotalSize()).AtLeast0();
Point lefttop{outer_space.left, outer_space.top};
- if (lefttop.x > total_size.width) {
- lefttop.x = total_size.width;
- }
- if (lefttop.y > total_size.height) {
- lefttop.y = total_size.height;
- }
+ lefttop.x = std::min(lefttop.x, total_size.width);
+ lefttop.y = std::min(lefttop.y, total_size.height);
const Rect content_rect{lefttop, content_size};
@@ -172,7 +135,7 @@ void RenderObject::OnLayoutCore() {
}
Rect RenderObject::GetPaddingRect() {
- const auto size = GetDesiredSize();
+ const auto size = GetMeasureResultSize();
Rect rect{Point{}, size};
rect = rect.Shrink(GetMargin());
rect.left = std::min(rect.left, size.width);
@@ -183,7 +146,7 @@ Rect RenderObject::GetPaddingRect() {
}
Rect RenderObject::GetContentRect() {
- const auto size = GetDesiredSize();
+ const auto size = GetMeasureResultSize();
Rect rect{Point{}, size};
rect = rect.Shrink(GetMargin());
rect = rect.Shrink(GetPadding());
diff --git a/src/ui/render/ScrollBar.cpp b/src/ui/render/ScrollBar.cpp
index 9e35cd30..8b2beac5 100644
--- a/src/ui/render/ScrollBar.cpp
+++ b/src/ui/render/ScrollBar.cpp
@@ -422,7 +422,7 @@ bool HorizontalScrollBar::IsShowBar() {
if (child == nullptr) return false;
const auto view_rect = render_object_->GetViewRect();
- const auto child_size = child->GetDesiredSize();
+ const auto child_size = child->GetMeasureResultSize();
if (view_rect.width >= child_size.width) return false;
@@ -439,7 +439,7 @@ std::optional<Rect> HorizontalScrollBar::GetExpandedAreaRect(
const auto child = render_object_->GetChild();
const auto view_rect = render_object_->GetViewRect();
- const auto child_size = child->GetDesiredSize();
+ const auto child_size = child->GetMeasureResultSize();
const float start_percentage = view_rect.left / child_size.width;
const float length_percentage = view_rect.width / child_size.width;
@@ -491,7 +491,7 @@ std::optional<Rect> HorizontalScrollBar::GetCollapsedThumbRect() {
const auto child = render_object_->GetChild();
const auto view_rect = render_object_->GetViewRect();
- const auto child_size = child->GetDesiredSize();
+ const auto child_size = child->GetMeasureResultSize();
const float start_percentage = view_rect.left / child_size.width;
const float length_percentage = view_rect.width / child_size.width;
@@ -517,7 +517,7 @@ float HorizontalScrollBar::CalculateNewScrollPosition(
auto thumb_head_end = scroll_area_end - thumb_original_rect.width;
const auto child = render_object_->GetChild();
- const auto child_size = child->GetDesiredSize();
+ const auto child_size = child->GetMeasureResultSize();
new_thumb_start =
std::clamp(new_thumb_start, scroll_area_start, thumb_head_end);
@@ -570,7 +570,7 @@ bool VerticalScrollBar::IsShowBar() {
if (child == nullptr) return false;
const auto view_rect = render_object_->GetViewRect();
- const auto child_size = child->GetDesiredSize();
+ const auto child_size = child->GetMeasureResultSize();
if (view_rect.height >= child_size.height) return false;
@@ -587,7 +587,7 @@ std::optional<Rect> VerticalScrollBar::GetExpandedAreaRect(
const auto child = render_object_->GetChild();
const auto view_rect = render_object_->GetViewRect();
- const auto child_size = child->GetDesiredSize();
+ const auto child_size = child->GetMeasureResultSize();
const float start_percentage = view_rect.top / child_size.height;
const float length_percentage = view_rect.height / child_size.height;
@@ -637,7 +637,7 @@ std::optional<Rect> VerticalScrollBar::GetCollapsedThumbRect() {
const auto view_rect = render_object_->GetViewRect();
const auto padding_rect = render_object_->GetPaddingRect();
- const auto child_size = child->GetDesiredSize();
+ const auto child_size = child->GetMeasureResultSize();
if (view_rect.height >= child_size.height) return std::nullopt;
@@ -663,7 +663,7 @@ float VerticalScrollBar::CalculateNewScrollPosition(
auto thumb_head_end = scroll_area_end - thumb_original_rect.height;
const auto child = render_object_->GetChild();
- const auto child_size = child->GetDesiredSize();
+ const auto child_size = child->GetMeasureResultSize();
new_thumb_start =
std::clamp(new_thumb_start, scroll_area_start, thumb_head_end);
diff --git a/src/ui/render/ScrollRenderObject.cpp b/src/ui/render/ScrollRenderObject.cpp
index d3e00db1..4d359a86 100644
--- a/src/ui/render/ScrollRenderObject.cpp
+++ b/src/ui/render/ScrollRenderObject.cpp
@@ -163,29 +163,18 @@ void ScrollRenderObject::SetMouseWheelScrollEnabled(bool enable) {
}
}
-Size ScrollRenderObject::OnMeasureContent(const MeasureRequirement& requirement,
- const MeasureSize& preferred_size) {
+Size ScrollRenderObject::OnMeasureContent(
+ const MeasureRequirement& requirement) {
if (auto child = GetChild()) {
- child->Measure(MeasureRequirement{MeasureSize::NotSpecified(),
- MeasureSize::NotSpecified()},
- MeasureSize::NotSpecified());
+ child->Measure({MeasureSize::NotSpecified(), MeasureSize::NotSpecified(),
+ MeasureSize::NotSpecified()});
+
+ auto result =
+ requirement.ExpandToSuggestAndCoerce(child->GetMeasureResultSize());
- Size result = requirement.Coerce(child->GetDesiredSize());
- if (preferred_size.width.IsSpecified()) {
- result.width = preferred_size.width.GetLengthOrUndefined();
- }
- if (preferred_size.height.IsSpecified()) {
- result.height = preferred_size.height.GetLengthOrUndefined();
- }
return result;
} else {
- Size result{preferred_size.width.IsSpecified()
- ? preferred_size.width.GetLengthOrUndefined()
- : requirement.min.width.GetLengthOr0(),
- preferred_size.height.IsSpecified()
- ? preferred_size.height.GetLengthOrUndefined()
- : requirement.min.height.GetLengthOr0()};
- return result;
+ return requirement.suggest.GetSizeOr0();
}
}
@@ -247,7 +236,7 @@ bool ScrollRenderObject::HorizontalCanScrollDown() {
auto child = GetChild();
if (child == nullptr) return false;
return GetScrollOffset().x <
- child->GetDesiredSize().width - GetViewRect().width;
+ child->GetMeasureResultSize().width - GetViewRect().width;
}
bool ScrollRenderObject::VerticalCanScrollUp() {
@@ -258,6 +247,6 @@ bool ScrollRenderObject::VerticalCanScrollDown() {
auto child = GetChild();
if (child == nullptr) return false;
return GetScrollOffset().y <
- child->GetDesiredSize().height - GetViewRect().height;
+ child->GetMeasureResultSize().height - GetViewRect().height;
}
} // namespace cru::ui::render
diff --git a/src/ui/render/StackLayoutRenderObject.cpp b/src/ui/render/StackLayoutRenderObject.cpp
index 6d5b9a10..d7017227 100644
--- a/src/ui/render/StackLayoutRenderObject.cpp
+++ b/src/ui/render/StackLayoutRenderObject.cpp
@@ -3,8 +3,6 @@
#include "cru/ui/render/LayoutHelper.h"
#include "cru/ui/render/MeasureRequirement.h"
-#include <algorithm>
-
namespace cru::ui::render {
StackLayoutRenderObject::StackLayoutRenderObject()
@@ -22,20 +20,18 @@ void StackLayoutRenderObject::SetDefaultVerticalAlignment(Alignment alignment) {
}
Size StackLayoutRenderObject::OnMeasureContent(
- const MeasureRequirement& requirement, const MeasureSize& preferred_size) {
+ const MeasureRequirement& requirement) {
Size child_max_size;
for (int i = 0; i < GetChildCount(); i++) {
auto child = GetChildAt(i);
- child->Measure(
- MeasureRequirement(requirement.max, MeasureSize::NotSpecified()),
- MeasureSize::NotSpecified());
- const auto size = child->GetDesiredSize();
- child_max_size.width = std::max(child_max_size.width, size.width);
- child_max_size.height = std::max(child_max_size.height, size.height);
+ child->Measure({requirement.max, MeasureSize::NotSpecified(),
+ MeasureSize::NotSpecified()});
+ auto size = child->GetMeasureResultSize();
+ child_max_size = child_max_size.Max(size);
}
- child_max_size = Max(preferred_size.GetSizeOr0(), child_max_size);
- child_max_size = Max(requirement.min.GetSizeOr0(), child_max_size);
+ child_max_size = requirement.suggest.Max(child_max_size);
+ child_max_size = requirement.min.Max(child_max_size);
for (Index i = 0; i < GetChildCount(); ++i) {
auto child_layout_data = GetChildLayoutDataAt(i);
@@ -47,8 +43,9 @@ Size StackLayoutRenderObject::OnMeasureContent(
Alignment::Stretch;
if (horizontal_stretch || vertical_stretch) {
auto child = GetChildAt(i);
- auto child_size = child->GetDesiredSize();
- MeasureRequirement child_requirement(child_size, child_size);
+ auto child_size = child->GetMeasureResultSize();
+ MeasureRequirement child_requirement(child_size, child_size,
+ MeasureSize::NotSpecified());
if (horizontal_stretch) {
child_requirement.min.width = child_requirement.max.width =
child_max_size.width;
@@ -58,7 +55,7 @@ Size StackLayoutRenderObject::OnMeasureContent(
child_requirement.min.height = child_requirement.max.height =
child_max_size.height;
}
- child->Measure(child_requirement, MeasureSize::NotSpecified());
+ child->Measure(child_requirement);
}
}
@@ -71,7 +68,7 @@ void StackLayoutRenderObject::OnLayoutContent(const Rect& content_rect) {
for (int i = 0; i < count; i++) {
const auto child = GetChildAt(i);
const auto& layout_data = GetChildLayoutDataAt(i);
- const auto& size = child->GetDesiredSize();
+ const auto& size = child->GetMeasureResultSize();
child->Layout(Point{
CalculateAnchorByAlignment(
layout_data.horizontal.value_or(default_horizontal_alignment_),
diff --git a/src/ui/render/TextRenderObject.cpp b/src/ui/render/TextRenderObject.cpp
index b9ab8dd9..44dee1aa 100644
--- a/src/ui/render/TextRenderObject.cpp
+++ b/src/ui/render/TextRenderObject.cpp
@@ -8,7 +8,6 @@
#include "cru/ui/DebugFlags.h"
#include "cru/ui/render/RenderObject.h"
-#include <algorithm>
#include <limits>
namespace cru::ui::render {
@@ -180,7 +179,7 @@ void TextRenderObject::Draw(platform::graphics::IPainter* painter) {
CRU_LOG_TAG_DEBUG(
"Begin to paint, total_offset: {}, size: {}, text_layout: "
"{}, brush: {}.",
- this->GetTotalOffset(), this->GetDesiredSize(),
+ this->GetTotalOffset(), this->GetMeasureResultSize(),
this->text_layout_->GetDebugString(), this->brush_->GetDebugString());
}
@@ -197,32 +196,16 @@ void TextRenderObject::Draw(platform::graphics::IPainter* painter) {
}
}
-Size TextRenderObject::OnMeasureContent(const MeasureRequirement& requirement,
- const MeasureSize& preferred_size) {
- float measure_width;
- if (preferred_size.width.IsSpecified())
- measure_width = preferred_size.width.GetLengthOrUndefined();
- else
- measure_width = requirement.max.width.GetLengthOrMax();
+Size TextRenderObject::OnMeasureContent(const MeasureRequirement& requirement) {
+ float measure_width = requirement.suggest.width.GetLengthOr(
+ requirement.max.width.GetLengthOrMaxFloat());
text_layout_->SetMaxWidth(measure_width);
text_layout_->SetMaxHeight(std::numeric_limits<float>::max());
- const Size text_size(
- text_layout_->GetTextBounds(is_measure_including_trailing_space_)
- .GetRightBottom());
- auto result = text_size;
-
- result.width = std::max(result.width, preferred_size.width.GetLengthOr0());
- result.width = std::max(result.width, requirement.min.width.GetLengthOr0());
- result.width = std::min(result.width, requirement.max.width.GetLengthOrMax());
-
- result.height = std::max(result.height, preferred_size.height.GetLengthOr0());
- result.height =
- std::max(result.height, requirement.min.height.GetLengthOr0());
- result.height =
- std::min(result.height, requirement.max.height.GetLengthOrMax());
-
+ Size result(text_layout_->GetTextBounds(is_measure_including_trailing_space_)
+ .GetRightBottom());
+ result = requirement.ExpandToSuggestAndCoerce(result);
return result;
}
diff --git a/src/ui/render/TreeRenderObject.cpp b/src/ui/render/TreeRenderObject.cpp
index 8c13e93a..758108f6 100644
--- a/src/ui/render/TreeRenderObject.cpp
+++ b/src/ui/render/TreeRenderObject.cpp
@@ -101,12 +101,12 @@ static Size MeasureTreeRenderObjectItem(MeasureSize max_size,
float tab_width) {
auto render_object = item->GetRenderObject();
if (render_object) {
- render_object->Measure(
- MeasureRequirement(max_size, MeasureSize::NotSpecified()),
- MeasureSize::NotSpecified());
+ render_object->Measure(MeasureRequirement(
+ max_size, MeasureSize::NotSpecified(), MeasureSize::NotSpecified()));
}
- Size item_size = render_object ? render_object->GetDesiredSize() : Size{};
+ Size item_size =
+ render_object ? render_object->GetMeasureResultSize() : Size{};
if (max_size.width.IsSpecified()) {
max_size.width = max_size.width.GetLengthOrUndefined() - tab_width;
@@ -128,14 +128,10 @@ static Size MeasureTreeRenderObjectItem(MeasureSize max_size,
return result_size;
}
-Size TreeRenderObject::OnMeasureContent(const MeasureRequirement& requirement,
- const MeasureSize& preferred_size) {
+Size TreeRenderObject::OnMeasureContent(const MeasureRequirement& requirement) {
auto size =
MeasureTreeRenderObjectItem(requirement.max, root_item_, tab_width_);
-
- size = Max(size, requirement.min.GetSizeOr0());
-
- return size;
+ return requirement.ExpandToSuggestAndCoerce(size);
}
static void LayoutTreeRenderObjectItem(Rect rect, TreeRenderObjectItem* item,
@@ -144,7 +140,7 @@ static void LayoutTreeRenderObjectItem(Rect rect, TreeRenderObjectItem* item,
float item_height = 0.f;
if (render_object) {
render_object->Layout(rect.GetLeftTop());
- item_height = render_object->GetDesiredSize().height;
+ item_height = render_object->GetMeasureResultSize().height;
}
rect.left += tab_width;
@@ -156,7 +152,7 @@ static void LayoutTreeRenderObjectItem(Rect rect, TreeRenderObjectItem* item,
LayoutTreeRenderObjectItem(rect, child, tab_width);
auto child_render_object = child->GetRenderObject();
auto child_height = child_render_object
- ? child_render_object->GetDesiredSize().height
+ ? child_render_object->GetMeasureResultSize().height
: 0.f;
rect.top += child_height;
rect.height -= child_height;
diff --git a/src/ui/style/Styler.cpp b/src/ui/style/Styler.cpp
index 251d403c..b0b14c61 100644
--- a/src/ui/style/Styler.cpp
+++ b/src/ui/style/Styler.cpp
@@ -31,7 +31,7 @@ void CursorStyler::Apply(controls::Control* control) const {
}
void PreferredSizeStyler::Apply(controls::Control* control) const {
- control->SetPreferredSize(size_);
+ control->SetSuggestSize(size_);
}
void MarginStyler::Apply(controls::Control* control) const {