use peniko::Color;
use crate::elevation::{Elevation, ShadowSpec};
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct GlassFill {
pub color: Color,
}
impl GlassFill {
pub fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
Self {
color: Color::new([r, g, b, a]),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct GlassMaterial {
pub blur_radius_intent: f64,
pub fills_light: Vec<GlassFill>,
pub fills_dark: Vec<GlassFill>,
pub hairline_alpha: f32,
pub shadow: ShadowSpec,
}
impl GlassMaterial {
pub fn is_opaque(&self) -> bool {
self.blur_radius_intent == 0.0
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct GlassScale {
pub chrome: GlassMaterial,
pub bar: GlassMaterial,
pub control: GlassMaterial,
}
impl GlassScale {
pub fn opaque_material() -> Self {
let elevation = Elevation::neutral();
let opaque = |shadow: ShadowSpec| GlassMaterial {
blur_radius_intent: 0.0,
fills_light: Vec::new(),
fills_dark: Vec::new(),
hairline_alpha: 0.0,
shadow,
};
Self {
chrome: opaque(elevation.level3.shadow_light),
bar: opaque(elevation.level2.shadow_light),
control: opaque(elevation.level1.shadow_light),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn opaque_material_is_opaque_in_every_tier() {
let g = GlassScale::opaque_material();
for m in [&g.chrome, &g.bar, &g.control] {
assert_eq!(m.blur_radius_intent, 0.0);
assert!(m.is_opaque());
assert!(m.fills_light.is_empty());
assert!(m.fills_dark.is_empty());
}
}
#[test]
fn opaque_material_shadows_track_the_neutral_elevation_table() {
let g = GlassScale::opaque_material();
let elevation = Elevation::neutral();
assert_eq!(g.chrome.shadow, elevation.level3.shadow_light);
assert_eq!(g.bar.shadow, elevation.level2.shadow_light);
assert_eq!(g.control.shadow, elevation.level1.shadow_light);
}
#[test]
fn a_design_system_scale_stays_a_lens_on_every_tier() {
let lens = |blur: f64| GlassMaterial {
blur_radius_intent: blur,
fills_light: vec![GlassFill::new(1.0, 1.0, 1.0, 0.34)],
fills_dark: vec![GlassFill::new(0.0, 0.0, 0.0, 0.41)],
hairline_alpha: 0.5,
shadow: ShadowSpec {
y_offset: 18.0,
blur_std_dev: 24.0,
color_alpha: 0.30,
},
};
let glass = GlassScale {
chrome: lens(75.0),
bar: lens(45.0),
control: lens(15.0),
};
for m in [&glass.chrome, &glass.bar, &glass.control] {
assert!(!m.is_opaque(), "a non-zero blur intent is never opaque");
}
assert!(GlassScale::opaque_material().chrome.is_opaque());
}
}