use crate::geometry::Point;
pub struct TreeNode {
pub label: String,
pub icon: NodeIcon,
pub parent: Option<usize>,
pub is_expanded: bool,
pub is_selected: bool,
pub order: u32,
}
impl TreeNode {
pub fn new(
label: impl Into<String>,
icon: NodeIcon,
parent: Option<usize>,
order: u32,
) -> Self {
Self {
label: label.into(),
icon,
parent,
is_expanded: false,
is_selected: false,
order,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum NodeIcon {
Folder,
File,
Package,
}
pub struct FlatRow {
pub node_idx: usize,
pub depth: u32,
pub has_children: bool,
}
pub fn flatten_visible(nodes: &[TreeNode]) -> Vec<FlatRow> {
if nodes.is_empty() {
return Vec::new();
}
let mut roots: Vec<usize> = nodes
.iter()
.enumerate()
.filter(|(_, n)| n.parent.is_none())
.map(|(i, _)| i)
.collect();
roots.sort_by_key(|&i| nodes[i].order);
let mut result = Vec::new();
let mut stack: Vec<(usize, u32)> = roots.into_iter().rev().map(|i| (i, 0)).collect();
while let Some((node_idx, depth)) = stack.pop() {
let mut children: Vec<usize> = nodes
.iter()
.enumerate()
.filter(|(_, n)| n.parent == Some(node_idx))
.map(|(i, _)| i)
.collect();
children.sort_by_key(|&i| nodes[i].order);
let has_children = !children.is_empty();
result.push(FlatRow {
node_idx,
depth,
has_children,
});
if nodes[node_idx].is_expanded && has_children {
for &child in children.iter().rev() {
stack.push((child, depth + 1));
}
}
}
result
}
pub fn is_descendant(nodes: &[TreeNode], ancestor_idx: usize, mut node_idx: usize) -> bool {
loop {
match nodes[node_idx].parent {
None => return false,
Some(p) if p == ancestor_idx => return true,
Some(p) => node_idx = p,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum DropPosition {
Before(usize), After(usize), AsChild(usize), }
pub struct DragState {
pub node_idx: usize,
pub _cursor_row_offset: f64,
pub current_pos: Point,
pub live: bool,
}