zng_view_api/
config.rs

1//! System config types.
2
3use std::{fmt, time::Duration};
4
5use serde::{Deserialize, Serialize};
6
7use zng_txt::Txt;
8use zng_unit::{Dip, DipSize, Rgba};
9
10/// System settings needed for implementing double/triple clicks.
11#[derive(Debug, Clone, Copy, Serialize, PartialEq, Eq, Deserialize)]
12#[non_exhaustive]
13pub struct MultiClickConfig {
14    /// Maximum time interval between clicks.
15    ///
16    /// Only repeated clicks within this time interval can count as double-clicks.
17    pub time: Duration,
18
19    /// Maximum (x, y) distance in pixels.
20    ///
21    /// Only repeated clicks that are within this distance of the first click can count as double-clicks.
22    pub area: DipSize,
23}
24impl MultiClickConfig {
25    /// New config.
26    pub fn new(time: Duration, area: DipSize) -> Self {
27        Self { time, area }
28    }
29}
30impl Default for MultiClickConfig {
31    /// `500ms` and `4, 4`.
32    fn default() -> Self {
33        Self {
34            time: Duration::from_millis(500),
35            area: DipSize::splat(Dip::new(4)),
36        }
37    }
38}
39
40/// System settings needed to implementing touch gestures.
41#[derive(Debug, Clone, Copy, Serialize, PartialEq, Eq, Deserialize)]
42#[non_exhaustive]
43pub struct TouchConfig {
44    /// Maximum (x, y) distance between a touch start and end that generates a touch click.
45    ///
46    /// Area can be disregarded if the touch is not ambiguous. This usually defines the initial lag
47    /// for a single finger drag gesture.
48    pub tap_area: DipSize,
49
50    /// Maximum (x, y) distance that a subsequent touch click is linked with the previous one as a double click.
51    ///
52    /// Area can be disregarded if the touch is not ambiguous.
53    pub double_tap_area: DipSize,
54
55    /// Maximum time between start and end in the `tap_area` that generates a touch click.
56    ///
57    /// Time can be disregarded if the touch is not ambiguous. This usually defines the *long press* delay.
58    pub tap_max_time: Duration,
59
60    /// Maximum time between taps that generates a double click.
61    pub double_tap_max_time: Duration,
62
63    /// Minimum velocity that can be considered a fling gesture, in dip per seconds.
64    pub min_fling_velocity: Dip,
65
66    /// Fling velocity ceiling, in dip per seconds.
67    pub max_fling_velocity: Dip,
68}
69
70impl TouchConfig {
71    /// New config.
72    pub fn new(
73        tap_area: DipSize,
74        double_tap_area: DipSize,
75        tap_max_time: Duration,
76        double_tap_max_time: Duration,
77        min_fling_velocity: Dip,
78        max_fling_velocity: Dip,
79    ) -> Self {
80        Self {
81            tap_area,
82            double_tap_area,
83            tap_max_time,
84            double_tap_max_time,
85            min_fling_velocity,
86            max_fling_velocity,
87        }
88    }
89}
90impl Default for TouchConfig {
91    fn default() -> Self {
92        Self {
93            tap_area: DipSize::splat(Dip::new(8)),
94            double_tap_area: DipSize::splat(Dip::new(28)),
95            tap_max_time: Duration::from_millis(500),
96            double_tap_max_time: Duration::from_millis(500),
97            min_fling_velocity: Dip::new(50),
98            max_fling_velocity: Dip::new(8000),
99        }
100    }
101}
102
103/// System settings that define the key pressed repeat.
104#[derive(Debug, Clone, Copy, Serialize, PartialEq, Eq, Deserialize)]
105#[non_exhaustive]
106pub struct KeyRepeatConfig {
107    /// Delay before repeat starts.
108    pub start_delay: Duration,
109    /// Delay before each repeat event after the first.
110    pub interval: Duration,
111}
112impl KeyRepeatConfig {
113    /// New config.
114    pub fn new(start_delay: Duration, interval: Duration) -> Self {
115        Self { start_delay, interval }
116    }
117}
118impl Default for KeyRepeatConfig {
119    /// 600ms, 100ms.
120    fn default() -> Self {
121        Self {
122            start_delay: Duration::from_millis(600),
123            interval: Duration::from_millis(100),
124        }
125    }
126}
127
128/// System settings that control animations.
129#[derive(Debug, Clone, Copy, Serialize, PartialEq, Eq, Deserialize)]
130#[non_exhaustive]
131pub struct AnimationsConfig {
132    /// If animation are enabled.
133    ///
134    /// People with photo-sensitive epilepsy usually disable animations system wide.
135    pub enabled: bool,
136
137    /// Interval of the caret blink animation.
138    ///
139    /// This is the duration the cursor stays visible.
140    pub caret_blink_interval: Duration,
141    /// Duration after which the blink animation stops.
142    pub caret_blink_timeout: Duration,
143}
144impl AnimationsConfig {
145    /// New config.
146    pub fn new(enabled: bool, caret_blink_interval: Duration, caret_blink_timeout: Duration) -> Self {
147        Self {
148            enabled,
149            caret_blink_interval,
150            caret_blink_timeout,
151        }
152    }
153}
154impl Default for AnimationsConfig {
155    /// true, 530ms, 5s.
156    fn default() -> Self {
157        Self {
158            enabled: true,
159            caret_blink_interval: Duration::from_millis(530),
160            caret_blink_timeout: Duration::from_secs(5),
161        }
162    }
163}
164
165/// System settings that define the locale.
166#[derive(Debug, Clone, Serialize, PartialEq, Eq, Deserialize, Default)]
167#[non_exhaustive]
168pub struct LocaleConfig {
169    /// BCP-47 language tags, if the locale can be obtained.
170    pub langs: Vec<Txt>,
171}
172impl LocaleConfig {
173    /// New config.
174    pub fn new(langs: Vec<Txt>) -> Self {
175        Self { langs }
176    }
177}
178
179/// Text anti-aliasing.
180#[derive(Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
181#[non_exhaustive]
182pub enum FontAntiAliasing {
183    /// Uses the operating system configuration.
184    #[default]
185    Default,
186    /// Sub-pixel anti-aliasing if a fast implementation is available, otherwise uses `Alpha`.
187    Subpixel,
188    /// Alpha blending anti-aliasing.
189    Alpha,
190    /// Disable anti-aliasing.
191    Mono,
192}
193impl fmt::Debug for FontAntiAliasing {
194    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195        if f.alternate() {
196            write!(f, "FontAntiAliasing::")?;
197        }
198        match self {
199            FontAntiAliasing::Default => write!(f, "Default"),
200            FontAntiAliasing::Subpixel => write!(f, "Subpixel"),
201            FontAntiAliasing::Alpha => write!(f, "Alpha"),
202            FontAntiAliasing::Mono => write!(f, "Mono"),
203        }
204    }
205}
206
207/// Color scheme preference.
208#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
209#[non_exhaustive]
210pub enum ColorScheme {
211    /// Dark text, light background.
212    Light,
213
214    /// Light text, dark background.
215    Dark,
216}
217impl Default for ColorScheme {
218    /// Light.
219    fn default() -> Self {
220        ColorScheme::Light
221    }
222}
223
224/// System colors and color scheme.
225#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
226#[non_exhaustive]
227pub struct ColorsConfig {
228    /// Color scheme (light/dark) preference.
229    pub scheme: ColorScheme,
230    /// Accent color.
231    ///
232    /// Accent color preference.
233    ///
234    /// Expect a saturated color that contrasts with the text color.
235    pub accent: Rgba,
236}
237impl ColorsConfig {
238    /// New config.
239    pub fn new(scheme: ColorScheme, accent: Rgba) -> Self {
240        Self { scheme, accent }
241    }
242}
243impl Default for ColorsConfig {
244    fn default() -> Self {
245        Self {
246            scheme: Default::default(),
247            accent: Rgba::new(10, 10, 200, 255),
248        }
249    }
250}
251
252#[cfg(feature = "var")]
253zng_var::impl_from_and_into_var! {
254    fn from(some: ColorScheme) -> Option<ColorScheme>;
255}
256
257/// Window chrome (decorations) preference.
258#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
259#[non_exhaustive]
260pub struct ChromeConfig {
261    /// Window manager prefers that the window renders a custom chrome.
262    ///
263    /// This is also called "Client-Side Decorations", it is `true` in GNOME+Wayland.
264    pub prefer_custom: bool,
265
266    /// If the Window manager provides a chrome.
267    ///
268    /// When this is `false` the view-process implementation may provide just a very basic fallback chrome,
269    /// if the app-process still requests system chrome.
270    pub provided: bool,
271}
272impl ChromeConfig {
273    /// New config.
274    pub fn new(prefer_custom: bool, provided: bool) -> Self {
275        Self { prefer_custom, provided }
276    }
277
278    /// If system prefers custom and does not provide chrome.
279    ///
280    /// Note that a chromeless window is not forbidden if this is `true`.
281    pub fn needs_custom(&self) -> bool {
282        self.prefer_custom && !self.provided
283    }
284}
285impl Default for ChromeConfig {
286    fn default() -> Self {
287        Self {
288            prefer_custom: false,
289            provided: true,
290        }
291    }
292}