1pub type WidgetId = u64;
5
6#[derive(Clone, Copy, Debug, PartialEq, Eq)]
8pub enum FocusState {
9 Focused,
11 Unfocused,
13}
14
15#[derive(Clone, Debug)]
19pub struct FocusManager {
20 order: Vec<WidgetId>,
22 current: Option<usize>,
24}
25
26impl FocusManager {
27 pub fn new() -> Self {
29 Self {
30 order: Vec::new(),
31 current: None,
32 }
33 }
34
35 pub fn register(&mut self, id: WidgetId) {
37 if !self.order.contains(&id) {
38 self.order.push(id);
39 if self.current.is_none() {
41 self.current = Some(0);
42 }
43 }
44 }
45
46 pub fn unregister(&mut self, id: WidgetId) {
48 if let Some(pos) = self.order.iter().position(|&w| w == id) {
49 self.order.remove(pos);
50 if self.order.is_empty() {
51 self.current = None;
52 } else if let Some(current) = self.current {
53 if current >= self.order.len() {
54 self.current = Some(self.order.len() - 1);
55 } else if current > pos {
56 self.current = Some(current - 1);
57 }
58 }
59 }
60 }
61
62 pub fn focused(&self) -> Option<WidgetId> {
64 self.current.and_then(|i| self.order.get(i).copied())
65 }
66
67 pub fn focus_state(&self, id: WidgetId) -> FocusState {
69 if self.focused() == Some(id) {
70 FocusState::Focused
71 } else {
72 FocusState::Unfocused
73 }
74 }
75
76 pub fn focus_next(&mut self) {
78 if self.order.is_empty() {
79 return;
80 }
81 match self.current {
82 Some(i) => {
83 self.current = Some((i + 1) % self.order.len());
84 }
85 None => {
86 self.current = Some(0);
87 }
88 }
89 }
90
91 pub fn focus_previous(&mut self) {
93 if self.order.is_empty() {
94 return;
95 }
96 match self.current {
97 Some(i) => {
98 if i == 0 {
99 self.current = Some(self.order.len() - 1);
100 } else {
101 self.current = Some(i - 1);
102 }
103 }
104 None => {
105 self.current = Some(self.order.len() - 1);
106 }
107 }
108 }
109
110 pub fn set_focus(&mut self, id: WidgetId) {
112 if let Some(pos) = self.order.iter().position(|&w| w == id) {
113 self.current = Some(pos);
114 }
115 }
116
117 pub fn count(&self) -> usize {
119 self.order.len()
120 }
121}
122
123impl Default for FocusManager {
124 fn default() -> Self {
125 Self::new()
126 }
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132
133 #[test]
134 fn empty_focus_manager() {
135 let fm = FocusManager::new();
136 assert!(fm.focused().is_none());
137 assert_eq!(fm.count(), 0);
138 }
139
140 #[test]
141 fn register_auto_focuses_first() {
142 let mut fm = FocusManager::new();
143 fm.register(1);
144 assert_eq!(fm.focused(), Some(1));
145 }
146
147 #[test]
148 fn focus_next_cycles() {
149 let mut fm = FocusManager::new();
150 fm.register(1);
151 fm.register(2);
152 fm.register(3);
153
154 assert_eq!(fm.focused(), Some(1));
155 fm.focus_next();
156 assert_eq!(fm.focused(), Some(2));
157 fm.focus_next();
158 assert_eq!(fm.focused(), Some(3));
159 fm.focus_next();
160 assert_eq!(fm.focused(), Some(1)); }
162
163 #[test]
164 fn focus_previous_cycles() {
165 let mut fm = FocusManager::new();
166 fm.register(1);
167 fm.register(2);
168 fm.register(3);
169
170 assert_eq!(fm.focused(), Some(1));
171 fm.focus_previous();
172 assert_eq!(fm.focused(), Some(3)); fm.focus_previous();
174 assert_eq!(fm.focused(), Some(2));
175 }
176
177 #[test]
178 fn focus_state_query() {
179 let mut fm = FocusManager::new();
180 fm.register(1);
181 fm.register(2);
182
183 assert_eq!(fm.focus_state(1), FocusState::Focused);
184 assert_eq!(fm.focus_state(2), FocusState::Unfocused);
185 }
186
187 #[test]
188 fn set_focus_directly() {
189 let mut fm = FocusManager::new();
190 fm.register(10);
191 fm.register(20);
192 fm.register(30);
193
194 fm.set_focus(30);
195 assert_eq!(fm.focused(), Some(30));
196 }
197
198 #[test]
199 fn unregister_adjusts_focus() {
200 let mut fm = FocusManager::new();
201 fm.register(1);
202 fm.register(2);
203 fm.register(3);
204 fm.set_focus(2);
205
206 fm.unregister(2);
207 assert_eq!(fm.count(), 2);
209 assert!(fm.focused().is_some());
210 }
211
212 #[test]
213 fn unregister_last_clears_focus() {
214 let mut fm = FocusManager::new();
215 fm.register(1);
216 fm.unregister(1);
217 assert!(fm.focused().is_none());
218 }
219
220 #[test]
221 fn duplicate_register_ignored() {
222 let mut fm = FocusManager::new();
223 fm.register(1);
224 fm.register(1);
225 assert_eq!(fm.count(), 1);
226 }
227
228 #[test]
229 fn focus_next_on_empty_is_noop() {
230 let mut fm = FocusManager::new();
231 fm.focus_next(); assert!(fm.focused().is_none());
233 }
234}