Skip to main content

tui_treelistview/state/
marks.rs

1use std::hash::Hash;
2
3use crate::context::TreeMarkState;
4use crate::model::TreeModel;
5use crate::traversal::TreePostorder;
6
7use super::TreeListViewState;
8
9impl<Id: Copy + Eq + Hash> TreeListViewState<Id> {
10    /// Rebuilds tri-state marks after the model or manual marks change.
11    pub fn ensure_mark_states<T: TreeModel<Id = Id>>(&mut self, model: &T) {
12        let stamp = (model.revision(), self.manual_marked.revision());
13        if self.mark_stamp == Some(stamp) {
14            return;
15        }
16
17        self.mark_states.clear();
18        for node in TreePostorder::forest(model) {
19            let mark = if self.manual_marked.contains(&node.id) {
20                TreeMarkState::Marked
21            } else {
22                let children = node.children;
23                if children.is_empty() {
24                    TreeMarkState::Unmarked
25                } else {
26                    let mut any = false;
27                    let mut all = true;
28                    for child in children {
29                        let child_mark = self.mark_states.get(child).copied().unwrap_or_default();
30                        any |= child_mark != TreeMarkState::Unmarked;
31                        all &= child_mark == TreeMarkState::Marked;
32                    }
33                    if all {
34                        TreeMarkState::Marked
35                    } else if any {
36                        TreeMarkState::Partial
37                    } else {
38                        TreeMarkState::Unmarked
39                    }
40                }
41            };
42            if mark != TreeMarkState::Unmarked {
43                self.mark_states.insert(node.id, mark);
44            }
45        }
46
47        for id in self.manual_marked.iter().copied() {
48            self.mark_states.insert(id, TreeMarkState::Marked);
49        }
50        self.mark_stamp = Some(stamp);
51    }
52
53    /// Returns an aggregated mark from the most recently computed cache.
54    #[must_use]
55    pub fn mark_state(&self, id: Id) -> TreeMarkState {
56        self.mark_state_cached(id)
57    }
58
59    #[must_use]
60    pub fn is_manually_marked(&self, id: Id) -> bool {
61        self.manual_marked.contains(&id)
62    }
63
64    /// Sets a node's manual mark.
65    pub fn set_marked(&mut self, id: Id, marked: bool) -> bool {
66        self.manual_marked.set_membership(id, marked)
67    }
68
69    /// Toggles a node's manual mark.
70    pub fn toggle_marked(&mut self, id: Id) -> bool {
71        let marked = !self.manual_marked.contains(&id);
72        self.set_marked(id, marked)
73    }
74
75    /// Removes every manual mark.
76    pub fn clear_marks(&mut self) -> bool {
77        self.manual_marked.clear()
78    }
79
80    pub fn manual_marked_ids(&self) -> impl Iterator<Item = Id> + '_ {
81        self.manual_marked.iter().copied()
82    }
83}