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
138
139
140
141
142
|
#include "linear_layout.h"
namespace cru::ui::controls
{
LinearLayout::LinearLayout(const Orientation orientation)
: Control(true), orientation_(orientation)
{
}
Size LinearLayout::OnMeasure(const Size& available_size)
{
const auto layout_params = GetLayoutParams();
if (!layout_params->Validate())
throw std::runtime_error("LayoutParams is not valid. Please check it.");
auto&& get_available_length_for_child = [](const MeasureLength& layout_length, const float available_length) -> float
{
switch (layout_length.mode)
{
case MeasureMode::Exactly:
{
return std::min(layout_length.length, available_length);
}
case MeasureMode::Stretch:
case MeasureMode::Content:
{
return available_length;
}
default:
UnreachableCode();
}
};
Size total_available_size_for_children(
get_available_length_for_child(layout_params->width, available_size.width),
get_available_length_for_child(layout_params->height, available_size.height)
);
auto rest_available_size_for_children = total_available_size_for_children;
std::list<Control*> stretch_control_list;
// First measure Content and Exactly and count Stretch.
if (orientation_ == Orientation::Horizontal)
ForeachChild([&rest_available_size_for_children, &stretch_control_list](Control* const control)
{
const auto mode = control->GetLayoutParams()->width.mode;
if (mode == MeasureMode::Content || mode == MeasureMode::Exactly)
{
control->Measure(rest_available_size_for_children);
rest_available_size_for_children.width -= control->GetDesiredSize().width;
if (rest_available_size_for_children.width < 0)
rest_available_size_for_children.width = 0;
}
else
stretch_control_list.push_back(control);
});
else
ForeachChild([&rest_available_size_for_children, &stretch_control_list](Control* const control)
{
const auto mode = control->GetLayoutParams()->height.mode;
if (mode == MeasureMode::Content || mode == MeasureMode::Exactly)
{
control->Measure(rest_available_size_for_children);
rest_available_size_for_children.height -= control->GetDesiredSize().height;
if (rest_available_size_for_children.height < 0)
rest_available_size_for_children.height = 0;
}
else
stretch_control_list.push_back(control);
});
if (orientation_ == Orientation::Horizontal)
{
const auto available_width = rest_available_size_for_children.width / stretch_control_list.size();
for (const auto control : stretch_control_list)
{
control->Measure(Size(available_width, rest_available_size_for_children.height));
rest_available_size_for_children.width -= control->GetDesiredSize().width;
if (rest_available_size_for_children.width < 0)
rest_available_size_for_children.width = 0;
}
}
else
{
const auto available_height = rest_available_size_for_children.height / stretch_control_list.size();
for (const auto control : stretch_control_list)
{
control->Measure(Size(rest_available_size_for_children.width, available_height));
rest_available_size_for_children.height -= control->GetDesiredSize().height;
if (rest_available_size_for_children.height < 0)
rest_available_size_for_children.height = 0;
}
}
auto actual_size_for_children = total_available_size_for_children;
if (orientation_ == Orientation::Horizontal)
actual_size_for_children.width -= rest_available_size_for_children.width;
else
actual_size_for_children.height -= rest_available_size_for_children.height;
auto&& calculate_final_length = [](const MeasureLength& layout_length, const float length_for_children, const float max_child_length) -> float
{
switch (layout_length.mode)
{
case MeasureMode::Exactly:
case MeasureMode::Stretch:
return length_for_children;
case MeasureMode::Content:
return max_child_length;
default:
UnreachableCode();
}
};
return Size(
calculate_final_length(layout_params->width, total_available_size_for_children.width, actual_size_for_children.width),
calculate_final_length(layout_params->height, total_available_size_for_children.height, actual_size_for_children.height)
);
}
void LinearLayout::OnLayout(const Rect& rect)
{
float current_anchor_length = 0;
ForeachChild([this, ¤t_anchor_length, rect](Control* control)
{
const auto size = control->GetDesiredSize();
if (orientation_ == Orientation::Horizontal)
{
control->Layout(Rect(Point(current_anchor_length, (rect.height - size.height) / 2), size));
current_anchor_length += size.width;
}
else
{
control->Layout(Rect(Point((rect.width - size.width) / 2, current_anchor_length), size));
current_anchor_length += size.height;
}
});
}
}
|