use crate::layout_struct::layout_states::element_info_states::TotalMinSize;
use crate::layout_struct::layout_states::{
ChildWrapping, LayoutElement, LayoutElementInfo, element_info_states,
};
use crate::layout_struct::layout_tree::LayoutTreeNodeLocal;
use cotis_defaults::element_configs::style::types::LayoutDirection;
pub(crate) fn merged_vertical_bounds_from_children(
element: &LayoutElement,
children: &[&LayoutElement],
) -> (f32, f32) {
let mut total_min_height =
element.config.layout.padding.top + element.config.layout.padding.bottom;
let mut total_pref_height =
element.config.layout.padding.top + element.config.layout.padding.bottom;
match element.config.layout.layout_direction {
LayoutDirection::LeftToRight => {
let mut max_min_height = 0.0f32;
let mut max_pref_height = 0.0f32;
for child in children {
if child.config.floating.config.is_some() {
continue;
}
max_min_height = max_min_height.max(
child
.info
.min_height()
.expect("child must expose min height during layout"),
);
max_pref_height = max_pref_height.max(
child
.info
.temp_height()
.expect("child must expose temp height during layout"),
);
}
total_min_height += max_min_height;
total_pref_height += max_pref_height;
}
LayoutDirection::TopToBottom => {
for child in children {
if child.config.floating.config.is_some() {
continue;
}
total_min_height += child
.info
.min_height()
.expect("child must expose min height during layout");
total_pref_height += child
.info
.temp_height()
.expect("child must expose temp height during layout");
}
total_min_height += element.config.layout.child_gap * children.len().max(1) as f32;
}
}
let node_mins = element.calc_start_dim().into_total_min_size();
let raw_pref_h = node_mins.preferred_size_height.max(total_pref_height);
let merged_min_h = node_mins
.min_size_height
.max(if element.config.clip.vertical {
0.0
} else {
total_min_height
});
let merged_pref_h = if element.config.clip.vertical {
raw_pref_h
} else {
raw_pref_h
};
(merged_min_h, merged_pref_h)
}
impl LayoutTreeNodeLocal<'_> {
pub(crate) fn recalculate_min_height_from_children(&mut self) {
let (merged_min_h, merged_pref_h) =
merged_vertical_bounds_from_children(self.self_element, &self.children_elements);
match &self.self_element.info {
LayoutElementInfo::NotInitialized
| LayoutElementInfo::TotalSize(_)
| LayoutElementInfo::TotalSizedAndPosition(_) => {}
_ => {
self.self_element.info.set_min_height(merged_min_h);
self.self_element.info.set_tmp_height(merged_pref_h);
}
}
}
pub fn open_configuration(&mut self) {
if self.self_element.config.floating.config.is_none() {
self.self_element.config.floating.z_index = self
.parent_element
.map(|p| p.config.floating.z_index)
.unwrap_or(0);
}
}
pub fn close_element(&mut self) {
let mut total_min_size: element_info_states::TotalMinSize = TotalMinSize {
min_size_width: self.self_element.config.layout.padding.left
+ self.self_element.config.layout.padding.right,
min_size_height: self.self_element.config.layout.padding.top
+ self.self_element.config.layout.padding.bottom,
preferred_size_width: self.self_element.config.layout.padding.left
+ self.self_element.config.layout.padding.right,
preferred_size_height: self.self_element.config.layout.padding.top
+ self.self_element.config.layout.padding.bottom,
};
match self.self_element.config.layout.layout_direction {
LayoutDirection::LeftToRight => {
let mut max_min_height = 0.0;
let mut max_pref_height = 0.0;
let wrap = self.self_element.config.layout.wrapping == ChildWrapping::Text;
let mut max_min_child_width = 0.0f32;
for child in &self.children_elements {
if let LayoutElementInfo::TotalMinSize(child_min_size) = &child.info {
if wrap {
max_min_child_width =
max_min_child_width.max(child_min_size.min_size_width);
} else {
total_min_size.min_size_width += child_min_size.min_size_width;
}
max_min_height = child_min_size.min_size_height.max(max_min_height);
total_min_size.preferred_size_width += child_min_size.preferred_size_width;
max_pref_height = child_min_size.preferred_size_height.max(max_pref_height);
} else {
panic!(
"How did we get here. Trying to calculate total min size without child total min size"
)
}
}
total_min_size.min_size_height += max_min_height;
total_min_size.preferred_size_height += max_pref_height;
if wrap {
total_min_size.min_size_width += max_min_child_width;
total_min_size.preferred_size_width +=
self.self_element.config.layout.child_gap
* self.children_elements.len().saturating_sub(1) as f32;
} else {
total_min_size.min_size_width += self.self_element.config.layout.child_gap
as f32
* self.children_elements.len().max(1) as f32;
}
}
LayoutDirection::TopToBottom => {
let mut max_min_width = 0.0;
let mut max_pref_width = 0.0;
for child in &self.children_elements {
if let LayoutElementInfo::TotalMinSize(child_min_size) = &child.info {
total_min_size.min_size_height += child_min_size.min_size_height;
max_min_width = child_min_size.min_size_width.max(max_min_width);
total_min_size.preferred_size_height +=
child_min_size.preferred_size_height;
max_pref_width = child_min_size.preferred_size_width.max(max_pref_width);
} else {
panic!(
"How did we get here. Trying to calculate total min size without child total min size"
)
}
}
total_min_size.min_size_width += max_min_width;
total_min_size.preferred_size_width += max_pref_width;
total_min_size.min_size_height += self.self_element.config.layout.child_gap as f32
* self.children_elements.len().max(1) as f32;
}
}
let node_mins = self.self_element.calc_start_dim().into_total_min_size();
let raw_pref_w = node_mins
.preferred_size_width
.max(total_min_size.preferred_size_width);
let raw_pref_h = node_mins
.preferred_size_height
.max(total_min_size.preferred_size_height);
let max_w = self.self_element.declared_max_axis(true);
let max_h = self.self_element.declared_max_axis(false);
let total_min_size = TotalMinSize {
min_size_width: node_mins.min_size_width.max(
if self.self_element.config.clip.horizontal {
0.0
} else {
total_min_size.min_size_width.min(max_w)
},
),
min_size_height: node_mins.min_size_height.max(
if self.self_element.config.clip.vertical {
0.0
} else {
total_min_size.min_size_height.min(max_h)
},
),
preferred_size_width: raw_pref_w.min(max_w),
preferred_size_height: raw_pref_h.min(max_h),
};
self.self_element.info = LayoutElementInfo::TotalMinSize(total_min_size);
}
}