use egui::Modifiers;
use std::collections::BTreeSet;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ClickIntent {
Replace,
Toggle,
Add,
Remove,
}
impl ClickIntent {
pub(crate) fn from_modifiers(modifiers: Modifiers) -> Self {
if modifiers.command {
Self::Toggle
} else if modifiers.shift {
Self::Add
} else if modifiers.alt {
Self::Remove
} else {
Self::Replace
}
}
pub(crate) fn apply<K: Ord>(self, selection: &mut BTreeSet<K>, hit: Option<K>) {
let Some(hit) = hit else {
if self == Self::Replace {
selection.clear();
}
return;
};
match self {
Self::Replace => {
selection.clear();
selection.insert(hit);
}
Self::Toggle => {
if !selection.remove(&hit) {
selection.insert(hit);
}
}
Self::Add => {
selection.insert(hit);
}
Self::Remove => {
selection.remove(&hit);
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn set(keys: &[usize]) -> BTreeSet<usize> {
keys.iter().copied().collect()
}
fn clicked(intent: ClickIntent, hit: Option<usize>) -> BTreeSet<usize> {
let mut selection = set(&[1, 2]);
intent.apply(&mut selection, hit);
selection
}
#[test]
fn a_click_replaces_toggles_adds_or_removes() {
assert_eq!(clicked(ClickIntent::Replace, Some(3)), set(&[3]));
assert_eq!(clicked(ClickIntent::Toggle, Some(3)), set(&[1, 2, 3]));
assert_eq!(clicked(ClickIntent::Toggle, Some(2)), set(&[1]));
assert_eq!(clicked(ClickIntent::Add, Some(2)), set(&[1, 2]));
assert_eq!(clicked(ClickIntent::Remove, Some(2)), set(&[1]));
}
#[test]
fn only_a_plain_click_on_the_background_clears() {
assert!(clicked(ClickIntent::Replace, None).is_empty());
for intent in [ClickIntent::Toggle, ClickIntent::Add, ClickIntent::Remove] {
assert_eq!(clicked(intent, None), set(&[1, 2]), "{intent:?}");
}
}
#[test]
fn cmd_wins_over_shift_and_shift_over_alt() {
let held = |command, shift, alt| Modifiers {
command,
shift,
alt,
..Default::default()
};
assert_eq!(
ClickIntent::from_modifiers(held(true, true, true)),
ClickIntent::Toggle
);
assert_eq!(
ClickIntent::from_modifiers(held(false, true, true)),
ClickIntent::Add
);
assert_eq!(
ClickIntent::from_modifiers(held(false, false, true)),
ClickIntent::Remove
);
assert_eq!(
ClickIntent::from_modifiers(Modifiers::NONE),
ClickIntent::Replace
);
}
}