veloren_voxygen/ui/
scale.rs

1use serde::{Deserialize, Serialize};
2use vek::*;
3
4/// Type of scaling to use.
5#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq)]
6pub enum ScaleMode {
7    // Scale against physical size.
8    Absolute(f64),
9    // Scale based on the window's physical size, but maintain aspect ratio of widgets.
10    // Contains width and height of the "default" window size (ie where there should be no
11    // scaling).
12    RelativeToWindow(Vec2<f64>),
13    // Use the dpi factor provided by the windowing system (i.e. use logical size).
14    #[serde(other)]
15    // Would be `RelativeToWindow([1920.0, 1080.0].into())`, but only supported on unit variants
16    DpiFactor,
17}
18
19#[derive(Clone, Copy)]
20pub struct Scale {
21    mode: ScaleMode,
22    // Current dpi factor
23    scale_factor: f64,
24    // Current pixel size of the window
25    physical_resolution: Vec2<u32>,
26    // TEMP
27    extra_factor: f64,
28}
29
30impl Scale {
31    pub fn new(
32        physical_resolution: Vec2<u32>,
33        scale_factor: f64,
34        mode: ScaleMode,
35        extra_factor: f64,
36    ) -> Self {
37        Scale {
38            mode,
39            scale_factor,
40            physical_resolution,
41            extra_factor,
42        }
43    }
44
45    // Change the scaling mode.
46    // Returns false if the mode matches the current mode
47    pub fn set_scaling_mode(&mut self, mode: ScaleMode) -> bool {
48        let old_mode = self.mode;
49        self.mode = mode;
50        old_mode != mode
51    }
52
53    // Get scaling mode transformed into absolute scaling
54    pub fn scaling_mode_as_absolute(&self) -> ScaleMode {
55        ScaleMode::Absolute(self.scale_factor_physical())
56    }
57
58    // Get scaling mode transformed to be relative to the window with the same
59    // aspect ratio as the current window
60    pub fn scaling_mode_as_relative(&self) -> ScaleMode {
61        ScaleMode::RelativeToWindow(self.scaled_resolution())
62    }
63
64    /// Calculate factor to transform between physical coordinates and our
65    /// scaled coordinates.
66    /// Multiply by scaled coordinates to get the physical coordinates
67    pub fn scale_factor_physical(&self) -> f64 {
68        self.extra_factor
69            * match self.mode {
70                ScaleMode::Absolute(scale) => scale,
71                ScaleMode::DpiFactor => 1.0 * self.scale_factor,
72                ScaleMode::RelativeToWindow(dims) => (f64::from(self.physical_resolution.x)
73                    / dims.x)
74                    .min(f64::from(self.physical_resolution.y) / dims.y),
75            }
76    }
77
78    /// Calculate factor to transform between logical coordinates and our scaled
79    /// coordinates.
80    /// Multiply by scaled coordinates to get the logical coordinates
81    ///
82    /// Used to scale coordinates from window events (e.g. the mouse cursor
83    /// position)
84    pub fn scale_factor_logical(&self) -> f64 { self.scale_factor_physical() / self.scale_factor }
85
86    /// Updates window size
87    /// Returns true if the value was changed
88    pub fn surface_resized(&mut self, new_res: Vec2<u32>) -> bool {
89        let old_res = self.physical_resolution;
90        self.physical_resolution = new_res;
91        old_res != self.physical_resolution
92    }
93
94    /// Updates scale factor
95    /// Returns true if the value was changed
96    pub fn scale_factor_changed(&mut self, scale_factor: f64) -> bool {
97        let old_scale_factor = self.scale_factor;
98        self.scale_factor = scale_factor;
99        old_scale_factor != self.scale_factor
100    }
101
102    /// Get physical resolution.
103    pub fn physical_resolution(&self) -> Vec2<u32> { self.physical_resolution }
104
105    /// Get scaled window size.
106    pub fn scaled_resolution(&self) -> Vec2<f64> {
107        self.physical_resolution.map(f64::from) / self.scale_factor_physical()
108    }
109
110    // Transform point from logical to scaled coordinates.
111    pub fn scale_point(&self, point: Vec2<f64>) -> Vec2<f64> { point / self.scale_factor_logical() }
112}