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>) -> usize {
36 self.handles
37 .iter()
38 .position(|h| Some(&h.id) == focused_id)
39 .unwrap_or_default()
40 }
41
42 pub(crate) fn next(&self, focused_id: Option<&FocusId>) -> Option<FocusHandle> {
43 let ix = self.current_index(focused_id);
44
45 let mut next_ix = ix + 1;
46 if next_ix + 1 > self.handles.len() {
47 next_ix = 0;
48 }
49
50 if let Some(next_handle) = self.handles.get(next_ix) {
51 Some(next_handle.clone())
52 } else {
53 None
54 }
55 }
56
57 pub(crate) fn prev(&self, focused_id: Option<&FocusId>) -> Option<FocusHandle> {
58 let ix = self.current_index(focused_id);
59 let prev_ix;
60 if ix == 0 {
61 prev_ix = self.handles.len().saturating_sub(1);
62 } else {
63 prev_ix = ix.saturating_sub(1);
64 }
65
66 if let Some(prev_handle) = self.handles.get(prev_ix) {
67 Some(prev_handle.clone())
68 } else {
69 None
70 }
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use crate::{FocusHandle, FocusMap, TabHandles};
77 use std::sync::Arc;
78
79 #[test]
80 fn test_tab_handles() {
81 let focus_map = Arc::new(FocusMap::default());
82 let mut tab = TabHandles::default();
83
84 let focus_handles = vec![
85 FocusHandle::new(&focus_map).tab_stop(true).tab_index(0),
86 FocusHandle::new(&focus_map).tab_stop(true).tab_index(1),
87 FocusHandle::new(&focus_map).tab_stop(true).tab_index(1),
88 FocusHandle::new(&focus_map),
89 FocusHandle::new(&focus_map).tab_index(2),
90 FocusHandle::new(&focus_map).tab_stop(true).tab_index(0),
91 FocusHandle::new(&focus_map).tab_stop(true).tab_index(2),
92 ];
93
94 for handle in focus_handles.iter() {
95 tab.insert(&handle);
96 }
97 assert_eq!(
98 tab.handles
99 .iter()
100 .map(|handle| handle.id)
101 .collect::<Vec<_>>(),
102 vec![
103 focus_handles[0].id,
104 focus_handles[5].id,
105 focus_handles[1].id,
106 focus_handles[2].id,
107 focus_handles[6].id,
108 ]
109 );
110
111 // next
112 assert_eq!(tab.next(None), Some(tab.handles[1].clone()));
113 assert_eq!(
114 tab.next(Some(&tab.handles[0].id)),
115 Some(tab.handles[1].clone())
116 );
117 assert_eq!(
118 tab.next(Some(&tab.handles[1].id)),
119 Some(tab.handles[2].clone())
120 );
121 assert_eq!(
122 tab.next(Some(&tab.handles[2].id)),
123 Some(tab.handles[3].clone())
124 );
125 assert_eq!(
126 tab.next(Some(&tab.handles[3].id)),
127 Some(tab.handles[4].clone())
128 );
129 assert_eq!(
130 tab.next(Some(&tab.handles[4].id)),
131 Some(tab.handles[0].clone())
132 );
133
134 // prev
135 assert_eq!(tab.prev(None), Some(tab.handles[4].clone()));
136 assert_eq!(
137 tab.prev(Some(&tab.handles[0].id)),
138 Some(tab.handles[4].clone())
139 );
140 assert_eq!(
141 tab.prev(Some(&tab.handles[1].id)),
142 Some(tab.handles[0].clone())
143 );
144 assert_eq!(
145 tab.prev(Some(&tab.handles[2].id)),
146 Some(tab.handles[1].clone())
147 );
148 assert_eq!(
149 tab.prev(Some(&tab.handles[3].id)),
150 Some(tab.handles[2].clone())
151 );
152 assert_eq!(
153 tab.prev(Some(&tab.handles[4].id)),
154 Some(tab.handles[3].clone())
155 );
156 }
157}