use std::cell::OnceCell;
use oxiui_core::Color;
use crate::color::{darken, desaturate, lighten};
pub struct LazyPaletteVariants {
pub base: Color,
hover: OnceCell<Color>,
pressed: OnceCell<Color>,
disabled: OnceCell<Color>,
}
impl LazyPaletteVariants {
pub fn new(base: Color) -> Self {
Self {
base,
hover: OnceCell::new(),
pressed: OnceCell::new(),
disabled: OnceCell::new(),
}
}
pub fn hover(&self) -> &Color {
self.hover.get_or_init(|| lighten(self.base, 0.1))
}
pub fn pressed(&self) -> &Color {
self.pressed.get_or_init(|| darken(self.base, 0.1))
}
pub fn disabled(&self) -> &Color {
self.disabled.get_or_init(|| desaturate(self.base, 0.5))
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::atomic::{AtomicUsize, Ordering};
#[test]
fn test_lazy_palette_hover_is_lighter() {
let base = Color(100, 120, 200, 255);
let variants = LazyPaletteVariants::new(base);
let hover = *variants.hover();
assert!(
hover.0 >= base.0 && hover.1 >= base.1 && hover.2 >= base.2,
"hover must be lighter: base={base:?}, hover={hover:?}"
);
}
#[test]
fn test_lazy_palette_pressed_is_darker() {
let base = Color(100, 120, 200, 255);
let variants = LazyPaletteVariants::new(base);
let pressed = *variants.pressed();
assert!(
pressed.0 <= base.0 && pressed.1 <= base.1 && pressed.2 <= base.2,
"pressed must be darker: base={base:?}, pressed={pressed:?}"
);
}
#[test]
fn test_lazy_palette_disabled_differs_from_base() {
let base = Color(200, 100, 50, 255); let variants = LazyPaletteVariants::new(base);
let disabled = *variants.disabled();
assert_ne!(
disabled, base,
"disabled must differ from a saturated base colour"
);
}
#[test]
fn test_lazy_palette_variant_computed_once() {
static COUNTER: AtomicUsize = AtomicUsize::new(0);
let cell: OnceCell<u32> = OnceCell::new();
let _ = cell.get_or_init(|| {
COUNTER.fetch_add(1, Ordering::SeqCst);
42
});
let _ = cell.get_or_init(|| {
COUNTER.fetch_add(1, Ordering::SeqCst);
99
});
assert_eq!(
COUNTER.load(Ordering::SeqCst),
1,
"OnceCell must call the init closure exactly once"
);
let base = Color(100, 150, 200, 255);
let variants = LazyPaletteVariants::new(base);
let first: Color = *variants.hover();
let second: Color = *variants.hover();
assert_eq!(
first, second,
"hover() must return the same value on repeated calls"
);
}
}