1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use crate::checklist::{Checklist, ChecklistItem, ChecklistItems, Path};
use cursive::{traits::*, views::NamedView, Cursive};
use cursive_tree_view::{Placement, TreeView};

pub type ChecklistTree = TreeView<ChecklistItem>;

pub struct Tree {
    current: Path,
    checklist: Checklist,
}

fn collapse_func(siv: &mut Cursive, row: usize, is_collapsed: bool, children: usize) {
    if !is_collapsed && children == 0 {
        siv.call_on_name("tree", move |tree: &mut ChecklistTree| {
            tree_insert(
                tree,
                tree.borrow_item(row).unwrap().items().to_vec(),
                row,
                Placement::LastChild,
            );
        });
    }
}

fn tree_insert(tv: &mut ChecklistTree, items: ChecklistItems, parent: usize, placement: Placement) {
    for item in items {
        if item.items().is_empty() {
            tv.insert_item(item.clone(), placement, parent);
        } else {
            if let Some(id) = tv.insert_container_item(item.clone(), placement, parent) {
                tv.expand_item(id);

                tree_insert(
                    tv,
                    tv.borrow_item(id).unwrap().items().to_vec(),
                    id,
                    Placement::LastChild,
                );

                tv.collapse_item(id);
            }
        }
    }
}

impl Tree {
    pub fn new(checklist: Checklist) -> Self {
        Tree {
            current: Path::default(),
            checklist,
        }
    }

    pub fn title(&self) -> String {
        self.checklist.title.clone()
    }

    pub fn next_path(&self) -> Path {
        let mut path = self.current_path();
        while let Some(idx) = path.pop() {
            if let Some(item) = self.checklist.path(path.clone()) {
                if item.items().len() - 1 > idx {
                    path.push(idx + 1);
                    return path;
                }
            }
        }

        return Path::default();
    }

    pub fn last_path(&self) -> Path {
        let mut path = self.current_path();
        while let Some(idx) = path.pop() {
            if let Some(item) = self.checklist.path(path.clone()) {
                if idx > 0 && !item.items().is_empty() {
                    path.push(idx - 1);
                    return path;
                }
            }
        }

        return Path::default();
    }

    pub fn move_item(&mut self, _from: Path, _to: Path) {}
    pub fn delete_item(&mut self, _path: Path) {}

    pub fn set_current(&mut self, path: Path) {
        self.current = path;
    }

    pub fn current_path(&self) -> Path {
        self.current.clone()
    }

    pub fn current_item(&self) -> ChecklistItem {
        self.checklist.path(self.current.clone()).unwrap()
    }

    pub fn as_treeview(&self) -> NamedView<ChecklistTree> {
        let mut tv = ChecklistTree::new();
        tree_insert(&mut tv, self.checklist.items.to_vec(), 0, Placement::After);
        tv.set_on_collapse(collapse_func);
        tv.with_name("tree")
    }
}