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}