1
use std::ops::Mul;
2

            
3
use crate::{One, Scale};
4

            
5
/// A unit representing DPI-adjusted resolution configured on the system.
6
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, PartialOrd, Ord)]
8
pub struct Points;
9

            
10
/// A unit representing physical pixels.
11
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, PartialOrd, Ord)]
13
pub struct Pixels;
14

            
15
/// A unit representing virtual pixels that are scaled on top of the DPI
16
/// adjustment done for the [`Points`] unit.
17
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
18
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, PartialOrd, Ord)]
19
pub struct Scaled;
20

            
21
/// Scaling ratios for [`Scaled`] and [`Displayable`].
22
#[derive(Debug, Clone, Copy)]
23
pub struct DisplayScale<T> {
24
    pub(crate) total: Scale<T, Scaled, Pixels>,
25
    pub(crate) dpi: Scale<T, Points, Pixels>,
26
    pub(crate) additional: Scale<T, Scaled, Points>,
27
}
28

            
29
impl<T: Mul<T, Output = T> + Copy> DisplayScale<T> {
30
    /// Returns the scale between [`Pixels`] and [`Points`].
31
    pub fn dpi_scale(&self) -> Scale<T, Points, Pixels> {
32
        self.dpi
33
    }
34

            
35
    /// Returns the scale between [`Points`] and [`Scaled`].
36
    pub fn additional_scale(&self) -> Scale<T, Scaled, Points> {
37
        self.additional
38
    }
39

            
40
    /// Returns the scale between [`Pixels`] and [`Scaled`].
41
    pub fn total_scale(&self) -> Scale<T, Scaled, Pixels> {
42
        self.total
43
    }
44

            
45
    /// Sets the scale factor between [`Points`] and [`Scaled`].
46
    pub fn set_additional_scale(&mut self, scale: Scale<T, Scaled, Points>) {
47
        self.additional = scale;
48
        self.total = total_scale(self.dpi, self.additional);
49
    }
50

            
51
    /// Sets the scale factor between [`Pixels`] and [`Points`].
52
    pub fn set_dpi_scale(&mut self, scale: Scale<T, Points, Pixels>) {
53
        self.dpi = scale;
54
        self.total = total_scale(self.dpi, self.additional);
55
    }
56
}
57

            
58
impl<T: Mul<T, Output = T> + Copy> DisplayScale<T> {
59
    /// Returns a new instance with the two scales provided.
60
    ///
61
    /// * `dpi`: This scale represents the scaling between [`Pixels`] and
62
    ///   [`Points`]. It should be set to the system configured user interface
63
    ///   scaling, if possible. In general, this scale shouldn't be something an
64
    ///   end-user manually configures.
65
    /// * `additional_scaling`: This scale represents the scaling between
66
    ///   [`Points`] and [`Scaled`]. This is an additional layer of scaling on
67
    ///   top of the `dpi` scaling. It is intended to be used to provide a way
68
    ///   for applications to allow end-users to configure an
69
    ///   application-specific zoom setting.
70
4
    pub fn new(
71
4
        dpi: Scale<T, Points, Pixels>,
72
4
        additional_scaling: Scale<T, Scaled, Points>,
73
4
    ) -> Self {
74
4
        Self {
75
4
            dpi,
76
4
            additional: additional_scaling,
77
4
            total: total_scale(dpi, additional_scaling),
78
4
        }
79
4
    }
80
}
81

            
82
4
fn total_scale<T: Mul<T, Output = T> + Copy>(
83
4
    dpi: Scale<T, Points, Pixels>,
84
4
    additional_scaling: Scale<T, Scaled, Points>,
85
4
) -> Scale<T, Scaled, Pixels> {
86
4
    Scale::new(dpi.get() * additional_scaling.get())
87
4
}
88

            
89
impl<T> One for DisplayScale<T>
90
where
91
    T: num_traits::One + Mul<T, Output = T> + Copy,
92
{
93
    fn one() -> Self {
94
        Self::new(Scale::one(), Scale::one())
95
    }
96
}
97

            
98
/// Methods for converting between display scales.
99
pub trait Displayable<T> {
100
    /// The [`Pixels`] unit type for this implementor.
101
    type Pixels: Displayable<T>;
102
    /// The [`Points`] unit type for this implementor.
103
    type Points: Displayable<T>;
104
    /// The [`Scaled`] unit type for this implementor.
105
    type Scaled: Displayable<T>;
106

            
107
    /// Returns this value after applying `scale`, if needed.
108
    fn to_pixels(&self, scale: &DisplayScale<T>) -> Self::Pixels;
109
    /// Returns this value after applying `scale`, if needed.
110
    fn to_points(&self, scale: &DisplayScale<T>) -> Self::Points;
111
    /// Returns this value after applying `scale`, if needed.
112
    fn to_scaled(&self, scale: &DisplayScale<T>) -> Self::Scaled;
113
}