Skip to main content

cursive_tree/model/
node.rs

1use super::{super::backend::*, depth::*, kind::*, list::*, path::*, state::*, symbol::*};
2
3use {
4    cursive::{style::*, utils::span::*, *},
5    std::{borrow::*, marker::*},
6};
7
8//
9// Node
10//
11
12/// Tree node.
13pub struct Node<BackendT>
14where
15    BackendT: TreeBackend,
16{
17    /// Depth.
18    pub depth: usize,
19
20    /// Kind.
21    pub kind: NodeKind,
22
23    /// ID.
24    pub id: BackendT::ID,
25
26    /// Label.
27    pub label: SpannedString<Style>,
28
29    /// Label size.
30    ///
31    /// Cached so we only have to calculate it once.
32    ///
33    /// > Note that labels can ostensibly have heights >1, i.e. they can be multiline, however this
34    /// is *not* currently supported by [TreeView](super::super::TreeView).
35    pub label_size: Vec2,
36
37    /// State for [Branch](NodeKind::Branch) node.
38    pub branch_state: BranchState,
39
40    /// Children for [Branch](NodeKind::Branch) node.
41    pub children: Option<NodeList<BackendT>>,
42
43    /// Data.
44    pub data: Option<BackendT::Data>,
45
46    backend: PhantomData<BackendT>,
47}
48
49impl<BackendT> Node<BackendT>
50where
51    BackendT: TreeBackend,
52{
53    /// Constructor.
54    pub fn new<IdT, LabelT>(depth: usize, kind: NodeKind, id: IdT, label: LabelT) -> Self
55    where
56        IdT: Into<BackendT::ID>,
57        LabelT: Into<SpannedString<Style>>,
58    {
59        let id = id.into();
60        let label = label.into();
61        let label_size = (label.width(), 1).into();
62        Self {
63            depth,
64            kind,
65            id,
66            label,
67            label_size,
68            branch_state: Default::default(),
69            children: None,
70            data: None,
71            backend: Default::default(),
72        }
73    }
74
75    /// Symbol.
76    ///
77    /// Its char count is always 1.
78    pub fn symbol(&self, context: BackendT::Context) -> Symbol<'_> {
79        BackendT::symbol(self, context)
80    }
81
82    /// Get node at path.
83    pub fn at_path(&self, path: NodePath) -> Option<&Self> {
84        if path.is_empty() { Some(self) } else { self.children.as_ref().and_then(|children| children.at_path(path)) }
85    }
86
87    /// Get node at path.
88    pub fn at_path_mut(&mut self, path: NodePath) -> Option<&mut Self> {
89        if path.is_empty() {
90            Some(self)
91        } else {
92            self.children.as_mut().and_then(|children| children.at_path_mut(path))
93        }
94    }
95
96    /// Fill path to node.
97    ///
98    /// Returns true if found.
99    pub fn fill_path(&self, path: &mut NodePath, node: &Self) -> bool {
100        self.children.as_ref().map(|children| children.fill_path(path, node)).unwrap_or_default()
101    }
102
103    /// Fetch the branch's children from backend.
104    ///
105    /// If depth is [None] will populate all depths.
106    ///
107    /// If depth is 0 or not a [Branch](NodeKind::Branch) will do nothing.
108    ///
109    /// Note that populating a node will *not* automatically expand it.
110    pub fn populate(&mut self, mut depth: Option<usize>, context: BackendT::Context) -> Result<(), BackendT::Error>
111    where
112        BackendT::Context: Clone,
113    {
114        if depth.is_zero() || !self.kind.is_branch() {
115            return Ok(());
116        }
117
118        if self.children.is_none() {
119            BackendT::populate(self, context.clone())?;
120        }
121
122        depth.decrease();
123        if !depth.is_zero()
124            && let Some(children) = &mut self.children
125        {
126            for node in children {
127                node.populate(depth, context.clone())?;
128            }
129        }
130
131        Ok(())
132    }
133
134    /// Add a child node.
135    ///
136    /// Will do nothing if not a [Branch](NodeKind::Branch).
137    pub fn add_child<IdT, LabelT>(&mut self, kind: NodeKind, id: IdT, label: LabelT)
138    where
139        IdT: Into<BackendT::ID>,
140        LabelT: Into<SpannedString<Style>>,
141    {
142        if !self.kind.is_branch() {
143            return;
144        }
145
146        if self.children.is_none() {
147            self.children = Some(Default::default());
148        }
149
150        self.children.as_mut().expect("children").add(self.depth + 1, kind, id, label);
151    }
152
153    /// Inserts a child node.
154    ///
155    /// Will do nothing if not a [Branch](NodeKind::Branch).
156    pub fn insert_child<IdT, LabelT>(&mut self, index: usize, kind: NodeKind, id: IdT, label: LabelT)
157    where
158        IdT: Into<BackendT::ID>,
159        LabelT: Into<SpannedString<Style>>,
160    {
161        if !self.kind.is_branch() {
162            return;
163        }
164
165        if self.children.is_none() {
166            self.children = Some(Default::default());
167        }
168
169        self.children.as_mut().expect("children").insert(index, self.depth + 1, kind, id, label);
170    }
171
172    /// Expand the branch.
173    ///
174    /// If depth is [None] will expand all depths.
175    ///
176    /// If depth is 0 or not a [Branch](NodeKind::Branch) will do nothing.
177    ///
178    /// Note that this *will* populate expanded nodes from the backend.
179    pub fn expand(&mut self, mut depth: Option<usize>, context: BackendT::Context) -> Result<(), BackendT::Error>
180    where
181        BackendT::Context: Clone,
182    {
183        if depth.is_zero() || !self.kind.is_branch() {
184            return Ok(());
185        }
186
187        if !self.branch_state.is_expanded() {
188            self.populate(Some(1), context.clone())?;
189            self.branch_state = BranchState::Expanded;
190        }
191
192        depth.decrease();
193        if !depth.is_zero()
194            && let Some(children) = &mut self.children
195        {
196            children.expand(depth, context.clone())?;
197        }
198
199        Ok(())
200    }
201
202    /// Collapse the branch.
203    ///
204    /// If depth is [None] will collapse all depths.
205    ///
206    /// If depth is 0 or not a [Branch](NodeKind::Branch) will do nothing.
207    pub fn collapse(&mut self, mut depth: Option<usize>) {
208        if depth.is_zero() || !self.kind.is_branch() {
209            return;
210        }
211
212        if !self.branch_state.is_collapsed() {
213            self.branch_state = BranchState::Collapsed;
214        }
215
216        depth.decrease();
217        if !depth.is_zero()
218            && let Some(children) = &mut self.children
219        {
220            children.collapse(depth);
221        }
222    }
223
224    /// Toggle the branch state.
225    ///
226    /// Expand if collapsed, collapse if expanded.
227    ///
228    /// Will do nothing if not a [Branch](NodeKind::Branch).
229    pub fn toggle_branch_state(&mut self, context: BackendT::Context) -> Result<(), BackendT::Error>
230    where
231        BackendT::Context: Clone,
232    {
233        if !self.kind.is_branch() {
234            return Ok(());
235        }
236
237        _ = match self.branch_state {
238            BranchState::Collapsed => self.expand(Some(1), context)?,
239            BranchState::Expanded => self.collapse(Some(1)),
240        };
241
242        Ok(())
243    }
244
245    /// Data.
246    ///
247    /// If not already cached will fetch it from the backend.
248    pub fn data(&mut self, context: BackendT::Context) -> Result<Option<Cow<'_, BackendT::Data>>, BackendT::Error>
249    where
250        BackendT::Data: Clone,
251    {
252        if self.data.is_none() {
253            if let Some((data, cache)) = BackendT::data(self, context)? {
254                if cache {
255                    self.data = Some(data);
256                } else {
257                    return Ok(Some(Cow::Owned(data)));
258                }
259            }
260        }
261
262        Ok(self.data.as_ref().map(Cow::Borrowed))
263    }
264}