use crate::compat::BTreeMap;
use crate::theme::types::{Colors, ThemeStyleToken};
const HOVER_BLEND: f32 = 0.08;
const PRESSED_BLEND: f32 = 0.12;
const DISABLED_FADE: f32 = 0.55;
pub(super) fn preset_state_overrides(colors: &Colors) -> BTreeMap<String, ThemeStyleToken> {
let mut styles = BTreeMap::new();
let ink = colors.foreground;
for kind in ["button", "toggle_button", "tool_button", "split_button"] {
styles.insert(
format!("{kind}:hover"),
ThemeStyleToken {
background: Some(colors.background.blend(&ink, HOVER_BLEND)),
..ThemeStyleToken::default()
},
);
styles.insert(
format!("{kind}:pressed"),
ThemeStyleToken {
background: Some(colors.background.blend(&ink, PRESSED_BLEND)),
..ThemeStyleToken::default()
},
);
styles.insert(
format!("{kind}:disabled"),
ThemeStyleToken {
background: Some(colors.disabled),
foreground: Some(colors.background.blend(&ink, DISABLED_FADE)),
..ThemeStyleToken::default()
},
);
}
for kind in ["check_box", "radio_button", "switch"] {
styles.insert(
format!("{kind}:checked"),
ThemeStyleToken {
background: Some(colors.primary),
foreground: Some(colors.primary.contrast_color()),
..ThemeStyleToken::default()
},
);
}
styles.insert(
"chip:selected".to_string(),
ThemeStyleToken {
background: Some(colors.primary),
foreground: Some(colors.primary.contrast_color()),
..ThemeStyleToken::default()
},
);
for kind in [
"line_edit",
"text_edit",
"text_area",
"combo_box",
"editable_combo_box",
"spin_box",
"date_edit",
"time_edit",
"date_time_edit",
"masked_edit",
] {
styles.insert(
format!("{kind}:error"),
ThemeStyleToken {
border: Some(colors.error),
border_width: Some(2),
..ThemeStyleToken::default()
},
);
}
styles
}
pub fn preset_state_key_count() -> usize {
4 * 3 + 3 + 1 + 10
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn every_preset_family_carries_its_states() {
for colors in [Colors::default(), crate::theme::Theme::dark().colors] {
let styles = preset_state_overrides(&colors);
assert_eq!(
styles.len(),
preset_state_key_count(),
"a preset must carry the full state table, not a subset"
);
assert!(styles.contains_key("button:hover"));
assert!(styles.contains_key("button:pressed"));
assert!(styles.contains_key("button:disabled"));
assert!(styles.contains_key("check_box:checked"));
assert!(styles.contains_key("chip:selected"));
assert!(
!styles.contains_key("chip:checked"),
"`chip` is a collection and reports `Selected`, never `Checked`"
);
assert!(styles.contains_key("line_edit:error"));
}
}
#[test]
fn a_hover_fill_differs_from_the_background() {
let colors = Colors::default();
let styles = preset_state_overrides(&colors);
let hover = styles["button:hover"].background.expect("hover sets a background");
assert_ne!(hover, colors.background, "hover must move the fill");
let pressed = styles["button:pressed"].background.expect("pressed sets a background");
assert_ne!(pressed, hover, "a press must be a firmer step than a hover");
}
}