ratatui_interact/state/
focus.rs1use std::hash::Hash;
45
46#[derive(Debug, Clone)]
56pub struct FocusManager<T: Clone + Eq + Hash = usize> {
57 elements: Vec<T>,
59 current_index: Option<usize>,
61}
62
63impl<T: Clone + Eq + Hash> Default for FocusManager<T> {
64 fn default() -> Self {
65 Self::new()
66 }
67}
68
69impl<T: Clone + Eq + Hash> FocusManager<T> {
70 pub fn new() -> Self {
72 Self {
73 elements: Vec::new(),
74 current_index: None,
75 }
76 }
77
78 pub fn with_capacity(capacity: usize) -> Self {
80 Self {
81 elements: Vec::with_capacity(capacity),
82 current_index: None,
83 }
84 }
85
86 pub fn register(&mut self, element: T) {
93 if !self.elements.contains(&element) {
94 self.elements.push(element);
95 if self.current_index.is_none() {
97 self.current_index = Some(0);
98 }
99 }
100 }
101
102 pub fn register_all(&mut self, elements: impl IntoIterator<Item = T>) {
104 for element in elements {
105 self.register(element);
106 }
107 }
108
109 pub fn clear(&mut self) {
111 self.elements.clear();
112 self.current_index = None;
113 }
114
115 pub fn current(&self) -> Option<&T> {
119 self.current_index.and_then(|i| self.elements.get(i))
120 }
121
122 pub fn current_index(&self) -> Option<usize> {
124 self.current_index
125 }
126
127 pub fn is_focused(&self, element: &T) -> bool {
129 self.current() == Some(element)
130 }
131
132 pub fn next(&mut self) {
136 if self.elements.is_empty() {
137 return;
138 }
139
140 self.current_index = Some(
141 self.current_index
142 .map(|i| (i + 1) % self.elements.len())
143 .unwrap_or(0),
144 );
145 }
146
147 pub fn prev(&mut self) {
151 if self.elements.is_empty() {
152 return;
153 }
154
155 self.current_index = Some(
156 self.current_index
157 .map(|i| {
158 if i == 0 {
159 self.elements.len() - 1
160 } else {
161 i - 1
162 }
163 })
164 .unwrap_or(0),
165 );
166 }
167
168 pub fn set(&mut self, element: T) {
172 if let Some(idx) = self.elements.iter().position(|e| *e == element) {
173 self.current_index = Some(idx);
174 }
175 }
176
177 pub fn set_index(&mut self, index: usize) {
181 if index < self.elements.len() {
182 self.current_index = Some(index);
183 }
184 }
185
186 pub fn first(&mut self) {
188 if !self.elements.is_empty() {
189 self.current_index = Some(0);
190 }
191 }
192
193 pub fn last(&mut self) {
195 if !self.elements.is_empty() {
196 self.current_index = Some(self.elements.len() - 1);
197 }
198 }
199
200 pub fn unfocus(&mut self) {
202 self.current_index = None;
203 }
204
205 pub fn has_focus(&self) -> bool {
207 self.current_index.is_some()
208 }
209
210 pub fn len(&self) -> usize {
212 self.elements.len()
213 }
214
215 pub fn is_empty(&self) -> bool {
217 self.elements.is_empty()
218 }
219
220 pub fn elements(&self) -> &[T] {
222 &self.elements
223 }
224
225 pub fn remove(&mut self, element: &T) -> bool {
230 if let Some(idx) = self.elements.iter().position(|e| e == element) {
231 self.elements.remove(idx);
232
233 if self.elements.is_empty() {
235 self.current_index = None;
236 } else if let Some(current) = self.current_index {
237 if current == idx {
238 if current >= self.elements.len() {
241 self.current_index = Some(self.elements.len() - 1);
242 }
243 } else if current > idx {
244 self.current_index = Some(current - 1);
246 }
247 }
248
249 true
250 } else {
251 false
252 }
253 }
254}
255
256#[cfg(test)]
257mod tests {
258 use super::*;
259
260 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
261 enum TestElement {
262 First,
263 Second,
264 Third,
265 }
266
267 #[test]
268 fn test_new_manager() {
269 let manager: FocusManager<usize> = FocusManager::new();
270 assert!(manager.is_empty());
271 assert_eq!(manager.len(), 0);
272 assert_eq!(manager.current(), None);
273 assert!(!manager.has_focus());
274 }
275
276 #[test]
277 fn test_register_auto_focus() {
278 let mut manager = FocusManager::new();
279 manager.register(TestElement::First);
280
281 assert_eq!(manager.len(), 1);
282 assert!(manager.has_focus());
283 assert_eq!(manager.current(), Some(&TestElement::First));
284 }
285
286 #[test]
287 fn test_register_duplicates_ignored() {
288 let mut manager = FocusManager::new();
289 manager.register(TestElement::First);
290 manager.register(TestElement::First); assert_eq!(manager.len(), 1);
293 }
294
295 #[test]
296 fn test_register_all() {
297 let mut manager = FocusManager::new();
298 manager.register_all([TestElement::First, TestElement::Second, TestElement::Third]);
299
300 assert_eq!(manager.len(), 3);
301 assert_eq!(manager.current(), Some(&TestElement::First));
302 }
303
304 #[test]
305 fn test_next_navigation() {
306 let mut manager = FocusManager::new();
307 manager.register_all([TestElement::First, TestElement::Second, TestElement::Third]);
308
309 assert_eq!(manager.current(), Some(&TestElement::First));
310
311 manager.next();
312 assert_eq!(manager.current(), Some(&TestElement::Second));
313
314 manager.next();
315 assert_eq!(manager.current(), Some(&TestElement::Third));
316
317 manager.next();
319 assert_eq!(manager.current(), Some(&TestElement::First));
320 }
321
322 #[test]
323 fn test_prev_navigation() {
324 let mut manager = FocusManager::new();
325 manager.register_all([TestElement::First, TestElement::Second, TestElement::Third]);
326
327 manager.prev();
329 assert_eq!(manager.current(), Some(&TestElement::Third));
330
331 manager.prev();
332 assert_eq!(manager.current(), Some(&TestElement::Second));
333
334 manager.prev();
335 assert_eq!(manager.current(), Some(&TestElement::First));
336 }
337
338 #[test]
339 fn test_set_focus() {
340 let mut manager = FocusManager::new();
341 manager.register_all([TestElement::First, TestElement::Second, TestElement::Third]);
342
343 manager.set(TestElement::Third);
344 assert_eq!(manager.current(), Some(&TestElement::Third));
345
346 manager.set(TestElement::First);
347 assert_eq!(manager.current(), Some(&TestElement::First));
348 }
349
350 #[test]
351 fn test_set_index() {
352 let mut manager = FocusManager::new();
353 manager.register_all([TestElement::First, TestElement::Second, TestElement::Third]);
354
355 manager.set_index(2);
356 assert_eq!(manager.current(), Some(&TestElement::Third));
357 assert_eq!(manager.current_index(), Some(2));
358
359 manager.set_index(10);
361 assert_eq!(manager.current(), Some(&TestElement::Third));
362 }
363
364 #[test]
365 fn test_first_last() {
366 let mut manager = FocusManager::new();
367 manager.register_all([TestElement::First, TestElement::Second, TestElement::Third]);
368
369 manager.last();
370 assert_eq!(manager.current(), Some(&TestElement::Third));
371
372 manager.first();
373 assert_eq!(manager.current(), Some(&TestElement::First));
374 }
375
376 #[test]
377 fn test_unfocus() {
378 let mut manager = FocusManager::new();
379 manager.register(TestElement::First);
380
381 assert!(manager.has_focus());
382
383 manager.unfocus();
384 assert!(!manager.has_focus());
385 assert_eq!(manager.current(), None);
386 }
387
388 #[test]
389 fn test_is_focused() {
390 let mut manager = FocusManager::new();
391 manager.register_all([TestElement::First, TestElement::Second]);
392
393 assert!(manager.is_focused(&TestElement::First));
394 assert!(!manager.is_focused(&TestElement::Second));
395
396 manager.next();
397 assert!(!manager.is_focused(&TestElement::First));
398 assert!(manager.is_focused(&TestElement::Second));
399 }
400
401 #[test]
402 fn test_clear() {
403 let mut manager = FocusManager::new();
404 manager.register_all([TestElement::First, TestElement::Second]);
405
406 manager.clear();
407 assert!(manager.is_empty());
408 assert!(!manager.has_focus());
409 }
410
411 #[test]
412 fn test_remove_unfocused() {
413 let mut manager = FocusManager::new();
414 manager.register_all([TestElement::First, TestElement::Second, TestElement::Third]);
415
416 let removed = manager.remove(&TestElement::Third);
418 assert!(removed);
419 assert_eq!(manager.len(), 2);
420 assert_eq!(manager.current(), Some(&TestElement::First)); }
422
423 #[test]
424 fn test_remove_focused() {
425 let mut manager = FocusManager::new();
426 manager.register_all([TestElement::First, TestElement::Second, TestElement::Third]);
427
428 let removed = manager.remove(&TestElement::First);
430 assert!(removed);
431 assert_eq!(manager.len(), 2);
432 assert_eq!(manager.current(), Some(&TestElement::Second)); }
434
435 #[test]
436 fn test_remove_last_focused() {
437 let mut manager = FocusManager::new();
438 manager.register_all([TestElement::First, TestElement::Second, TestElement::Third]);
439 manager.last();
440
441 let removed = manager.remove(&TestElement::Third);
443 assert!(removed);
444 assert_eq!(manager.current(), Some(&TestElement::Second)); }
446
447 #[test]
448 fn test_empty_navigation() {
449 let mut manager: FocusManager<usize> = FocusManager::new();
450
451 manager.next();
453 manager.prev();
454 manager.first();
455 manager.last();
456
457 assert!(!manager.has_focus());
458 }
459
460 #[test]
461 fn test_integer_focus_manager() {
462 let mut manager: FocusManager<usize> = FocusManager::new();
463 manager.register_all([0, 1, 2, 3, 4]);
464
465 assert_eq!(manager.current(), Some(&0));
466 manager.next();
467 assert_eq!(manager.current(), Some(&1));
468 }
469}