diff options
author | crupest <crupest@outlook.com> | 2020-06-22 01:09:24 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2020-06-22 01:09:24 +0800 |
commit | 4f0a2f32c273780c32cc3937615c2a8bbd993aab (patch) | |
tree | 6e1f45447854a40fe2d16ef9bec79f3c0fef030a /src | |
parent | d86a71f79afe0e4dac768f61d6bff690567aca5b (diff) | |
download | cru-4f0a2f32c273780c32cc3937615c2a8bbd993aab.tar.gz cru-4f0a2f32c273780c32cc3937615c2a8bbd993aab.tar.bz2 cru-4f0a2f32c273780c32cc3937615c2a8bbd993aab.zip |
...
Diffstat (limited to 'src')
-rw-r--r-- | src/ui/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/ui/UiHost.cpp | 11 | ||||
-rw-r--r-- | src/ui/render/BorderRenderObject.cpp | 117 | ||||
-rw-r--r-- | src/ui/render/CanvasRenderObject.cpp | 5 | ||||
-rw-r--r-- | src/ui/render/FlexLayoutRenderObject.cpp | 180 | ||||
-rw-r--r-- | src/ui/render/RenderObject.cpp | 94 | ||||
-rw-r--r-- | src/ui/render/ScrollRenderObject.cpp | 77 | ||||
-rw-r--r-- | src/ui/render/StackLayoutRenderObject.cpp | 15 | ||||
-rw-r--r-- | src/ui/render/TextRenderObject.cpp | 10 | ||||
-rw-r--r-- | src/ui/render/WindowRenderObject.cpp | 11 |
10 files changed, 323 insertions, 198 deletions
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index f37982e9..68efa903 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -54,6 +54,7 @@ target_sources(cru_ui PUBLIC ${CRU_UI_INCLUDE_DIR}/render/FlexLayoutRenderObject.hpp ${CRU_UI_INCLUDE_DIR}/render/LayoutRenderObject.hpp ${CRU_UI_INCLUDE_DIR}/render/LayoutUtility.hpp + ${CRU_UI_INCLUDE_DIR}/render/MeasureRequirement.hpp ${CRU_UI_INCLUDE_DIR}/render/RenderObject.hpp ${CRU_UI_INCLUDE_DIR}/render/ScrollRenderObject.hpp ${CRU_UI_INCLUDE_DIR}/render/StackLayoutRenderObject.hpp diff --git a/src/ui/UiHost.cpp b/src/ui/UiHost.cpp index 069e68de..7047d43f 100644 --- a/src/ui/UiHost.cpp +++ b/src/ui/UiHost.cpp @@ -1,12 +1,12 @@ #include "cru/ui/UiHost.hpp" +#include "RoutedEventDispatch.hpp" #include "cru/common/Logger.hpp" #include "cru/platform/graph/Painter.hpp" #include "cru/platform/native/UiApplication.hpp" #include "cru/platform/native/Window.hpp" -#include "cru/ui/render/WindowRenderObject.hpp" #include "cru/ui/Window.hpp" -#include "RoutedEventDispatch.hpp" +#include "cru/ui/render/WindowRenderObject.hpp" namespace cru::ui { using platform::native::INativeWindow; @@ -28,7 +28,6 @@ CRU_DEFINE_EVENT_NAME(MouseDown) CRU_DEFINE_EVENT_NAME(MouseUp) CRU_DEFINE_EVENT_NAME(KeyDown) CRU_DEFINE_EVENT_NAME(KeyUp) -CRU_DEFINE_EVENT_NAME(Char) #undef CRU_DEFINE_EVENT_NAME } // namespace event_names @@ -93,10 +92,10 @@ inline void BindNativeEvent( } // namespace UiHost::UiHost(Window* window) - : mouse_hover_control_(nullptr), + : window_control_(window), + mouse_hover_control_(nullptr), focus_control_(window), - mouse_captured_control_(nullptr), - window_control_(window) { + mouse_captured_control_(nullptr) { native_window_resolver_ = IUiApplication::GetInstance()->CreateWindow(nullptr); diff --git a/src/ui/render/BorderRenderObject.cpp b/src/ui/render/BorderRenderObject.cpp index a656cb99..fbc3c65f 100644 --- a/src/ui/render/BorderRenderObject.cpp +++ b/src/ui/render/BorderRenderObject.cpp @@ -73,84 +73,97 @@ RenderObject* BorderRenderObject::HitTest(const Point& point) { } } -void BorderRenderObject::OnMeasureCore(const Size& available_size) { +Size BorderRenderObject::OnMeasureCore(const MeasureRequirement& requirement) { + if (!is_border_enabled_) { + return RenderObject::OnMeasureCore(requirement); + } + const auto margin = GetMargin(); const auto padding = GetPadding(); - Size margin_border_padding_size{ - margin.GetHorizontalTotal() + padding.GetHorizontalTotal(), - margin.GetVerticalTotal() + padding.GetVerticalTotal()}; - - if (is_border_enabled_) { - margin_border_padding_size.width += border_thickness_.GetHorizontalTotal(); - margin_border_padding_size.height += border_thickness_.GetVerticalTotal(); + const Size space_size{margin.GetHorizontalTotal() + + padding.GetHorizontalTotal() + + border_thickness_.GetHorizontalTotal(), + margin.GetVerticalTotal() + padding.GetVerticalTotal() + + border_thickness_.GetVerticalTotal()}; + + auto coerced_space_size = space_size; + + MeasureRequirement content_requirement = requirement; + + if (!requirement.max_width.IsInfinate()) { + const auto max_width = requirement.max_width.GetLength(); + if (coerced_space_size.width > max_width) { + log::Warn( + "Measure: horizontal length of padding and margin is bigger than " + "available length."); + coerced_space_size.width = max_width; + } + content_requirement.max_width = max_width - coerced_space_size.width; } - auto coerced_margin_border_padding_size = margin_border_padding_size; - if (coerced_margin_border_padding_size.width > available_size.width) { - log::Warn( - "Measure: horizontal length of padding, border and margin is bigger " - "than available length."); - coerced_margin_border_padding_size.width = available_size.width; - } - if (coerced_margin_border_padding_size.height > available_size.height) { - log::Warn( - "Measure: vertical length of padding, border and margin is bigger " - "than available length."); - coerced_margin_border_padding_size.height = available_size.height; + if (!requirement.max_height.IsInfinate()) { + const auto max_height = requirement.max_height.GetLength(); + if (coerced_space_size.height > max_height) { + log::Warn( + "Measure: horizontal length of padding and margin is bigger than " + "available length."); + coerced_space_size.height = max_height; + } + content_requirement.max_height = max_height - coerced_space_size.height; } - const auto coerced_content_available_size = - available_size - coerced_margin_border_padding_size; + const auto content_size = OnMeasureContent(content_requirement); - const auto actual_content_size = - OnMeasureContent(coerced_content_available_size); + return coerced_space_size + content_size; +} // namespace cru::ui::render - SetPreferredSize(coerced_margin_border_padding_size + actual_content_size); -} +void BorderRenderObject::OnLayoutCore(const Size& size) { + if (!is_border_enabled_) { + return RenderObject::OnLayoutCore(size); + } -void BorderRenderObject::OnLayoutCore(const Rect& rect) { const auto margin = GetMargin(); const auto padding = GetPadding(); - Size margin_border_padding_size{ - margin.GetHorizontalTotal() + padding.GetHorizontalTotal(), - margin.GetVerticalTotal() + padding.GetVerticalTotal()}; - - if (is_border_enabled_) { - margin_border_padding_size.width += border_thickness_.GetHorizontalTotal(); - margin_border_padding_size.height += border_thickness_.GetVerticalTotal(); - } + Size space_size{margin.GetHorizontalTotal() + padding.GetHorizontalTotal() + + border_thickness_.GetHorizontalTotal(), + margin.GetVerticalTotal() + padding.GetVerticalTotal() + + border_thickness_.GetVerticalTotal()}; - const auto content_available_size = - rect.GetSize() - margin_border_padding_size; - auto coerced_content_available_size = content_available_size; + auto content_size = size - space_size; - if (coerced_content_available_size.width < 0) { + if (content_size.width < 0) { log::Warn( "Layout: horizontal length of padding, border and margin is bigger " "than available length."); - coerced_content_available_size.width = 0; + content_size.width = 0; } - if (coerced_content_available_size.height < 0) { + if (content_size.height < 0) { log::Warn( "Layout: vertical length of padding, border and margin is bigger " "than available length."); - coerced_content_available_size.height = 0; + content_size.height = 0; + } + + Point lefttop{margin.left + padding.left + border_thickness_.left, + margin.top + padding.top + border_thickness_.top}; + if (lefttop.x > size.width) { + lefttop.x = size.width; } + if (lefttop.y > size.height) { + lefttop.y = size.height; + } + + const Rect content_rect{lefttop, content_size}; - OnLayoutContent( - Rect{margin.left + (is_border_enabled_ ? border_thickness_.left : 0) + - padding.left, - margin.top + (is_border_enabled_ ? border_thickness_.top : 0) + - padding.top, - coerced_content_available_size.width, - coerced_content_available_size.height}); + OnLayoutContent(content_rect); } -Size BorderRenderObject::OnMeasureContent(const Size& available_size) { +Size BorderRenderObject::OnMeasureContent( + const MeasureRequirement& requirement) { const auto child = GetChild(); if (child) { - child->Measure(available_size); - return child->GetPreferredSize(); + child->Measure(requirement); + return child->GetMeasuredSize(); } else { return Size{}; } diff --git a/src/ui/render/CanvasRenderObject.cpp b/src/ui/render/CanvasRenderObject.cpp index 16ac9239..72eb3570 100644 --- a/src/ui/render/CanvasRenderObject.cpp +++ b/src/ui/render/CanvasRenderObject.cpp @@ -18,8 +18,9 @@ RenderObject* CanvasRenderObject::HitTest(const Point& point) { return padding_rect.IsPointInside(point) ? this : nullptr; } -Size CanvasRenderObject::OnMeasureContent(const Size& available_size) { - return Min(available_size, GetDesiredSize()); +Size CanvasRenderObject::OnMeasureContent( + const MeasureRequirement& requirement) { + return Min(requirement.GetMaxSize(), GetDesiredSize()); } void CanvasRenderObject::OnLayoutContent(const Rect& content_rect) { diff --git a/src/ui/render/FlexLayoutRenderObject.cpp b/src/ui/render/FlexLayoutRenderObject.cpp index b609fd97..079bc5a9 100644 --- a/src/ui/render/FlexLayoutRenderObject.cpp +++ b/src/ui/render/FlexLayoutRenderObject.cpp @@ -6,111 +6,115 @@ #include <functional> namespace cru::ui::render { -Size FlexLayoutRenderObject::OnMeasureContent(const Size& available_size) { - std::vector<int> has_basis_children; - std::vector<int> no_basis_children; - std::vector<int> grow_children; - std::vector<int> shrink_chilren; - const auto child_count = GetChildCount(); - for (int i = 0; i < child_count; i++) { - const auto& layout_data = *GetChildLayoutData(i); - if (layout_data.flex_basis.has_value()) - has_basis_children.push_back(i); - else - no_basis_children.push_back(i); - if (layout_data.flex_grow > 0) grow_children.push_back(i); - if (layout_data.flex_shrink > 0) shrink_chilren.push_back(i); - } +Size FlexLayoutRenderObject::OnMeasureContent( + const MeasureRequirement& requirement) { + const bool horizontal = (direction_ == FlexDirection::Horizontal || + direction_ == FlexDirection::HorizontalReverse); + + const auto main_max_length = + horizontal ? requirement.max_width : requirement.max_height; + const auto cross_max_length = + horizontal ? requirement.max_height : requirement.max_width; std::function<float(const Size&)> get_main_length; std::function<float(const Size&)> get_cross_length; - std::function<Size(float main, float cross)> create_size; + std::function<void(Size&, const Size&)> calculate_result_size; + std::function<MeasureRequirement(MeasureLength main, MeasureLength cross)> + create_requirement; - if (direction_ == FlexDirection::Horizontal || - direction_ == FlexDirection::HorizontalReverse) { + if (horizontal) { get_main_length = [](const Size& size) { return size.width; }; get_cross_length = [](const Size& size) { return size.height; }; - create_size = [](float main, float cross) { return Size(main, cross); }; + calculate_result_size = [](Size& result, const Size& child_size) { + result.width += child_size.width; + result.height = std::max(result.height, child_size.height); + }; + create_requirement = [](MeasureLength main, MeasureLength cross) { + return MeasureRequirement{main, cross}; + }; } else { get_main_length = [](const Size& size) { return size.height; }; get_cross_length = [](const Size& size) { return size.width; }; - create_size = [](float main, float cross) { return Size(cross, main); }; + calculate_result_size = [](Size& result, const Size& child_size) { + result.height += child_size.height; + result.width = std::max(result.width, child_size.width); + }; + create_requirement = [](MeasureLength main, MeasureLength cross) { + return MeasureRequirement{cross, main}; + }; } const auto& children = GetChildren(); + Index children_count = children.size(); - float remain_main_length = get_main_length(available_size); - float max_cross_length = 0; - - for (const int i : has_basis_children) { - const auto child = children[i]; - const float basis = GetChildLayoutData(i)->flex_basis.value(); - child->Measure(create_size(basis, get_cross_length(available_size))); - remain_main_length -= basis; - const float child_preferred_cross_length = - get_cross_length(child->GetPreferredSize()); - child->SetPreferredSize(create_size(basis, child_preferred_cross_length)); - max_cross_length = std::max(max_cross_length, child_preferred_cross_length); - } - - for (const int i : no_basis_children) { - const auto child = children[i]; - child->Measure(create_size(remain_main_length > 0 ? remain_main_length : 0, - get_cross_length(available_size))); - remain_main_length -= get_main_length(child->GetPreferredSize()); - max_cross_length = - std::max(max_cross_length, get_cross_length(child->GetPreferredSize())); - } - - if (remain_main_length > 0) { - float total_grow = 0; - for (const int i : grow_children) - total_grow += GetChildLayoutData(i)->flex_grow; + if (!main_max_length.IsInfinate()) { + float remain_main_length = main_max_length.GetLength(); - for (const int i : grow_children) { - const float distributed_grow_length = - remain_main_length * (GetChildLayoutData(i)->flex_grow / total_grow); + for (Index i = 0; i < children_count; i++) { const auto child = children[i]; - const float new_main_length = - get_main_length(child->GetPreferredSize()) + distributed_grow_length; - child->Measure( - create_size(new_main_length, get_cross_length(available_size))); - const float new_child_preferred_cross_length = - get_cross_length(child->GetPreferredSize()); - child->SetPreferredSize( - create_size(new_main_length, new_child_preferred_cross_length)); - max_cross_length = - std::max(max_cross_length, new_child_preferred_cross_length); + child->Measure(create_requirement(remain_main_length, cross_max_length)); + const auto measure_result = child->GetMeasuredSize(); + remain_main_length -= get_main_length(measure_result); } - } - if (remain_main_length < 0) { - float total_shrink = 0; - for (const int i : shrink_chilren) - total_shrink += GetChildLayoutData(i)->flex_shrink; + if (remain_main_length > 0) { + std::vector<Index> expand_children; + float total_expand_factor = 0; + + for (Index i = 0; i < children_count; i++) { + const auto factor = GetChildLayoutData(i)->expand_factor; + if (factor > 0) { + expand_children.push_back(i); + total_expand_factor += factor; + } + } - for (const int i : shrink_chilren) { - const float distributed_shrink_length = // negative - remain_main_length * - (GetChildLayoutData(i)->flex_shrink / total_shrink); + for (const int i : expand_children) { + const float distributed_grow_length = + remain_main_length * + (GetChildLayoutData(i)->expand_factor / total_expand_factor); + const auto child = children[i]; + const float new_main_length = + get_main_length(child->GetMeasuredSize()) + + distributed_grow_length; + child->Measure(create_requirement(new_main_length, cross_max_length)); + } + } else if (remain_main_length < 0) { + std::vector<Index> shrink_children; + float total_shrink_factor = 0; + + for (Index i = 0; i < children_count; i++) { + const auto factor = GetChildLayoutData(i)->shrink_factor; + if (factor > 0) { + shrink_children.push_back(i); + total_shrink_factor += factor; + } + } + + for (const int i : shrink_children) { + const float distributed_shrink_length = // negative + remain_main_length * + (GetChildLayoutData(i)->shrink_factor / total_shrink_factor); + const auto child = children[i]; + float new_main_length = get_main_length(child->GetMeasuredSize()) + + distributed_shrink_length; + new_main_length = new_main_length > 0 ? new_main_length : 0; + child->Measure(create_requirement(new_main_length, cross_max_length)); + } + } + } else { + for (Index i = 0; i < children_count; i++) { const auto child = children[i]; - float new_main_length = get_main_length(child->GetPreferredSize()) + - distributed_shrink_length; - new_main_length = new_main_length > 0 ? new_main_length : 0; - child->Measure( - create_size(new_main_length, get_cross_length(available_size))); - const float new_child_preferred_cross_length = - get_cross_length(child->GetPreferredSize()); - child->SetPreferredSize( - create_size(new_main_length, new_child_preferred_cross_length)); - max_cross_length = - std::max(max_cross_length, new_child_preferred_cross_length); + child->Measure(requirement); } } - return create_size(get_main_length(available_size) - - (remain_main_length > 0 ? remain_main_length : 0), - max_cross_length); + Size result; + for (auto child : children) { + calculate_result_size(result, child->GetMeasuredSize()); + } + + return result; } void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) { @@ -125,7 +129,7 @@ void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) { case internal::align_end: return start_point + total_length - content_length; default: - return 0; + return start_point; } }; @@ -134,7 +138,7 @@ void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) { direction_ == FlexDirection::HorizontalReverse) { float actual_content_width = 0; for (const auto child : children) { - actual_content_width += child->GetPreferredSize().width; + actual_content_width += child->GetMeasuredSize().width; } const float content_anchor_x = @@ -144,7 +148,7 @@ void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) { float anchor_x = 0; for (int i = 0; i < static_cast<int>(children.size()); i++) { const auto child = children[i]; - const auto size = child->GetPreferredSize(); + const auto size = child->GetMeasuredSize(); float real_anchor_x = anchor_x + content_anchor_x; if (direction_ == FlexDirection::Horizontal) @@ -164,7 +168,7 @@ void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) { } else { float actual_content_height = 0; for (const auto child : children) { - actual_content_height = child->GetPreferredSize().height; + actual_content_height = child->GetMeasuredSize().height; } const float content_anchor_y = @@ -174,7 +178,7 @@ void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) { float anchor_y = 0; for (int i = 0; i < static_cast<int>(children.size()); i++) { const auto child = children[i]; - const auto size = child->GetPreferredSize(); + const auto size = child->GetMeasuredSize(); float real_anchor_y = anchor_y + content_anchor_y; if (direction_ == FlexDirection::Vertical) { diff --git a/src/ui/render/RenderObject.cpp b/src/ui/render/RenderObject.cpp index 83e306a8..cdc3032f 100644 --- a/src/ui/render/RenderObject.cpp +++ b/src/ui/render/RenderObject.cpp @@ -57,14 +57,20 @@ Point RenderObject::FromRootToContent(const Point& point) const { point.y - (offset.y + rect.top)}; } -void RenderObject::Measure(const Size& available_size) { - OnMeasureCore(available_size); +void RenderObject::Measure(const MeasureRequirement& requirement) { + measured_size_ = OnMeasureCore(requirement); + + Ensures(measured_size_.width >= 0); + Ensures(measured_size_.height >= 0); + Ensures(requirement.Satisfy(measured_size_)); } void RenderObject::Layout(const Rect& rect) { - SetOffset(rect.GetLeftTop()); - SetSize(rect.GetSize()); - OnLayoutCore(Rect{Point{}, rect.GetSize()}); + Expects(rect.width >= 0); + Expects(rect.height >= 0); + offset_ = rect.GetLeftTop(); + size_ = rect.GetSize(); + OnLayoutCore(rect.GetSize()); } void RenderObject::OnParentChanged(RenderObject* old_parent, @@ -89,56 +95,72 @@ void RenderObject::OnRemoveChild(RenderObject* removed_child, Index position) { InvalidatePaint(); } -void RenderObject::OnMeasureCore(const Size& available_size) { - Size margin_padding_size{ +Size RenderObject::OnMeasureCore(const MeasureRequirement& requirement) { + const Size space_size{ margin_.GetHorizontalTotal() + padding_.GetHorizontalTotal(), margin_.GetVerticalTotal() + padding_.GetVerticalTotal()}; - auto coerced_margin_padding_size = margin_padding_size; - if (coerced_margin_padding_size.width > available_size.width) { - log::Warn( - "Measure: horizontal length of padding and margin is bigger than " - "available length."); - coerced_margin_padding_size.width = available_size.width; + auto coerced_space_size = space_size; + + MeasureRequirement content_requirement = requirement; + + if (!requirement.max_width.IsInfinate()) { + const auto max_width = requirement.max_width.GetLength(); + if (coerced_space_size.width > max_width) { + log::Warn( + "Measure: horizontal length of padding and margin is bigger than " + "available length."); + coerced_space_size.width = max_width; + } + content_requirement.max_width = max_width - coerced_space_size.width; } - if (coerced_margin_padding_size.height > available_size.height) { - log::Warn( - "Measure: vertical length of padding and margin is bigger than " - "available length."); - coerced_margin_padding_size.height = available_size.height; + + if (!requirement.max_height.IsInfinate()) { + const auto max_height = requirement.max_height.GetLength(); + if (coerced_space_size.height > max_height) { + log::Warn( + "Measure: horizontal length of padding and margin is bigger than " + "available length."); + coerced_space_size.height = max_height; + } + content_requirement.max_height = max_height - coerced_space_size.height; } - const auto coerced_content_available_size = - available_size - coerced_margin_padding_size; - const auto actual_content_size = - OnMeasureContent(coerced_content_available_size); + const auto content_size = OnMeasureContent(content_requirement); - SetPreferredSize(coerced_margin_padding_size + actual_content_size); + return coerced_space_size + content_size; } -void RenderObject::OnLayoutCore(const Rect& rect) { - Size margin_padding_size{ - margin_.GetHorizontalTotal() + padding_.GetHorizontalTotal(), - margin_.GetVerticalTotal() + padding_.GetVerticalTotal()}; - const auto content_available_size = rect.GetSize() - margin_padding_size; - auto coerced_content_available_size = content_available_size; +void RenderObject::OnLayoutCore(const Size& size) { + Size space_size{margin_.GetHorizontalTotal() + padding_.GetHorizontalTotal(), + margin_.GetVerticalTotal() + padding_.GetVerticalTotal()}; - if (coerced_content_available_size.width < 0) { + auto content_size = size - space_size; + + if (content_size.width < 0) { log::Warn( "Layout: horizontal length of padding and margin is bigger than " "available length."); - coerced_content_available_size.width = 0; + content_size.width = 0; } - if (coerced_content_available_size.height < 0) { + if (content_size.height < 0) { log::Warn( "Layout: vertical length of padding and margin is bigger than " "available length."); - coerced_content_available_size.height = 0; + content_size.height = 0; } - OnLayoutContent(Rect{margin_.left + padding_.left, margin_.top + padding_.top, - coerced_content_available_size.width, - coerced_content_available_size.height}); + Point lefttop{margin_.left + padding_.left, margin_.top + padding_.top}; + if (lefttop.x > size.width) { + lefttop.x = size.width; + } + if (lefttop.y > size.height) { + lefttop.y = size.height; + } + + const Rect content_rect{lefttop, content_size}; + + OnLayoutContent(content_rect); } void RenderObject::OnAfterLayout() {} diff --git a/src/ui/render/ScrollRenderObject.cpp b/src/ui/render/ScrollRenderObject.cpp index 33e9e407..f1df9d8b 100644 --- a/src/ui/render/ScrollRenderObject.cpp +++ b/src/ui/render/ScrollRenderObject.cpp @@ -1 +1,78 @@ #include "cru/ui/render/ScrollRenderObject.hpp" + +#include "cru/platform/graph/Painter.hpp" +#include "cru/platform/graph/util/Painter.hpp" + +#include <algorithm> + +namespace cru::ui::render { +namespace { +// This method assumes margin offset is already considered. +// It promises that it won't return negetive value. +Point CalculateChildOffsetOfScroll(const Point& scroll_offset, + const Size& content_area_size, + const Thickness& padding, + const Size& child_size) { + Point result(scroll_offset); + + Point max_scroll(child_size - content_area_size); + max_scroll.x = std::max(max_scroll.x, 0.f); + max_scroll.y = std::max(max_scroll.y, 0.f); + + auto coerce = [](float& n, float max) { + if (n < 0) + n = 0; + else if (n > max) + n = max; + }; + + coerce(result.x, scroll_offset.x); + coerce(result.y, scroll_offset.y); + + result.x += padding.left; + result.y += padding.top; + + return result; +} +} // namespace + +void ScrollRenderObject::Draw(platform::graph::IPainter* painter) { + for (auto child : this->GetChildren()) { + painter->PushLayer(this->GetPaddingRect()); + const auto true_offset = + CalculateChildOffsetOfScroll(scroll_offset_, GetContentRect().GetSize(), + GetPadding(), child->GetSize()); + platform::graph::util::WithTransform( + painter, Matrix::Translation(true_offset.x, true_offset.y), + [child](platform::graph::IPainter* p) { child->Draw(p); }); + painter->PopLayer(); + } +} + +RenderObject* ScrollRenderObject::HitTest(const Point& point) { + const auto rect = GetPaddingRect(); + return rect.IsPointInside(point) ? this : nullptr; +} + +void ScrollRenderObject::SetScrollOffset(const Point& offset) { + scroll_offset_ = offset; + InvalidatePaint(); +} + +Size ScrollRenderObject::OnMeasureContent( + const MeasureRequirement& requirement) { + CRU_UNUSED(requirement); + // TODO! + // const auto& children = GetChildren(); + // if (children.empty()) return Size{}; + // const auto child = children.front(); + // child->Measure(MeasureRequirement::Infinate()); + // const auto preferred_size = child->GetMeasuredSize(); + return Size{}; +} // namespace cru::ui::render + +void ScrollRenderObject::OnLayoutContent(const Rect& content_rect) { + CRU_UNUSED(content_rect); + // TODO! +} +} // namespace cru::ui::render diff --git a/src/ui/render/StackLayoutRenderObject.cpp b/src/ui/render/StackLayoutRenderObject.cpp index d08e136d..7dce1a83 100644 --- a/src/ui/render/StackLayoutRenderObject.cpp +++ b/src/ui/render/StackLayoutRenderObject.cpp @@ -3,13 +3,14 @@ #include <algorithm> namespace cru::ui::render { -Size StackLayoutRenderObject::OnMeasureContent(const Size& available_size) { +Size StackLayoutRenderObject::OnMeasureContent( + const MeasureRequirement& requirement) { auto size = Size{}; for (const auto child : GetChildren()) { - child->Measure(available_size); - const auto& preferred_size = child->GetPreferredSize(); - size.width = std::max(size.width, preferred_size.width); - size.height = std::max(size.height, preferred_size.height); + child->Measure(requirement); + const auto& measure_result = child->GetMeasuredSize(); + size.width = std::max(size.width, measure_result.width); + size.height = std::max(size.height, measure_result.height); } return size; } @@ -26,7 +27,7 @@ void StackLayoutRenderObject::OnLayoutContent(const Rect& rect) { case internal::align_end: return start_point + total_length - content_length; default: - return 0; + return start_point; } }; @@ -36,7 +37,7 @@ void StackLayoutRenderObject::OnLayoutContent(const Rect& rect) { for (int i = 0; i < count; i++) { const auto layout_data = GetChildLayoutData(i); const auto child = children[i]; - const auto& size = child->GetPreferredSize(); + const auto& size = child->GetMeasuredSize(); child->Layout( Rect{calculate_anchor(static_cast<int>(layout_data->horizontal), rect.left, rect.width, size.width), diff --git a/src/ui/render/TextRenderObject.cpp b/src/ui/render/TextRenderObject.cpp index 05acd086..ececfbc2 100644 --- a/src/ui/render/TextRenderObject.cpp +++ b/src/ui/render/TextRenderObject.cpp @@ -4,8 +4,10 @@ #include "cru/platform/graph/Factory.hpp" #include "cru/platform/graph/TextLayout.hpp" #include "cru/platform/graph/util/Painter.hpp" +#include "cru/ui/render/LayoutUtility.hpp" #include <algorithm> +#include <limits> namespace cru::ui::render { TextRenderObject::TextRenderObject( @@ -158,10 +160,10 @@ RenderObject* TextRenderObject::HitTest(const Point& point) { return padding_rect.IsPointInside(point) ? this : nullptr; } -Size TextRenderObject::OnMeasureContent(const Size& available_size) { - text_layout_->SetMaxWidth(available_size.width); - text_layout_->SetMaxHeight(available_size.height); - return text_layout_->GetTextBounds().GetSize(); +Size TextRenderObject::OnMeasureContent(const MeasureRequirement& requirement) { + text_layout_->SetMaxWidth(requirement.max_height.GetLength()); + text_layout_->SetMaxHeight(requirement.max_height.GetLength()); + return Min(text_layout_->GetTextBounds().GetSize(), requirement.GetMaxSize()); } void TextRenderObject::OnLayoutContent(const Rect& content_rect) { diff --git a/src/ui/render/WindowRenderObject.cpp b/src/ui/render/WindowRenderObject.cpp index cd1f806f..28afe01d 100644 --- a/src/ui/render/WindowRenderObject.cpp +++ b/src/ui/render/WindowRenderObject.cpp @@ -34,9 +34,14 @@ RenderObject* WindowRenderObject::HitTest(const Point& point) { return Rect{Point{}, GetSize()}.IsPointInside(point) ? this : nullptr; } -Size WindowRenderObject::OnMeasureContent(const Size& available_size) { - if (const auto child = GetChild()) child->Measure(available_size); - return available_size; +Size WindowRenderObject::OnMeasureContent( + const MeasureRequirement& requirement) { + if (const auto child = GetChild()) { + child->Measure(requirement); + return child->GetMeasuredSize(); + } else { + return Size{}; + } } void WindowRenderObject::OnLayoutContent(const Rect& content_rect) { |