Skip to main content

cranpose_ui_graphics/
accessibility.rs

1use std::cell::Cell;
2
3/// What the person set in the system's accessibility settings.
4#[derive(Clone, Copy, Debug, PartialEq)]
5pub struct AccessibilityOptions {
6    /// The text size setting as a multiplier of the default, 1.0 when the
7    /// person left it alone. Dynamic Type on iOS, the font size on Android
8    /// and the web, the text scale of the desktop.
9    pub font_scale: f32,
10    /// Whether the person asked for less motion. Every animation then ends on
11    /// its first frame.
12    pub reduce_motion: bool,
13    /// Whether the person asked for less transparency. Glass then draws as a
14    /// flat surface with no blur.
15    pub reduce_transparency: bool,
16    /// Whether the person asked for more contrast. Secondary text, separators
17    /// and fills then draw darker on light and lighter on dark.
18    pub increase_contrast: bool,
19    /// Whether the person asked for bold text. Every text style then gains a
20    /// weight step.
21    pub bold_text: bool,
22    /// Whether the system inverts colors and leaves this app's window to
23    /// invert its own, the way iOS Smart Invert does. The theme then swaps to
24    /// its other palette and pictures stay as they are. A system that inverts
25    /// the whole screen itself reports false.
26    pub invert_colors: bool,
27}
28
29impl Default for AccessibilityOptions {
30    fn default() -> Self {
31        Self {
32            font_scale: 1.0,
33            reduce_motion: false,
34            reduce_transparency: false,
35            increase_contrast: false,
36            bold_text: false,
37            invert_colors: false,
38        }
39    }
40}
41
42impl AccessibilityOptions {
43    /// The options with the font scale made a plain number: finite and above
44    /// zero, else 1.0.
45    pub fn normalized(mut self) -> Self {
46        if !(self.font_scale.is_finite() && self.font_scale > 0.0) {
47            self.font_scale = 1.0;
48        }
49        self
50    }
51}
52
53thread_local! {
54    static PLATFORM_ACCESSIBILITY_OPTIONS: Cell<AccessibilityOptions> =
55        const { Cell::new(AccessibilityOptions {
56            font_scale: 1.0,
57            reduce_motion: false,
58            reduce_transparency: false,
59            increase_contrast: false,
60            bold_text: false,
61            invert_colors: false,
62        }) };
63}
64
65/// Installs what the platform reports. A backend calls this at start and on
66/// every change, and forces a root render when the answer is true, so the
67/// theme, the glass and the animations read the new options.
68pub fn set_platform_accessibility_options(options: AccessibilityOptions) -> bool {
69    let options = options.normalized();
70    PLATFORM_ACCESSIBILITY_OPTIONS.with(|cell| {
71        let changed = cell.get() != options;
72        cell.set(options);
73        changed
74    })
75}
76
77/// What the platform last reported.
78pub fn platform_accessibility_options() -> AccessibilityOptions {
79    PLATFORM_ACCESSIBILITY_OPTIONS.with(Cell::get)
80}