1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
#pragma once
#include "LayoutRenderObject.h"
namespace cru::ui::render {
enum class FlexDirection {
Horizontal,
HorizontalReverse,
Vertical,
VertivalReverse
};
using FlexMainAlignment = Alignment;
using FlexCrossAlignment = Alignment;
struct FlexChildLayoutData {
float expand_factor = 0;
float shrink_factor = 1;
// nullopt stands for looking at parent's setting
std::optional<FlexCrossAlignment> cross_alignment = std::nullopt;
};
// Measure Logic (v0.1):
// 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.
//
// 2.1. If preferred main axis length of parent is specified, then compare
// total length with it. If bigger, shrink is performed. If smaller, expand is
// performed. And preferred main axis length is used as target length.
//
// 2.2. If preferred main axis length of parent is not specified.
//
// 2.2.1. If max main axis length is specified and total length is bigger
// than max main axis length, shrink is performed and max main axis length is
// used as target length.
//
// 2.2.2. Or if max main axis length is specified and total length is smaller
// than max main axis length and any child has a positive expand factor, then
// expand is performed and max main axis length is used as target length.
//
// 2.2.3. Or if min main axis length is specified and total length is smaller
// than min main axis length, expand is performed and min main axis length is
// used as target length.
//
// 3. If shrink or expand is needed, then
//
// 3.1. Shrink:
//
// 3.1.1. Find out all shrink_factor > 0 children to form a adjusting list.
//
// 3.1.2. Use total main length minus target length to get the total shrink
// length. Add up all shrink_factor in adjusting list to get total shrink
// factor.
//
// 3.1.3. Iterate all children in adjusting list:
//
// 3.1.3.1. Calculate its own shrink length as
// shrink_factor / total_shrink_factor * total_shrink_length .
// Use current main axis length of child minus shrink length to get new
// measure length.
//
// 3.1.3.2. If min main axis length of the child is specified and new
// measure length is less than it, then min main axis length is used as new
// measure length.
//
// 3.1.3.3. Or if new measure length is less than 0, then it is coerced to
// 0.
//
// 3.1.3.4. Call measure with max and preferred main axis length set to new
// measure length. Cross axis length requirement is the same as step 1.
//
// 3.1.3.5. After measure, if it has min main axis length specified and
// actual main axis length is equal to it or its actual main axis length is
// 0, then remove it from adjusting list.
//
// 3.1.4. Add up main axis length of children to update total main length. If
// total main length is less than or equal to target length, goto step 4.
//
// 3.1.4. If adjusting list is not empty, go to step 3.1.2.
//
// 3.2. Expand:
// The same as shrink after you exchange related things except some minor
// things like do not do special things on 0.
//
// 4. If final total main axis length exceeeds the max main axis length (if
// specified), then report an error. And result main axis length is the coerced
// length. If final total main axis length is smaller than min main axis length
// (if specified), then coerce the length to the min value but not report error
// and just fill the rest space with blank.
//
class CRU_UI_API FlexLayoutRenderObject
: public LayoutRenderObject<FlexChildLayoutData> {
CRU_DEFINE_CLASS_LOG_TAG("FlexLayoutRenderObject")
public:
FlexLayoutRenderObject() = default;
FlexLayoutRenderObject(const FlexLayoutRenderObject& other) = delete;
FlexLayoutRenderObject& operator=(const FlexLayoutRenderObject& other) =
delete;
FlexLayoutRenderObject(FlexLayoutRenderObject&& other) = delete;
FlexLayoutRenderObject& operator=(FlexLayoutRenderObject&& other) = delete;
~FlexLayoutRenderObject() override = default;
String GetName() const override;
FlexDirection GetFlexDirection() const { return direction_; }
void SetFlexDirection(FlexDirection direction) {
direction_ = direction;
InvalidateLayout();
}
FlexMainAlignment GetContentMainAlign() const { return content_main_align_; }
void SetContentMainAlign(FlexMainAlignment align) {
content_main_align_ = align;
InvalidateLayout();
}
FlexCrossAlignment GetItemCrossAlign() const { return item_cross_align_; }
void SetItemCrossAlign(FlexCrossAlignment align) {
item_cross_align_ = align;
InvalidateLayout();
}
protected:
Size OnMeasureContent(const MeasureRequirement& requirement,
const MeasureSize& preferred_size) override;
void OnLayoutContent(const Rect& content_rect) override;
private:
FlexDirection direction_ = FlexDirection::Horizontal;
FlexMainAlignment content_main_align_ = FlexMainAlignment::Start;
FlexCrossAlignment item_cross_align_ = FlexCrossAlignment::Center;
};
} // namespace cru::ui::render
|