use std::fmt;
#[derive(Clone, Copy, serde::Serialize, serde::Deserialize)]
#[serde(transparent)]
pub struct PxDensity(f32);
impl fmt::Debug for PxDensity {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PxDensity")
.field(".ppi()", &self.ppi())
.field(".ppcm()", &self.ppcm())
.finish()
}
}
impl fmt::Display for PxDensity {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
write!(f, "{:.0}ppcm", self.ppcm())
} else {
write!(f, "{:.0}ppi", self.ppi())
}
}
}
impl Default for PxDensity {
fn default() -> Self {
PxDensity::new_ppi(96.0)
}
}
impl PxDensity {
pub const CM_TO_INCH: f32 = 2.54;
pub fn new_ppi(pixels_per_inch: f32) -> Self {
Self::new_ppcm(pixels_per_inch / Self::CM_TO_INCH)
}
pub fn new_ppm(pixels_per_meter: f32) -> Self {
Self::new_ppcm(pixels_per_meter / 100.0)
}
pub fn new_ppcm(pixels_per_centimeter: f32) -> Self {
Self(pixels_per_centimeter)
}
pub fn ppi(self) -> f32 {
self.0 * Self::CM_TO_INCH
}
pub fn ppm(self) -> f32 {
self.0 * 100.0
}
pub fn ppcm(self) -> f32 {
self.0
}
}
impl PartialEq for PxDensity {
fn eq(&self, other: &Self) -> bool {
super::about_eq(self.0, other.0, 0.001)
}
}
impl Eq for PxDensity {}
impl std::hash::Hash for PxDensity {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
super::about_eq_hash(self.0, 0.001, state)
}
}
impl Ord for PxDensity {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
super::about_eq_ord(self.0, other.0, 0.001)
}
}
impl PartialOrd for PxDensity {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl std::str::FromStr for PxDensity {
type Err = std::num::ParseFloatError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
for suffix in ["ppi", "dpi", ".ppi()", ".dpi()"] {
if let Some(s) = s.strip_suffix(suffix) {
return Ok(PxDensity::new_ppi(s.trim_end().parse()?));
}
}
for suffix in ["ppcm", ".ppcm()"] {
if let Some(s) = s.strip_suffix(suffix) {
return Ok(PxDensity::new_ppcm(s.parse()?));
}
}
Ok(PxDensity::new_ppi(s.parse()?))
}
}
pub trait PxDensityUnits {
fn ppi(self) -> PxDensity;
fn dpi(self) -> PxDensity
where
Self: Sized,
{
self.ppi()
}
fn ppcm(self) -> PxDensity;
}
impl PxDensityUnits for u32 {
fn ppi(self) -> PxDensity {
PxDensity::new_ppi(self as f32)
}
fn ppcm(self) -> PxDensity {
PxDensity::new_ppcm(self as f32)
}
}
impl PxDensityUnits for f32 {
fn ppi(self) -> PxDensity {
PxDensity::new_ppi(self)
}
fn ppcm(self) -> PxDensity {
PxDensity::new_ppcm(self)
}
}
pub type PxDensity2d = euclid::Size2D<PxDensity, PxDensity>;