Skip to main content

speedy2d/
window.rs

1/*
2 *  Copyright 2021 QuantumBadger
3 *
4 *  Licensed under the Apache License, Version 2.0 (the "License");
5 *  you may not use this file except in compliance with the License.
6 *  You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 *  Unless required by applicable law or agreed to in writing, software
11 *  distributed under the License is distributed on an "AS IS" BASIS,
12 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 *  See the License for the specific language governing permissions and
14 *  limitations under the License.
15 */
16
17use std::fmt::{Display, Formatter};
18use std::marker::PhantomData;
19
20use crate::dimen::{IVec2, UVec2, Vec2};
21use crate::error::{BacktraceError, ErrorMessage};
22use crate::{GLRenderer, Graphics2D};
23
24#[cfg(all(not(target_arch = "wasm32"), not(any(doc, doctest))))]
25type WindowHelperInnerType<UserEventType> =
26    crate::window_internal_glutin::WindowHelperGlutin<UserEventType>;
27
28#[cfg(all(not(target_arch = "wasm32"), not(any(doc, doctest))))]
29type UserEventSenderInnerType<UserEventType> =
30    crate::window_internal_glutin::UserEventSenderGlutin<UserEventType>;
31
32#[cfg(all(target_arch = "wasm32", not(any(doc, doctest))))]
33type WindowHelperInnerType<UserEventType> =
34    crate::window_internal_web::WindowHelperWeb<UserEventType>;
35
36#[cfg(all(target_arch = "wasm32", not(any(doc, doctest))))]
37type UserEventSenderInnerType<UserEventType> =
38    crate::window_internal_web::UserEventSenderWeb<UserEventType>;
39
40#[cfg(any(doc, doctest))]
41type WindowHelperInnerType<UserEventType> = PhantomData<UserEventType>;
42
43#[cfg(any(doc, doctest))]
44type UserEventSenderInnerType<UserEventType> = PhantomData<UserEventType>;
45
46/// Error occurring when sending a user event.
47#[derive(Clone, Debug, Hash, Eq, PartialEq, Copy)]
48pub enum EventLoopSendError
49{
50    /// Send failed as the event loop no longer exists.
51    EventLoopNoLongerExists
52}
53
54/// Allows user events to be sent to the event loop from other threads.
55pub struct UserEventSender<UserEventType: 'static>
56{
57    inner: UserEventSenderInnerType<UserEventType>
58}
59
60impl<UserEventType> Clone for UserEventSender<UserEventType>
61{
62    fn clone(&self) -> Self
63    {
64        UserEventSender {
65            inner: self.inner.clone()
66        }
67    }
68}
69
70impl<UserEventType> UserEventSender<UserEventType>
71{
72    pub(crate) fn new(inner: UserEventSenderInnerType<UserEventType>) -> Self
73    {
74        Self { inner }
75    }
76
77    /// Sends a user-defined event to the event loop. This will cause
78    /// [WindowHandler::on_user_event] to be invoked on the event loop
79    /// thread.
80    ///
81    /// This may be invoked from a different thread to the one running the event
82    /// loop.
83    #[inline]
84    pub fn send_event(&self, event: UserEventType) -> Result<(), EventLoopSendError>
85    {
86        self.inner.send_event(event)
87    }
88}
89
90/// Error occurring when creating a window.
91#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
92#[non_exhaustive]
93pub enum WindowCreationError
94{
95    /// Could not find the primary monitor.
96    PrimaryMonitorNotFound,
97    /// Could not find a suitable graphics context. Speedy2D attempts to find
98    /// the best possible context configuration by trying multiple options for
99    /// vsync and multisampling.
100    SuitableContextNotFound,
101    /// Failed to make the graphics context current.
102    MakeContextCurrentFailed,
103    /// Failed to instantiate the renderer.
104    RendererCreationFailed,
105    /// Failed to instantiate the main window event loop.
106    EventLoopCreationFailed
107}
108
109impl Display for WindowCreationError
110{
111    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result
112    {
113        f.write_str(match self {
114            WindowCreationError::PrimaryMonitorNotFound => "Primary monitor not found",
115            WindowCreationError::SuitableContextNotFound => {
116                "Could not find a suitable graphics context"
117            }
118            WindowCreationError::MakeContextCurrentFailed => {
119                "Failed to make the graphics context current"
120            }
121            WindowCreationError::RendererCreationFailed => {
122                "Failed to create the renderer"
123            }
124            WindowCreationError::EventLoopCreationFailed => {
125                "Failed to instantiate the main window event loop"
126            }
127        })
128    }
129}
130
131/// A set of callbacks for an active window. If a callback is not implemented,
132/// it will do nothing by default, so it is only necessary to implement the
133/// callbacks you actually need.
134pub trait WindowHandler<UserEventType = ()>
135{
136    /// Invoked once when the window first starts.
137    #[allow(unused_variables)]
138    #[inline]
139    fn on_start(
140        &mut self,
141        helper: &mut WindowHelper<UserEventType>,
142        info: WindowStartupInfo
143    )
144    {
145    }
146
147    /// Invoked when a user-defined event is received, allowing you to wake up
148    /// the event loop to handle events from other threads.
149    ///
150    /// See [WindowHelper::create_user_event_sender].
151    #[allow(unused_variables)]
152    #[inline]
153    fn on_user_event(
154        &mut self,
155        helper: &mut WindowHelper<UserEventType>,
156        user_event: UserEventType
157    )
158    {
159    }
160
161    /// Invoked when the window is resized.
162    #[allow(unused_variables)]
163    #[inline]
164    fn on_resize(&mut self, helper: &mut WindowHelper<UserEventType>, size_pixels: UVec2)
165    {
166    }
167
168    /// Invoked if the mouse cursor becomes grabbed or un-grabbed. See
169    /// [WindowHelper::set_cursor_grab].
170    ///
171    /// Note: mouse movement events will behave differently depending on the
172    /// current cursor grabbing status.
173    #[allow(unused_variables)]
174    #[inline]
175    fn on_mouse_grab_status_changed(
176        &mut self,
177        helper: &mut WindowHelper<UserEventType>,
178        mouse_grabbed: bool
179    )
180    {
181    }
182
183    /// Invoked if the window enters or exits fullscreen mode. See
184    /// [WindowHelper::set_fullscreen_mode].
185    #[allow(unused_variables)]
186    #[inline]
187    fn on_fullscreen_status_changed(
188        &mut self,
189        helper: &mut WindowHelper<UserEventType>,
190        fullscreen: bool
191    )
192    {
193    }
194
195    /// Invoked when the window scale factor changes.
196    #[allow(unused_variables)]
197    #[inline]
198    fn on_scale_factor_changed(
199        &mut self,
200        helper: &mut WindowHelper<UserEventType>,
201        scale_factor: f64
202    )
203    {
204    }
205
206    /// Invoked when the contents of the window needs to be redrawn.
207    ///
208    /// It is possible to request a redraw from any callback using
209    /// [WindowHelper::request_redraw].
210    #[allow(unused_variables)]
211    #[inline]
212    fn on_draw(
213        &mut self,
214        helper: &mut WindowHelper<UserEventType>,
215        graphics: &mut Graphics2D
216    )
217    {
218    }
219
220    /// Invoked when the mouse changes position.
221    ///
222    /// Normally, this provides the absolute  position of the mouse in the
223    /// window/canvas. However, if the mouse cursor is grabbed, this will
224    /// instead provide the amount of relative movement since the last move
225    /// event.
226    ///
227    /// See [WindowHandler::on_mouse_grab_status_changed].
228    #[allow(unused_variables)]
229    #[inline]
230    fn on_mouse_move(&mut self, helper: &mut WindowHelper<UserEventType>, position: Vec2)
231    {
232    }
233
234    /// Invoked when a mouse button is pressed.
235    #[allow(unused_variables)]
236    #[inline]
237    fn on_mouse_button_down(
238        &mut self,
239        helper: &mut WindowHelper<UserEventType>,
240        button: MouseButton
241    )
242    {
243    }
244
245    /// Invoked when a mouse button is released.
246    #[allow(unused_variables)]
247    #[inline]
248    fn on_mouse_button_up(
249        &mut self,
250        helper: &mut WindowHelper<UserEventType>,
251        button: MouseButton
252    )
253    {
254    }
255
256    /// Invoked when the mouse wheel moves.
257    #[allow(unused_variables)]
258    #[inline]
259    fn on_mouse_wheel_scroll(
260        &mut self,
261        helper: &mut WindowHelper<UserEventType>,
262        distance: MouseScrollDistance
263    )
264    {
265    }
266
267    /// Invoked when a keyboard key is pressed.
268    ///
269    /// To detect when a character is typed, see the
270    /// [WindowHandler::on_keyboard_char] callback.
271    #[allow(unused_variables)]
272    #[inline]
273    fn on_key_down(
274        &mut self,
275        helper: &mut WindowHelper<UserEventType>,
276        virtual_key_code: Option<VirtualKeyCode>,
277        scancode: KeyScancode
278    )
279    {
280    }
281
282    /// Invoked when a keyboard key is released.
283    #[allow(unused_variables)]
284    #[inline]
285    fn on_key_up(
286        &mut self,
287        helper: &mut WindowHelper<UserEventType>,
288        virtual_key_code: Option<VirtualKeyCode>,
289        scancode: KeyScancode
290    )
291    {
292    }
293
294    /// Invoked when a character is typed on the keyboard.
295    ///
296    /// This is invoked in addition to the [WindowHandler::on_key_up] and
297    /// [WindowHandler::on_key_down] callbacks.
298    #[allow(unused_variables)]
299    #[inline]
300    fn on_keyboard_char(
301        &mut self,
302        helper: &mut WindowHelper<UserEventType>,
303        unicode_codepoint: char
304    )
305    {
306    }
307
308    /// Invoked when the state of the modifier keys has changed.
309    #[allow(unused_variables)]
310    #[inline]
311    fn on_keyboard_modifiers_changed(
312        &mut self,
313        helper: &mut WindowHelper<UserEventType>,
314        state: ModifiersState
315    )
316    {
317    }
318}
319
320/// Boxed handlers delegate to their contents, so the multi-window machinery
321/// can store windows with differing handler types in one collection.
322impl<UserEventType, H> WindowHandler<UserEventType> for Box<H>
323where
324    H: WindowHandler<UserEventType> + ?Sized
325{
326    #[inline]
327    fn on_start(
328        &mut self,
329        helper: &mut WindowHelper<UserEventType>,
330        info: WindowStartupInfo
331    )
332    {
333        (**self).on_start(helper, info)
334    }
335
336    #[inline]
337    fn on_user_event(
338        &mut self,
339        helper: &mut WindowHelper<UserEventType>,
340        user_event: UserEventType
341    )
342    {
343        (**self).on_user_event(helper, user_event)
344    }
345
346    #[inline]
347    fn on_resize(&mut self, helper: &mut WindowHelper<UserEventType>, size_pixels: UVec2)
348    {
349        (**self).on_resize(helper, size_pixels)
350    }
351
352    #[inline]
353    fn on_mouse_grab_status_changed(
354        &mut self,
355        helper: &mut WindowHelper<UserEventType>,
356        mouse_grabbed: bool
357    )
358    {
359        (**self).on_mouse_grab_status_changed(helper, mouse_grabbed)
360    }
361
362    #[inline]
363    fn on_fullscreen_status_changed(
364        &mut self,
365        helper: &mut WindowHelper<UserEventType>,
366        fullscreen: bool
367    )
368    {
369        (**self).on_fullscreen_status_changed(helper, fullscreen)
370    }
371
372    #[inline]
373    fn on_scale_factor_changed(
374        &mut self,
375        helper: &mut WindowHelper<UserEventType>,
376        scale_factor: f64
377    )
378    {
379        (**self).on_scale_factor_changed(helper, scale_factor)
380    }
381
382    #[inline]
383    fn on_draw(
384        &mut self,
385        helper: &mut WindowHelper<UserEventType>,
386        graphics: &mut Graphics2D
387    )
388    {
389        (**self).on_draw(helper, graphics)
390    }
391
392    #[inline]
393    fn on_mouse_move(&mut self, helper: &mut WindowHelper<UserEventType>, position: Vec2)
394    {
395        (**self).on_mouse_move(helper, position)
396    }
397
398    #[inline]
399    fn on_mouse_button_down(
400        &mut self,
401        helper: &mut WindowHelper<UserEventType>,
402        button: MouseButton
403    )
404    {
405        (**self).on_mouse_button_down(helper, button)
406    }
407
408    #[inline]
409    fn on_mouse_button_up(
410        &mut self,
411        helper: &mut WindowHelper<UserEventType>,
412        button: MouseButton
413    )
414    {
415        (**self).on_mouse_button_up(helper, button)
416    }
417
418    #[inline]
419    fn on_mouse_wheel_scroll(
420        &mut self,
421        helper: &mut WindowHelper<UserEventType>,
422        distance: MouseScrollDistance
423    )
424    {
425        (**self).on_mouse_wheel_scroll(helper, distance)
426    }
427
428    #[inline]
429    fn on_key_down(
430        &mut self,
431        helper: &mut WindowHelper<UserEventType>,
432        virtual_key_code: Option<VirtualKeyCode>,
433        scancode: KeyScancode
434    )
435    {
436        (**self).on_key_down(helper, virtual_key_code, scancode)
437    }
438
439    #[inline]
440    fn on_key_up(
441        &mut self,
442        helper: &mut WindowHelper<UserEventType>,
443        virtual_key_code: Option<VirtualKeyCode>,
444        scancode: KeyScancode
445    )
446    {
447        (**self).on_key_up(helper, virtual_key_code, scancode)
448    }
449
450    #[inline]
451    fn on_keyboard_char(
452        &mut self,
453        helper: &mut WindowHelper<UserEventType>,
454        unicode_codepoint: char
455    )
456    {
457        (**self).on_keyboard_char(helper, unicode_codepoint)
458    }
459
460    #[inline]
461    fn on_keyboard_modifiers_changed(
462        &mut self,
463        helper: &mut WindowHelper<UserEventType>,
464        state: ModifiersState
465    )
466    {
467        (**self).on_keyboard_modifiers_changed(helper, state)
468    }
469}
470
471pub(crate) struct DrawingWindowHandler<UserEventType, H>
472where
473    UserEventType: 'static,
474    H: WindowHandler<UserEventType>
475{
476    window_handler: H,
477    renderer: GLRenderer,
478    phantom: PhantomData<UserEventType>
479}
480
481impl<UserEventType, H> DrawingWindowHandler<UserEventType, H>
482where
483    H: WindowHandler<UserEventType>,
484    UserEventType: 'static
485{
486    pub fn new(window_handler: H, renderer: GLRenderer) -> Self
487    {
488        DrawingWindowHandler {
489            window_handler,
490            renderer,
491            phantom: PhantomData
492        }
493    }
494
495    #[inline]
496    pub fn on_start(
497        &mut self,
498        helper: &mut WindowHelper<UserEventType>,
499        info: WindowStartupInfo
500    )
501    {
502        self.window_handler.on_start(helper, info);
503    }
504
505    #[inline]
506    pub fn on_user_event(
507        &mut self,
508        helper: &mut WindowHelper<UserEventType>,
509        user_event: UserEventType
510    )
511    {
512        self.window_handler.on_user_event(helper, user_event)
513    }
514
515    #[inline]
516    pub fn on_resize(
517        &mut self,
518        helper: &mut WindowHelper<UserEventType>,
519        size_pixels: UVec2
520    )
521    {
522        self.renderer.set_viewport_size_pixels(size_pixels);
523        self.window_handler.on_resize(helper, size_pixels)
524    }
525
526    #[inline]
527    pub fn on_mouse_grab_status_changed(
528        &mut self,
529        helper: &mut WindowHelper<UserEventType>,
530        mouse_grabbed: bool
531    )
532    {
533        self.window_handler
534            .on_mouse_grab_status_changed(helper, mouse_grabbed)
535    }
536
537    #[inline]
538    pub fn on_fullscreen_status_changed(
539        &mut self,
540        helper: &mut WindowHelper<UserEventType>,
541        fullscreen: bool
542    )
543    {
544        self.window_handler
545            .on_fullscreen_status_changed(helper, fullscreen)
546    }
547
548    #[inline]
549    pub fn on_scale_factor_changed(
550        &mut self,
551        helper: &mut WindowHelper<UserEventType>,
552        scale_factor: f64
553    )
554    {
555        self.window_handler
556            .on_scale_factor_changed(helper, scale_factor)
557    }
558
559    #[inline]
560    pub fn on_draw(&mut self, helper: &mut WindowHelper<UserEventType>)
561    {
562        let renderer = &mut self.renderer;
563        let window_handler = &mut self.window_handler;
564
565        renderer.draw_frame(|graphics| window_handler.on_draw(helper, graphics))
566    }
567
568    #[inline]
569    pub fn on_mouse_move(
570        &mut self,
571        helper: &mut WindowHelper<UserEventType>,
572        position: Vec2
573    )
574    {
575        self.window_handler.on_mouse_move(helper, position)
576    }
577
578    #[inline]
579    pub fn on_mouse_button_down(
580        &mut self,
581        helper: &mut WindowHelper<UserEventType>,
582        button: MouseButton
583    )
584    {
585        self.window_handler.on_mouse_button_down(helper, button)
586    }
587
588    #[inline]
589    pub fn on_mouse_button_up(
590        &mut self,
591        helper: &mut WindowHelper<UserEventType>,
592        button: MouseButton
593    )
594    {
595        self.window_handler.on_mouse_button_up(helper, button)
596    }
597
598    #[inline]
599    pub fn on_mouse_wheel_scroll(
600        &mut self,
601        helper: &mut WindowHelper<UserEventType>,
602        distance: MouseScrollDistance
603    )
604    {
605        self.window_handler.on_mouse_wheel_scroll(helper, distance)
606    }
607
608    #[inline]
609    pub fn on_key_down(
610        &mut self,
611        helper: &mut WindowHelper<UserEventType>,
612        virtual_key_code: Option<VirtualKeyCode>,
613        scancode: KeyScancode
614    )
615    {
616        self.window_handler
617            .on_key_down(helper, virtual_key_code, scancode)
618    }
619
620    #[inline]
621    pub fn on_key_up(
622        &mut self,
623        helper: &mut WindowHelper<UserEventType>,
624        virtual_key_code: Option<VirtualKeyCode>,
625        scancode: KeyScancode
626    )
627    {
628        self.window_handler
629            .on_key_up(helper, virtual_key_code, scancode)
630    }
631
632    #[inline]
633    pub fn on_keyboard_char(
634        &mut self,
635        helper: &mut WindowHelper<UserEventType>,
636        unicode_codepoint: char
637    )
638    {
639        self.window_handler
640            .on_keyboard_char(helper, unicode_codepoint)
641    }
642
643    #[inline]
644    pub fn on_keyboard_modifiers_changed(
645        &mut self,
646        helper: &mut WindowHelper<UserEventType>,
647        state: ModifiersState
648    )
649    {
650        self.window_handler
651            .on_keyboard_modifiers_changed(helper, state)
652    }
653}
654
655/// A set of helper methods to perform actions on a [crate::Window].
656pub struct WindowHelper<UserEventType = ()>
657where
658    UserEventType: 'static
659{
660    inner: WindowHelperInnerType<UserEventType>
661}
662
663impl<UserEventType> WindowHelper<UserEventType>
664{
665    pub(crate) fn new(inner: WindowHelperInnerType<UserEventType>) -> Self
666    {
667        WindowHelper { inner }
668    }
669
670    #[inline]
671    #[must_use]
672    pub(crate) fn inner(&mut self) -> &mut WindowHelperInnerType<UserEventType>
673    {
674        &mut self.inner
675    }
676
677    /// Causes the event loop to stop processing events, and terminate the
678    /// application.
679    ///
680    /// Note: The event loop will stop only once the current callback has
681    /// returned, rather than terminating immediately.
682    ///
683    /// Once the event loop has stopped, the entire process will end with error
684    /// code 0, even if other threads are running.
685    ///
686    /// If your `WindowHandler` struct implements `Drop`, it will be safely
687    /// destructed before exiting.
688    ///
689    /// No further callbacks will be given once this function has been called.
690    pub fn terminate_loop(&mut self)
691    {
692        self.inner.terminate_loop()
693    }
694
695    /// Sets the window icon from the provided RGBA pixels.
696    ///
697    /// On Windows, the base icon size is 16x16, however a multiple of this
698    /// (e.g. 32x32) should be provided for high-resolution displays.
699    ///
700    /// For `WebCanvas`, this function has no effect.
701    pub fn set_icon_from_rgba_pixels<S>(
702        &self,
703        data: Vec<u8>,
704        size: S
705    ) -> Result<(), BacktraceError<ErrorMessage>>
706    where
707        S: Into<UVec2>
708    {
709        self.inner.set_icon_from_rgba_pixels(data, size.into())
710    }
711
712    /// Sets the visibility of the mouse cursor.
713    pub fn set_cursor_visible(&self, visible: bool)
714    {
715        self.inner.set_cursor_visible(visible)
716    }
717
718    /// Grabs the cursor, preventing it from leaving the window.
719    pub fn set_cursor_grab(
720        &self,
721        grabbed: bool
722    ) -> Result<(), BacktraceError<ErrorMessage>>
723    {
724        self.inner.set_cursor_grab(grabbed)
725    }
726
727    /// Sets the shape of the mouse cursor shown over the window.
728    pub fn set_cursor(&self, cursor: MouseCursorType)
729    {
730        self.inner.set_cursor(cursor)
731    }
732
733    /// Set to false to prevent the user from resizing the window.
734    ///
735    /// For `WebCanvas`, this function has no effect.
736    pub fn set_resizable(&self, resizable: bool)
737    {
738        self.inner.set_resizable(resizable)
739    }
740
741    /// Sets whether the window is visible. Hiding the window (passing `false`)
742    /// keeps it and the event loop alive, so it can be shown again later by
743    /// passing `true`. This pairs with
744    /// [WindowCreationOptions::with_visible] (to start hidden) and
745    /// [WindowCreationOptions::with_hide_on_close] (to hide instead of exit),
746    /// allowing an application to live in the system tray.
747    ///
748    /// After re-showing a window you may want to call
749    /// [WindowHelper::request_redraw] to ensure its contents are drawn.
750    ///
751    /// For `WebCanvas`, this function has no effect.
752    pub fn set_visible(&self, visible: bool)
753    {
754        self.inner.set_visible(visible)
755    }
756
757    /// Request that the window is redrawn.
758    ///
759    /// This will cause the [WindowHandler::on_draw] callback to be invoked on
760    /// the next frame.
761    #[inline]
762    pub fn request_redraw(&self)
763    {
764        self.inner.request_redraw()
765    }
766
767    /// Sets the window title.
768    pub fn set_title<S: AsRef<str>>(&self, title: S)
769    {
770        self.inner.set_title(title.as_ref())
771    }
772
773    /// Sets the window fullscreen mode.
774    ///
775    /// When using a web canvas, permission for this operation may be denied,
776    /// depending on where this is called from, and the user's browser settings.
777    /// If the operation is successful, the
778    /// [WindowHandler::on_fullscreen_status_changed] callback will be invoked.
779    pub fn set_fullscreen_mode(&self, mode: WindowFullscreenMode)
780    {
781        self.inner.set_fullscreen_mode(mode)
782    }
783
784    /// Sets the window size in pixels. This is the window's inner size,
785    /// excluding the border.
786    ///
787    /// For `WebCanvas`, this function has no effect.
788    pub fn set_size_pixels<S: Into<UVec2>>(&self, size: S)
789    {
790        self.inner.set_size_pixels(size)
791    }
792
793    /// Gets the window size in pixels.
794    pub fn get_size_pixels(&self) -> UVec2
795    {
796        self.inner.get_size_pixels()
797    }
798
799    /// Sets the position of the window in pixels. If multiple monitors are in
800    /// use, this will be the distance from the top left of the display
801    /// area, spanning all the monitors.
802    ///
803    /// For `WebCanvas`, this function has no effect.
804    pub fn set_position_pixels<P: Into<IVec2>>(&self, position: P)
805    {
806        self.inner.set_position_pixels(position)
807    }
808
809    /// Sets the window size in scaled device-independent pixels. This is the
810    /// window's inner size, excluding the border.
811    ///
812    /// For `WebCanvas`, this function has no effect.
813    pub fn set_size_scaled_pixels<S: Into<Vec2>>(&self, size: S)
814    {
815        self.inner.set_size_scaled_pixels(size)
816    }
817
818    /// Sets the position of the window in scaled device-independent pixels. If
819    /// multiple monitors are in use, this will be the distance from the top
820    /// left of the display area, spanning all the monitors.
821    ///
822    /// For `WebCanvas`, this function has no effect.
823    pub fn set_position_scaled_pixels<P: Into<Vec2>>(&self, position: P)
824    {
825        self.inner.set_position_scaled_pixels(position)
826    }
827
828    /// Gets the window's scale factor.
829    #[inline]
830    #[must_use]
831    pub fn get_scale_factor(&self) -> f64
832    {
833        self.inner.get_scale_factor()
834    }
835
836    /// Creates a [UserEventSender], which can be used to post custom events to
837    /// this event loop from another thread.
838    ///
839    /// Events from a sender created here are delivered to **this window's**
840    /// handler. Senders created via [crate::Window::create_user_event_sender]
841    /// (before the loop starts) deliver to the main window.
842    ///
843    /// See [UserEventSender::send_event], [WindowHandler::on_user_event].
844    pub fn create_user_event_sender(&self) -> UserEventSender<UserEventType>
845    {
846        self.inner.create_user_event_sender()
847    }
848
849    /// Opens an additional window with its own handler, rendering context and
850    /// event routing. The window is created once the current callback
851    /// returns.
852    ///
853    /// Closing the main (first) window still exits the app; windows created
854    /// here close individually.
855    #[cfg(all(not(target_arch = "wasm32"), not(any(doc, doctest))))]
856    pub fn create_window(
857        &self,
858        title: &str,
859        options: WindowCreationOptions,
860        handler: Box<dyn WindowHandler<UserEventType>>
861    )
862    {
863        self.inner.create_window(title, options, handler, false);
864    }
865
866    /// Like [WindowHelper::create_window], but the new window is
867    /// application-modal: until it is closed, all other windows ignore mouse,
868    /// keyboard and close events, and clicking them refocuses the modal
869    /// window. Modal windows stack.
870    #[cfg(all(not(target_arch = "wasm32"), not(any(doc, doctest))))]
871    pub fn create_modal_window(
872        &self,
873        title: &str,
874        options: WindowCreationOptions,
875        handler: Box<dyn WindowHandler<UserEventType>>
876    )
877    {
878        self.inner.create_window(title, options, handler, true);
879    }
880
881    /// Closes this window once the current callback returns, dropping its
882    /// handler. If this is the main (first) window, the whole app exits.
883    #[cfg(all(not(target_arch = "wasm32"), not(any(doc, doctest))))]
884    pub fn close_window(&self)
885    {
886        self.inner.close_window();
887    }
888}
889
890#[cfg(any(doc, doctest, not(target_arch = "wasm32")))]
891#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
892#[must_use]
893pub(crate) enum WindowEventLoopAction
894{
895    /// Continue running the event loop.
896    Continue,
897
898    /// Stops the event loop. This will cause the entire process to end with
899    /// error code 0, even if other threads are running.
900    ///
901    /// No further callbacks will be given once a handler has returned this
902    /// value. The handler itself will be dropped before exiting.
903    Exit
904}
905
906/// Information about the starting state of the window.
907#[derive(Debug, PartialEq, Clone)]
908pub struct WindowStartupInfo
909{
910    viewport_size_pixels: UVec2,
911    scale_factor: f64
912}
913
914impl WindowStartupInfo
915{
916    pub(crate) fn new(viewport_size_pixels: UVec2, scale_factor: f64) -> Self
917    {
918        WindowStartupInfo {
919            viewport_size_pixels,
920            scale_factor
921        }
922    }
923
924    /// The scale factor of the window. When a high-dpi display is in use,
925    /// this will be greater than `1.0`.
926    pub fn scale_factor(&self) -> f64
927    {
928        self.scale_factor
929    }
930
931    /// The size of the viewport in pixels.
932    pub fn viewport_size_pixels(&self) -> &UVec2
933    {
934        &self.viewport_size_pixels
935    }
936}
937
938/// Identifies a mouse button.
939#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
940#[non_exhaustive]
941pub enum MouseButton
942{
943    /// The left mouse button.
944    Left,
945    /// The middle mouse button.
946    Middle,
947    /// The right mouse button.
948    Right,
949    /// The mouse back button.
950    Back,
951    /// The mouse forward button.
952    Forward,
953    /// Another mouse button, identified by a number.
954    Other(u16)
955}
956
957/// Identifies the shape of the mouse cursor displayed over the window. See
958/// [WindowHelper::set_cursor].
959///
960/// The variants mirror the standard CSS cursor keywords and map directly onto
961/// the native cursors provided by each platform backend.
962#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, Default)]
963#[non_exhaustive]
964pub enum MouseCursorType
965{
966    /// The platform-dependent default cursor (usually an arrow).
967    #[default]
968    Default,
969    /// A pointing hand, typically used to indicate a link.
970    Pointer,
971    /// A crosshair.
972    Crosshair,
973    /// Indicates editable text (usually an I-beam).
974    Text,
975    /// Indicates editable vertical text.
976    VerticalText,
977    /// Indicates that something can be moved.
978    Move,
979    /// Indicates that something can be grabbed (an open hand).
980    Grab,
981    /// Indicates that something is being grabbed (a closed hand).
982    Grabbing,
983    /// Indicates that the program is busy and the user should wait.
984    Wait,
985    /// Indicates that the program is busy in the background, but the user can
986    /// still interact with the interface.
987    Progress,
988    /// Indicates that a cell or set of cells may be selected.
989    Cell,
990    /// Indicates an alias of/shortcut to something is to be created.
991    Alias,
992    /// Indicates something is to be copied.
993    Copy,
994    /// Indicates that the dragged item cannot be dropped at the current
995    /// location.
996    NoDrop,
997    /// Indicates that the requested action will not be carried out.
998    NotAllowed,
999    /// Indicates that an edge of a box is to be moved left/right.
1000    ColResize,
1001    /// Indicates that an edge of a box is to be moved up/down.
1002    RowResize,
1003    /// Indicates a horizontal (east-west) resize.
1004    EwResize,
1005    /// Indicates a vertical (north-south) resize.
1006    NsResize,
1007    /// Indicates a bidirectional north-east/south-west resize.
1008    NeswResize,
1009    /// Indicates a bidirectional north-west/south-east resize.
1010    NwseResize,
1011    /// Indicates that something can be zoomed in.
1012    ZoomIn,
1013    /// Indicates that something can be zoomed out.
1014    ZoomOut
1015}
1016
1017/// Describes a difference in the mouse scroll wheel position.
1018#[derive(Debug, PartialEq, Clone, Copy)]
1019pub enum MouseScrollDistance
1020{
1021    /// Number of lines or rows to scroll in each direction. The `y` field
1022    /// represents the vertical scroll direction on a typical mouse wheel.
1023    Lines
1024    {
1025        /// The horizontal scroll distance. Negative values indicate scrolling
1026        /// left, and positive values indicate scrolling right.
1027        x: f64,
1028        /// The vertical scroll distance. Negative values indicate scrolling
1029        /// down, and positive values indicate scrolling up.
1030        y: f64,
1031        /// The forward/backward scroll distance, supported on some 3D mice.
1032        z: f64
1033    },
1034    /// Number of pixels to scroll in each direction. Scroll events are
1035    /// expressed in pixels if supported by the device (eg. a touchpad) and
1036    /// platform. The `y` field represents the vertical scroll direction on a
1037    /// typical mouse wheel.
1038    Pixels
1039    {
1040        /// The horizontal scroll distance. Negative values indicate scrolling
1041        /// left, and positive values indicate scrolling right.
1042        x: f64,
1043        /// The vertical scroll distance. Negative values indicate scrolling
1044        /// down, and positive values indicate scrolling up.
1045        y: f64,
1046        /// The forward/backward scroll distance, supported on some 3D mice.
1047        z: f64
1048    },
1049    /// Number of pages to scroll in each direction (only supported for
1050    /// WebCanvas). The `y` field represents the vertical scroll direction on a
1051    /// typical mouse wheel.
1052    Pages
1053    {
1054        /// The horizontal scroll distance. Negative values indicate scrolling
1055        /// left, and positive values indicate scrolling right.
1056        x: f64,
1057        /// The vertical scroll distance. Negative values indicate scrolling
1058        /// down, and positive values indicate scrolling up.
1059        y: f64,
1060        /// The forward/backward scroll distance, supported on some 3D mice.
1061        z: f64
1062    }
1063}
1064
1065/// A virtual key code.
1066#[allow(missing_docs)]
1067#[derive(Debug, Hash, Ord, PartialOrd, PartialEq, Eq, Clone, Copy)]
1068#[non_exhaustive]
1069pub enum VirtualKeyCode
1070{
1071    Key1,
1072    Key2,
1073    Key3,
1074    Key4,
1075    Key5,
1076    Key6,
1077    Key7,
1078    Key8,
1079    Key9,
1080    Key0,
1081
1082    A,
1083    B,
1084    C,
1085    D,
1086    E,
1087    F,
1088    G,
1089    H,
1090    I,
1091    J,
1092    K,
1093    L,
1094    M,
1095    N,
1096    O,
1097    P,
1098    Q,
1099    R,
1100    S,
1101    T,
1102    U,
1103    V,
1104    W,
1105    X,
1106    Y,
1107    Z,
1108
1109    Escape,
1110
1111    F1,
1112    F2,
1113    F3,
1114    F4,
1115    F5,
1116    F6,
1117    F7,
1118    F8,
1119    F9,
1120    F10,
1121    F11,
1122    F12,
1123    F13,
1124    F14,
1125    F15,
1126    F16,
1127    F17,
1128    F18,
1129    F19,
1130    F20,
1131    F21,
1132    F22,
1133    F23,
1134    F24,
1135
1136    PrintScreen,
1137    ScrollLock,
1138    PauseBreak,
1139
1140    Insert,
1141    Home,
1142    Delete,
1143    End,
1144    PageDown,
1145    PageUp,
1146
1147    Left,
1148    Up,
1149    Right,
1150    Down,
1151
1152    Backspace,
1153    Return,
1154    Space,
1155
1156    Compose,
1157
1158    Caret,
1159
1160    Numlock,
1161    Numpad0,
1162    Numpad1,
1163    Numpad2,
1164    Numpad3,
1165    Numpad4,
1166    Numpad5,
1167    Numpad6,
1168    Numpad7,
1169    Numpad8,
1170    Numpad9,
1171    NumpadAdd,
1172    NumpadDivide,
1173    NumpadDecimal,
1174    NumpadComma,
1175    NumpadEnter,
1176    NumpadEquals,
1177    NumpadMultiply,
1178    NumpadSubtract,
1179
1180    AbntC1,
1181    AbntC2,
1182    Apostrophe,
1183    Apps,
1184    Asterisk,
1185    At,
1186    Ax,
1187    Backslash,
1188    Calculator,
1189    Capital,
1190    Colon,
1191    Comma,
1192    Convert,
1193    Equals,
1194    Grave,
1195    Kana,
1196    Kanji,
1197    LAlt,
1198    LBracket,
1199    LControl,
1200    LShift,
1201    LWin,
1202    Mail,
1203    MediaSelect,
1204    MediaStop,
1205    Minus,
1206    Mute,
1207    MyComputer,
1208    NavigateForward,
1209    NavigateBackward,
1210    NextTrack,
1211    NoConvert,
1212    OEM102,
1213    Period,
1214    PlayPause,
1215    Plus,
1216    Power,
1217    PrevTrack,
1218    RAlt,
1219    RBracket,
1220    RControl,
1221    RShift,
1222    RWin,
1223    Semicolon,
1224    Slash,
1225    Sleep,
1226    Stop,
1227    Sysrq,
1228    Tab,
1229    Underline,
1230    Unlabeled,
1231    VolumeDown,
1232    VolumeUp,
1233    Wake,
1234    WebBack,
1235    WebFavorites,
1236    WebForward,
1237    WebHome,
1238    WebRefresh,
1239    WebSearch,
1240    WebStop,
1241    Yen,
1242    Copy,
1243    Paste,
1244    Cut
1245}
1246
1247/// The state of the modifier keys.
1248#[derive(Debug, Hash, PartialEq, Eq, Clone, Default)]
1249pub struct ModifiersState
1250{
1251    pub(crate) ctrl: bool,
1252    pub(crate) alt: bool,
1253    pub(crate) shift: bool,
1254    pub(crate) logo: bool
1255}
1256
1257impl ModifiersState
1258{
1259    /// This is true if the CTRL key is pressed.
1260    #[inline]
1261    #[must_use]
1262    pub fn ctrl(&self) -> bool
1263    {
1264        self.ctrl
1265    }
1266
1267    /// This is true if the ALT key is pressed.
1268    #[inline]
1269    #[must_use]
1270    pub fn alt(&self) -> bool
1271    {
1272        self.alt
1273    }
1274
1275    /// This is true if the SHIFT key is pressed.
1276    #[inline]
1277    #[must_use]
1278    pub fn shift(&self) -> bool
1279    {
1280        self.shift
1281    }
1282
1283    /// This is true if the logo key is pressed (normally the Windows key).
1284    #[inline]
1285    #[must_use]
1286    pub fn logo(&self) -> bool
1287    {
1288        self.logo
1289    }
1290}
1291
1292/// Configuration options about the mode in which the window should be created,
1293/// for example fullscreen or windowed.
1294#[derive(Debug, PartialEq, Clone)]
1295pub(crate) enum WindowCreationMode
1296{
1297    /// Create the window in non-fullscreen mode.
1298    Windowed
1299    {
1300        /// The size of the window.
1301        size: WindowSize,
1302
1303        /// The position of the window.
1304        position: Option<WindowPosition>
1305    },
1306
1307    /// Create the window in fullscreen borderless mode.
1308    FullscreenBorderless
1309}
1310
1311/// The size of the window to create.
1312#[derive(Debug, PartialEq, Clone)]
1313pub enum WindowSize
1314{
1315    /// Define the window size in pixels.
1316    PhysicalPixels(UVec2),
1317    /// Define the window size in device-independent scaled pixels.
1318    ScaledPixels(Vec2),
1319    /// Make the window fill the screen, except for a margin around the outer
1320    /// edges.
1321    MarginPhysicalPixels(u32),
1322    /// Make the window fill the screen, except for a margin around the outer
1323    /// edges.
1324    MarginScaledPixels(f32)
1325}
1326
1327/// The position of the window to create.
1328#[derive(Debug, Hash, PartialEq, Eq, Clone)]
1329pub enum WindowPosition
1330{
1331    /// Place the window in the center of the primary monitor.
1332    Center,
1333    /// Center the window over its parent window. Only meaningful for child
1334    /// windows opened via `WindowHelper::create_window` /
1335    /// `WindowHelper::create_modal_window`; falls back to
1336    /// [WindowPosition::Center] when there is no parent (e.g. the main
1337    /// window).
1338    CenterOnParent,
1339    /// Place the window at the specified pixel location from the top left of
1340    /// the primary monitor.
1341    PrimaryMonitorPixelsFromTopLeft(IVec2)
1342}
1343
1344/// Whether or not the window is in fullscreen mode.
1345#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
1346pub enum WindowFullscreenMode
1347{
1348    /// Non-fullscreen mode.
1349    Windowed,
1350    /// Fullscreen borderless mode.
1351    FullscreenBorderless
1352}
1353
1354/// Options used during the creation of a window.
1355#[derive(Debug, Clone, PartialEq)]
1356pub struct WindowCreationOptions
1357{
1358    pub(crate) mode: WindowCreationMode,
1359    pub(crate) multisampling: u16,
1360    pub(crate) vsync: bool,
1361    pub(crate) always_on_top: bool,
1362    pub(crate) resizable: bool,
1363    pub(crate) minimizable: bool,
1364    pub(crate) maximizable: bool,
1365    pub(crate) maximized: bool,
1366    pub(crate) transparent: bool,
1367    pub(crate) decorations: bool,
1368    pub(crate) visible: bool,
1369    pub(crate) hide_on_close: bool
1370}
1371
1372impl WindowCreationOptions
1373{
1374    /// Instantiates a new `WindowCreationOptions` structure with the default
1375    /// options, in non-fullscreen mode.
1376    pub fn new_windowed(size: WindowSize, position: Option<WindowPosition>) -> Self
1377    {
1378        Self::new(WindowCreationMode::Windowed { size, position })
1379    }
1380
1381    /// Instantiates a new `WindowCreationOptions` structure with the default
1382    /// options, in borderless fullscreen mode.
1383    #[inline]
1384    #[must_use]
1385    pub fn new_fullscreen_borderless() -> Self
1386    {
1387        Self::new(WindowCreationMode::FullscreenBorderless)
1388    }
1389
1390    #[inline]
1391    #[must_use]
1392    fn new(mode: WindowCreationMode) -> Self
1393    {
1394        WindowCreationOptions {
1395            mode,
1396            multisampling: 16,
1397            vsync: true,
1398            always_on_top: false,
1399            resizable: true,
1400            minimizable: true,
1401            maximizable: true,
1402            maximized: false,
1403            decorations: true,
1404            transparent: false,
1405            visible: true,
1406            hide_on_close: false
1407        }
1408    }
1409
1410    /// Sets the maximum level of multisampling which will be applied. By
1411    /// default this is set to `16`.
1412    ///
1413    /// Note that this depends on platform support, and setting this may have no
1414    /// effect.
1415    #[inline]
1416    #[must_use]
1417    pub fn with_multisampling(mut self, multisampling: u16) -> Self
1418    {
1419        self.multisampling = multisampling;
1420        self
1421    }
1422
1423    /// Sets whether or not vsync should be enabled. This can increase latency,
1424    /// but should eliminate tearing. By default this is set to `true`.
1425    ///
1426    /// Note that this depends on platform support, and setting this may have no
1427    /// effect.
1428    #[inline]
1429    #[must_use]
1430    pub fn with_vsync(mut self, vsync: bool) -> Self
1431    {
1432        self.vsync = vsync;
1433        self
1434    }
1435
1436    /// Sets whether or not the window can be resized by the user. The default
1437    /// is `true`.
1438    #[inline]
1439    #[must_use]
1440    pub fn with_resizable(mut self, resizable: bool) -> Self
1441    {
1442        self.resizable = resizable;
1443        self
1444    }
1445
1446    /// Sets whether the window shows an enabled minimize button. The default is
1447    /// `true`.
1448    ///
1449    /// Note that this depends on platform support, and setting this may have no
1450    /// effect.
1451    #[inline]
1452    #[must_use]
1453    pub fn with_minimizable(mut self, minimizable: bool) -> Self
1454    {
1455        self.minimizable = minimizable;
1456        self
1457    }
1458
1459    /// Sets whether the window shows an enabled maximize button. The default is
1460    /// `true`. Note that a non-resizable window also can't be maximized on most
1461    /// platforms.
1462    ///
1463    /// Note that this depends on platform support, and setting this may have no
1464    /// effect.
1465    #[inline]
1466    #[must_use]
1467    pub fn with_maximizable(mut self, maximizable: bool) -> Self
1468    {
1469        self.maximizable = maximizable;
1470        self
1471    }
1472
1473    /// If set to `true`, the window will be placed above other windows. The
1474    /// default is `false`.
1475    #[inline]
1476    #[must_use]
1477    pub fn with_always_on_top(mut self, always_on_top: bool) -> Self
1478    {
1479        self.always_on_top = always_on_top;
1480        self
1481    }
1482
1483    /// If set to `true`, the window will be initially maximized. The default is
1484    /// `false`.
1485    #[inline]
1486    #[must_use]
1487    pub fn with_maximized(mut self, maximized: bool) -> Self
1488    {
1489        self.maximized = maximized;
1490        self
1491    }
1492
1493    /// If set to `false`, the window will have no border.  The default is
1494    /// `true`.
1495    #[inline]
1496    #[must_use]
1497    pub fn with_decorations(mut self, decorations: bool) -> Self
1498    {
1499        self.decorations = decorations;
1500        self
1501    }
1502
1503    /// Sets whether the background of the window should be transparent. The
1504    /// default is `false`.
1505    ///
1506    /// Note that this depends on platform support, and setting this may have no
1507    /// effect.
1508    #[inline]
1509    #[must_use]
1510    pub fn with_transparent(mut self, transparent: bool) -> Self
1511    {
1512        self.transparent = transparent;
1513        self
1514    }
1515
1516    /// If set to `false`, the window will not be shown when it is created. It
1517    /// can be shown later using [WindowHelper::set_visible]. This is useful for
1518    /// applications that live in the system tray and only show a window on
1519    /// demand. The default is `true`.
1520    ///
1521    /// For `WebCanvas`, this option has no effect.
1522    #[inline]
1523    #[must_use]
1524    pub fn with_visible(mut self, visible: bool) -> Self
1525    {
1526        self.visible = visible;
1527        self
1528    }
1529
1530    /// If set to `true`, clicking the window's close button will hide the
1531    /// window instead of closing it and terminating the application. The window
1532    /// can be shown again using [WindowHelper::set_visible]. This is useful for
1533    /// applications that should keep running in the system tray after the
1534    /// window is closed. The default is `false`.
1535    ///
1536    /// This applies to every window created with these options, including the
1537    /// main window. Note that with this enabled, closing the main window no
1538    /// longer exits the app; use [WindowHelper::terminate_loop] for that.
1539    ///
1540    /// For `WebCanvas`, this option has no effect.
1541    #[inline]
1542    #[must_use]
1543    pub fn with_hide_on_close(mut self, hide_on_close: bool) -> Self
1544    {
1545        self.hide_on_close = hide_on_close;
1546        self
1547    }
1548}
1549
1550/// Type representing a keyboard scancode.
1551pub type KeyScancode = u32;