Skip to main content

portlight/
window.rs

1use std::ffi::{c_ulong, c_void};
2use std::fmt;
3use std::marker::PhantomData;
4use std::rc::Rc;
5
6use crate::{backend, EventLoop, Result};
7
8#[derive(Copy, Clone, Debug, PartialEq)]
9pub struct Point {
10    pub x: f64,
11    pub y: f64,
12}
13
14impl Point {
15    #[inline]
16    pub fn new(x: f64, y: f64) -> Point {
17        Point { x, y }
18    }
19
20    #[inline]
21    pub fn scale(self, scale: f64) -> Point {
22        Point::new(self.x * scale, self.y * scale)
23    }
24}
25
26#[derive(Copy, Clone, Debug, PartialEq)]
27pub struct Size {
28    pub width: f64,
29    pub height: f64,
30}
31
32impl Size {
33    #[inline]
34    pub fn new(width: f64, height: f64) -> Size {
35        Size { width, height }
36    }
37
38    #[inline]
39    pub fn scale(self, scale: f64) -> Size {
40        Size::new(self.width * scale, self.height * scale)
41    }
42}
43
44#[derive(Copy, Clone, Debug, PartialEq)]
45pub struct Rect {
46    pub x: f64,
47    pub y: f64,
48    pub width: f64,
49    pub height: f64,
50}
51
52impl Rect {
53    #[inline]
54    pub fn new(x: f64, y: f64, width: f64, height: f64) -> Rect {
55        Rect {
56            x,
57            y,
58            width,
59            height,
60        }
61    }
62
63    #[inline]
64    pub fn scale(self, scale: f64) -> Rect {
65        Rect::new(
66            self.x * scale,
67            self.y * scale,
68            self.width * scale,
69            self.height * scale,
70        )
71    }
72}
73
74pub struct Bitmap<'a> {
75    data: &'a [u32],
76    width: usize,
77    height: usize,
78}
79
80impl<'a> Bitmap<'a> {
81    #[inline]
82    pub fn new(data: &'a [u32], width: usize, height: usize) -> Bitmap<'a> {
83        assert!(width * height == data.len(), "invalid bitmap dimensions");
84
85        Bitmap {
86            data,
87            width,
88            height,
89        }
90    }
91
92    #[inline]
93    pub fn data(&self) -> &'a [u32] {
94        self.data
95    }
96
97    #[inline]
98    pub fn width(&self) -> usize {
99        self.width
100    }
101
102    #[inline]
103    pub fn height(&self) -> usize {
104        self.height
105    }
106}
107
108#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
109pub enum MouseButton {
110    Left,
111    Middle,
112    Right,
113    Back,
114    Forward,
115}
116
117#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
118pub enum Cursor {
119    Arrow,
120    Crosshair,
121    Hand,
122    IBeam,
123    No,
124    SizeNs,
125    SizeWe,
126    SizeNesw,
127    SizeNwse,
128    Wait,
129    None,
130}
131
132#[derive(Copy, Clone, Debug, PartialEq)]
133pub enum Event<'a> {
134    Expose(&'a [Rect]),
135    Frame,
136    Close,
137    GainFocus,
138    LoseFocus,
139    MouseEnter,
140    MouseExit,
141    MouseMove(Point),
142    MouseDown(MouseButton),
143    MouseUp(MouseButton),
144    Scroll(Point),
145}
146
147#[derive(Copy, Clone, Debug, Eq, PartialEq)]
148pub enum Response {
149    Capture,
150    Ignore,
151}
152
153#[derive(Copy, Clone, Debug)]
154pub enum RawWindow {
155    Win32(*mut c_void),
156    AppKit(*mut c_void),
157    X11(c_ulong),
158}
159
160#[derive(Clone, Debug)]
161pub struct WindowOptions {
162    pub(crate) title: String,
163    pub(crate) position: Option<Point>,
164    pub(crate) size: Size,
165    pub(crate) parent: Option<RawWindow>,
166}
167
168impl Default for WindowOptions {
169    fn default() -> Self {
170        WindowOptions {
171            title: String::new(),
172            position: None,
173            size: Size::new(0.0, 0.0),
174            parent: None,
175        }
176    }
177}
178
179impl WindowOptions {
180    pub fn new() -> WindowOptions {
181        Self::default()
182    }
183
184    pub fn title<S: AsRef<str>>(&mut self, title: S) -> &mut Self {
185        self.title = title.as_ref().to_string();
186        self
187    }
188
189    pub fn position(&mut self, position: Point) -> &mut Self {
190        self.position = Some(position);
191        self
192    }
193
194    pub fn size(&mut self, size: Size) -> &mut Self {
195        self.size = size;
196        self
197    }
198
199    pub unsafe fn raw_parent(&mut self, parent: RawWindow) -> &mut Self {
200        self.parent = Some(parent);
201        self
202    }
203
204    pub fn open<F>(&self, event_loop: &EventLoop, handler: F) -> Result<Window>
205    where
206        F: FnMut(Event) -> Response + 'static,
207    {
208        Ok(Window {
209            state: backend::WindowState::open(self, event_loop, handler)?,
210            _marker: PhantomData,
211        })
212    }
213}
214
215pub struct Window {
216    pub(crate) state: Rc<backend::WindowState>,
217    // ensure !Send and !Sync on all platforms
218    _marker: PhantomData<*mut ()>,
219}
220
221impl Window {
222    pub fn show(&self) {
223        self.state.show();
224    }
225
226    pub fn hide(&self) {
227        self.state.hide();
228    }
229
230    pub fn size(&self) -> Size {
231        self.state.size()
232    }
233
234    pub fn scale(&self) -> f64 {
235        self.state.scale()
236    }
237
238    pub fn present(&self, bitmap: Bitmap) {
239        self.state.present(bitmap);
240    }
241
242    pub fn present_partial(&self, bitmap: Bitmap, rects: &[Rect]) {
243        self.state.present_partial(bitmap, rects);
244    }
245
246    pub fn set_cursor(&self, cursor: Cursor) {
247        self.state.set_cursor(cursor);
248    }
249
250    pub fn set_mouse_position(&self, position: Point) {
251        self.state.set_mouse_position(position);
252    }
253
254    pub fn as_raw(&self) -> Result<RawWindow> {
255        self.state.as_raw()
256    }
257}
258
259impl Drop for Window {
260    fn drop(&mut self) {
261        self.state.close();
262    }
263}
264
265impl fmt::Debug for Window {
266    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
267        fmt.debug_struct("Window").finish_non_exhaustive()
268    }
269}