Skip to main content

tessera_ui/
scroll.rs

1//! Platform scroll delta normalization helpers.
2//!
3//! ## Usage
4//!
5//! Normalize wheel deltas before applying them inside scrollable containers.
6
7use crate::{Dp, Px, ScrollDeltaUnit, ScrollEventSource};
8
9/// Platform-specific wheel scroll normalization parameters.
10#[derive(Debug, Clone, Copy, PartialEq)]
11pub struct PlatformScrollConfig {
12    /// Density-independent distance consumed for one wheel line step.
13    pub wheel_line_step: Dp,
14}
15
16impl PlatformScrollConfig {
17    /// Returns the default configuration for the current compilation target.
18    pub fn current() -> Self {
19        #[cfg(target_arch = "wasm32")]
20        {
21            Self {
22                wheel_line_step: Dp(16.0),
23            }
24        }
25
26        #[cfg(not(target_arch = "wasm32"))]
27        {
28            Self {
29                wheel_line_step: Dp(40.0),
30            }
31        }
32    }
33
34    /// Converts a raw platform scroll delta into logical scroll pixels.
35    pub fn normalize_scroll_delta(
36        self,
37        delta_x: f32,
38        delta_y: f32,
39        unit: ScrollDeltaUnit,
40        source: ScrollEventSource,
41    ) -> (f32, f32) {
42        let multiplier = match (source, unit) {
43            (ScrollEventSource::Wheel, ScrollDeltaUnit::Line) => {
44                Px::from(self.wheel_line_step).to_f32()
45            }
46            _ => 1.0,
47        };
48        (delta_x * multiplier, delta_y * multiplier)
49    }
50}
51
52impl Default for PlatformScrollConfig {
53    fn default() -> Self {
54        Self::current()
55    }
56}
57
58/// Returns the platform scroll configuration for the current target.
59pub fn platform_scroll_config() -> PlatformScrollConfig {
60    PlatformScrollConfig::current()
61}
62
63/// Converts a raw platform scroll delta into logical scroll pixels.
64pub fn normalize_platform_scroll_delta(
65    delta_x: f32,
66    delta_y: f32,
67    unit: ScrollDeltaUnit,
68    source: ScrollEventSource,
69) -> (f32, f32) {
70    platform_scroll_config().normalize_scroll_delta(delta_x, delta_y, unit, source)
71}
72
73#[cfg(test)]
74mod tests {
75    use super::PlatformScrollConfig;
76    use crate::{Dp, ScrollDeltaUnit, ScrollEventSource};
77
78    #[test]
79    fn wheel_line_delta_is_scaled_by_platform_step() {
80        let config = PlatformScrollConfig {
81            wheel_line_step: Dp(24.0),
82        };
83        let (x, y) = config.normalize_scroll_delta(
84            1.0,
85            -2.0,
86            ScrollDeltaUnit::Line,
87            ScrollEventSource::Wheel,
88        );
89        assert_eq!((x, y), (24.0, -48.0));
90    }
91
92    #[test]
93    fn wheel_pixel_delta_is_left_untouched() {
94        let config = PlatformScrollConfig {
95            wheel_line_step: Dp(24.0),
96        };
97        let (x, y) = config.normalize_scroll_delta(
98            3.0,
99            -5.0,
100            ScrollDeltaUnit::Pixel,
101            ScrollEventSource::Wheel,
102        );
103        assert_eq!((x, y), (3.0, -5.0));
104    }
105}