use std::cell::Cell as StdCell;
use ratatui::layout::Position;
use crate::core::node::{NodeId, NodeTree};
pub(crate) struct CursorPlacement<'a> {
sink: Option<&'a StdCell<Option<Position>>>,
owner: Option<(&'a NodeTree, NodeId)>,
}
impl<'a> CursorPlacement<'a> {
pub(crate) fn tracked(
sink: &'a StdCell<Option<Position>>,
tree: &'a NodeTree,
owner: NodeId,
) -> Self {
Self {
sink: Some(sink),
owner: Some((tree, owner)),
}
}
#[cfg(test)]
pub(crate) fn untracked() -> Self {
Self {
sink: None,
owner: None,
}
}
pub(crate) fn place(&self, f: &mut ratatui::Frame<'_>, position: Position) {
if self.occluded(position) {
return;
}
f.set_cursor_position(position);
if let Some(sink) = self.sink {
sink.set(Some(position));
}
}
fn occluded(&self, position: Position) -> bool {
self.owner
.is_some_and(|(tree, owner)| caret_occluded(tree, owner, position))
}
}
pub(crate) fn caret_occluded(tree: &NodeTree, owner: NodeId, position: Position) -> bool {
let (Ok(x), Ok(y)) = (i16::try_from(position.x), i16::try_from(position.y)) else {
return false;
};
tree.hit_test(x, y)
.is_some_and(|top| !tree.is_descendant(owner, top) && !tree.is_descendant(top, owner))
}