use std::collections::HashSet;
use crate::utils::tree::prefix::TreePrefix;
use crate::utils::tree::types::TreeItem;
pub struct TreeNav {
items: Vec<TreeItem>,
selected: usize,
selected_row: usize,
collapsed: HashSet<usize>,
}
impl TreeNav {
pub fn new() -> Self {
Self {
items: Vec::new(),
selected: 0,
selected_row: 0,
collapsed: HashSet::new(),
}
}
pub fn add_item(&mut self, item: TreeItem) {
self.items.push(item);
}
pub fn clear(&mut self) {
self.items.clear();
self.selected = 0;
self.selected_row = 0;
}
pub fn selected(&self) -> usize {
self.selected
}
pub fn selected_row(&self) -> usize {
self.selected_row
}
pub fn is_collapsed(&self, id: usize) -> bool {
self.collapsed.contains(&id)
}
pub fn is_visible(&self, id: usize) -> bool {
if let Some(item) = self.items.get(id) {
if let Some(parent) = item.parent {
if self.collapsed.contains(&parent) {
return false;
}
return self.is_visible(parent);
}
}
true
}
pub fn visible_items(&self) -> Vec<&TreeItem> {
self.items
.iter()
.filter(|item| self.is_visible(item.id))
.collect()
}
pub fn next(&mut self) {
let visible: Vec<_> = self.visible_items().iter().map(|i| i.id).collect();
if visible.is_empty() {
return;
}
if let Some(item) = self.items.get(self.selected) {
if self.selected_row + 1 < item.row_count {
self.selected_row += 1;
return;
}
}
if let Some(pos) = visible.iter().position(|&id| id == self.selected) {
let next_pos = (pos + 1) % visible.len();
self.selected = visible[next_pos];
self.selected_row = 0;
}
}
pub fn prev(&mut self) {
let visible: Vec<_> = self.visible_items().iter().map(|i| i.id).collect();
if visible.is_empty() {
return;
}
if self.selected_row > 0 {
self.selected_row -= 1;
return;
}
if let Some(pos) = visible.iter().position(|&id| id == self.selected) {
let prev_pos = if pos == 0 { visible.len() - 1 } else { pos - 1 };
self.selected = visible[prev_pos];
if let Some(item) = self.items.get(self.selected) {
self.selected_row = item.row_count.saturating_sub(1);
}
}
}
pub fn next_item(&mut self) {
let visible: Vec<_> = self.visible_items().iter().map(|i| i.id).collect();
if visible.is_empty() {
return;
}
if let Some(pos) = visible.iter().position(|&id| id == self.selected) {
let next_pos = (pos + 1) % visible.len();
self.selected = visible[next_pos];
self.selected_row = 0;
}
}
pub fn prev_item(&mut self) {
let visible: Vec<_> = self.visible_items().iter().map(|i| i.id).collect();
if visible.is_empty() {
return;
}
if let Some(pos) = visible.iter().position(|&id| id == self.selected) {
let prev_pos = if pos == 0 { visible.len() - 1 } else { pos - 1 };
self.selected = visible[prev_pos];
self.selected_row = 0;
}
}
pub fn toggle_collapse(&mut self) {
if let Some(item) = self.items.get(self.selected) {
if item.collapsible {
if self.collapsed.contains(&self.selected) {
self.collapsed.remove(&self.selected);
} else {
self.collapsed.insert(self.selected);
}
}
}
}
pub fn collapse(&mut self) {
if let Some(item) = self.items.get(self.selected) {
if item.collapsible {
self.collapsed.insert(self.selected);
}
}
}
pub fn expand(&mut self) {
self.collapsed.remove(&self.selected);
}
pub fn collapse_all(&mut self) {
for item in &self.items {
if item.collapsible {
self.collapsed.insert(item.id);
}
}
}
pub fn expand_all(&mut self) {
self.collapsed.clear();
}
pub fn select(&mut self, id: usize) {
if id < self.items.len() && self.is_visible(id) {
self.selected = id;
self.selected_row = 0;
}
}
pub fn first(&mut self) {
if let Some(item) = self.visible_items().first() {
self.selected = item.id;
self.selected_row = 0;
}
}
pub fn last(&mut self) {
if let Some(item) = self.visible_items().last() {
self.selected = item.id;
self.selected_row = 0;
}
}
pub fn get_prefix(&self, id: usize) -> (String, bool) {
let _visible = self.visible_items();
let is_last = self.is_last_sibling(id);
let mut prefix = TreePrefix::new();
if let Some(item) = self.items.get(id) {
let mut ancestors = Vec::new();
let mut current = item.parent;
while let Some(parent_id) = current {
ancestors.push(parent_id);
if let Some(parent) = self.items.get(parent_id) {
current = parent.parent;
} else {
break;
}
}
for ancestor_id in ancestors.into_iter().rev() {
prefix.push(!self.is_last_sibling(ancestor_id));
}
}
(prefix.prefix(is_last), is_last)
}
pub fn is_last_sibling(&self, id: usize) -> bool {
if let Some(item) = self.items.get(id) {
let parent = item.parent;
let depth = item.depth;
let siblings: Vec<_> = self
.items
.iter()
.filter(|i| i.parent == parent && i.depth == depth && self.is_visible(i.id))
.collect();
siblings.last().map(|last| last.id == id).unwrap_or(true)
} else {
true
}
}
pub fn render_items(&self) -> Vec<(&TreeItem, String, bool)> {
self.visible_items()
.into_iter()
.map(|item| {
let (prefix, _) = self.get_prefix(item.id);
let is_selected = item.id == self.selected;
(item, prefix, is_selected)
})
.collect()
}
}
impl Default for TreeNav {
fn default() -> Self {
Self::new()
}
}