tab_stop.rs

  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}