diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ui/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/ui/UiHost.cpp | 7 | ||||
-rw-r--r-- | src/ui/render/BorderRenderObject.cpp | 68 | ||||
-rw-r--r-- | src/ui/render/CanvasRenderObject.cpp | 9 | ||||
-rw-r--r-- | src/ui/render/FlexLayoutRenderObject.cpp | 385 | ||||
-rw-r--r-- | src/ui/render/LayoutUtility.cpp | 15 | ||||
-rw-r--r-- | src/ui/render/RenderObject.cpp | 86 | ||||
-rw-r--r-- | src/ui/render/ScrollRenderObject.cpp | 40 | ||||
-rw-r--r-- | src/ui/render/StackLayoutRenderObject.cpp | 86 | ||||
-rw-r--r-- | src/ui/render/TextRenderObject.cpp | 44 | ||||
-rw-r--r-- | src/ui/render/WindowRenderObject.cpp | 10 |
11 files changed, 420 insertions, 332 deletions
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 68efa903..9043974e 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -23,7 +23,6 @@ add_library(cru_ui STATIC render/BorderRenderObject.cpp render/CanvasRenderObject.cpp render/FlexLayoutRenderObject.cpp - render/LayoutUtility.cpp render/RenderObject.cpp render/ScrollRenderObject.cpp render/StackLayoutRenderObject.cpp @@ -53,7 +52,6 @@ target_sources(cru_ui PUBLIC ${CRU_UI_INCLUDE_DIR}/render/CanvasRenderObject.hpp ${CRU_UI_INCLUDE_DIR}/render/FlexLayoutRenderObject.hpp ${CRU_UI_INCLUDE_DIR}/render/LayoutRenderObject.hpp - ${CRU_UI_INCLUDE_DIR}/render/LayoutUtility.hpp ${CRU_UI_INCLUDE_DIR}/render/MeasureRequirement.hpp ${CRU_UI_INCLUDE_DIR}/render/RenderObject.hpp ${CRU_UI_INCLUDE_DIR}/render/ScrollRenderObject.hpp diff --git a/src/ui/UiHost.cpp b/src/ui/UiHost.cpp index 7047d43f..09f8fd9b 100644 --- a/src/ui/UiHost.cpp +++ b/src/ui/UiHost.cpp @@ -166,8 +166,11 @@ void UiHost::Relayout() { const auto client_size = native_window ? native_window->GetClientSize() : Size{100, 100}; // a reasonable assumed size - root_render_object_->Measure(client_size); - root_render_object_->Layout(Rect{Point{}, client_size}); + root_render_object_->Measure( + render::MeasureRequirement{client_size, + render::MeasureSize::NotSpecified()}, + render::MeasureSize::NotSpecified()); + root_render_object_->Layout(Point{}); } bool UiHost::RequestFocusFor(Control* control) { diff --git a/src/ui/render/BorderRenderObject.cpp b/src/ui/render/BorderRenderObject.cpp index ad0c6455..74e50561 100644 --- a/src/ui/render/BorderRenderObject.cpp +++ b/src/ui/render/BorderRenderObject.cpp @@ -73,9 +73,10 @@ RenderObject* BorderRenderObject::HitTest(const Point& point) { } } -Size BorderRenderObject::OnMeasureCore(const MeasureRequirement& requirement) { +Size BorderRenderObject::OnMeasureCore(const MeasureRequirement& requirement, + const MeasureSize& preferred_size) { if (!is_border_enabled_) { - return RenderObject::OnMeasureCore(requirement); + return RenderObject::OnMeasureCore(requirement, preferred_size); } const auto margin = GetMargin(); @@ -90,36 +91,51 @@ Size BorderRenderObject::OnMeasureCore(const MeasureRequirement& requirement) { MeasureRequirement content_requirement = requirement; - if (!requirement.max_width.IsNotSpecify()) { - const auto max_width = requirement.max_width.GetLength(); + if (!requirement.max.width.IsNotSpecified()) { + const auto max_width = requirement.max.width.GetLengthOrMax(); if (coerced_space_size.width > max_width) { log::Warn( - "Measure: horizontal length of padding and margin is bigger than " - "available length."); + "BorderRenderObject: During measure, horizontal length of padding, " + "border and margin is bigger than required max length."); coerced_space_size.width = max_width; } - content_requirement.max_width = max_width - coerced_space_size.width; + content_requirement.max.width = max_width - coerced_space_size.width; } - if (!requirement.max_height.IsNotSpecify()) { - const auto max_height = requirement.max_height.GetLength(); + if (!requirement.min.width.IsNotSpecified()) { + const auto min_width = requirement.min.width.GetLengthOr0(); + content_requirement.min.width = std::max(0.f, min_width - space_size.width); + } + + if (!requirement.max.height.IsNotSpecified()) { + const auto max_height = requirement.max.height.GetLengthOrMax(); if (coerced_space_size.height > max_height) { log::Warn( - "Measure: horizontal length of padding and margin is bigger than " - "available length."); + "BorderRenderObject: During measure, vertical length of padding, " + "border and margin is bigger than required max length."); coerced_space_size.height = max_height; } - content_requirement.max_height = max_height - coerced_space_size.height; + content_requirement.max.height = max_height - coerced_space_size.height; } - const auto content_size = OnMeasureContent(content_requirement); + if (!requirement.min.height.IsNotSpecified()) { + const auto min_height = requirement.min.height.GetLengthOr0(); + content_requirement.min.height = + std::max(0.f, min_height - space_size.height); + } + + MeasureSize content_preferred_size = + content_requirement.Coerce(preferred_size.Minus(space_size)); + + const auto content_size = + OnMeasureContent(content_requirement, content_preferred_size); return coerced_space_size + content_size; -} // namespace cru::ui::render +} -void BorderRenderObject::OnLayoutCore(const Size& size) { +void BorderRenderObject::OnLayoutCore() { if (!is_border_enabled_) { - return RenderObject::OnLayoutCore(size); + return RenderObject::OnLayoutCore(); } const auto margin = GetMargin(); @@ -129,18 +145,20 @@ void BorderRenderObject::OnLayoutCore(const Size& size) { margin.GetVerticalTotal() + padding.GetVerticalTotal() + border_thickness_.GetVerticalTotal()}; + const auto size = GetSize(); + auto content_size = size - space_size; if (content_size.width < 0) { log::Warn( - "Layout: horizontal length of padding, border and margin is bigger " - "than available length."); + "BorderRenderObject: During layout, horizontal length of padding, " + "border and margin is bigger than available length."); content_size.width = 0; } if (content_size.height < 0) { log::Warn( - "Layout: vertical length of padding, border and margin is bigger " - "than available length."); + "BorderRenderObject: During layout, vertical length of padding, " + "border and margin is bigger than available length."); content_size.height = 0; } @@ -158,12 +176,12 @@ void BorderRenderObject::OnLayoutCore(const Size& size) { OnLayoutContent(content_rect); } -Size BorderRenderObject::OnMeasureContent( - const MeasureRequirement& requirement) { +Size BorderRenderObject::OnMeasureContent(const MeasureRequirement& requirement, + const MeasureSize& preferred_size) { const auto child = GetSingleChild(); if (child) { - child->Measure(requirement); - return child->GetMeasuredSize(); + child->Measure(requirement, preferred_size); + return child->GetSize(); } else { return Size{}; } @@ -172,7 +190,7 @@ Size BorderRenderObject::OnMeasureContent( void BorderRenderObject::OnLayoutContent(const Rect& content_rect) { const auto child = GetSingleChild(); if (child) { - child->Layout(content_rect); + child->Layout(content_rect.GetLeftTop()); } } diff --git a/src/ui/render/CanvasRenderObject.cpp b/src/ui/render/CanvasRenderObject.cpp index 72eb3570..211d1fce 100644 --- a/src/ui/render/CanvasRenderObject.cpp +++ b/src/ui/render/CanvasRenderObject.cpp @@ -1,7 +1,5 @@ #include "cru/ui/render/CanvasRenderObject.hpp" -#include "cru/ui/render/LayoutUtility.hpp" - namespace cru::ui::render { CanvasRenderObject::CanvasRenderObject() : RenderObject(ChildMode::None) {} @@ -18,9 +16,10 @@ RenderObject* CanvasRenderObject::HitTest(const Point& point) { return padding_rect.IsPointInside(point) ? this : nullptr; } -Size CanvasRenderObject::OnMeasureContent( - const MeasureRequirement& requirement) { - return Min(requirement.GetMaxSize(), GetDesiredSize()); +Size CanvasRenderObject::OnMeasureContent(const MeasureRequirement& requirement, + const MeasureSize& preferred_size) { + return requirement.Coerce(Size{preferred_size.width.GetLengthOr(100), + preferred_size.height.GetLengthOr(100)}); } void CanvasRenderObject::OnLayoutContent(const Rect& content_rect) { diff --git a/src/ui/render/FlexLayoutRenderObject.cpp b/src/ui/render/FlexLayoutRenderObject.cpp index 72341a64..fcaf6f9a 100644 --- a/src/ui/render/FlexLayoutRenderObject.cpp +++ b/src/ui/render/FlexLayoutRenderObject.cpp @@ -7,194 +7,207 @@ namespace cru::ui::render { Size FlexLayoutRenderObject::OnMeasureContent( - const MeasureRequirement& requirement) { - const bool horizontal = (direction_ == FlexDirection::Horizontal || - direction_ == FlexDirection::HorizontalReverse); - - const auto main_max_length = - horizontal ? requirement.max_width : requirement.max_height; - const auto cross_max_length = - horizontal ? requirement.max_height : requirement.max_width; - - std::function<float(const Size&)> get_main_length; - std::function<float(const Size&)> get_cross_length; - std::function<void(Size&, const Size&)> calculate_result_size; - std::function<MeasureRequirement(MeasureLength main, MeasureLength cross)> - create_requirement; - - if (horizontal) { - get_main_length = [](const Size& size) { return size.width; }; - get_cross_length = [](const Size& size) { return size.height; }; - calculate_result_size = [](Size& result, const Size& child_size) { - result.width += child_size.width; - result.height = std::max(result.height, child_size.height); - }; - create_requirement = [](MeasureLength main, MeasureLength cross) { - return MeasureRequirement{main, cross}; - }; - } else { - get_main_length = [](const Size& size) { return size.height; }; - get_cross_length = [](const Size& size) { return size.width; }; - calculate_result_size = [](Size& result, const Size& child_size) { - result.height += child_size.height; - result.width = std::max(result.width, child_size.width); - }; - create_requirement = [](MeasureLength main, MeasureLength cross) { - return MeasureRequirement{cross, main}; - }; - } - - const auto& children = GetChildren(); - Index children_count = children.size(); - - if (!main_max_length.IsNotSpecify()) { - float remain_main_length = main_max_length.GetLength(); - - for (Index i = 0; i < children_count; i++) { - const auto child = children[i]; - child->Measure(create_requirement(remain_main_length, cross_max_length)); - const auto measure_result = child->GetMeasuredSize(); - remain_main_length -= get_main_length(measure_result); - } - - if (remain_main_length > 0) { - std::vector<Index> expand_children; - float total_expand_factor = 0; - - for (Index i = 0; i < children_count; i++) { - const auto factor = GetChildLayoutData(i)->expand_factor; - if (factor > 0) { - expand_children.push_back(i); - total_expand_factor += factor; - } - } - - for (const Index i : expand_children) { - const float distributed_grow_length = - remain_main_length * - (GetChildLayoutData(i)->expand_factor / total_expand_factor); - const auto child = children[i]; - const float new_main_length = - get_main_length(child->GetMeasuredSize()) + distributed_grow_length; - child->Measure(create_requirement(new_main_length, cross_max_length)); - } - } else if (remain_main_length < 0) { - std::vector<Index> shrink_children; - float total_shrink_factor = 0; - - for (Index i = 0; i < children_count; i++) { - const auto factor = GetChildLayoutData(i)->shrink_factor; - if (factor > 0) { - shrink_children.push_back(i); - total_shrink_factor += factor; - } - } - - for (const Index i : shrink_children) { - const float distributed_shrink_length = // negative - remain_main_length * - (GetChildLayoutData(i)->shrink_factor / total_shrink_factor); - const auto child = children[i]; - float new_main_length = get_main_length(child->GetMeasuredSize()) + - distributed_shrink_length; - new_main_length = new_main_length > 0 ? new_main_length : 0; - child->Measure(create_requirement(new_main_length, cross_max_length)); - } - } - } else { - for (Index i = 0; i < children_count; i++) { - const auto child = children[i]; - child->Measure(requirement); - } - } - - Size result; - for (auto child : children) { - calculate_result_size(result, child->GetMeasuredSize()); - } - - return result; + const MeasureRequirement& requirement, const MeasureSize& preferred_size) { + // TODO: Rewrite this. + CRU_UNUSED(requirement); + CRU_UNUSED(preferred_size); + throw std::runtime_error("Not implemented."); + + // const bool horizontal = (direction_ == FlexDirection::Horizontal || + // direction_ == FlexDirection::HorizontalReverse); + + // const auto main_max_length = + // horizontal ? requirement.max_width : requirement.max_height; + // const auto cross_max_length = + // horizontal ? requirement.max_height : requirement.max_width; + + // std::function<float(const Size&)> get_main_length; + // std::function<float(const Size&)> get_cross_length; + // std::function<void(Size&, const Size&)> calculate_result_size; + // std::function<MeasureRequirement(MeasureLength main, MeasureLength cross)> + // create_requirement; + + // if (horizontal) { + // get_main_length = [](const Size& size) { return size.width; }; + // get_cross_length = [](const Size& size) { return size.height; }; + // calculate_result_size = [](Size& result, const Size& child_size) { + // result.width += child_size.width; + // result.height = std::max(result.height, child_size.height); + // }; + // create_requirement = [](MeasureLength main, MeasureLength cross) { + // return MeasureRequirement{main, cross}; + // }; + // } else { + // get_main_length = [](const Size& size) { return size.height; }; + // get_cross_length = [](const Size& size) { return size.width; }; + // calculate_result_size = [](Size& result, const Size& child_size) { + // result.height += child_size.height; + // result.width = std::max(result.width, child_size.width); + // }; + // create_requirement = [](MeasureLength main, MeasureLength cross) { + // return MeasureRequirement{cross, main}; + // }; + // } + + // const auto& children = GetChildren(); + // Index children_count = children.size(); + + // if (!main_max_length.IsNotSpecify()) { + // float remain_main_length = main_max_length.GetLengthOrMax(); + + // for (Index i = 0; i < children_count; i++) { + // const auto child = children[i]; + // child->Measure(create_requirement(remain_main_length, + // cross_max_length)); const auto measure_result = + // child->GetMeasuredSize(); remain_main_length -= + // get_main_length(measure_result); + // } + + // if (remain_main_length > 0) { + // std::vector<Index> expand_children; + // float total_expand_factor = 0; + + // for (Index i = 0; i < children_count; i++) { + // const auto factor = GetChildLayoutData(i)->expand_factor; + // if (factor > 0) { + // expand_children.push_back(i); + // total_expand_factor += factor; + // } + // } + + // for (const Index i : expand_children) { + // const float distributed_grow_length = + // remain_main_length * + // (GetChildLayoutData(i)->expand_factor / total_expand_factor); + // const auto child = children[i]; + // const float new_main_length = + // get_main_length(child->GetMeasuredSize()) + + // distributed_grow_length; + // child->Measure(create_requirement(new_main_length, + // cross_max_length)); + // } + // } else if (remain_main_length < 0) { + // std::vector<Index> shrink_children; + // float total_shrink_factor = 0; + + // for (Index i = 0; i < children_count; i++) { + // const auto factor = GetChildLayoutData(i)->shrink_factor; + // if (factor > 0) { + // shrink_children.push_back(i); + // total_shrink_factor += factor; + // } + // } + + // for (const Index i : shrink_children) { + // const float distributed_shrink_length = // negative + // remain_main_length * + // (GetChildLayoutData(i)->shrink_factor / total_shrink_factor); + // const auto child = children[i]; + // float new_main_length = get_main_length(child->GetMeasuredSize()) + + // distributed_shrink_length; + // new_main_length = new_main_length > 0 ? new_main_length : 0; + // child->Measure(create_requirement(new_main_length, + // cross_max_length)); + // } + // } + // } else { + // for (Index i = 0; i < children_count; i++) { + // const auto child = children[i]; + // child->Measure(requirement); + // } + // } + + // Size result; + // for (auto child : children) { + // calculate_result_size(result, child->GetMeasuredSize()); + // } + + // return result; } void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) { - auto calculate_anchor = [](int alignment, float start_point, - float total_length, - float content_length) -> float { - switch (alignment) { - case internal::align_start: - return start_point; - case internal::align_center: - return start_point + (total_length - content_length) / 2.0f; - case internal::align_end: - return start_point + total_length - content_length; - default: - return start_point; - } - }; - - const auto& children = GetChildren(); - if (direction_ == FlexDirection::Horizontal || - direction_ == FlexDirection::HorizontalReverse) { - float actual_content_width = 0; - for (const auto child : children) { - actual_content_width += child->GetMeasuredSize().width; - } - - const float content_anchor_x = - calculate_anchor(static_cast<int>(content_main_align_), 0, - content_rect.width, actual_content_width); - - float anchor_x = 0; - for (int i = 0; i < static_cast<int>(children.size()); i++) { - const auto child = children[i]; - const auto size = child->GetMeasuredSize(); - - float real_anchor_x = anchor_x + content_anchor_x; - if (direction_ == FlexDirection::Horizontal) - real_anchor_x = content_rect.left + real_anchor_x; - else - real_anchor_x = content_rect.GetRight() - real_anchor_x; - child->Layout(Rect{ - real_anchor_x, - calculate_anchor( - static_cast<int>(GetChildLayoutData(i)->cross_alignment.value_or( - this->item_cross_align_)), - content_rect.top, content_rect.height, size.height), - size.width, size.height}); - - anchor_x += size.width; - } - } else { - float actual_content_height = 0; - for (const auto child : children) { - actual_content_height = child->GetMeasuredSize().height; - } - - const float content_anchor_y = - calculate_anchor(static_cast<int>(content_main_align_), 0, - content_rect.height, actual_content_height); - - float anchor_y = 0; - for (int i = 0; i < static_cast<int>(children.size()); i++) { - const auto child = children[i]; - const auto size = child->GetMeasuredSize(); - - float real_anchor_y = anchor_y + content_anchor_y; - if (direction_ == FlexDirection::Vertical) { - real_anchor_y = content_rect.top + real_anchor_y; - } else { - real_anchor_y = content_rect.GetBottom() - real_anchor_y; - } - child->Layout(Rect{ - real_anchor_y, - calculate_anchor( - static_cast<int>(GetChildLayoutData(i)->cross_alignment.value_or( - this->item_cross_align_)), - content_rect.left, content_rect.width, size.width), - size.width, size.height}); - - anchor_y += size.height; - } - } + // TODO: Rewrite this. + CRU_UNUSED(content_rect); + throw std::runtime_error("Not implemented."); + + // auto calculate_anchor = [](int alignment, float start_point, + // float total_length, + // float content_length) -> float { + // switch (alignment) { + // case internal::align_start: + // return start_point; + // case internal::align_center: + // return start_point + (total_length - content_length) / 2.0f; + // case internal::align_end: + // return start_point + total_length - content_length; + // default: + // return start_point; + // } + // }; + + // const auto& children = GetChildren(); + // if (direction_ == FlexDirection::Horizontal || + // direction_ == FlexDirection::HorizontalReverse) { + // float actual_content_width = 0; + // for (const auto child : children) { + // actual_content_width += child->GetMeasuredSize().width; + // } + + // const float content_anchor_x = + // calculate_anchor(static_cast<int>(content_main_align_), 0, + // content_rect.width, actual_content_width); + + // float anchor_x = 0; + // for (int i = 0; i < static_cast<int>(children.size()); i++) { + // const auto child = children[i]; + // const auto size = child->GetMeasuredSize(); + + // float real_anchor_x = anchor_x + content_anchor_x; + // if (direction_ == FlexDirection::Horizontal) + // real_anchor_x = content_rect.left + real_anchor_x; + // else + // real_anchor_x = content_rect.GetRight() - real_anchor_x; + // child->Layout(Rect{ + // real_anchor_x, + // calculate_anchor( + // static_cast<int>(GetChildLayoutData(i)->cross_alignment.value_or( + // this->item_cross_align_)), + // content_rect.top, content_rect.height, size.height), + // size.width, size.height}); + + // anchor_x += size.width; + // } + // } else { + // float actual_content_height = 0; + // for (const auto child : children) { + // actual_content_height = child->GetMeasuredSize().height; + // } + + // const float content_anchor_y = + // calculate_anchor(static_cast<int>(content_main_align_), 0, + // content_rect.height, actual_content_height); + + // float anchor_y = 0; + // for (int i = 0; i < static_cast<int>(children.size()); i++) { + // const auto child = children[i]; + // const auto size = child->GetMeasuredSize(); + + // float real_anchor_y = anchor_y + content_anchor_y; + // if (direction_ == FlexDirection::Vertical) { + // real_anchor_y = content_rect.top + real_anchor_y; + // } else { + // real_anchor_y = content_rect.GetBottom() - real_anchor_y; + // } + // child->Layout(Rect{ + // real_anchor_y, + // calculate_anchor( + // static_cast<int>(GetChildLayoutData(i)->cross_alignment.value_or( + // this->item_cross_align_)), + // content_rect.left, content_rect.width, size.width), + // size.width, size.height}); + + // anchor_y += size.height; + // } + // } } } // namespace cru::ui::render diff --git a/src/ui/render/LayoutUtility.cpp b/src/ui/render/LayoutUtility.cpp deleted file mode 100644 index 03252f1c..00000000 --- a/src/ui/render/LayoutUtility.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "cru/ui/render/LayoutUtility.hpp" - -#include <algorithm> - -namespace cru::ui::render { -Size Min(const Size& left, const Size& right) { - return Size{std::min(left.width, right.width), - std::min(left.height, right.height)}; -} - -Size Max(const Size& left, const Size& right) { - return Size{std::max(left.width, right.width), - std::max(left.height, right.height)}; -} -} // namespace cru::ui::render diff --git a/src/ui/render/RenderObject.cpp b/src/ui/render/RenderObject.cpp index abd5e1c4..ac38c6b5 100644 --- a/src/ui/render/RenderObject.cpp +++ b/src/ui/render/RenderObject.cpp @@ -57,20 +57,23 @@ Point RenderObject::FromRootToContent(const Point& point) const { point.y - (offset.y + rect.top)}; } -void RenderObject::Measure(const MeasureRequirement& requirement) { - measured_size_ = OnMeasureCore(requirement); +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_); - Ensures(measured_size_.width >= 0); - Ensures(measured_size_.height >= 0); - Ensures(requirement.Satisfy(measured_size_)); + size_ = OnMeasureCore(merged_requirement, merged_preferred_size); + Ensures(size_.width >= 0); + Ensures(size_.height >= 0); + Ensures(requirement.Satisfy(size_)); } -void RenderObject::Layout(const Rect& rect) { - Expects(rect.width >= 0); - Expects(rect.height >= 0); - offset_ = rect.GetLeftTop(); - size_ = rect.GetSize(); - OnLayoutCore(rect.GetSize()); +void RenderObject::Layout(const Point& offset) { + offset_ = offset; + OnLayoutCore(); } RenderObject* RenderObject::GetSingleChild() const { @@ -104,7 +107,8 @@ void RenderObject::OnRemoveChild(RenderObject* removed_child, Index position) { InvalidatePaint(); } -Size RenderObject::OnMeasureCore(const MeasureRequirement& requirement) { +Size RenderObject::OnMeasureCore(const MeasureRequirement& requirement, + const MeasureSize& preferred_size) { const Size space_size{ margin_.GetHorizontalTotal() + padding_.GetHorizontalTotal(), margin_.GetVerticalTotal() + padding_.GetVerticalTotal()}; @@ -113,58 +117,74 @@ Size RenderObject::OnMeasureCore(const MeasureRequirement& requirement) { MeasureRequirement content_requirement = requirement; - if (!requirement.max_width.IsNotSpecify()) { - const auto max_width = requirement.max_width.GetLength(); + if (!requirement.max.width.IsNotSpecified()) { + const auto max_width = requirement.max.width.GetLengthOrMax(); if (coerced_space_size.width > max_width) { log::Warn( - "Measure: horizontal length of padding and margin is bigger than " - "available length."); + "RenderObject: During measure, horizontal length of padding and " + "margin is bigger than required max length."); coerced_space_size.width = max_width; } - content_requirement.max_width = max_width - coerced_space_size.width; + content_requirement.max.width = max_width - coerced_space_size.width; } - if (!requirement.max_height.IsNotSpecify()) { - const auto max_height = requirement.max_height.GetLength(); + if (!requirement.min.width.IsNotSpecified()) { + const auto min_width = requirement.min.width.GetLengthOr0(); + content_requirement.min.width = std::max(0.f, min_width - space_size.width); + } + + if (!requirement.max.height.IsNotSpecified()) { + const auto max_height = requirement.max.height.GetLengthOrMax(); if (coerced_space_size.height > max_height) { log::Warn( - "Measure: horizontal length of padding and margin is bigger than " - "available length."); + "RenderObject: During measure, vertical length of padding and " + "margin is bigger than required max length."); coerced_space_size.height = max_height; } - content_requirement.max_height = max_height - coerced_space_size.height; + content_requirement.max.height = max_height - coerced_space_size.height; } - const auto content_size = OnMeasureContent(content_requirement); + if (!requirement.min.height.IsNotSpecified()) { + const auto min_height = requirement.min.height.GetLengthOr0(); + content_requirement.min.height = + std::max(0.f, min_height - space_size.height); + } + + MeasureSize content_preferred_size = + content_requirement.Coerce(preferred_size.Minus(space_size)); + + const auto content_size = + OnMeasureContent(content_requirement, content_preferred_size); return coerced_space_size + content_size; } -void RenderObject::OnLayoutCore(const Size& size) { +void RenderObject::OnLayoutCore() { + Size total_size = GetSize(); Size space_size{margin_.GetHorizontalTotal() + padding_.GetHorizontalTotal(), margin_.GetVerticalTotal() + padding_.GetVerticalTotal()}; - auto content_size = size - space_size; + auto content_size = total_size - space_size; if (content_size.width < 0) { log::Warn( - "Layout: horizontal length of padding and margin is bigger than " - "available length."); + "RenderObject: During layout, horizontal length of padding and margin " + "is bigger than available length."); content_size.width = 0; } if (content_size.height < 0) { log::Warn( - "Layout: vertical length of padding and margin is bigger than " - "available length."); + "RenderObject: During layout, vertical length of padding and margin " + "is bigger than available length."); content_size.height = 0; } Point lefttop{margin_.left + padding_.left, margin_.top + padding_.top}; - if (lefttop.x > size.width) { - lefttop.x = size.width; + if (lefttop.x > total_size.width) { + lefttop.x = total_size.width; } - if (lefttop.y > size.height) { - lefttop.y = size.height; + if (lefttop.y > total_size.height) { + lefttop.y = total_size.height; } const Rect content_rect{lefttop, content_size}; diff --git a/src/ui/render/ScrollRenderObject.cpp b/src/ui/render/ScrollRenderObject.cpp index 98254690..e4cc27f3 100644 --- a/src/ui/render/ScrollRenderObject.cpp +++ b/src/ui/render/ScrollRenderObject.cpp @@ -2,7 +2,6 @@ #include "cru/platform/graph/Painter.hpp" #include "cru/platform/graph/util/Painter.hpp" -#include "cru/ui/render/LayoutUtility.hpp" #include <algorithm> @@ -67,23 +66,32 @@ void ScrollRenderObject::SetScrollOffset(const Point& offset) { InvalidateLayout(); } -Size ScrollRenderObject::OnMeasureContent( - const MeasureRequirement& requirement) { - if (const auto child = GetSingleChild()) { - child->Measure(MeasureRequirement::Infinate()); - const auto preferred_size = child->GetMeasuredSize(); - return Min(preferred_size, requirement.GetMaxSize()); - } else { - return Size{}; - } +Size ScrollRenderObject::OnMeasureContent(const MeasureRequirement& requirement, + const MeasureSize& preferred_size) { + // TODO: Rewrite this. + CRU_UNUSED(requirement); + CRU_UNUSED(preferred_size); + throw std::runtime_error("Not implemented."); + + // if (const auto child = GetSingleChild()) { + // child->Measure(MeasureRequirement::Infinate()); + // const auto preferred_size = child->GetMeasuredSize(); + // return Min(preferred_size, requirement.GetMaxSize()); + // } else { + // return Size{}; + // } } // namespace cru::ui::render void ScrollRenderObject::OnLayoutContent(const Rect& content_rect) { - if (const auto child = GetSingleChild()) { - const auto child_size = child->GetMeasuredSize(); - const auto true_scroll = - CoerceScroll(scroll_offset_, content_rect.GetSize(), child_size); - child->Layout(Rect{content_rect.GetLeftTop() - true_scroll, child_size}); - } + // TODO: Rewrite this. + CRU_UNUSED(content_rect); + throw std::runtime_error("Not implemented."); + + // if (const auto child = GetSingleChild()) { + // const auto child_size = child->GetMeasuredSize(); + // const auto true_scroll = + // CoerceScroll(scroll_offset_, content_rect.GetSize(), child_size); + // child->Layout(Rect{content_rect.GetLeftTop() - true_scroll, child_size}); + // } } } // namespace cru::ui::render diff --git a/src/ui/render/StackLayoutRenderObject.cpp b/src/ui/render/StackLayoutRenderObject.cpp index 7dce1a83..b953ae7e 100644 --- a/src/ui/render/StackLayoutRenderObject.cpp +++ b/src/ui/render/StackLayoutRenderObject.cpp @@ -4,47 +4,57 @@ namespace cru::ui::render { Size StackLayoutRenderObject::OnMeasureContent( - const MeasureRequirement& requirement) { - auto size = Size{}; - for (const auto child : GetChildren()) { - child->Measure(requirement); - const auto& measure_result = child->GetMeasuredSize(); - size.width = std::max(size.width, measure_result.width); - size.height = std::max(size.height, measure_result.height); - } - return size; + const MeasureRequirement& requirement, const MeasureSize& preferred_size) { + // TODO: Rewrite this. + CRU_UNUSED(requirement); + CRU_UNUSED(preferred_size); + throw std::runtime_error("Not implemented."); + + // throw std::runtime_error("Not implemented."); + // auto size = Size{}; + // for (const auto child : GetChildren()) { + // child->Measure(requirement); + // const auto& measure_result = child->GetMeasuredSize(); + // size.width = std::max(size.width, measure_result.width); + // size.height = std::max(size.height, measure_result.height); + // } + // return size; } -void StackLayoutRenderObject::OnLayoutContent(const Rect& rect) { - auto calculate_anchor = [](int alignment, float start_point, - float total_length, - float content_length) -> float { - switch (alignment) { - case internal::align_start: - return start_point; - case internal::align_center: - return start_point + (total_length - content_length) / 2.0f; - case internal::align_end: - return start_point + total_length - content_length; - default: - return start_point; - } - }; +void StackLayoutRenderObject::OnLayoutContent(const Rect& content_rect) { + // TODO: Rewrite this. + CRU_UNUSED(content_rect); + throw std::runtime_error("Not implemented."); - const auto count = GetChildCount(); - const auto& children = GetChildren(); + // auto calculate_anchor = [](int alignment, float start_point, + // float total_length, + // float content_length) -> float { + // switch (alignment) { + // case internal::align_start: + // return start_point; + // case internal::align_center: + // return start_point + (total_length - content_length) / 2.0f; + // case internal::align_end: + // return start_point + total_length - content_length; + // default: + // return start_point; + // } + // }; - for (int i = 0; i < count; i++) { - const auto layout_data = GetChildLayoutData(i); - const auto child = children[i]; - const auto& size = child->GetMeasuredSize(); - child->Layout( - Rect{calculate_anchor(static_cast<int>(layout_data->horizontal), - rect.left, rect.width, size.width), - calculate_anchor(static_cast<int>(layout_data->vertical), rect.top, - rect.height, size.height), - size.width, size.height}); - } -} + // const auto count = GetChildCount(); + // const auto& children = GetChildren(); + // for (int i = 0; i < count; i++) { + // const auto layout_data = GetChildLayoutData(i); + // const auto child = children[i]; + // const auto& size = child->GetMeasuredSize(); + // child->Layout( + // Rect{calculate_anchor(static_cast<int>(layout_data->horizontal), + // rect.left, rect.width, size.width), + // calculate_anchor(static_cast<int>(layout_data->vertical), + // rect.top, + // rect.height, size.height), + // size.width, size.height}); + // } +} } // namespace cru::ui::render diff --git a/src/ui/render/TextRenderObject.cpp b/src/ui/render/TextRenderObject.cpp index ececfbc2..9cae65d6 100644 --- a/src/ui/render/TextRenderObject.cpp +++ b/src/ui/render/TextRenderObject.cpp @@ -1,10 +1,10 @@ #include "cru/ui/render/TextRenderObject.hpp" #include "../Helper.hpp" +#include "cru/common/Logger.hpp" #include "cru/platform/graph/Factory.hpp" #include "cru/platform/graph/TextLayout.hpp" #include "cru/platform/graph/util/Painter.hpp" -#include "cru/ui/render/LayoutUtility.hpp" #include <algorithm> #include <limits> @@ -160,10 +160,44 @@ RenderObject* TextRenderObject::HitTest(const Point& point) { return padding_rect.IsPointInside(point) ? this : nullptr; } -Size TextRenderObject::OnMeasureContent(const MeasureRequirement& requirement) { - text_layout_->SetMaxWidth(requirement.max_height.GetLength()); - text_layout_->SetMaxHeight(requirement.max_height.GetLength()); - return Min(text_layout_->GetTextBounds().GetSize(), requirement.GetMaxSize()); +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 = preferred_size.width.GetLengthOrMax(); + + text_layout_->SetMaxWidth(measure_width); + text_layout_->SetMaxHeight(std::numeric_limits<float>::max()); + + const auto text_size = text_layout_->GetTextBounds().GetSize(); + auto result = text_size; + + if (requirement.max.width.IsSpecified() && + text_size.width > requirement.max.width.GetLengthOrUndefined()) { + log::Warn( + "TextRenderObject: Text actual width exceeds the required max width."); + result.width = requirement.max.width.GetLengthOrUndefined(); + } else { + result.width = std::max(result.width, preferred_size.width.GetLengthOr0()); + result.width = std::max(result.width, requirement.min.width.GetLengthOr0()); + } + + if (requirement.max.height.IsSpecified() && + text_size.height > requirement.max.height.GetLengthOrUndefined()) { + log::Warn( + "TextRenderObject: Text actual height exceeds the required max " + "height."); + result.width = requirement.max.width.GetLengthOrUndefined(); + } else { + result.height = + std::max(result.height, preferred_size.height.GetLengthOr0()); + result.width = + std::max(result.height, requirement.min.height.GetLengthOr0()); + } + + return result; } void TextRenderObject::OnLayoutContent(const Rect& content_rect) { diff --git a/src/ui/render/WindowRenderObject.cpp b/src/ui/render/WindowRenderObject.cpp index 28afe01d..a2c7ae4d 100644 --- a/src/ui/render/WindowRenderObject.cpp +++ b/src/ui/render/WindowRenderObject.cpp @@ -34,17 +34,17 @@ RenderObject* WindowRenderObject::HitTest(const Point& point) { return Rect{Point{}, GetSize()}.IsPointInside(point) ? this : nullptr; } -Size WindowRenderObject::OnMeasureContent( - const MeasureRequirement& requirement) { +Size WindowRenderObject::OnMeasureContent(const MeasureRequirement& requirement, + const MeasureSize& preferred_size) { if (const auto child = GetChild()) { - child->Measure(requirement); - return child->GetMeasuredSize(); + child->Measure(requirement, preferred_size); + return child->GetSize(); } else { return Size{}; } } void WindowRenderObject::OnLayoutContent(const Rect& content_rect) { - if (const auto child = GetChild()) child->Layout(content_rect); + if (const auto child = GetChild()) child->Layout(content_rect.GetLeftTop()); } } // namespace cru::ui::render |