use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Transparency(u8);
impl Transparency {
pub const OPAQUE: Transparency = Transparency(0);
pub const TRANSPARENT: Transparency = Transparency(255);
pub const BY_LAYER: Transparency = Transparency(0);
pub const fn new(alpha: u8) -> Self {
Transparency(alpha)
}
pub fn from_percent(percent: f64) -> Self {
let alpha = (percent.clamp(0.0, 1.0) * 255.0) as u8;
Transparency(alpha)
}
pub fn from_alpha_value(value: u32) -> Self {
let type_byte = (value >> 24) as u8;
match type_byte {
0 => Transparency::BY_LAYER,
1 => Transparency::OPAQUE, 2 | 3 => Transparency((value & 0xFF) as u8),
_ => Transparency::OPAQUE,
}
}
pub const fn alpha(&self) -> u8 {
self.0
}
pub fn as_percent(&self) -> f64 {
self.0 as f64 / 255.0
}
pub const fn is_opaque(&self) -> bool {
self.0 == 0
}
pub const fn is_transparent(&self) -> bool {
self.0 == 255
}
pub const T_10: Transparency = Transparency(26); pub const T_20: Transparency = Transparency(51); pub const T_30: Transparency = Transparency(77); pub const T_40: Transparency = Transparency(102); pub const T_50: Transparency = Transparency(128); pub const T_60: Transparency = Transparency(153); pub const T_70: Transparency = Transparency(179); pub const T_80: Transparency = Transparency(204); pub const T_90: Transparency = Transparency(230);
pub fn to_alpha_value(&self) -> i32 {
if self.0 == 0 {
0
} else {
((3u32 << 24) | self.0 as u32) as i32
}
}
pub fn to_dxf_value(&self) -> i32 {
if self.0 == 0 {
0
} else {
((2u32 << 24) | self.0 as u32) as i32
}
}
}
impl Default for Transparency {
fn default() -> Self {
Transparency::OPAQUE
}
}
impl From<u8> for Transparency {
fn from(alpha: u8) -> Self {
Transparency(alpha)
}
}
impl From<Transparency> for u8 {
fn from(transparency: Transparency) -> Self {
transparency.0
}
}
impl fmt::Display for Transparency {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:.1}%", self.as_percent() * 100.0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_transparency_creation() {
let t = Transparency::new(128);
assert_eq!(t.alpha(), 128);
}
#[test]
fn test_transparency_from_percent() {
let t = Transparency::from_percent(0.5);
assert_eq!(t.alpha(), 127);
let t = Transparency::from_percent(0.0);
assert_eq!(t.alpha(), 0);
let t = Transparency::from_percent(1.0);
assert_eq!(t.alpha(), 255);
}
#[test]
fn test_transparency_as_percent() {
assert_eq!(Transparency::OPAQUE.as_percent(), 0.0);
assert_eq!(Transparency::TRANSPARENT.as_percent(), 1.0);
assert!((Transparency::T_50.as_percent() - 0.5).abs() < 0.01);
}
#[test]
fn test_transparency_checks() {
assert!(Transparency::OPAQUE.is_opaque());
assert!(!Transparency::OPAQUE.is_transparent());
assert!(Transparency::TRANSPARENT.is_transparent());
assert!(!Transparency::TRANSPARENT.is_opaque());
}
#[test]
fn test_transparency_display() {
assert_eq!(Transparency::OPAQUE.to_string(), "0.0%");
assert_eq!(Transparency::TRANSPARENT.to_string(), "100.0%");
}
#[test]
fn test_transparency_conversion() {
let alpha: u8 = 100;
let t: Transparency = alpha.into();
let back: u8 = t.into();
assert_eq!(alpha, back);
}
#[test]
fn test_default_transparency() {
assert_eq!(Transparency::default(), Transparency::OPAQUE);
}
}