aboutsummaryrefslogtreecommitdiff
path: root/CruUI/ui/controls/linear_layout.cpp
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2018-09-08 23:31:20 +0800
committercrupest <crupest@outlook.com>2018-09-08 23:31:20 +0800
commit74031db4b8c366531db5be8fa8d765483ab377b0 (patch)
tree558ed98f22eb182b7d7017e5a51bdb14d5e92268 /CruUI/ui/controls/linear_layout.cpp
parent7cbe80c19170c8c742fd280c555eafbd2a51b4da (diff)
downloadcru-74031db4b8c366531db5be8fa8d765483ab377b0.tar.gz
cru-74031db4b8c366531db5be8fa8d765483ab377b0.tar.bz2
cru-74031db4b8c366531db5be8fa8d765483ab377b0.zip
...
Diffstat (limited to 'CruUI/ui/controls/linear_layout.cpp')
-rw-r--r--CruUI/ui/controls/linear_layout.cpp88
1 files changed, 88 insertions, 0 deletions
diff --git a/CruUI/ui/controls/linear_layout.cpp b/CruUI/ui/controls/linear_layout.cpp
new file mode 100644
index 00000000..f639720d
--- /dev/null
+++ b/CruUI/ui/controls/linear_layout.cpp
@@ -0,0 +1,88 @@
+#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;
+
+ ForeachChild([this, &rest_available_size_for_children](Control* const control)
+ {
+ control->Measure(rest_available_size_for_children);
+ if (orientation_ == Orientation::Horizontal)
+ rest_available_size_for_children.width -= control->GetDesiredSize().width;
+ else
+ rest_available_size_for_children.height -= control->GetDesiredSize().height;
+ });
+
+ auto actual_size_for_children = total_available_size_for_children - rest_available_size_for_children;
+
+ 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)
+ {
+ auto current_anchor = Point::zero;
+ ForeachChild([this, &current_anchor](Control* control)
+ {
+ const auto size = control->GetDesiredSize();
+ control->Layout(Rect(current_anchor, size));
+
+ if (orientation_ == Orientation::Horizontal)
+ current_anchor.x += size.width;
+ else
+ current_anchor.y += size.height;
+ });
+ }
+}