1use 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#[derive(Clone, Debug, Hash, Eq, PartialEq, Copy)]
48pub enum EventLoopSendError
49{
50 EventLoopNoLongerExists
52}
53
54pub 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 #[inline]
84 pub fn send_event(&self, event: UserEventType) -> Result<(), EventLoopSendError>
85 {
86 self.inner.send_event(event)
87 }
88}
89
90#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
92#[non_exhaustive]
93pub enum WindowCreationError
94{
95 PrimaryMonitorNotFound,
97 SuitableContextNotFound,
101 MakeContextCurrentFailed,
103 RendererCreationFailed,
105 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
131pub trait WindowHandler<UserEventType = ()>
135{
136 #[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 #[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 #[allow(unused_variables)]
163 #[inline]
164 fn on_resize(&mut self, helper: &mut WindowHelper<UserEventType>, size_pixels: UVec2)
165 {
166 }
167
168 #[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 #[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 #[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 #[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 #[allow(unused_variables)]
229 #[inline]
230 fn on_mouse_move(&mut self, helper: &mut WindowHelper<UserEventType>, position: Vec2)
231 {
232 }
233
234 #[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 #[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 #[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 #[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 #[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 #[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 #[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
320pub(crate) struct DrawingWindowHandler<UserEventType, H>
321where
322 UserEventType: 'static,
323 H: WindowHandler<UserEventType>
324{
325 window_handler: H,
326 renderer: GLRenderer,
327 phantom: PhantomData<UserEventType>
328}
329
330impl<UserEventType, H> DrawingWindowHandler<UserEventType, H>
331where
332 H: WindowHandler<UserEventType>,
333 UserEventType: 'static
334{
335 pub fn new(window_handler: H, renderer: GLRenderer) -> Self
336 {
337 DrawingWindowHandler {
338 window_handler,
339 renderer,
340 phantom: PhantomData
341 }
342 }
343
344 #[inline]
345 pub fn on_start(
346 &mut self,
347 helper: &mut WindowHelper<UserEventType>,
348 info: WindowStartupInfo
349 )
350 {
351 self.window_handler.on_start(helper, info);
352 }
353
354 #[inline]
355 pub fn on_user_event(
356 &mut self,
357 helper: &mut WindowHelper<UserEventType>,
358 user_event: UserEventType
359 )
360 {
361 self.window_handler.on_user_event(helper, user_event)
362 }
363
364 #[inline]
365 pub fn on_resize(
366 &mut self,
367 helper: &mut WindowHelper<UserEventType>,
368 size_pixels: UVec2
369 )
370 {
371 self.renderer.set_viewport_size_pixels(size_pixels);
372 self.window_handler.on_resize(helper, size_pixels)
373 }
374
375 #[inline]
376 pub fn on_mouse_grab_status_changed(
377 &mut self,
378 helper: &mut WindowHelper<UserEventType>,
379 mouse_grabbed: bool
380 )
381 {
382 self.window_handler
383 .on_mouse_grab_status_changed(helper, mouse_grabbed)
384 }
385
386 #[inline]
387 pub fn on_fullscreen_status_changed(
388 &mut self,
389 helper: &mut WindowHelper<UserEventType>,
390 fullscreen: bool
391 )
392 {
393 self.window_handler
394 .on_fullscreen_status_changed(helper, fullscreen)
395 }
396
397 #[inline]
398 pub fn on_scale_factor_changed(
399 &mut self,
400 helper: &mut WindowHelper<UserEventType>,
401 scale_factor: f64
402 )
403 {
404 self.window_handler
405 .on_scale_factor_changed(helper, scale_factor)
406 }
407
408 #[inline]
409 pub fn on_draw(&mut self, helper: &mut WindowHelper<UserEventType>)
410 {
411 let renderer = &mut self.renderer;
412 let window_handler = &mut self.window_handler;
413
414 renderer.draw_frame(|graphics| window_handler.on_draw(helper, graphics))
415 }
416
417 #[inline]
418 pub fn on_mouse_move(
419 &mut self,
420 helper: &mut WindowHelper<UserEventType>,
421 position: Vec2
422 )
423 {
424 self.window_handler.on_mouse_move(helper, position)
425 }
426
427 #[inline]
428 pub fn on_mouse_button_down(
429 &mut self,
430 helper: &mut WindowHelper<UserEventType>,
431 button: MouseButton
432 )
433 {
434 self.window_handler.on_mouse_button_down(helper, button)
435 }
436
437 #[inline]
438 pub fn on_mouse_button_up(
439 &mut self,
440 helper: &mut WindowHelper<UserEventType>,
441 button: MouseButton
442 )
443 {
444 self.window_handler.on_mouse_button_up(helper, button)
445 }
446
447 #[inline]
448 pub fn on_mouse_wheel_scroll(
449 &mut self,
450 helper: &mut WindowHelper<UserEventType>,
451 distance: MouseScrollDistance
452 )
453 {
454 self.window_handler.on_mouse_wheel_scroll(helper, distance)
455 }
456
457 #[inline]
458 pub fn on_key_down(
459 &mut self,
460 helper: &mut WindowHelper<UserEventType>,
461 virtual_key_code: Option<VirtualKeyCode>,
462 scancode: KeyScancode
463 )
464 {
465 self.window_handler
466 .on_key_down(helper, virtual_key_code, scancode)
467 }
468
469 #[inline]
470 pub fn on_key_up(
471 &mut self,
472 helper: &mut WindowHelper<UserEventType>,
473 virtual_key_code: Option<VirtualKeyCode>,
474 scancode: KeyScancode
475 )
476 {
477 self.window_handler
478 .on_key_up(helper, virtual_key_code, scancode)
479 }
480
481 #[inline]
482 pub fn on_keyboard_char(
483 &mut self,
484 helper: &mut WindowHelper<UserEventType>,
485 unicode_codepoint: char
486 )
487 {
488 self.window_handler
489 .on_keyboard_char(helper, unicode_codepoint)
490 }
491
492 #[inline]
493 pub fn on_keyboard_modifiers_changed(
494 &mut self,
495 helper: &mut WindowHelper<UserEventType>,
496 state: ModifiersState
497 )
498 {
499 self.window_handler
500 .on_keyboard_modifiers_changed(helper, state)
501 }
502}
503
504pub struct WindowHelper<UserEventType = ()>
506where
507 UserEventType: 'static
508{
509 inner: WindowHelperInnerType<UserEventType>
510}
511
512impl<UserEventType> WindowHelper<UserEventType>
513{
514 pub(crate) fn new(inner: WindowHelperInnerType<UserEventType>) -> Self
515 {
516 WindowHelper { inner }
517 }
518
519 #[inline]
520 #[must_use]
521 pub(crate) fn inner(&mut self) -> &mut WindowHelperInnerType<UserEventType>
522 {
523 &mut self.inner
524 }
525
526 pub fn terminate_loop(&mut self)
540 {
541 self.inner.terminate_loop()
542 }
543
544 pub fn set_icon_from_rgba_pixels<S>(
551 &self,
552 data: Vec<u8>,
553 size: S
554 ) -> Result<(), BacktraceError<ErrorMessage>>
555 where
556 S: Into<UVec2>
557 {
558 self.inner.set_icon_from_rgba_pixels(data, size.into())
559 }
560
561 pub fn set_cursor_visible(&self, visible: bool)
563 {
564 self.inner.set_cursor_visible(visible)
565 }
566
567 pub fn set_cursor_grab(
569 &self,
570 grabbed: bool
571 ) -> Result<(), BacktraceError<ErrorMessage>>
572 {
573 self.inner.set_cursor_grab(grabbed)
574 }
575
576 pub fn set_resizable(&self, resizable: bool)
580 {
581 self.inner.set_resizable(resizable)
582 }
583
584 #[inline]
589 pub fn request_redraw(&self)
590 {
591 self.inner.request_redraw()
592 }
593
594 pub fn set_title<S: AsRef<str>>(&self, title: S)
596 {
597 self.inner.set_title(title.as_ref())
598 }
599
600 pub fn set_fullscreen_mode(&self, mode: WindowFullscreenMode)
607 {
608 self.inner.set_fullscreen_mode(mode)
609 }
610
611 pub fn set_size_pixels<S: Into<UVec2>>(&self, size: S)
616 {
617 self.inner.set_size_pixels(size)
618 }
619
620 pub fn get_size_pixels(&self) -> UVec2
622 {
623 self.inner.get_size_pixels()
624 }
625
626 pub fn set_position_pixels<P: Into<IVec2>>(&self, position: P)
632 {
633 self.inner.set_position_pixels(position)
634 }
635
636 pub fn set_size_scaled_pixels<S: Into<Vec2>>(&self, size: S)
641 {
642 self.inner.set_size_scaled_pixels(size)
643 }
644
645 pub fn set_position_scaled_pixels<P: Into<Vec2>>(&self, position: P)
651 {
652 self.inner.set_position_scaled_pixels(position)
653 }
654
655 #[inline]
657 #[must_use]
658 pub fn get_scale_factor(&self) -> f64
659 {
660 self.inner.get_scale_factor()
661 }
662
663 pub fn create_user_event_sender(&self) -> UserEventSender<UserEventType>
668 {
669 self.inner.create_user_event_sender()
670 }
671}
672
673#[cfg(any(doc, doctest, not(target_arch = "wasm32")))]
674#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
675#[must_use]
676pub(crate) enum WindowEventLoopAction
677{
678 Continue,
680
681 Exit
687}
688
689#[derive(Debug, PartialEq, Clone)]
691pub struct WindowStartupInfo
692{
693 viewport_size_pixels: UVec2,
694 scale_factor: f64
695}
696
697impl WindowStartupInfo
698{
699 pub(crate) fn new(viewport_size_pixels: UVec2, scale_factor: f64) -> Self
700 {
701 WindowStartupInfo {
702 viewport_size_pixels,
703 scale_factor
704 }
705 }
706
707 pub fn scale_factor(&self) -> f64
710 {
711 self.scale_factor
712 }
713
714 pub fn viewport_size_pixels(&self) -> &UVec2
716 {
717 &self.viewport_size_pixels
718 }
719}
720
721#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
723#[non_exhaustive]
724pub enum MouseButton
725{
726 Left,
728 Middle,
730 Right,
732 Back,
734 Forward,
736 Other(u16)
738}
739
740#[derive(Debug, PartialEq, Clone, Copy)]
742pub enum MouseScrollDistance
743{
744 Lines
747 {
748 x: f64,
751 y: f64,
754 z: f64
756 },
757 Pixels
762 {
763 x: f64,
766 y: f64,
769 z: f64
771 },
772 Pages
776 {
777 x: f64,
780 y: f64,
783 z: f64
785 }
786}
787
788#[allow(missing_docs)]
790#[derive(Debug, Hash, Ord, PartialOrd, PartialEq, Eq, Clone, Copy)]
791#[non_exhaustive]
792pub enum VirtualKeyCode
793{
794 Key1,
795 Key2,
796 Key3,
797 Key4,
798 Key5,
799 Key6,
800 Key7,
801 Key8,
802 Key9,
803 Key0,
804
805 A,
806 B,
807 C,
808 D,
809 E,
810 F,
811 G,
812 H,
813 I,
814 J,
815 K,
816 L,
817 M,
818 N,
819 O,
820 P,
821 Q,
822 R,
823 S,
824 T,
825 U,
826 V,
827 W,
828 X,
829 Y,
830 Z,
831
832 Escape,
833
834 F1,
835 F2,
836 F3,
837 F4,
838 F5,
839 F6,
840 F7,
841 F8,
842 F9,
843 F10,
844 F11,
845 F12,
846 F13,
847 F14,
848 F15,
849 F16,
850 F17,
851 F18,
852 F19,
853 F20,
854 F21,
855 F22,
856 F23,
857 F24,
858
859 PrintScreen,
860 ScrollLock,
861 PauseBreak,
862
863 Insert,
864 Home,
865 Delete,
866 End,
867 PageDown,
868 PageUp,
869
870 Left,
871 Up,
872 Right,
873 Down,
874
875 Backspace,
876 Return,
877 Space,
878
879 Compose,
880
881 Caret,
882
883 Numlock,
884 Numpad0,
885 Numpad1,
886 Numpad2,
887 Numpad3,
888 Numpad4,
889 Numpad5,
890 Numpad6,
891 Numpad7,
892 Numpad8,
893 Numpad9,
894 NumpadAdd,
895 NumpadDivide,
896 NumpadDecimal,
897 NumpadComma,
898 NumpadEnter,
899 NumpadEquals,
900 NumpadMultiply,
901 NumpadSubtract,
902
903 AbntC1,
904 AbntC2,
905 Apostrophe,
906 Apps,
907 Asterisk,
908 At,
909 Ax,
910 Backslash,
911 Calculator,
912 Capital,
913 Colon,
914 Comma,
915 Convert,
916 Equals,
917 Grave,
918 Kana,
919 Kanji,
920 LAlt,
921 LBracket,
922 LControl,
923 LShift,
924 LWin,
925 Mail,
926 MediaSelect,
927 MediaStop,
928 Minus,
929 Mute,
930 MyComputer,
931 NavigateForward,
932 NavigateBackward,
933 NextTrack,
934 NoConvert,
935 OEM102,
936 Period,
937 PlayPause,
938 Plus,
939 Power,
940 PrevTrack,
941 RAlt,
942 RBracket,
943 RControl,
944 RShift,
945 RWin,
946 Semicolon,
947 Slash,
948 Sleep,
949 Stop,
950 Sysrq,
951 Tab,
952 Underline,
953 Unlabeled,
954 VolumeDown,
955 VolumeUp,
956 Wake,
957 WebBack,
958 WebFavorites,
959 WebForward,
960 WebHome,
961 WebRefresh,
962 WebSearch,
963 WebStop,
964 Yen,
965 Copy,
966 Paste,
967 Cut
968}
969
970#[derive(Debug, Hash, PartialEq, Eq, Clone, Default)]
972pub struct ModifiersState
973{
974 pub(crate) ctrl: bool,
975 pub(crate) alt: bool,
976 pub(crate) shift: bool,
977 pub(crate) logo: bool
978}
979
980impl ModifiersState
981{
982 #[inline]
984 #[must_use]
985 pub fn ctrl(&self) -> bool
986 {
987 self.ctrl
988 }
989
990 #[inline]
992 #[must_use]
993 pub fn alt(&self) -> bool
994 {
995 self.alt
996 }
997
998 #[inline]
1000 #[must_use]
1001 pub fn shift(&self) -> bool
1002 {
1003 self.shift
1004 }
1005
1006 #[inline]
1008 #[must_use]
1009 pub fn logo(&self) -> bool
1010 {
1011 self.logo
1012 }
1013}
1014
1015#[derive(Debug, PartialEq, Clone)]
1018pub(crate) enum WindowCreationMode
1019{
1020 Windowed
1022 {
1023 size: WindowSize,
1025
1026 position: Option<WindowPosition>
1028 },
1029
1030 FullscreenBorderless
1032}
1033
1034#[derive(Debug, PartialEq, Clone)]
1036pub enum WindowSize
1037{
1038 PhysicalPixels(UVec2),
1040 ScaledPixels(Vec2),
1042 MarginPhysicalPixels(u32),
1045 MarginScaledPixels(f32)
1048}
1049
1050#[derive(Debug, Hash, PartialEq, Eq, Clone)]
1052pub enum WindowPosition
1053{
1054 Center,
1056 PrimaryMonitorPixelsFromTopLeft(IVec2)
1059}
1060
1061#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
1063pub enum WindowFullscreenMode
1064{
1065 Windowed,
1067 FullscreenBorderless
1069}
1070
1071#[derive(Debug, Clone, PartialEq)]
1073pub struct WindowCreationOptions
1074{
1075 pub(crate) mode: WindowCreationMode,
1076 pub(crate) multisampling: u16,
1077 pub(crate) vsync: bool,
1078 pub(crate) always_on_top: bool,
1079 pub(crate) resizable: bool,
1080 pub(crate) maximized: bool,
1081 pub(crate) transparent: bool,
1082 pub(crate) decorations: bool
1083}
1084
1085impl WindowCreationOptions
1086{
1087 pub fn new_windowed(size: WindowSize, position: Option<WindowPosition>) -> Self
1090 {
1091 Self::new(WindowCreationMode::Windowed { size, position })
1092 }
1093
1094 #[inline]
1097 #[must_use]
1098 pub fn new_fullscreen_borderless() -> Self
1099 {
1100 Self::new(WindowCreationMode::FullscreenBorderless)
1101 }
1102
1103 #[inline]
1104 #[must_use]
1105 fn new(mode: WindowCreationMode) -> Self
1106 {
1107 WindowCreationOptions {
1108 mode,
1109 multisampling: 16,
1110 vsync: true,
1111 always_on_top: false,
1112 resizable: true,
1113 maximized: false,
1114 decorations: true,
1115 transparent: false
1116 }
1117 }
1118
1119 #[inline]
1125 #[must_use]
1126 pub fn with_multisampling(mut self, multisampling: u16) -> Self
1127 {
1128 self.multisampling = multisampling;
1129 self
1130 }
1131
1132 #[inline]
1138 #[must_use]
1139 pub fn with_vsync(mut self, vsync: bool) -> Self
1140 {
1141 self.vsync = vsync;
1142 self
1143 }
1144
1145 #[inline]
1148 #[must_use]
1149 pub fn with_resizable(mut self, resizable: bool) -> Self
1150 {
1151 self.resizable = resizable;
1152 self
1153 }
1154
1155 #[inline]
1158 #[must_use]
1159 pub fn with_always_on_top(mut self, always_on_top: bool) -> Self
1160 {
1161 self.always_on_top = always_on_top;
1162 self
1163 }
1164
1165 #[inline]
1168 #[must_use]
1169 pub fn with_maximized(mut self, maximized: bool) -> Self
1170 {
1171 self.maximized = maximized;
1172 self
1173 }
1174
1175 #[inline]
1178 #[must_use]
1179 pub fn with_decorations(mut self, decorations: bool) -> Self
1180 {
1181 self.decorations = decorations;
1182 self
1183 }
1184
1185 #[inline]
1191 #[must_use]
1192 pub fn with_transparent(mut self, transparent: bool) -> Self
1193 {
1194 self.transparent = transparent;
1195 self
1196 }
1197}
1198
1199pub type KeyScancode = u32;