Skip to main content

cranpose_ui_graphics/
unit.rs

1//! Unit types: Dp, Sp, and conversions
2
3/// Density-independent pixels
4#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
5pub struct Dp(pub f32);
6
7impl Dp {
8    pub fn to_px(&self, density: f32) -> f32 {
9        self.0 * density
10    }
11
12    pub fn from_px(px: f32, density: f32) -> Self {
13        Self(px / density)
14    }
15}
16
17/// Scale-independent pixels (for text)
18#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
19pub struct Sp(pub f32);
20
21impl Sp {
22    pub fn to_px(&self, density: f32, font_scale: f32) -> f32 {
23        self.0 * density * font_scale
24    }
25
26    pub fn from_px(px: f32, density: f32, font_scale: f32) -> Self {
27        Self(px / (density * font_scale))
28    }
29}
30
31/// Raw pixels
32#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
33pub struct Px(pub f32);
34
35#[cfg(test)]
36mod tests {
37    use super::*;
38
39    /// The two directions have to be each other's inverse, or a value that made
40    /// a round trip through the platform — a touch slop measured in pixels,
41    /// stored as `Dp`, applied back in pixels — comes back a different size on
42    /// every screen but the one it was written on.
43    #[test]
44    fn density_independent_pixels_round_trip_through_a_density() {
45        for density in [1.0f32, 1.5, 2.0, 3.0] {
46            let dp = Dp(24.0);
47            assert_eq!(dp.to_px(density), 24.0 * density);
48            assert_eq!(Dp::from_px(dp.to_px(density), density), dp);
49        }
50    }
51
52    /// Text carries the user's font-scale setting as well as the screen's
53    /// density, and both have to survive the trip.
54    #[test]
55    fn scale_independent_pixels_round_trip_through_density_and_font_scale() {
56        for density in [1.0f32, 2.0, 3.0] {
57            for font_scale in [0.85f32, 1.0, 1.3] {
58                let sp = Sp(16.0);
59                assert_eq!(sp.to_px(density, font_scale), 16.0 * density * font_scale);
60                assert_eq!(
61                    Sp::from_px(sp.to_px(density, font_scale), density, font_scale),
62                    sp
63                );
64            }
65        }
66    }
67}