use crossterm::event::MouseEvent;
use rdom_core::{NodeId, Position, Selection};
use crate::TuiDom;
use crate::layout::UserSelect;
use crate::node::{TuiNodeExt, first_text_descendant, last_text_descendant, text_len};
pub(crate) fn ancestor_with(dom: &TuiDom, id: NodeId, value: UserSelect) -> Option<NodeId> {
let mut cur = Some(id);
while let Some(n) = cur {
if let Some(c) = dom.node(n).computed()
&& c.user_select == value
{
return Some(n);
}
cur = dom.node(n).parent_node().map(|p| p.id());
}
None
}
pub(crate) fn has_none_ancestor(dom: &TuiDom, id: NodeId) -> bool {
ancestor_with(dom, id, UserSelect::None).is_some()
}
pub(crate) fn span_all_text(dom: &TuiDom, host: NodeId) -> Option<Selection> {
let first = first_text_descendant(dom, host)?;
let last = last_text_descendant(dom, host).unwrap_or(first);
let end = text_len(dom, last);
Some(Selection::new(
Position::new(first, 0),
Position::new(last, end),
))
}
pub(crate) fn clamp_to_contain_host(
dom: &TuiDom,
host: NodeId,
mouse: MouseEvent,
) -> Option<Position> {
let rect = dom.node(host).layout_rect()?;
let below = (mouse.row as i32) >= rect.y + rect.height as i32;
let above = (mouse.row as i32) < rect.y;
let want_end = if below {
true
} else if above {
false
} else {
(mouse.column as i32) >= rect.x + rect.width as i32
};
if want_end {
let node = last_text_descendant(dom, host)?;
Some(Position::new(node, text_len(dom, node)))
} else {
let node = first_text_descendant(dom, host)?;
Some(Position::new(node, 0))
}
}