aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2020-06-28 21:25:09 +0800
committercrupest <crupest@outlook.com>2020-06-28 21:25:09 +0800
commitb3c0c076e5a1b1e7d76fa8d32af0bcbb2c1cd4cf (patch)
treedf90c6ae501508931fbd46ebc6340c90391e1ed5
parent698242c10cbef4ceaade848fa6aedac71baaf1f2 (diff)
downloadcru-b3c0c076e5a1b1e7d76fa8d32af0bcbb2c1cd4cf.tar.gz
cru-b3c0c076e5a1b1e7d76fa8d32af0bcbb2c1cd4cf.tar.bz2
cru-b3c0c076e5a1b1e7d76fa8d32af0bcbb2c1cd4cf.zip
...
-rw-r--r--include/cru/ui/render/FlexLayoutRenderObject.hpp9
-rw-r--r--include/cru/ui/render/LayoutHelper.hpp13
-rw-r--r--include/cru/ui/render/StackLayoutRenderObject.hpp19
-rw-r--r--src/ui/CMakeLists.txt2
-rw-r--r--src/ui/render/FlexLayoutRenderObject.cpp77
-rw-r--r--src/ui/render/LayoutHelper.cpp36
-rw-r--r--src/ui/render/StackLayoutRenderObject.cpp85
7 files changed, 151 insertions, 90 deletions
diff --git a/include/cru/ui/render/FlexLayoutRenderObject.hpp b/include/cru/ui/render/FlexLayoutRenderObject.hpp
index 83d1e268..4b1e079d 100644
--- a/include/cru/ui/render/FlexLayoutRenderObject.hpp
+++ b/include/cru/ui/render/FlexLayoutRenderObject.hpp
@@ -3,8 +3,9 @@
namespace cru::ui::render {
// Measure Logic (v0.1):
-// 1. Layout all children with unspecified(infinate) max main axis length. If
-// max cross axis length of parent is specified, then it is passed to children.
+// Cross axis measure logic is the same as stack layout.
+//
+// 1. Layout all children with unspecified(infinate) max main axis length.
//
// 2. Add up main axis length of children to get total main length.
//
@@ -72,10 +73,6 @@ namespace cru::ui::render {
// (if specified), then coerce the length to the min value but not report error
// and just fill the rest space with blank.
//
-// 5. Result cross axis length is the max cross axis length of all children. If
-// min cross axis length is specified and result length is smaller than it, then
-// result length is coerced to it.
-//
class FlexLayoutRenderObject : public LayoutRenderObject<FlexChildLayoutData> {
public:
FlexLayoutRenderObject() = default;
diff --git a/include/cru/ui/render/LayoutHelper.hpp b/include/cru/ui/render/LayoutHelper.hpp
new file mode 100644
index 00000000..8536c451
--- /dev/null
+++ b/include/cru/ui/render/LayoutHelper.hpp
@@ -0,0 +1,13 @@
+#pragma once
+#include "Base.hpp"
+
+#include "MeasureRequirement.hpp"
+
+namespace cru::ui::render {
+float CalculateAnchorByAlignment(Alignment alignment, float start_point,
+ float content_length, float child_length);
+
+MeasureLength StackLayoutCalculateChildMaxLength(
+ MeasureLength parent_preferred_size, MeasureLength parent_max_size,
+ MeasureLength child_min_size, std::string_view exceeds_message);
+} // namespace cru::ui::render
diff --git a/include/cru/ui/render/StackLayoutRenderObject.hpp b/include/cru/ui/render/StackLayoutRenderObject.hpp
index e89e5346..f6b4ffb7 100644
--- a/include/cru/ui/render/StackLayoutRenderObject.hpp
+++ b/include/cru/ui/render/StackLayoutRenderObject.hpp
@@ -3,7 +3,24 @@
namespace cru::ui::render {
// Measure Logic:
-//
+// Following rules are applied both horizontally and vertically.
+//
+// 1. Measure each children with min size not specified and max size as
+// following rules:
+//
+// 1.1. If parent's preferred size is set and it is not less than child's min
+// size, then it is used as child's max size.
+//
+// 1.2. Or if parent's max size is set, then it is used as child's max size.
+// If it is less than child's min size, then log an warning about that.
+//
+// 2. Result size is children's max size.
+//
+// 3. If preferred size is specified and result size is smaller than it, coerce
+// result size to preferred size.
+//
+// 4. If result size is smaller than min size (if specified), coerce result size
+// to min size.
class StackLayoutRenderObject
: public LayoutRenderObject<StackChildLayoutData> {
public:
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt
index 9043974e..954dacb0 100644
--- a/src/ui/CMakeLists.txt
+++ b/src/ui/CMakeLists.txt
@@ -23,6 +23,7 @@ add_library(cru_ui STATIC
render/BorderRenderObject.cpp
render/CanvasRenderObject.cpp
render/FlexLayoutRenderObject.cpp
+ render/LayoutHelper.cpp
render/RenderObject.cpp
render/ScrollRenderObject.cpp
render/StackLayoutRenderObject.cpp
@@ -51,6 +52,7 @@ target_sources(cru_ui PUBLIC
${CRU_UI_INCLUDE_DIR}/render/BorderRenderObject.hpp
${CRU_UI_INCLUDE_DIR}/render/CanvasRenderObject.hpp
${CRU_UI_INCLUDE_DIR}/render/FlexLayoutRenderObject.hpp
+ ${CRU_UI_INCLUDE_DIR}/render/LayoutHelper.hpp
${CRU_UI_INCLUDE_DIR}/render/LayoutRenderObject.hpp
${CRU_UI_INCLUDE_DIR}/render/MeasureRequirement.hpp
${CRU_UI_INCLUDE_DIR}/render/RenderObject.hpp
diff --git a/src/ui/render/FlexLayoutRenderObject.cpp b/src/ui/render/FlexLayoutRenderObject.cpp
index 0afe6ef5..9e5139ff 100644
--- a/src/ui/render/FlexLayoutRenderObject.cpp
+++ b/src/ui/render/FlexLayoutRenderObject.cpp
@@ -2,6 +2,7 @@
#include "cru/common/Logger.hpp"
#include "cru/platform/graph/util/Painter.hpp"
+#include "cru/ui/render/LayoutHelper.hpp"
#include <algorithm>
#include <functional>
@@ -101,11 +102,25 @@ Size FlexLayoutMeasureContentImpl(
MeasureLength min_main_length = GetMain(requirement.min, direction_tag);
MeasureLength min_cross_length = GetCross(requirement.min, direction_tag);
- // step 1.
+ std::vector<MeasureLength> child_cross_measure_requirement;
+ child_cross_measure_requirement.reserve(children.size());
+
for (auto child : children) {
+ child_cross_measure_requirement.push_back(
+ StackLayoutCalculateChildMaxLength(
+ preferred_cross_length, max_cross_length,
+ GetCross(child->GetMinSize(), direction_tag),
+ "StackLayoutRenderObject: Child's min cross size is bigger than "
+ "parent's max cross size."));
+ }
+
+ // 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),
+ child_cross_measure_requirement[i],
+ direction_tag),
MeasureSize::NotSpecified()},
MeasureSize::NotSpecified());
}
@@ -193,13 +208,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,
+ child_cross_measure_requirement[i],
+ direction_tag),
+ MeasureSize::NotSpecified()},
+ CreateTSize<MeasureSize>(new_measure_length,
+ MeasureLength::NotSpecified(),
+ direction_tag));
const Size new_size = child->GetSize();
const float new_main_length = GetMain(new_size, direction_tag);
@@ -256,7 +273,8 @@ Size FlexLayoutMeasureContentImpl(
child->Measure(
MeasureRequirement{
CreateTSize<MeasureSize>(MeasureLength::NotSpecified(),
- max_cross_length, direction_tag),
+ child_cross_measure_requirement[i],
+ direction_tag),
CreateTSize<MeasureSize>(new_measure_length,
MeasureLength::NotSpecified(),
direction_tag)},
@@ -303,10 +321,10 @@ Size FlexLayoutMeasureContentImpl(
total_length = min_main_length.GetLengthOrUndefined();
}
- if (min_main_length.IsSpecified() &&
- child_max_cross_length < min_main_length.GetLengthOrUndefined()) {
- child_max_cross_length = min_main_length.GetLengthOrUndefined();
- }
+ child_max_cross_length =
+ std::max(preferred_cross_length.GetLengthOr0(), child_max_cross_length);
+ child_max_cross_length =
+ std::max(min_cross_length.GetLengthOr0(), child_max_cross_length);
return CreateTSize<Size>(total_length, child_max_cross_length, direction_tag);
}
@@ -326,21 +344,6 @@ Size FlexLayoutRenderObject::OnMeasureContent(
}
void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) {
- auto calculate_cross_anchor = [](FlexCrossAlignment alignment,
- float start_point, float content_length,
- float child_length) -> float {
- switch (alignment) {
- case FlexCrossAlignment::Start:
- return start_point;
- case FlexCrossAlignment::Center:
- return start_point + (content_length - child_length) / 2.0f;
- case FlexCrossAlignment::End:
- return start_point + content_length - child_length;
- default:
- return start_point;
- }
- };
-
const auto& children = GetChildren();
const Index child_count = children.size();
@@ -354,8 +357,8 @@ void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) {
GetItemCrossAlign());
child->Layout(
Point{content_rect.left + current_main_offset,
- calculate_cross_anchor(cross_align, content_rect.top,
- content_rect.height, size.height)});
+ CalculateAnchorByAlignment(cross_align, content_rect.top,
+ content_rect.height, size.height)});
current_main_offset += size.width;
}
@@ -369,8 +372,8 @@ void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) {
GetItemCrossAlign());
child->Layout(
Point{content_rect.GetRight() - current_main_offset,
- calculate_cross_anchor(cross_align, content_rect.top,
- content_rect.height, size.height)});
+ CalculateAnchorByAlignment(cross_align, content_rect.top,
+ content_rect.height, size.height)});
current_main_offset += size.width;
}
} else if (direction_ == FlexDirection::Vertical) {
@@ -383,8 +386,8 @@ void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) {
GetItemCrossAlign());
child->Layout(
Point{content_rect.top + current_main_offset,
- calculate_cross_anchor(cross_align, content_rect.left,
- content_rect.width, size.width)});
+ CalculateAnchorByAlignment(cross_align, content_rect.left,
+ content_rect.width, size.width)});
current_main_offset += size.height;
}
} else {
@@ -397,8 +400,8 @@ void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) {
GetItemCrossAlign());
child->Layout(
Point{content_rect.GetBottom() - current_main_offset,
- calculate_cross_anchor(cross_align, content_rect.left,
- content_rect.width, size.width)});
+ CalculateAnchorByAlignment(cross_align, content_rect.left,
+ content_rect.width, size.width)});
current_main_offset += size.height;
}
}
diff --git a/src/ui/render/LayoutHelper.cpp b/src/ui/render/LayoutHelper.cpp
new file mode 100644
index 00000000..31cf5c08
--- /dev/null
+++ b/src/ui/render/LayoutHelper.cpp
@@ -0,0 +1,36 @@
+#include "cru/ui/render/LayoutHelper.hpp"
+
+#include "cru/common/Logger.hpp"
+
+namespace cru::ui::render {
+float CalculateAnchorByAlignment(Alignment alignment, float start_point,
+ float content_length, float child_length) {
+ switch (alignment) {
+ case FlexCrossAlignment::Start:
+ return start_point;
+ case FlexCrossAlignment::Center:
+ return start_point + (content_length - child_length) / 2.0f;
+ case FlexCrossAlignment::End:
+ return start_point + content_length - child_length;
+ default:
+ return start_point;
+ }
+}
+
+MeasureLength StackLayoutCalculateChildMaxLength(
+ MeasureLength parent_preferred_size, MeasureLength parent_max_size,
+ MeasureLength child_min_size, std::string_view exceeds_message) {
+ if (parent_max_size.GetLengthOrMax() < child_min_size.GetLengthOr0()) {
+ log::Warn(exceeds_message);
+ return parent_max_size;
+ }
+
+ if (parent_preferred_size.IsSpecified() &&
+ parent_preferred_size.GetLengthOrUndefined() >=
+ child_min_size.GetLengthOr0()) {
+ return parent_preferred_size;
+ } else {
+ return parent_max_size;
+ }
+}
+} // namespace cru::ui::render
diff --git a/src/ui/render/StackLayoutRenderObject.cpp b/src/ui/render/StackLayoutRenderObject.cpp
index b953ae7e..a6ed7708 100644
--- a/src/ui/render/StackLayoutRenderObject.cpp
+++ b/src/ui/render/StackLayoutRenderObject.cpp
@@ -1,60 +1,53 @@
#include "cru/ui/render/StackLayoutRenderObject.hpp"
+#include "cru/common/Logger.hpp"
+#include "cru/ui/render/LayoutHelper.hpp"
+
#include <algorithm>
namespace cru::ui::render {
Size StackLayoutRenderObject::OnMeasureContent(
const MeasureRequirement& requirement, const MeasureSize& preferred_size) {
- // TODO: Rewrite this.
- CRU_UNUSED(requirement);
- CRU_UNUSED(preferred_size);
- throw std::runtime_error("Not implemented.");
+ Size max_size;
+ for (const auto child : GetChildren()) {
+ child->Measure(
+ MeasureRequirement{
+ MeasureSize{StackLayoutCalculateChildMaxLength(
+ preferred_size.width, requirement.max.width,
+ child->GetMinSize().width,
+ "StackLayoutRenderObject: Child's min width is "
+ "bigger than parent's max width."),
+ StackLayoutCalculateChildMaxLength(
+ preferred_size.height, requirement.max.height,
+ child->GetMinSize().height,
+ "StackLayoutRenderObject: Child's min height is "
+ "bigger than parent's max height.")},
+ MeasureSize::NotSpecified()},
+ MeasureSize::NotSpecified());
+ const auto size = child->GetSize();
+ max_size.width = std::max(max_size.width, size.width);
+ max_size.height = std::max(max_size.height, size.height);
+ }
+
+ max_size = Max(preferred_size.GetSizeOr0(), max_size);
+ max_size = Max(requirement.min.GetSizeOr0(), max_size);
- // 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;
+ return max_size;
}
void StackLayoutRenderObject::OnLayoutContent(const Rect& content_rect) {
- // 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 count = GetChildCount();
- // const auto& children = GetChildren();
+ 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});
- // }
+ for (int i = 0; i < count; i++) {
+ const auto child = children[i];
+ const auto& layout_data = GetChildLayoutData(i);
+ const auto& size = child->GetSize();
+ child->Layout(Point{
+ CalculateAnchorByAlignment(layout_data.horizontal, content_rect.left,
+ content_rect.width, size.width),
+ CalculateAnchorByAlignment(layout_data.vertical, content_rect.top,
+ content_rect.height, size.height)});
+ }
}
} // namespace cru::ui::render