revue/utils/tree/
navigation.rs1use std::collections::HashSet;
4
5use crate::utils::tree::prefix::TreePrefix;
6use crate::utils::tree::types::TreeItem;
7
8pub struct TreeNav {
25 items: Vec<TreeItem>,
26 selected: usize,
27 selected_row: usize,
28 collapsed: HashSet<usize>,
29}
30
31impl TreeNav {
32 pub fn new() -> Self {
34 Self {
35 items: Vec::new(),
36 selected: 0,
37 selected_row: 0,
38 collapsed: HashSet::new(),
39 }
40 }
41
42 pub fn add_item(&mut self, item: TreeItem) {
44 self.items.push(item);
45 }
46
47 pub fn clear(&mut self) {
49 self.items.clear();
50 self.selected = 0;
51 self.selected_row = 0;
52 }
53
54 pub fn selected(&self) -> usize {
56 self.selected
57 }
58
59 pub fn selected_row(&self) -> usize {
61 self.selected_row
62 }
63
64 pub fn is_collapsed(&self, id: usize) -> bool {
66 self.collapsed.contains(&id)
67 }
68
69 pub fn is_visible(&self, id: usize) -> bool {
71 if let Some(item) = self.items.get(id) {
72 if let Some(parent) = item.parent {
73 if self.collapsed.contains(&parent) {
74 return false;
75 }
76 return self.is_visible(parent);
78 }
79 }
80 true
81 }
82
83 pub fn visible_items(&self) -> Vec<&TreeItem> {
85 self.items
86 .iter()
87 .filter(|item| self.is_visible(item.id))
88 .collect()
89 }
90
91 pub fn next(&mut self) {
93 let visible: Vec<_> = self.visible_items().iter().map(|i| i.id).collect();
94 if visible.is_empty() {
95 return;
96 }
97
98 if let Some(item) = self.items.get(self.selected) {
100 if self.selected_row + 1 < item.row_count {
101 self.selected_row += 1;
102 return;
103 }
104 }
105
106 if let Some(pos) = visible.iter().position(|&id| id == self.selected) {
108 let next_pos = (pos + 1) % visible.len();
109 self.selected = visible[next_pos];
110 self.selected_row = 0;
111 }
112 }
113
114 pub fn prev(&mut self) {
116 let visible: Vec<_> = self.visible_items().iter().map(|i| i.id).collect();
117 if visible.is_empty() {
118 return;
119 }
120
121 if self.selected_row > 0 {
123 self.selected_row -= 1;
124 return;
125 }
126
127 if let Some(pos) = visible.iter().position(|&id| id == self.selected) {
129 let prev_pos = if pos == 0 { visible.len() - 1 } else { pos - 1 };
130 self.selected = visible[prev_pos];
131 if let Some(item) = self.items.get(self.selected) {
133 self.selected_row = item.row_count.saturating_sub(1);
134 }
135 }
136 }
137
138 pub fn next_item(&mut self) {
140 let visible: Vec<_> = self.visible_items().iter().map(|i| i.id).collect();
141 if visible.is_empty() {
142 return;
143 }
144
145 if let Some(pos) = visible.iter().position(|&id| id == self.selected) {
146 let next_pos = (pos + 1) % visible.len();
147 self.selected = visible[next_pos];
148 self.selected_row = 0;
149 }
150 }
151
152 pub fn prev_item(&mut self) {
154 let visible: Vec<_> = self.visible_items().iter().map(|i| i.id).collect();
155 if visible.is_empty() {
156 return;
157 }
158
159 if let Some(pos) = visible.iter().position(|&id| id == self.selected) {
160 let prev_pos = if pos == 0 { visible.len() - 1 } else { pos - 1 };
161 self.selected = visible[prev_pos];
162 self.selected_row = 0;
163 }
164 }
165
166 pub fn toggle_collapse(&mut self) {
168 if let Some(item) = self.items.get(self.selected) {
169 if item.collapsible {
170 if self.collapsed.contains(&self.selected) {
171 self.collapsed.remove(&self.selected);
172 } else {
173 self.collapsed.insert(self.selected);
174 }
175 }
176 }
177 }
178
179 pub fn collapse(&mut self) {
181 if let Some(item) = self.items.get(self.selected) {
182 if item.collapsible {
183 self.collapsed.insert(self.selected);
184 }
185 }
186 }
187
188 pub fn expand(&mut self) {
190 self.collapsed.remove(&self.selected);
191 }
192
193 pub fn collapse_all(&mut self) {
195 for item in &self.items {
196 if item.collapsible {
197 self.collapsed.insert(item.id);
198 }
199 }
200 }
201
202 pub fn expand_all(&mut self) {
204 self.collapsed.clear();
205 }
206
207 pub fn select(&mut self, id: usize) {
209 if id < self.items.len() && self.is_visible(id) {
210 self.selected = id;
211 self.selected_row = 0;
212 }
213 }
214
215 pub fn first(&mut self) {
217 if let Some(item) = self.visible_items().first() {
218 self.selected = item.id;
219 self.selected_row = 0;
220 }
221 }
222
223 pub fn last(&mut self) {
225 if let Some(item) = self.visible_items().last() {
226 self.selected = item.id;
227 self.selected_row = 0;
228 }
229 }
230
231 pub fn get_prefix(&self, id: usize) -> (String, bool) {
242 let _visible = self.visible_items();
243 let is_last = self.is_last_sibling(id);
244
245 let mut prefix = TreePrefix::new();
246
247 if let Some(item) = self.items.get(id) {
249 let mut ancestors = Vec::new();
250 let mut current = item.parent;
251
252 while let Some(parent_id) = current {
253 ancestors.push(parent_id);
254 if let Some(parent) = self.items.get(parent_id) {
255 current = parent.parent;
256 } else {
257 break;
258 }
259 }
260
261 for ancestor_id in ancestors.into_iter().rev() {
263 prefix.push(!self.is_last_sibling(ancestor_id));
264 }
265 }
266
267 (prefix.prefix(is_last), is_last)
268 }
269
270 pub fn is_last_sibling(&self, id: usize) -> bool {
272 if let Some(item) = self.items.get(id) {
273 let parent = item.parent;
274 let depth = item.depth;
275
276 let siblings: Vec<_> = self
278 .items
279 .iter()
280 .filter(|i| i.parent == parent && i.depth == depth && self.is_visible(i.id))
281 .collect();
282
283 siblings.last().map(|last| last.id == id).unwrap_or(true)
284 } else {
285 true
286 }
287 }
288
289 pub fn render_items(&self) -> Vec<(&TreeItem, String, bool)> {
293 self.visible_items()
294 .into_iter()
295 .map(|item| {
296 let (prefix, _) = self.get_prefix(item.id);
297 let is_selected = item.id == self.selected;
298 (item, prefix, is_selected)
299 })
300 .collect()
301 }
302}
303
304impl Default for TreeNav {
305 fn default() -> Self {
306 Self::new()
307 }
308}