use rdom_core::{Dom, NodeId};
use crate::ext::TuiExt;
use crate::layout::{Direction, Size, clamp_size};
use crate::render::layout_pass::intrinsic::intrinsic_size;
use crate::style::ComputedStyle;
pub(super) fn resolve_block_height(
dom: &Dom<TuiExt>,
id: NodeId,
computed: &ComputedStyle,
resolved_width: u16,
container_height: u16,
containing_block_width: u16,
) -> u16 {
let parent_height_definite = nearest_block_ancestor_height_is_definite(dom, id);
let raw = match &computed.height {
Size::Auto | Size::Flex(_) => {
intrinsic_size(
dom,
id,
Direction::Column,
resolved_width,
containing_block_width,
)
}
Size::Fixed(n) => *n,
Size::Percent(p) => {
if parent_height_definite {
Size::percent_of(container_height as i32, *p).clamp(0, u16::MAX as i32) as u16
} else {
intrinsic_size(
dom,
id,
Direction::Column,
resolved_width,
containing_block_width,
)
}
}
Size::Calc(expr) => {
if parent_height_definite {
let v = expr.resolve(&rdom_style::calc::ResolveCtx::new(container_height as i32));
v.max(0).min(u16::MAX as i32) as u16
} else {
intrinsic_size(
dom,
id,
Direction::Column,
resolved_width,
containing_block_width,
)
}
}
};
let min_cells: Option<u16> = match computed.min_height {
Some(crate::layout::MinSize::Cells(n)) => Some(n),
Some(crate::layout::MinSize::Auto) | None => None,
};
clamp_size(raw, min_cells, computed.max_height)
}
pub(crate) fn nearest_block_ancestor_height_is_definite(dom: &Dom<TuiExt>, id: NodeId) -> bool {
use crate::layout::{MinSize, Position};
let mut cur = id;
loop {
let node = dom.node(cur);
let Some(parent) = node.parent_node() else {
return true;
};
let parent_id = parent.id();
let Some(parent_computed) = parent.ext().and_then(|e| e.computed.as_ref()) else {
return true; };
if matches!(
parent_computed.position,
Position::Absolute | Position::Fixed
) {
return true;
}
if let Some(MinSize::Cells(n)) = parent_computed.min_height
&& n > 0
{
return true;
}
match parent_computed.height {
Size::Fixed(_) => return true,
Size::Auto => return false,
Size::Flex(_) => {
use crate::layout::Flow;
match parent.parent_node() {
None => return true,
Some(gp) => match gp.ext().and_then(|e| e.computed.as_ref()).map(|c| c.flow) {
None => return true,
Some(Flow::Flex) => cur = parent_id,
Some(Flow::Block) => return false,
},
}
}
Size::Percent(_) | Size::Calc(_) => {
cur = parent_id;
}
}
}
}