diff options
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 { |
