use crate::color::Brightness;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ShadowSpec {
pub y_offset: f64,
pub blur_std_dev: f64,
pub color_alpha: f32,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum SurfaceRole {
Surface,
SurfaceContainerLowest,
SurfaceContainerLow,
SurfaceContainer,
SurfaceContainerHigh,
SurfaceContainerHighest,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ElevationLevel {
pub dp: f64,
pub shadow_light: ShadowSpec,
pub shadow_dark: ShadowSpec,
pub surface_role: SurfaceRole,
}
impl ElevationLevel {
pub fn shadow(&self, brightness: Brightness) -> &ShadowSpec {
match brightness {
Brightness::Light => &self.shadow_light,
Brightness::Dark => &self.shadow_dark,
}
}
}
const fn level(dp: f64, surface_role: SurfaceRole) -> ElevationLevel {
let shadow = ShadowSpec {
y_offset: dp / 2.0 + 1.0,
blur_std_dev: dp,
color_alpha: 0.3,
};
ElevationLevel {
dp,
shadow_light: shadow,
shadow_dark: shadow,
surface_role,
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Elevation {
pub level0: ElevationLevel,
pub level1: ElevationLevel,
pub level2: ElevationLevel,
pub level3: ElevationLevel,
pub level4: ElevationLevel,
pub level5: ElevationLevel,
}
impl Elevation {
pub const fn neutral() -> Self {
Self {
level0: level(0.0, SurfaceRole::Surface),
level1: level(1.0, SurfaceRole::SurfaceContainerLow),
level2: level(3.0, SurfaceRole::SurfaceContainer),
level3: level(6.0, SurfaceRole::SurfaceContainerHigh),
level4: level(8.0, SurfaceRole::SurfaceContainerHigh),
level5: level(12.0, SurfaceRole::SurfaceContainerHighest),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn dp_matches_table() {
let e = Elevation::neutral();
assert_eq!(e.level0.dp, 0.0);
assert_eq!(e.level1.dp, 1.0);
assert_eq!(e.level2.dp, 3.0);
assert_eq!(e.level3.dp, 6.0);
assert_eq!(e.level4.dp, 8.0);
assert_eq!(e.level5.dp, 12.0);
}
#[test]
fn shadow_mapping_is_consistent_with_dp() {
let e = Elevation::neutral();
assert_eq!(e.level3.shadow_light.y_offset, 4.0);
assert_eq!(e.level3.shadow_light.blur_std_dev, 6.0);
assert_eq!(e.level3.shadow_light.color_alpha, 0.3);
}
#[test]
fn neutral_shadow_is_identical_on_both_brightnesses() {
let e = Elevation::neutral();
assert_eq!(e.level3.shadow_light, e.level3.shadow_dark);
assert_eq!(
e.level3.shadow(Brightness::Light),
e.level3.shadow(Brightness::Dark)
);
assert_eq!(*e.level3.shadow(Brightness::Light), e.level3.shadow_light);
}
#[test]
fn surface_roles_match_static_container_direction() {
let e = Elevation::neutral();
assert_eq!(e.level0.surface_role, SurfaceRole::Surface);
assert_eq!(e.level3.surface_role, SurfaceRole::SurfaceContainerHigh);
assert_eq!(e.level5.surface_role, SurfaceRole::SurfaceContainerHighest);
}
}