maplibre/
window.rs

1//! Utilities for the window system.
2
3use std::num::NonZeroU32;
4
5use thiserror::Error;
6use wgpu::rwh::{HasDisplayHandle, HasWindowHandle};
7
8/// Window of a certain [`PhysicalSize`]. This can either be a proper window or a headless one.
9pub trait MapWindow {
10    fn size(&self) -> PhysicalSize;
11}
12
13/// Window which references a physical `RawWindow`. This is only implemented by headed windows and
14/// not by headless windows.
15pub trait HeadedMapWindow: MapWindow {
16    type WindowHandle: HasWindowHandle + HasDisplayHandle + Sync;
17
18    fn handle(&self) -> &Self::WindowHandle;
19
20    // TODO: Can we avoid this?
21    fn request_redraw(&self);
22
23    fn scale_factor(&self) -> f64;
24
25    fn id(&self) -> u64;
26}
27
28#[derive(Error, Debug)]
29pub enum WindowCreateError {
30    #[error("unable to create event loop")]
31    EventLoop,
32    #[error("unable to create window")]
33    Window,
34}
35
36/// A configuration for a window which determines the corresponding implementation of a
37/// [`MapWindow`] and is able to create it.
38pub trait MapWindowConfig: 'static + Clone {
39    type MapWindow: MapWindow;
40
41    fn create(&self) -> Result<Self::MapWindow, WindowCreateError>;
42}
43
44/// Window size with a width and an height in pixels.
45#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
46pub struct PhysicalSize {
47    width: NonZeroU32,
48    height: NonZeroU32,
49}
50
51impl PhysicalSize {
52    pub fn new(width: u32, height: u32) -> Option<Self> {
53        Some(Self {
54            width: NonZeroU32::new(width)?,
55            height: NonZeroU32::new(height)?,
56        })
57    }
58
59    pub fn width(&self) -> u32 {
60        self.width.get()
61    }
62
63    pub fn width_non_zero(&self) -> NonZeroU32 {
64        self.width
65    }
66
67    pub fn height(&self) -> u32 {
68        self.height.get()
69    }
70
71    pub fn height_non_zero(&self) -> NonZeroU32 {
72        self.height
73    }
74}
75
76#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
77pub struct LogicalSize {
78    width: NonZeroU32,
79    height: NonZeroU32,
80}
81
82impl LogicalSize {
83    pub fn new(width: u32, height: u32) -> Option<Self> {
84        Some(Self {
85            width: NonZeroU32::new(width)?,
86            height: NonZeroU32::new(height)?,
87        })
88    }
89
90    pub fn width(&self) -> u32 {
91        self.width.get()
92    }
93
94    pub fn width_non_zero(&self) -> NonZeroU32 {
95        self.width
96    }
97
98    pub fn height(&self) -> u32 {
99        self.height.get()
100    }
101
102    pub fn height_non_zero(&self) -> NonZeroU32 {
103        self.height
104    }
105}
106
107impl PhysicalSize {
108    pub fn to_logical(&self, scale_factor: f64) -> LogicalSize {
109        let width = self.width.get() as f64 / scale_factor;
110        let height = self.height.get() as f64 / scale_factor;
111        LogicalSize {
112            width: NonZeroU32::new(width as u32).expect("impossible to reach"),
113            height: NonZeroU32::new(height as u32).expect("impossible to reach"),
114        }
115    }
116}