1use super::focusable::WidgetId;
2
3#[derive(Debug, Clone)]
8pub struct FocusRing {
9 order: Vec<WidgetId>,
10 current: usize,
11}
12
13impl FocusRing {
14 pub fn new(order: Vec<WidgetId>) -> Self {
15 assert!(!order.is_empty(), "FocusRing must have at least one entry");
16 Self { order, current: 0 }
17 }
18
19 pub fn current(&self) -> WidgetId {
21 self.order[self.current]
22 }
23
24 pub fn focus_next(&mut self) {
26 self.current = (self.current + 1) % self.order.len();
27 }
28
29 pub fn focus_prev(&mut self) {
31 self.current = if self.current == 0 {
32 self.order.len() - 1
33 } else {
34 self.current - 1
35 };
36 }
37
38 pub fn set_focus(&mut self, id: WidgetId) {
41 if let Some(pos) = self.order.iter().position(|&w| w == id) {
42 self.current = pos;
43 }
44 }
45
46 pub fn is_focused(&self, id: WidgetId) -> bool {
48 self.order[self.current] == id
49 }
50
51 pub fn is_empty(&self) -> bool {
53 self.order.is_empty()
54 }
55
56 pub fn len(&self) -> usize {
58 self.order.len()
59 }
60
61 pub fn order(&self) -> &[WidgetId] {
63 &self.order
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn test_new_starts_at_first() {
73 let ring = FocusRing::new(vec!["a", "b", "c"]);
74 assert_eq!(ring.current(), "a");
75 }
76
77 #[test]
78 fn test_focus_next_cycles() {
79 let mut ring = FocusRing::new(vec!["a", "b", "c"]);
80 ring.focus_next();
81 assert_eq!(ring.current(), "b");
82 ring.focus_next();
83 assert_eq!(ring.current(), "c");
84 ring.focus_next();
85 assert_eq!(ring.current(), "a");
86 }
87
88 #[test]
89 fn test_focus_prev_cycles() {
90 let mut ring = FocusRing::new(vec!["a", "b", "c"]);
91 ring.focus_prev();
92 assert_eq!(ring.current(), "c");
93 ring.focus_prev();
94 assert_eq!(ring.current(), "b");
95 ring.focus_prev();
96 assert_eq!(ring.current(), "a");
97 }
98
99 #[test]
100 fn test_set_focus() {
101 let mut ring = FocusRing::new(vec!["a", "b", "c"]);
102 ring.set_focus("c");
103 assert_eq!(ring.current(), "c");
104 }
105
106 #[test]
107 fn test_set_focus_unknown_id_is_noop() {
108 let mut ring = FocusRing::new(vec!["a", "b", "c"]);
109 ring.set_focus("z");
110 assert_eq!(ring.current(), "a");
111 }
112
113 #[test]
114 fn test_is_focused() {
115 let ring = FocusRing::new(vec!["a", "b", "c"]);
116 assert!(ring.is_focused("a"));
117 assert!(!ring.is_focused("b"));
118 }
119
120 #[test]
121 fn test_single_element_ring() {
122 let mut ring = FocusRing::new(vec!["only"]);
123 assert_eq!(ring.current(), "only");
124 ring.focus_next();
125 assert_eq!(ring.current(), "only");
126 ring.focus_prev();
127 assert_eq!(ring.current(), "only");
128 }
129
130 #[test]
131 fn test_len() {
132 let ring = FocusRing::new(vec!["a", "b"]);
133 assert_eq!(ring.len(), 2);
134 }
135
136 #[test]
137 fn test_order() {
138 let ring = FocusRing::new(vec!["x", "y", "z"]);
139 assert_eq!(ring.order(), &["x", "y", "z"]);
140 }
141
142 #[test]
143 fn test_next_then_prev_returns_to_start() {
144 let mut ring = FocusRing::new(vec!["a", "b", "c"]);
145 ring.focus_next();
146 ring.focus_next();
147 ring.focus_prev();
148 ring.focus_prev();
149 assert_eq!(ring.current(), "a");
150 }
151
152 #[test]
153 #[should_panic(expected = "FocusRing must have at least one entry")]
154 fn test_empty_ring_panics() {
155 FocusRing::new(vec![]);
156 }
157}
158