ul_next/
window.rs

1//! `Window` to display web content in an [`App`].
2//!
3//! An [`App`] can have multiple [`Window`]s, and each [`Window`] can
4//! have multiple [`Overlay`]s managing multiple [`View`]s.
5//!
6//! [`App`]: crate::app::App
7
8use std::{self, ffi::CString, sync::Arc};
9
10use crate::{overlay::Overlay, view::Cursor, view::View, Library};
11
12/// Window creation flags
13pub struct WindowFlags {
14    /// Whether the window has borders or not
15    pub borderless: bool,
16    /// Whether the window has title or not
17    pub titled: bool,
18    /// Whether the window is resizable or not
19    pub resizable: bool,
20    /// Whether the window is maximizable or not
21    pub maximizable: bool,
22    /// The initial hide/show state of the window
23    pub hidden: bool,
24}
25
26impl WindowFlags {
27    /// Helper to convert this struct to a union enum for the C API
28    fn to_u32(&self) -> u32 {
29        let mut n = 0;
30
31        if self.borderless {
32            n |= ul_sys::ULWindowFlags_kWindowFlags_Borderless;
33        }
34        if self.titled {
35            n |= ul_sys::ULWindowFlags_kWindowFlags_Titled;
36        }
37        if self.resizable {
38            n |= ul_sys::ULWindowFlags_kWindowFlags_Resizable;
39        }
40        if self.maximizable {
41            n |= ul_sys::ULWindowFlags_kWindowFlags_Maximizable;
42        }
43        if self.hidden {
44            n |= ul_sys::ULWindowFlags_kWindowFlags_Hidden;
45        }
46
47        n
48    }
49}
50
51/// Window struct, represents a platform window.
52pub struct Window {
53    lib: Arc<Library>,
54    internal: ul_sys::ULWindow,
55    need_to_destroy: bool,
56}
57
58impl Window {
59    /// Internal function helper to create a view.
60    /// (See [`App::create_window`](crate::app::App::create_window))
61    ///
62    /// Returns [`None`] if failed to create the window.
63    pub(crate) unsafe fn create(
64        lib: Arc<Library>,
65        monitor_raw: ul_sys::ULMonitor,
66        width: u32,
67        height: u32,
68        fullscreen: bool,
69        window_flags: WindowFlags,
70    ) -> Option<Self> {
71        let internal = lib.appcore().ulCreateWindow(
72            monitor_raw,
73            width,
74            height,
75            fullscreen,
76            window_flags.to_u32(),
77        );
78
79        if internal.is_null() {
80            None
81        } else {
82            Some(Self {
83                lib,
84                internal,
85                need_to_destroy: true,
86            })
87        }
88    }
89
90    /// Helper internal function to allow getting a reference to a managed
91    /// session.
92    pub(crate) unsafe fn from_raw(lib: Arc<Library>, raw: ul_sys::ULWindow) -> Option<Self> {
93        if raw.is_null() {
94            None
95        } else {
96            Some(Self {
97                lib,
98                internal: raw,
99                need_to_destroy: false,
100            })
101        }
102    }
103
104    /// Get the window width (in screen coordinates).
105    pub fn screen_width(&self) -> u32 {
106        unsafe { self.lib.appcore().ulWindowGetScreenWidth(self.internal) }
107    }
108
109    /// Get the window width (in pixels).
110    pub fn width(&self) -> u32 {
111        unsafe { self.lib.appcore().ulWindowGetWidth(self.internal) }
112    }
113
114    /// Get the window height (in screen coordinates).
115    pub fn screen_height(&self) -> u32 {
116        unsafe { self.lib.appcore().ulWindowGetScreenHeight(self.internal) }
117    }
118
119    /// Get the window height (in pixels).
120    pub fn height(&self) -> u32 {
121        unsafe { self.lib.appcore().ulWindowGetHeight(self.internal) }
122    }
123
124    /// Move the window to a new position (in screen coordinates) relative
125    /// to the top-left of the monitor area.
126    pub fn move_to(&self, x: i32, y: i32) {
127        unsafe { self.lib.appcore().ulWindowMoveTo(self.internal, x, y) }
128    }
129
130    /// Move the window to the center of the monitor.
131    pub fn move_to_center(&self) {
132        unsafe { self.lib.appcore().ulWindowMoveToCenter(self.internal) }
133    }
134
135    /// Get the x-position of the window (in screen coordinates) relative
136    /// to the top-left of the monitor area.
137    pub fn x(&self) -> i32 {
138        unsafe { self.lib.appcore().ulWindowGetPositionX(self.internal) }
139    }
140
141    /// Get the y-position of the window (in screen coordinates) relative
142    /// to the top-left of the monitor area.
143    pub fn y(&self) -> i32 {
144        unsafe { self.lib.appcore().ulWindowGetPositionY(self.internal) }
145    }
146
147    /// Whether or not the window is fullscreen.
148    pub fn is_fullscreen(&self) -> bool {
149        unsafe { self.lib.appcore().ulWindowIsFullscreen(self.internal) }
150    }
151
152    /// The DPI scale of the window.
153    pub fn scale(&self) -> f64 {
154        unsafe { self.lib.appcore().ulWindowGetScale(self.internal) }
155    }
156
157    /// Set the window title.
158    pub fn set_title(&self, title: &str) {
159        let c_string = CString::new(title).unwrap();
160        unsafe {
161            self.lib
162                .appcore()
163                .ulWindowSetTitle(self.internal, c_string.as_ptr())
164        }
165    }
166
167    /// Set the cursor.
168    pub fn set_cursor(&self, cursor: Cursor) {
169        unsafe {
170            self.lib
171                .appcore()
172                .ulWindowSetCursor(self.internal, cursor as u32)
173        }
174    }
175
176    /// Show the window (if it was previously hidden).
177    pub fn show(&self) {
178        unsafe { self.lib.appcore().ulWindowShow(self.internal) }
179    }
180
181    /// Hide the window.
182    pub fn hide(&self) {
183        unsafe { self.lib.appcore().ulWindowHide(self.internal) }
184    }
185
186    /// Whether or not the window is currently visible (not hidden).
187    pub fn is_visible(&self) -> bool {
188        unsafe { self.lib.appcore().ulWindowIsVisible(self.internal) }
189    }
190
191    /// Close the window.
192    pub fn close(&self) {
193        unsafe { self.lib.appcore().ulWindowClose(self.internal) }
194    }
195
196    /// Convert screen coordinates to pixels using the current DPI scale.
197    pub fn screen_to_pixels(&self, val: i32) -> i32 {
198        unsafe {
199            self.lib
200                .appcore()
201                .ulWindowScreenToPixels(self.internal, val)
202        }
203    }
204
205    /// Convert pixels to screen coordinates using the current DPI scale.
206    pub fn pixels_to_screen(&self, val: i32) -> i32 {
207        unsafe {
208            self.lib
209                .appcore()
210                .ulWindowPixelsToScreen(self.internal, val)
211        }
212    }
213
214    set_callback! {
215        /// Called when the Window is closed.
216        ///
217        /// # Callback Arguments
218        /// * `window: &Window` - The window that fired the event (eg. self)
219        pub fn set_close_callback(&self, callback: FnMut(window: &Window)) :
220            [Window::lib.appcore()][s] ulWindowSetCloseCallback(ul_window: ul_sys::ULWindow) {
221               let window = &Window::from_raw(s.lib.clone(), ul_window).unwrap();
222        }
223    }
224
225    set_callback! {
226        /// Called when the Window is resized.
227        ///
228        /// # Callback Arguments
229        /// * `window: &Window` - The window that fired the event (eg. self)
230        /// * `width: u32` - The new width of the window (in pixels)
231        /// * `height: u32` - The new height of the window (in pixels)
232        pub fn set_resize_callback(&self, callback: FnMut(window: &Window, width: u32, height: u32)) :
233            [Window::lib.appcore()][s] ulWindowSetResizeCallback(ul_window: ul_sys::ULWindow, width: u32, height: u32) {
234               let window = &Window::from_raw(s.lib.clone(), ul_window).unwrap();
235        }
236    }
237
238    //pub fn is_accelerated(&self) -> bool {
239    //}
240    //
241    //pub fn render_buff_id(&self) -> u32 {
242    //}
243    //
244    //pub fn draw_surface(&self, surface: &Surface) {
245    //}
246}
247
248impl Window {
249    /// Create a new Overlay.
250    ///
251    /// # Arguments
252    /// * `width` - The width in pixels.
253    /// * `height` - The height in pixels.
254    /// * `x` - The x-position (offset from the left of this Window), in pixels.
255    /// * `y` - The y-position (offset from the top of this Window), in pixels.
256    ///
257    /// Returns [`None`] if failed to create [`Overlay`].
258    pub fn create_overlay(&self, width: u32, height: u32, x: i32, y: i32) -> Option<Overlay> {
259        unsafe { Overlay::create(self.lib.clone(), self.internal, width, height, x, y) }
260    }
261
262    /// Create a new Overlay, wrapping an existing view.
263    ///
264    /// # Arguments
265    /// * `view` - The view to wrap (will use its width and height).
266    /// * `x` - The x-position (offset from the left of this Window), in pixels.
267    /// * `y` - The y-position (offset from the top of this Window), in pixels.
268    ///
269    /// Returns [`None`] if failed to create [`Overlay`].
270    pub fn create_overlay_with_view(&self, view: View, x: i32, y: i32) -> Option<Overlay> {
271        unsafe { Overlay::create_with_view(self.lib.clone(), self.internal, view, x, y) }
272    }
273}
274
275impl Drop for Window {
276    fn drop(&mut self) {
277        if self.need_to_destroy {
278            unsafe { self.lib.appcore().ulDestroyWindow(self.internal) }
279        }
280    }
281}