lister_cli/
tree.rs

1use crate::checklist::{Checklist, ChecklistItem, ChecklistItems, Path};
2use cursive::{traits::*, views::NamedView, Cursive};
3use cursive_tree_view::{Placement, TreeView};
4
5pub type ChecklistTree = TreeView<ChecklistItem>;
6
7pub struct Tree {
8    current: Path,
9    checklist: Checklist,
10}
11
12fn collapse_func(siv: &mut Cursive, row: usize, is_collapsed: bool, children: usize) {
13    if !is_collapsed && children == 0 {
14        siv.call_on_name("tree", move |tree: &mut ChecklistTree| {
15            tree_insert(
16                tree,
17                tree.borrow_item(row).unwrap().items().to_vec(),
18                row,
19                Placement::LastChild,
20            );
21        });
22    }
23}
24
25fn tree_insert(tv: &mut ChecklistTree, items: ChecklistItems, parent: usize, placement: Placement) {
26    for item in items {
27        if item.items().is_empty() {
28            tv.insert_item(item.clone(), placement, parent);
29        } else {
30            if let Some(id) = tv.insert_container_item(item.clone(), placement, parent) {
31                tv.expand_item(id);
32
33                tree_insert(
34                    tv,
35                    tv.borrow_item(id).unwrap().items().to_vec(),
36                    id,
37                    Placement::LastChild,
38                );
39
40                tv.collapse_item(id);
41            }
42        }
43    }
44}
45
46impl Tree {
47    pub fn new(checklist: Checklist) -> Self {
48        Tree {
49            current: Path::default(),
50            checklist,
51        }
52    }
53
54    pub fn title(&self) -> String {
55        self.checklist.title.clone()
56    }
57
58    pub fn next_path(&self) -> Path {
59        let mut path = self.current_path();
60        while let Some(idx) = path.pop() {
61            if let Some(item) = self.checklist.path(path.clone()) {
62                if item.items().len() - 1 > idx {
63                    path.push(idx + 1);
64                    return path;
65                }
66            }
67        }
68
69        return Path::default();
70    }
71
72    pub fn last_path(&self) -> Path {
73        let mut path = self.current_path();
74        while let Some(idx) = path.pop() {
75            if let Some(item) = self.checklist.path(path.clone()) {
76                if idx > 0 && !item.items().is_empty() {
77                    path.push(idx - 1);
78                    return path;
79                }
80            }
81        }
82
83        return Path::default();
84    }
85
86    pub fn move_item(&mut self, _from: Path, _to: Path) {}
87    pub fn delete_item(&mut self, _path: Path) {}
88
89    pub fn set_current(&mut self, path: Path) {
90        self.current = path;
91    }
92
93    pub fn current_path(&self) -> Path {
94        self.current.clone()
95    }
96
97    pub fn current_item(&self) -> ChecklistItem {
98        self.checklist.path(self.current.clone()).unwrap()
99    }
100
101    pub fn as_treeview(&self) -> NamedView<ChecklistTree> {
102        let mut tv = ChecklistTree::new();
103        tree_insert(&mut tv, self.checklist.items.to_vec(), 0, Placement::After);
104        tv.set_on_collapse(collapse_func);
105        tv.with_name("tree")
106    }
107}