use rdom_core::NodeId;
use super::ScrollAxis;
use crate::TuiDom;
use crate::layout::Overflow;
use crate::node::TuiNodeExt;
pub(super) fn scroll_metrics(dom: &TuiDom, element: NodeId, axis: ScrollAxis) -> (u16, usize) {
let ext = match dom.node(element).tui_ext() {
Some(e) => e,
None => return (0, 0),
};
let border = dom
.node(element)
.computed()
.map(|c| c.border)
.unwrap_or_default();
let pb = crate::layout::compute_padding_box(ext.layout, border);
match axis {
ScrollAxis::Vertical => (pb.height, ext.scroll_y),
ScrollAxis::Horizontal => (pb.width, ext.scroll_x),
}
}
pub(super) fn nearest_scroll_container(dom: &TuiDom, id: NodeId) -> Option<NodeId> {
let mut cur = Some(id);
while let Some(id) = cur {
if is_vertical_scroll_container(dom, id) || is_horizontal_scroll_container(dom, id) {
return Some(id);
}
cur = dom.node(id).parent_node().map(|p| p.id());
}
None
}
pub(super) fn scrolls_vertically_by_style(dom: &TuiDom, id: NodeId) -> bool {
let overflow_y = dom
.node(id)
.computed()
.map(|c| c.overflow_y)
.unwrap_or(Overflow::Visible);
!matches!(overflow_y, Overflow::Visible)
}
pub(super) fn is_vertical_scroll_container(dom: &TuiDom, id: NodeId) -> bool {
let Some(ext) = dom.node(id).tui_ext() else {
return false;
};
if !scrolls_vertically_by_style(dom, id) {
return false;
}
let border = dom
.node(id)
.computed()
.map(|c| c.border)
.unwrap_or_default();
let pb = crate::layout::compute_padding_box(ext.layout, border);
ext.scroll_content_height > pb.height as usize
}
pub(super) fn is_horizontal_scroll_container(dom: &TuiDom, id: NodeId) -> bool {
let Some(ext) = dom.node(id).tui_ext() else {
return false;
};
let overflow_x = dom
.node(id)
.computed()
.map(|c| c.overflow_x)
.unwrap_or(Overflow::Visible);
if matches!(overflow_x, Overflow::Visible) {
return false;
}
let border = dom
.node(id)
.computed()
.map(|c| c.border)
.unwrap_or_default();
let pb = crate::layout::compute_padding_box(ext.layout, border);
ext.scroll_content_width > pb.width as usize
}