pub type WidgetId = u64;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum FocusState {
Focused,
Unfocused,
}
#[derive(Clone, Debug)]
pub struct FocusManager {
order: Vec<WidgetId>,
current: Option<usize>,
}
impl FocusManager {
pub fn new() -> Self {
Self {
order: Vec::new(),
current: None,
}
}
pub fn register(&mut self, id: WidgetId) {
if !self.order.contains(&id) {
self.order.push(id);
if self.current.is_none() {
self.current = Some(0);
}
}
}
pub fn unregister(&mut self, id: WidgetId) {
if let Some(pos) = self.order.iter().position(|&w| w == id) {
self.order.remove(pos);
if self.order.is_empty() {
self.current = None;
} else if let Some(current) = self.current {
if current >= self.order.len() {
self.current = Some(self.order.len() - 1);
} else if current > pos {
self.current = Some(current - 1);
}
}
}
}
pub fn focused(&self) -> Option<WidgetId> {
self.current.and_then(|i| self.order.get(i).copied())
}
pub fn focus_state(&self, id: WidgetId) -> FocusState {
if self.focused() == Some(id) {
FocusState::Focused
} else {
FocusState::Unfocused
}
}
pub fn focus_next(&mut self) {
if self.order.is_empty() {
return;
}
match self.current {
Some(i) => {
self.current = Some((i + 1) % self.order.len());
}
None => {
self.current = Some(0);
}
}
}
pub fn focus_previous(&mut self) {
if self.order.is_empty() {
return;
}
match self.current {
Some(i) => {
if i == 0 {
self.current = Some(self.order.len() - 1);
} else {
self.current = Some(i - 1);
}
}
None => {
self.current = Some(self.order.len() - 1);
}
}
}
pub fn set_focus(&mut self, id: WidgetId) {
if let Some(pos) = self.order.iter().position(|&w| w == id) {
self.current = Some(pos);
}
}
pub fn count(&self) -> usize {
self.order.len()
}
}
impl Default for FocusManager {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_focus_manager() {
let fm = FocusManager::new();
assert!(fm.focused().is_none());
assert_eq!(fm.count(), 0);
}
#[test]
fn register_auto_focuses_first() {
let mut fm = FocusManager::new();
fm.register(1);
assert_eq!(fm.focused(), Some(1));
}
#[test]
fn focus_next_cycles() {
let mut fm = FocusManager::new();
fm.register(1);
fm.register(2);
fm.register(3);
assert_eq!(fm.focused(), Some(1));
fm.focus_next();
assert_eq!(fm.focused(), Some(2));
fm.focus_next();
assert_eq!(fm.focused(), Some(3));
fm.focus_next();
assert_eq!(fm.focused(), Some(1)); }
#[test]
fn focus_previous_cycles() {
let mut fm = FocusManager::new();
fm.register(1);
fm.register(2);
fm.register(3);
assert_eq!(fm.focused(), Some(1));
fm.focus_previous();
assert_eq!(fm.focused(), Some(3)); fm.focus_previous();
assert_eq!(fm.focused(), Some(2));
}
#[test]
fn focus_state_query() {
let mut fm = FocusManager::new();
fm.register(1);
fm.register(2);
assert_eq!(fm.focus_state(1), FocusState::Focused);
assert_eq!(fm.focus_state(2), FocusState::Unfocused);
}
#[test]
fn set_focus_directly() {
let mut fm = FocusManager::new();
fm.register(10);
fm.register(20);
fm.register(30);
fm.set_focus(30);
assert_eq!(fm.focused(), Some(30));
}
#[test]
fn unregister_adjusts_focus() {
let mut fm = FocusManager::new();
fm.register(1);
fm.register(2);
fm.register(3);
fm.set_focus(2);
fm.unregister(2);
assert_eq!(fm.count(), 2);
assert!(fm.focused().is_some());
}
#[test]
fn unregister_last_clears_focus() {
let mut fm = FocusManager::new();
fm.register(1);
fm.unregister(1);
assert!(fm.focused().is_none());
}
#[test]
fn duplicate_register_ignored() {
let mut fm = FocusManager::new();
fm.register(1);
fm.register(1);
assert_eq!(fm.count(), 1);
}
#[test]
fn focus_next_on_empty_is_noop() {
let mut fm = FocusManager::new();
fm.focus_next(); assert!(fm.focused().is_none());
}
}