use std::hash::Hash;
#[derive(Debug, Clone)]
pub struct FocusManager<T: Clone + Eq + Hash = usize> {
elements: Vec<T>,
current_index: Option<usize>,
}
impl<T: Clone + Eq + Hash> Default for FocusManager<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: Clone + Eq + Hash> FocusManager<T> {
pub fn new() -> Self {
Self {
elements: Vec::new(),
current_index: None,
}
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
elements: Vec::with_capacity(capacity),
current_index: None,
}
}
pub fn register(&mut self, element: T) {
if !self.elements.contains(&element) {
self.elements.push(element);
if self.current_index.is_none() {
self.current_index = Some(0);
}
}
}
pub fn register_all(&mut self, elements: impl IntoIterator<Item = T>) {
for element in elements {
self.register(element);
}
}
pub fn clear(&mut self) {
self.elements.clear();
self.current_index = None;
}
pub fn current(&self) -> Option<&T> {
self.current_index.and_then(|i| self.elements.get(i))
}
pub fn current_index(&self) -> Option<usize> {
self.current_index
}
pub fn is_focused(&self, element: &T) -> bool {
self.current() == Some(element)
}
pub fn next(&mut self) {
if self.elements.is_empty() {
return;
}
self.current_index = Some(
self.current_index
.map(|i| (i + 1) % self.elements.len())
.unwrap_or(0),
);
}
pub fn prev(&mut self) {
if self.elements.is_empty() {
return;
}
self.current_index = Some(
self.current_index
.map(|i| {
if i == 0 {
self.elements.len() - 1
} else {
i - 1
}
})
.unwrap_or(0),
);
}
pub fn set(&mut self, element: T) {
if let Some(idx) = self.elements.iter().position(|e| *e == element) {
self.current_index = Some(idx);
}
}
pub fn set_index(&mut self, index: usize) {
if index < self.elements.len() {
self.current_index = Some(index);
}
}
pub fn first(&mut self) {
if !self.elements.is_empty() {
self.current_index = Some(0);
}
}
pub fn last(&mut self) {
if !self.elements.is_empty() {
self.current_index = Some(self.elements.len() - 1);
}
}
pub fn unfocus(&mut self) {
self.current_index = None;
}
pub fn has_focus(&self) -> bool {
self.current_index.is_some()
}
pub fn len(&self) -> usize {
self.elements.len()
}
pub fn is_empty(&self) -> bool {
self.elements.is_empty()
}
pub fn elements(&self) -> &[T] {
&self.elements
}
pub fn remove(&mut self, element: &T) -> bool {
if let Some(idx) = self.elements.iter().position(|e| e == element) {
self.elements.remove(idx);
if self.elements.is_empty() {
self.current_index = None;
} else if let Some(current) = self.current_index {
if current == idx {
if current >= self.elements.len() {
self.current_index = Some(self.elements.len() - 1);
}
} else if current > idx {
self.current_index = Some(current - 1);
}
}
true
} else {
false
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
enum TestElement {
First,
Second,
Third,
}
#[test]
fn test_new_manager() {
let manager: FocusManager<usize> = FocusManager::new();
assert!(manager.is_empty());
assert_eq!(manager.len(), 0);
assert_eq!(manager.current(), None);
assert!(!manager.has_focus());
}
#[test]
fn test_register_auto_focus() {
let mut manager = FocusManager::new();
manager.register(TestElement::First);
assert_eq!(manager.len(), 1);
assert!(manager.has_focus());
assert_eq!(manager.current(), Some(&TestElement::First));
}
#[test]
fn test_register_duplicates_ignored() {
let mut manager = FocusManager::new();
manager.register(TestElement::First);
manager.register(TestElement::First);
assert_eq!(manager.len(), 1);
}
#[test]
fn test_register_all() {
let mut manager = FocusManager::new();
manager.register_all([TestElement::First, TestElement::Second, TestElement::Third]);
assert_eq!(manager.len(), 3);
assert_eq!(manager.current(), Some(&TestElement::First));
}
#[test]
fn test_next_navigation() {
let mut manager = FocusManager::new();
manager.register_all([TestElement::First, TestElement::Second, TestElement::Third]);
assert_eq!(manager.current(), Some(&TestElement::First));
manager.next();
assert_eq!(manager.current(), Some(&TestElement::Second));
manager.next();
assert_eq!(manager.current(), Some(&TestElement::Third));
manager.next();
assert_eq!(manager.current(), Some(&TestElement::First));
}
#[test]
fn test_prev_navigation() {
let mut manager = FocusManager::new();
manager.register_all([TestElement::First, TestElement::Second, TestElement::Third]);
manager.prev();
assert_eq!(manager.current(), Some(&TestElement::Third));
manager.prev();
assert_eq!(manager.current(), Some(&TestElement::Second));
manager.prev();
assert_eq!(manager.current(), Some(&TestElement::First));
}
#[test]
fn test_set_focus() {
let mut manager = FocusManager::new();
manager.register_all([TestElement::First, TestElement::Second, TestElement::Third]);
manager.set(TestElement::Third);
assert_eq!(manager.current(), Some(&TestElement::Third));
manager.set(TestElement::First);
assert_eq!(manager.current(), Some(&TestElement::First));
}
#[test]
fn test_set_index() {
let mut manager = FocusManager::new();
manager.register_all([TestElement::First, TestElement::Second, TestElement::Third]);
manager.set_index(2);
assert_eq!(manager.current(), Some(&TestElement::Third));
assert_eq!(manager.current_index(), Some(2));
manager.set_index(10);
assert_eq!(manager.current(), Some(&TestElement::Third));
}
#[test]
fn test_first_last() {
let mut manager = FocusManager::new();
manager.register_all([TestElement::First, TestElement::Second, TestElement::Third]);
manager.last();
assert_eq!(manager.current(), Some(&TestElement::Third));
manager.first();
assert_eq!(manager.current(), Some(&TestElement::First));
}
#[test]
fn test_unfocus() {
let mut manager = FocusManager::new();
manager.register(TestElement::First);
assert!(manager.has_focus());
manager.unfocus();
assert!(!manager.has_focus());
assert_eq!(manager.current(), None);
}
#[test]
fn test_is_focused() {
let mut manager = FocusManager::new();
manager.register_all([TestElement::First, TestElement::Second]);
assert!(manager.is_focused(&TestElement::First));
assert!(!manager.is_focused(&TestElement::Second));
manager.next();
assert!(!manager.is_focused(&TestElement::First));
assert!(manager.is_focused(&TestElement::Second));
}
#[test]
fn test_clear() {
let mut manager = FocusManager::new();
manager.register_all([TestElement::First, TestElement::Second]);
manager.clear();
assert!(manager.is_empty());
assert!(!manager.has_focus());
}
#[test]
fn test_remove_unfocused() {
let mut manager = FocusManager::new();
manager.register_all([TestElement::First, TestElement::Second, TestElement::Third]);
let removed = manager.remove(&TestElement::Third);
assert!(removed);
assert_eq!(manager.len(), 2);
assert_eq!(manager.current(), Some(&TestElement::First)); }
#[test]
fn test_remove_focused() {
let mut manager = FocusManager::new();
manager.register_all([TestElement::First, TestElement::Second, TestElement::Third]);
let removed = manager.remove(&TestElement::First);
assert!(removed);
assert_eq!(manager.len(), 2);
assert_eq!(manager.current(), Some(&TestElement::Second)); }
#[test]
fn test_remove_last_focused() {
let mut manager = FocusManager::new();
manager.register_all([TestElement::First, TestElement::Second, TestElement::Third]);
manager.last();
let removed = manager.remove(&TestElement::Third);
assert!(removed);
assert_eq!(manager.current(), Some(&TestElement::Second)); }
#[test]
fn test_empty_navigation() {
let mut manager: FocusManager<usize> = FocusManager::new();
manager.next();
manager.prev();
manager.first();
manager.last();
assert!(!manager.has_focus());
}
#[test]
fn test_integer_focus_manager() {
let mut manager: FocusManager<usize> = FocusManager::new();
manager.register_all([0, 1, 2, 3, 4]);
assert_eq!(manager.current(), Some(&0));
manager.next();
assert_eq!(manager.current(), Some(&1));
}
}