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
|
#include "margin_container.h"
namespace cru::ui::controls
{
inline float AtLeast0(const float value)
{
return value < 0 ? 0 : value;
}
inline Size AtLeast0(const Size& size)
{
return Size(AtLeast0(size.width), AtLeast0(size.height));
}
MarginContainer::MarginContainer(const Thickness& margin)
: Control(true), margin_(margin)
{
}
void MarginContainer::SetMargin(const Thickness& margin)
{
margin_ = margin;
InvalidateLayout();
}
Size MarginContainer::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 LayoutSideParams& 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();
}
};
const Size 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));
const auto margin_size = Size(margin_.left + margin_.right, margin_.top + margin_.bottom);
const auto coerced_size_for_children = AtLeast0(size_for_children - margin_size);
auto max_child_size = Size::Zero();
ForeachChild([coerced_size_for_children, &max_child_size](Control* control)
{
control->Measure(coerced_size_for_children);
const auto&& size = control->GetDesiredSize();
if (max_child_size.width < size.width)
max_child_size.width = size.width;
if (max_child_size.height < size.height)
max_child_size.height = size.height;
});
auto&& calculate_final_length = [](const LayoutSideParams& 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, coerced_size_for_children.width, max_child_size.width),
calculate_final_length(layout_params->height, coerced_size_for_children.height, max_child_size.height)
);
}
void MarginContainer::OnLayout(const Rect& rect)
{
const auto anchor = Point(margin_.left, margin_.top);
const auto margin_size = Size(margin_.left + margin_.right, margin_.top + margin_.bottom);
Control::OnLayout(Rect(anchor, AtLeast0(rect.GetSize() - margin_size)));
}
}
|