pub const OFF_STATE: &str = "Off";
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct ToggleState {
pub state: String,
pub on_state: String,
pub checked_control: Option<crate::session::AnnotId>,
}
impl ToggleState {
#[must_use]
pub fn new(state: impl Into<String>, on_state: impl Into<String>) -> ToggleState {
ToggleState {
state: state.into(),
on_state: on_state.into(),
checked_control: None,
}
}
#[must_use]
pub fn is_checked(&self) -> bool {
self.state != OFF_STATE && !self.state.is_empty()
}
#[must_use]
pub fn state_for_control(&self, control: crate::session::AnnotId) -> Option<&str> {
let chosen = self.checked_control?;
if chosen == control {
Some(&self.state)
} else {
Some(OFF_STATE)
}
}
pub fn set_checked(&mut self, checked: bool) {
if checked && !self.on_state.is_empty() {
self.state.clone_from(&self.on_state);
} else {
self.state = OFF_STATE.to_string();
}
}
pub fn toggle(&mut self) {
let checked = self.is_checked();
self.set_checked(!checked);
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ToggleKind {
Check,
Radio,
}
pub fn activate(state: &mut ToggleState, kind: ToggleKind, read_only: bool) -> bool {
if read_only {
return false;
}
let before = state.state.clone();
match kind {
ToggleKind::Check => state.toggle(),
ToggleKind::Radio => state.set_checked(true),
}
state.state != before
}
#[cfg(test)]
mod tests {
use super::*;
fn check() -> ToggleState {
ToggleState::new(OFF_STATE, "On")
}
#[test]
fn a_check_box_flips_each_time_it_is_activated() {
let mut state = check();
assert!(!state.is_checked());
assert!(activate(&mut state, ToggleKind::Check, false));
assert!(state.is_checked());
assert_eq!(state.state, "On");
assert!(activate(&mut state, ToggleKind::Check, false));
assert!(!state.is_checked());
assert_eq!(state.state, OFF_STATE);
}
#[test]
fn a_radio_button_cannot_be_cleared_by_activating_it_again() {
let mut state = check();
assert!(activate(&mut state, ToggleKind::Radio, false));
assert!(state.is_checked());
assert!(!activate(&mut state, ToggleKind::Radio, false));
assert!(state.is_checked());
}
#[test]
fn a_read_only_control_does_not_move() {
let mut state = check();
assert!(!activate(&mut state, ToggleKind::Check, true));
assert!(!state.is_checked());
let mut radio = check();
assert!(!activate(&mut radio, ToggleKind::Radio, true));
assert!(!radio.is_checked());
}
#[test]
fn a_control_with_no_on_state_stays_clear() {
let mut state = ToggleState::new(OFF_STATE, "");
assert!(!activate(&mut state, ToggleKind::Check, false));
assert!(!state.is_checked());
}
#[test]
fn the_on_state_name_comes_from_the_file() {
let mut state = ToggleState::new(OFF_STATE, "Yes");
state.set_checked(true);
assert_eq!(state.state, "Yes");
assert!(state.is_checked());
state.set_checked(false);
assert_eq!(state.state, OFF_STATE);
}
#[test]
fn an_empty_state_reads_as_clear() {
assert!(!ToggleState::new("", "On").is_checked());
}
}