use super::focusable::WidgetId;
#[derive(Debug, Clone)]
pub struct FocusRing {
order: Vec<WidgetId>,
current: usize,
}
impl FocusRing {
pub fn new(order: Vec<WidgetId>) -> Self {
assert!(!order.is_empty(), "FocusRing must have at least one entry");
Self { order, current: 0 }
}
pub fn current(&self) -> WidgetId {
self.order[self.current]
}
pub fn focus_next(&mut self) {
self.current = (self.current + 1) % self.order.len();
}
pub fn focus_prev(&mut self) {
self.current = if self.current == 0 {
self.order.len() - 1
} else {
self.current - 1
};
}
pub fn set_focus(&mut self, id: WidgetId) {
if let Some(pos) = self.order.iter().position(|&w| w == id) {
self.current = pos;
}
}
pub fn is_focused(&self, id: WidgetId) -> bool {
self.order[self.current] == id
}
pub fn is_empty(&self) -> bool {
self.order.is_empty()
}
pub fn len(&self) -> usize {
self.order.len()
}
pub fn order(&self) -> &[WidgetId] {
&self.order
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_starts_at_first() {
let ring = FocusRing::new(vec!["a", "b", "c"]);
assert_eq!(ring.current(), "a");
}
#[test]
fn test_focus_next_cycles() {
let mut ring = FocusRing::new(vec!["a", "b", "c"]);
ring.focus_next();
assert_eq!(ring.current(), "b");
ring.focus_next();
assert_eq!(ring.current(), "c");
ring.focus_next();
assert_eq!(ring.current(), "a");
}
#[test]
fn test_focus_prev_cycles() {
let mut ring = FocusRing::new(vec!["a", "b", "c"]);
ring.focus_prev();
assert_eq!(ring.current(), "c");
ring.focus_prev();
assert_eq!(ring.current(), "b");
ring.focus_prev();
assert_eq!(ring.current(), "a");
}
#[test]
fn test_set_focus() {
let mut ring = FocusRing::new(vec!["a", "b", "c"]);
ring.set_focus("c");
assert_eq!(ring.current(), "c");
}
#[test]
fn test_set_focus_unknown_id_is_noop() {
let mut ring = FocusRing::new(vec!["a", "b", "c"]);
ring.set_focus("z");
assert_eq!(ring.current(), "a");
}
#[test]
fn test_is_focused() {
let ring = FocusRing::new(vec!["a", "b", "c"]);
assert!(ring.is_focused("a"));
assert!(!ring.is_focused("b"));
}
#[test]
fn test_single_element_ring() {
let mut ring = FocusRing::new(vec!["only"]);
assert_eq!(ring.current(), "only");
ring.focus_next();
assert_eq!(ring.current(), "only");
ring.focus_prev();
assert_eq!(ring.current(), "only");
}
#[test]
fn test_len() {
let ring = FocusRing::new(vec!["a", "b"]);
assert_eq!(ring.len(), 2);
}
#[test]
fn test_order() {
let ring = FocusRing::new(vec!["x", "y", "z"]);
assert_eq!(ring.order(), &["x", "y", "z"]);
}
#[test]
fn test_next_then_prev_returns_to_start() {
let mut ring = FocusRing::new(vec!["a", "b", "c"]);
ring.focus_next();
ring.focus_next();
ring.focus_prev();
ring.focus_prev();
assert_eq!(ring.current(), "a");
}
#[test]
#[should_panic(expected = "FocusRing must have at least one entry")]
fn test_empty_ring_panics() {
FocusRing::new(vec![]);
}
}