refactoring

This commit is contained in:
2026-10-31 01:06:21 +03:00
parent 27385a3edb
commit 19e05e7ed0
17 changed files with 2673 additions and 671 deletions
+32 -34
View File
@@ -92,6 +92,7 @@ pub enum TreeKeyResult {
}
/// Состояние абстрактного дерева.
#[derive(Default)]
pub struct TreeState {
nodes: HashMap<String, NodeRecord>,
roots: Vec<String>,
@@ -108,21 +109,6 @@ pub struct TreeState {
scroll: ScrollHandle,
}
impl Default for TreeState {
fn default() -> Self {
Self {
nodes: HashMap::new(),
roots: Vec::new(),
toggle_callback: None,
click_callback: None,
selected: None,
focus_handle: None,
focus_requested: false,
scroll: ScrollHandle::default(),
}
}
}
impl TreeState {
/// Создаёт пустое дерево.
pub fn new() -> Self {
@@ -153,11 +139,8 @@ impl TreeState {
return false;
}
self.expand_ancestors(id);
self.selected = Some(id.to_owned());
self.focus_requested = true;
if let Some(index) = self.rows().iter().position(|row| row.id == id) {
self.scroll.scroll_to_item(index);
}
self.select_and_scroll(id);
true
}
@@ -259,6 +242,16 @@ impl TreeState {
Ok(())
}
/// Удаляет все узлы и сбрасывает выбор.
///
/// Обработчики раскрытия и клика сохраняются: сценарий может наполнять
/// дерево заново, например при обновлении списка диагностики.
pub fn clear(&mut self) {
self.nodes.clear();
self.roots.clear();
self.selected = None;
}
/// Удаляет узел и все его дочерние узлы рекурсивно.
///
/// Возвращает `false`, если узла с таким `id` нет.
@@ -340,6 +333,14 @@ impl TreeState {
entries.into_iter().map(|(_, _, id)| id).collect()
}
/// Делает строку выбранной и прокручивает её в видимую часть.
fn select_and_scroll(&mut self, id: &str) {
self.selected = Some(id.to_owned());
if let Some(index) = self.rows().iter().position(|row| row.id == id) {
self.scroll.scroll_to_item(index);
}
}
/// Сдвигает выборку по видимым строкам.
fn move_selection(&mut self, delta: isize) {
let rows = self.rows();
@@ -357,8 +358,8 @@ impl TreeState {
None if delta < 0 => rows.len() - 1,
None => 0,
};
self.selected = Some(rows[next].id.clone());
self.scroll.scroll_to_item(next);
let id = rows[next].id.clone();
self.select_and_scroll(&id);
}
/// Enter: раскрывает папку или вызывает обработчик клика конечной ноды.
@@ -383,10 +384,7 @@ impl TreeState {
};
}
if let Some(parent) = self.nodes.get(&id).and_then(|record| record.parent.clone()) {
self.selected = Some(parent.clone());
if let Some(index) = self.rows().iter().position(|row| row.id == parent) {
self.scroll.scroll_to_item(index);
}
self.select_and_scroll(&parent);
}
TreeKeyResult::Handled
}
@@ -399,20 +397,20 @@ impl TreeState {
let Some(record) = self.nodes.get(&id) else {
return TreeKeyResult::Ignored;
};
if record.node.expandable && !record.node.expanded {
let expandable = record.node.expandable;
let expanded = record.node.expanded;
let first_child = expanded
.then(|| self.sorted(&record.children).first().cloned())
.flatten();
if expandable && !expanded {
return match self.activate(&id) {
Some(action) => TreeKeyResult::Action(action),
None => TreeKeyResult::Handled,
};
}
if record.node.expanded
&& let Some(child) = self.sorted(&record.children).first().cloned()
{
let index = self.rows().iter().position(|row| row.id == child);
self.selected = Some(child);
if let Some(index) = index {
self.scroll.scroll_to_item(index);
}
if let Some(child) = first_child {
self.select_and_scroll(&child);
}
TreeKeyResult::Handled
}