1use crate::{FocusHandle, FocusId};
2
3/// Represents a collection of tab handles.
4///
5/// Used to manage the `Tab` event to switch between focus handles.
6#[derive(Default)]
7pub(crate) struct TabHandles {
8 pub(crate) handles: Vec<FocusHandle>,
9}
10
11impl TabHandles {
12 pub(crate) fn insert(&mut self, focus_handle: &FocusHandle) {
13 if !focus_handle.tab_stop {
14 return;
15 }
16
17 let focus_handle = focus_handle.clone();
18
19 // Insert handle with same tab_index last
20 if let Some(ix) = self
21 .handles
22 .iter()
23 .position(|tab| tab.tab_index > focus_handle.tab_index)
24 {
25 self.handles.insert(ix, focus_handle);
26 } else {
27 self.handles.push(focus_handle);
28 }
29 }
30
31 pub(crate) fn clear(&mut self) {
32 self.handles.clear();
33 }
34
35 fn current_index(&self, focused_id: Option<&FocusId>) -> Option<usize> {
36 self.handles.iter().position(|h| Some(&h.id) == focused_id)
37 }
38
39 pub(crate) fn next(&self, focused_id: Option<&FocusId>) -> Option<FocusHandle> {
40 let next_ix = self
41 .current_index(focused_id)
42 .and_then(|ix| {
43 let next_ix = ix + 1;
44 (next_ix < self.handles.len()).then_some(next_ix)
45 })
46 .unwrap_or_default();
47
48 self.handles.get(next_ix).cloned()
49 }
50
51 pub(crate) fn prev(&self, focused_id: Option<&FocusId>) -> Option<FocusHandle> {
52 let ix = self.current_index(focused_id).unwrap_or_default();
53 let prev_ix = if ix == 0 {
54 self.handles.len().saturating_sub(1)
55 } else {
56 ix.saturating_sub(1)
57 };
58
59 self.handles.get(prev_ix).cloned()
60 }
61}
62
63#[cfg(test)]
64mod tests {
65 use crate::{FocusHandle, FocusMap, TabHandles};
66 use std::sync::Arc;
67
68 #[test]
69 fn test_tab_handles() {
70 let focus_map = Arc::new(FocusMap::default());
71 let mut tab = TabHandles::default();
72
73 let focus_handles = vec![
74 FocusHandle::new(&focus_map).tab_stop(true).tab_index(0),
75 FocusHandle::new(&focus_map).tab_stop(true).tab_index(1),
76 FocusHandle::new(&focus_map).tab_stop(true).tab_index(1),
77 FocusHandle::new(&focus_map),
78 FocusHandle::new(&focus_map).tab_index(2),
79 FocusHandle::new(&focus_map).tab_stop(true).tab_index(0),
80 FocusHandle::new(&focus_map).tab_stop(true).tab_index(2),
81 ];
82
83 for handle in focus_handles.iter() {
84 tab.insert(handle);
85 }
86 assert_eq!(
87 tab.handles
88 .iter()
89 .map(|handle| handle.id)
90 .collect::<Vec<_>>(),
91 vec![
92 focus_handles[0].id,
93 focus_handles[5].id,
94 focus_handles[1].id,
95 focus_handles[2].id,
96 focus_handles[6].id,
97 ]
98 );
99
100 // Select first tab index if no handle is currently focused.
101 assert_eq!(tab.next(None), Some(tab.handles[0].clone()));
102 // Select last tab index if no handle is currently focused.
103 assert_eq!(
104 tab.prev(None),
105 Some(tab.handles[tab.handles.len() - 1].clone())
106 );
107
108 assert_eq!(
109 tab.next(Some(&tab.handles[0].id)),
110 Some(tab.handles[1].clone())
111 );
112 assert_eq!(
113 tab.next(Some(&tab.handles[1].id)),
114 Some(tab.handles[2].clone())
115 );
116 assert_eq!(
117 tab.next(Some(&tab.handles[2].id)),
118 Some(tab.handles[3].clone())
119 );
120 assert_eq!(
121 tab.next(Some(&tab.handles[3].id)),
122 Some(tab.handles[4].clone())
123 );
124 assert_eq!(
125 tab.next(Some(&tab.handles[4].id)),
126 Some(tab.handles[0].clone())
127 );
128
129 // prev
130 assert_eq!(tab.prev(None), Some(tab.handles[4].clone()));
131 assert_eq!(
132 tab.prev(Some(&tab.handles[0].id)),
133 Some(tab.handles[4].clone())
134 );
135 assert_eq!(
136 tab.prev(Some(&tab.handles[1].id)),
137 Some(tab.handles[0].clone())
138 );
139 assert_eq!(
140 tab.prev(Some(&tab.handles[2].id)),
141 Some(tab.handles[1].clone())
142 );
143 assert_eq!(
144 tab.prev(Some(&tab.handles[3].id)),
145 Some(tab.handles[2].clone())
146 );
147 assert_eq!(
148 tab.prev(Some(&tab.handles[4].id)),
149 Some(tab.handles[3].clone())
150 );
151 }
152}