use std::collections::HashSet;
#[derive(Debug, Clone, Default)]
pub struct FocusSet {
pub hovered: Option<u64>,
pub selected: HashSet<u64>,
pub generation: u64,
}
impl FocusSet {
pub fn empty() -> Self {
Self::default()
}
pub fn set_hovered(&mut self, id: Option<u64>) -> bool {
if self.hovered == id {
return false;
}
self.hovered = id;
self.generation += 1;
true
}
pub fn select(&mut self, id: u64) -> bool {
if !self.selected.insert(id) {
return false;
}
self.generation += 1;
true
}
pub fn deselect(&mut self, id: u64) -> bool {
if !self.selected.remove(&id) {
return false;
}
self.generation += 1;
true
}
pub fn toggle_selected(&mut self, id: u64) -> bool {
if self.selected.contains(&id) {
self.deselect(id)
} else {
self.select(id)
}
}
pub fn select_many(&mut self, ids: impl IntoIterator<Item = u64>) {
self.selected = ids.into_iter().collect();
self.generation += 1;
}
pub fn clear_selection(&mut self) -> bool {
if self.selected.is_empty() {
return false;
}
self.selected.clear();
self.generation += 1;
true
}
pub fn is_hovered(&self, id: u64) -> bool {
self.hovered == Some(id)
}
pub fn is_selected(&self, id: u64) -> bool {
self.selected.contains(&id)
}
pub fn is_active(&self) -> bool {
self.hovered.is_some() || !self.selected.is_empty()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn set_hovered_bumps_generation_only_on_actual_change() {
let mut focus = FocusSet::empty();
assert!(focus.set_hovered(Some(3)));
assert_eq!(focus.generation, 1);
assert!(!focus.set_hovered(Some(3))); assert_eq!(focus.generation, 1);
assert!(focus.set_hovered(None));
assert_eq!(focus.generation, 2);
}
#[test]
fn select_deselect_toggle_selected() {
let mut focus = FocusSet::empty();
assert!(focus.select(1));
assert!(!focus.select(1)); assert!(focus.is_selected(1));
assert!(focus.toggle_selected(1)); assert!(!focus.is_selected(1));
assert!(focus.toggle_selected(1)); assert!(focus.is_selected(1));
}
#[test]
fn clear_selection_reports_whether_anything_changed() {
let mut focus = FocusSet::empty();
assert!(!focus.clear_selection()); focus.select(1);
focus.select(2);
let gen_before = focus.generation;
assert!(focus.clear_selection());
assert!(focus.selected.is_empty());
assert!(focus.generation > gen_before);
}
#[test]
fn select_many_replaces_the_whole_selection_and_always_bumps_generation() {
let mut focus = FocusSet::empty();
focus.select(99); let gen_before = focus.generation;
focus.select_many([1, 2, 3]);
assert_eq!(focus.selected, [1u64, 2, 3].into_iter().collect());
assert!(!focus.is_selected(99));
assert!(focus.generation > gen_before);
let gen_before2 = focus.generation;
focus.select_many([1, 2, 3]);
assert!(focus.generation > gen_before2);
}
#[test]
fn is_active_reflects_hover_or_selection() {
let mut focus = FocusSet::empty();
assert!(!focus.is_active());
focus.set_hovered(Some(5));
assert!(focus.is_active());
focus.set_hovered(None);
assert!(!focus.is_active());
focus.select(5);
assert!(focus.is_active());
}
}