pub struct FocusManager {
focusable: Vec<String>,
focused: Option<usize>,
}
impl FocusManager {
pub fn new() -> Self {
Self {
focusable: Vec::new(),
focused: None,
}
}
pub fn register(&mut self, agent_id: impl Into<String>) {
let id = agent_id.into();
if !self.focusable.contains(&id) {
self.focusable.push(id);
}
}
pub fn clear(&mut self) {
self.focusable.clear();
self.focused = None;
}
pub fn rebuild(&mut self, ids: Vec<String>) {
let current = self.focused_id().map(|s| s.to_string());
self.focusable = ids;
self.focused = current.and_then(|id| self.focusable.iter().position(|f| f == &id));
}
pub fn focus_next(&mut self) {
if self.focusable.is_empty() {
self.focused = None;
return;
}
self.focused = Some(match self.focused {
Some(i) => (i + 1) % self.focusable.len(),
None => 0,
});
}
pub fn focus_prev(&mut self) {
if self.focusable.is_empty() {
self.focused = None;
return;
}
self.focused = Some(match self.focused {
Some(0) => self.focusable.len() - 1,
Some(i) => i - 1,
None => self.focusable.len() - 1,
});
}
pub fn focus_on(&mut self, agent_id: &str) {
self.focused = self.focusable.iter().position(|f| f == agent_id);
}
pub fn blur(&mut self) {
self.focused = None;
}
pub fn focused_id(&self) -> Option<&str> {
self.focused
.and_then(|i| self.focusable.get(i))
.map(|s| s.as_str())
}
pub fn is_focused(&self, agent_id: &str) -> bool {
self.focused_id() == Some(agent_id)
}
pub fn len(&self) -> usize {
self.focusable.len()
}
pub fn is_empty(&self) -> bool {
self.focusable.is_empty()
}
}
impl Default for FocusManager {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn focus_ring_navigation() {
let mut fm = FocusManager::new();
fm.register("a");
fm.register("b");
fm.register("c");
assert_eq!(fm.focused_id(), None);
fm.focus_next();
assert_eq!(fm.focused_id(), Some("a"));
fm.focus_next();
assert_eq!(fm.focused_id(), Some("b"));
fm.focus_next();
assert_eq!(fm.focused_id(), Some("c"));
fm.focus_next();
assert_eq!(fm.focused_id(), Some("a"));
fm.focus_prev();
assert_eq!(fm.focused_id(), Some("c"));
}
#[test]
fn focus_by_id() {
let mut fm = FocusManager::new();
fm.register("x");
fm.register("y");
fm.focus_on("y");
assert!(fm.is_focused("y"));
assert!(!fm.is_focused("x"));
}
}