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>) -> 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}