Skip to main content

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                // TODO: Reconsider iced UI scaling. Iced should support more adaptive widget
73                // scaling, and a RelativeToWindow may not be needed at all. But either way, the
74                // current iced scaling has problems that need addressing.
75                ScaleMode::RelativeToWindow(dims) => f64::from(self.physical_resolution.y) / dims.y,
76            }
77    }
78
79    /// Calculate factor to transform between logical coordinates and our scaled
80    /// coordinates.
81    /// Multiply by scaled coordinates to get the logical coordinates
82    ///
83    /// Used to scale coordinates from window events (e.g. the mouse cursor
84    /// position)
85    pub fn scale_factor_logical(&self) -> f64 { self.scale_factor_physical() / self.scale_factor }
86
87    /// Updates window size
88    /// Returns true if the value was changed
89    pub fn surface_resized(&mut self, new_res: Vec2<u32>) -> bool {
90        let old_res = self.physical_resolution;
91        self.physical_resolution = new_res;
92        old_res != self.physical_resolution
93    }
94
95    /// Updates scale factor
96    /// Returns true if the value was changed
97    pub fn scale_factor_changed(&mut self, scale_factor: f64) -> bool {
98        let old_scale_factor = self.scale_factor;
99        self.scale_factor = scale_factor;
100        old_scale_factor != self.scale_factor
101    }
102
103    /// Get physical resolution.
104    pub fn physical_resolution(&self) -> Vec2<u32> { self.physical_resolution }
105
106    /// Get scaled window size.
107    pub fn scaled_resolution(&self) -> Vec2<f64> {
108        self.physical_resolution.map(f64::from) / self.scale_factor_physical()
109    }
110
111    // Transform point from logical to scaled coordinates.
112    pub fn scale_point(&self, point: Vec2<f64>) -> Vec2<f64> { point / self.scale_factor_logical() }
113}