use std::fmt::{Display, Formatter};
use std::marker::PhantomData;
use crate::dimen::{IVec2, UVec2, Vec2};
use crate::error::{BacktraceError, ErrorMessage};
use crate::{GLRenderer, Graphics2D};
#[cfg(all(not(target_arch = "wasm32"), not(any(doc, doctest))))]
type WindowHelperInnerType<UserEventType> =
crate::window_internal_glutin::WindowHelperGlutin<UserEventType>;
#[cfg(all(not(target_arch = "wasm32"), not(any(doc, doctest))))]
type UserEventSenderInnerType<UserEventType> =
crate::window_internal_glutin::UserEventSenderGlutin<UserEventType>;
#[cfg(all(target_arch = "wasm32", not(any(doc, doctest))))]
type WindowHelperInnerType<UserEventType> =
crate::window_internal_web::WindowHelperWeb<UserEventType>;
#[cfg(all(target_arch = "wasm32", not(any(doc, doctest))))]
type UserEventSenderInnerType<UserEventType> =
crate::window_internal_web::UserEventSenderWeb<UserEventType>;
#[cfg(any(doc, doctest))]
type WindowHelperInnerType<UserEventType> = PhantomData<UserEventType>;
#[cfg(any(doc, doctest))]
type UserEventSenderInnerType<UserEventType> = PhantomData<UserEventType>;
#[derive(Clone, Debug, Hash, Eq, PartialEq, Copy)]
pub enum EventLoopSendError
{
EventLoopNoLongerExists
}
pub struct UserEventSender<UserEventType: 'static>
{
inner: UserEventSenderInnerType<UserEventType>
}
impl<UserEventType> Clone for UserEventSender<UserEventType>
{
fn clone(&self) -> Self
{
UserEventSender {
inner: self.inner.clone()
}
}
}
impl<UserEventType> UserEventSender<UserEventType>
{
pub(crate) fn new(inner: UserEventSenderInnerType<UserEventType>) -> Self
{
Self { inner }
}
#[inline]
pub fn send_event(&self, event: UserEventType) -> Result<(), EventLoopSendError>
{
self.inner.send_event(event)
}
}
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
#[non_exhaustive]
pub enum WindowCreationError
{
PrimaryMonitorNotFound,
SuitableContextNotFound,
MakeContextCurrentFailed,
RendererCreationFailed,
EventLoopCreationFailed
}
impl Display for WindowCreationError
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result
{
f.write_str(match self {
WindowCreationError::PrimaryMonitorNotFound => "Primary monitor not found",
WindowCreationError::SuitableContextNotFound => {
"Could not find a suitable graphics context"
}
WindowCreationError::MakeContextCurrentFailed => {
"Failed to make the graphics context current"
}
WindowCreationError::RendererCreationFailed => {
"Failed to create the renderer"
}
WindowCreationError::EventLoopCreationFailed => {
"Failed to instantiate the main window event loop"
}
})
}
}
pub trait WindowHandler<UserEventType = ()>
{
#[allow(unused_variables)]
#[inline]
fn on_start(
&mut self,
helper: &mut WindowHelper<UserEventType>,
info: WindowStartupInfo
)
{
}
#[allow(unused_variables)]
#[inline]
fn on_user_event(
&mut self,
helper: &mut WindowHelper<UserEventType>,
user_event: UserEventType
)
{
}
#[allow(unused_variables)]
#[inline]
fn on_resize(&mut self, helper: &mut WindowHelper<UserEventType>, size_pixels: UVec2)
{
}
#[allow(unused_variables)]
#[inline]
fn on_mouse_grab_status_changed(
&mut self,
helper: &mut WindowHelper<UserEventType>,
mouse_grabbed: bool
)
{
}
#[allow(unused_variables)]
#[inline]
fn on_fullscreen_status_changed(
&mut self,
helper: &mut WindowHelper<UserEventType>,
fullscreen: bool
)
{
}
#[allow(unused_variables)]
#[inline]
fn on_scale_factor_changed(
&mut self,
helper: &mut WindowHelper<UserEventType>,
scale_factor: f64
)
{
}
#[allow(unused_variables)]
#[inline]
fn on_draw(
&mut self,
helper: &mut WindowHelper<UserEventType>,
graphics: &mut Graphics2D
)
{
}
#[allow(unused_variables)]
#[inline]
fn on_mouse_move(&mut self, helper: &mut WindowHelper<UserEventType>, position: Vec2)
{
}
#[allow(unused_variables)]
#[inline]
fn on_mouse_button_down(
&mut self,
helper: &mut WindowHelper<UserEventType>,
button: MouseButton
)
{
}
#[allow(unused_variables)]
#[inline]
fn on_mouse_button_up(
&mut self,
helper: &mut WindowHelper<UserEventType>,
button: MouseButton
)
{
}
#[allow(unused_variables)]
#[inline]
fn on_mouse_wheel_scroll(
&mut self,
helper: &mut WindowHelper<UserEventType>,
distance: MouseScrollDistance
)
{
}
#[allow(unused_variables)]
#[inline]
fn on_key_down(
&mut self,
helper: &mut WindowHelper<UserEventType>,
virtual_key_code: Option<VirtualKeyCode>,
scancode: KeyScancode
)
{
}
#[allow(unused_variables)]
#[inline]
fn on_key_up(
&mut self,
helper: &mut WindowHelper<UserEventType>,
virtual_key_code: Option<VirtualKeyCode>,
scancode: KeyScancode
)
{
}
#[allow(unused_variables)]
#[inline]
fn on_keyboard_char(
&mut self,
helper: &mut WindowHelper<UserEventType>,
unicode_codepoint: char
)
{
}
#[allow(unused_variables)]
#[inline]
fn on_keyboard_modifiers_changed(
&mut self,
helper: &mut WindowHelper<UserEventType>,
state: ModifiersState
)
{
}
}
pub(crate) struct DrawingWindowHandler<UserEventType, H>
where
UserEventType: 'static,
H: WindowHandler<UserEventType>
{
window_handler: H,
renderer: GLRenderer,
phantom: PhantomData<UserEventType>
}
impl<UserEventType, H> DrawingWindowHandler<UserEventType, H>
where
H: WindowHandler<UserEventType>,
UserEventType: 'static
{
pub fn new(window_handler: H, renderer: GLRenderer) -> Self
{
DrawingWindowHandler {
window_handler,
renderer,
phantom: PhantomData
}
}
#[inline]
pub fn on_start(
&mut self,
helper: &mut WindowHelper<UserEventType>,
info: WindowStartupInfo
)
{
self.window_handler.on_start(helper, info);
}
#[inline]
pub fn on_user_event(
&mut self,
helper: &mut WindowHelper<UserEventType>,
user_event: UserEventType
)
{
self.window_handler.on_user_event(helper, user_event)
}
#[inline]
pub fn on_resize(
&mut self,
helper: &mut WindowHelper<UserEventType>,
size_pixels: UVec2
)
{
self.renderer.set_viewport_size_pixels(size_pixels);
self.window_handler.on_resize(helper, size_pixels)
}
#[inline]
pub fn on_mouse_grab_status_changed(
&mut self,
helper: &mut WindowHelper<UserEventType>,
mouse_grabbed: bool
)
{
self.window_handler
.on_mouse_grab_status_changed(helper, mouse_grabbed)
}
#[inline]
pub fn on_fullscreen_status_changed(
&mut self,
helper: &mut WindowHelper<UserEventType>,
fullscreen: bool
)
{
self.window_handler
.on_fullscreen_status_changed(helper, fullscreen)
}
#[inline]
pub fn on_scale_factor_changed(
&mut self,
helper: &mut WindowHelper<UserEventType>,
scale_factor: f64
)
{
self.window_handler
.on_scale_factor_changed(helper, scale_factor)
}
#[inline]
pub fn on_draw(&mut self, helper: &mut WindowHelper<UserEventType>)
{
let renderer = &mut self.renderer;
let window_handler = &mut self.window_handler;
renderer.draw_frame(|graphics| window_handler.on_draw(helper, graphics))
}
#[inline]
pub fn on_mouse_move(
&mut self,
helper: &mut WindowHelper<UserEventType>,
position: Vec2
)
{
self.window_handler.on_mouse_move(helper, position)
}
#[inline]
pub fn on_mouse_button_down(
&mut self,
helper: &mut WindowHelper<UserEventType>,
button: MouseButton
)
{
self.window_handler.on_mouse_button_down(helper, button)
}
#[inline]
pub fn on_mouse_button_up(
&mut self,
helper: &mut WindowHelper<UserEventType>,
button: MouseButton
)
{
self.window_handler.on_mouse_button_up(helper, button)
}
#[inline]
pub fn on_mouse_wheel_scroll(
&mut self,
helper: &mut WindowHelper<UserEventType>,
distance: MouseScrollDistance
)
{
self.window_handler.on_mouse_wheel_scroll(helper, distance)
}
#[inline]
pub fn on_key_down(
&mut self,
helper: &mut WindowHelper<UserEventType>,
virtual_key_code: Option<VirtualKeyCode>,
scancode: KeyScancode
)
{
self.window_handler
.on_key_down(helper, virtual_key_code, scancode)
}
#[inline]
pub fn on_key_up(
&mut self,
helper: &mut WindowHelper<UserEventType>,
virtual_key_code: Option<VirtualKeyCode>,
scancode: KeyScancode
)
{
self.window_handler
.on_key_up(helper, virtual_key_code, scancode)
}
#[inline]
pub fn on_keyboard_char(
&mut self,
helper: &mut WindowHelper<UserEventType>,
unicode_codepoint: char
)
{
self.window_handler
.on_keyboard_char(helper, unicode_codepoint)
}
#[inline]
pub fn on_keyboard_modifiers_changed(
&mut self,
helper: &mut WindowHelper<UserEventType>,
state: ModifiersState
)
{
self.window_handler
.on_keyboard_modifiers_changed(helper, state)
}
}
pub struct WindowHelper<UserEventType = ()>
where
UserEventType: 'static
{
inner: WindowHelperInnerType<UserEventType>
}
impl<UserEventType> WindowHelper<UserEventType>
{
pub(crate) fn new(inner: WindowHelperInnerType<UserEventType>) -> Self
{
WindowHelper { inner }
}
#[inline]
#[must_use]
pub(crate) fn inner(&mut self) -> &mut WindowHelperInnerType<UserEventType>
{
&mut self.inner
}
pub fn terminate_loop(&mut self)
{
self.inner.terminate_loop()
}
pub fn set_icon_from_rgba_pixels<S>(
&self,
data: Vec<u8>,
size: S
) -> Result<(), BacktraceError<ErrorMessage>>
where
S: Into<UVec2>
{
self.inner.set_icon_from_rgba_pixels(data, size.into())
}
pub fn set_cursor_visible(&self, visible: bool)
{
self.inner.set_cursor_visible(visible)
}
pub fn set_cursor_grab(
&self,
grabbed: bool
) -> Result<(), BacktraceError<ErrorMessage>>
{
self.inner.set_cursor_grab(grabbed)
}
pub fn set_resizable(&self, resizable: bool)
{
self.inner.set_resizable(resizable)
}
#[inline]
pub fn request_redraw(&self)
{
self.inner.request_redraw()
}
pub fn set_title<S: AsRef<str>>(&self, title: S)
{
self.inner.set_title(title.as_ref())
}
pub fn set_fullscreen_mode(&self, mode: WindowFullscreenMode)
{
self.inner.set_fullscreen_mode(mode)
}
pub fn set_size_pixels<S: Into<UVec2>>(&self, size: S)
{
self.inner.set_size_pixels(size)
}
pub fn get_size_pixels(&self) -> UVec2
{
self.inner.get_size_pixels()
}
pub fn set_position_pixels<P: Into<IVec2>>(&self, position: P)
{
self.inner.set_position_pixels(position)
}
pub fn set_size_scaled_pixels<S: Into<Vec2>>(&self, size: S)
{
self.inner.set_size_scaled_pixels(size)
}
pub fn set_position_scaled_pixels<P: Into<Vec2>>(&self, position: P)
{
self.inner.set_position_scaled_pixels(position)
}
#[inline]
#[must_use]
pub fn get_scale_factor(&self) -> f64
{
self.inner.get_scale_factor()
}
pub fn create_user_event_sender(&self) -> UserEventSender<UserEventType>
{
self.inner.create_user_event_sender()
}
}
#[cfg(any(doc, doctest, not(target_arch = "wasm32")))]
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
#[must_use]
pub(crate) enum WindowEventLoopAction
{
Continue,
Exit
}
#[derive(Debug, PartialEq, Clone)]
pub struct WindowStartupInfo
{
viewport_size_pixels: UVec2,
scale_factor: f64
}
impl WindowStartupInfo
{
pub(crate) fn new(viewport_size_pixels: UVec2, scale_factor: f64) -> Self
{
WindowStartupInfo {
viewport_size_pixels,
scale_factor
}
}
pub fn scale_factor(&self) -> f64
{
self.scale_factor
}
pub fn viewport_size_pixels(&self) -> &UVec2
{
&self.viewport_size_pixels
}
}
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
#[non_exhaustive]
pub enum MouseButton
{
Left,
Middle,
Right,
Back,
Forward,
Other(u16)
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum MouseScrollDistance
{
Lines
{
x: f64,
y: f64,
z: f64
},
Pixels
{
x: f64,
y: f64,
z: f64
},
Pages
{
x: f64,
y: f64,
z: f64
}
}
#[allow(missing_docs)]
#[derive(Debug, Hash, Ord, PartialOrd, PartialEq, Eq, Clone, Copy)]
#[non_exhaustive]
pub enum VirtualKeyCode
{
Key1,
Key2,
Key3,
Key4,
Key5,
Key6,
Key7,
Key8,
Key9,
Key0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
Escape,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
F13,
F14,
F15,
F16,
F17,
F18,
F19,
F20,
F21,
F22,
F23,
F24,
PrintScreen,
ScrollLock,
PauseBreak,
Insert,
Home,
Delete,
End,
PageDown,
PageUp,
Left,
Up,
Right,
Down,
Backspace,
Return,
Space,
Compose,
Caret,
Numlock,
Numpad0,
Numpad1,
Numpad2,
Numpad3,
Numpad4,
Numpad5,
Numpad6,
Numpad7,
Numpad8,
Numpad9,
NumpadAdd,
NumpadDivide,
NumpadDecimal,
NumpadComma,
NumpadEnter,
NumpadEquals,
NumpadMultiply,
NumpadSubtract,
AbntC1,
AbntC2,
Apostrophe,
Apps,
Asterisk,
At,
Ax,
Backslash,
Calculator,
Capital,
Colon,
Comma,
Convert,
Equals,
Grave,
Kana,
Kanji,
LAlt,
LBracket,
LControl,
LShift,
LWin,
Mail,
MediaSelect,
MediaStop,
Minus,
Mute,
MyComputer,
NavigateForward,
NavigateBackward,
NextTrack,
NoConvert,
OEM102,
Period,
PlayPause,
Plus,
Power,
PrevTrack,
RAlt,
RBracket,
RControl,
RShift,
RWin,
Semicolon,
Slash,
Sleep,
Stop,
Sysrq,
Tab,
Underline,
Unlabeled,
VolumeDown,
VolumeUp,
Wake,
WebBack,
WebFavorites,
WebForward,
WebHome,
WebRefresh,
WebSearch,
WebStop,
Yen,
Copy,
Paste,
Cut
}
#[derive(Debug, Hash, PartialEq, Eq, Clone, Default)]
pub struct ModifiersState
{
pub(crate) ctrl: bool,
pub(crate) alt: bool,
pub(crate) shift: bool,
pub(crate) logo: bool
}
impl ModifiersState
{
#[inline]
#[must_use]
pub fn ctrl(&self) -> bool
{
self.ctrl
}
#[inline]
#[must_use]
pub fn alt(&self) -> bool
{
self.alt
}
#[inline]
#[must_use]
pub fn shift(&self) -> bool
{
self.shift
}
#[inline]
#[must_use]
pub fn logo(&self) -> bool
{
self.logo
}
}
#[derive(Debug, PartialEq, Clone)]
pub(crate) enum WindowCreationMode
{
Windowed
{
size: WindowSize,
position: Option<WindowPosition>
},
FullscreenBorderless
}
#[derive(Debug, PartialEq, Clone)]
pub enum WindowSize
{
PhysicalPixels(UVec2),
ScaledPixels(Vec2),
MarginPhysicalPixels(u32),
MarginScaledPixels(f32)
}
#[derive(Debug, Hash, PartialEq, Eq, Clone)]
pub enum WindowPosition
{
Center,
PrimaryMonitorPixelsFromTopLeft(IVec2)
}
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum WindowFullscreenMode
{
Windowed,
FullscreenBorderless
}
#[derive(Debug, Clone, PartialEq)]
pub struct WindowCreationOptions
{
pub(crate) mode: WindowCreationMode,
pub(crate) multisampling: u16,
pub(crate) vsync: bool,
pub(crate) always_on_top: bool,
pub(crate) resizable: bool,
pub(crate) maximized: bool,
pub(crate) transparent: bool,
pub(crate) decorations: bool
}
impl WindowCreationOptions
{
pub fn new_windowed(size: WindowSize, position: Option<WindowPosition>) -> Self
{
Self::new(WindowCreationMode::Windowed { size, position })
}
#[inline]
#[must_use]
pub fn new_fullscreen_borderless() -> Self
{
Self::new(WindowCreationMode::FullscreenBorderless)
}
#[inline]
#[must_use]
fn new(mode: WindowCreationMode) -> Self
{
WindowCreationOptions {
mode,
multisampling: 16,
vsync: true,
always_on_top: false,
resizable: true,
maximized: false,
decorations: true,
transparent: false
}
}
#[inline]
#[must_use]
pub fn with_multisampling(mut self, multisampling: u16) -> Self
{
self.multisampling = multisampling;
self
}
#[inline]
#[must_use]
pub fn with_vsync(mut self, vsync: bool) -> Self
{
self.vsync = vsync;
self
}
#[inline]
#[must_use]
pub fn with_resizable(mut self, resizable: bool) -> Self
{
self.resizable = resizable;
self
}
#[inline]
#[must_use]
pub fn with_always_on_top(mut self, always_on_top: bool) -> Self
{
self.always_on_top = always_on_top;
self
}
#[inline]
#[must_use]
pub fn with_maximized(mut self, maximized: bool) -> Self
{
self.maximized = maximized;
self
}
#[inline]
#[must_use]
pub fn with_decorations(mut self, decorations: bool) -> Self
{
self.decorations = decorations;
self
}
#[inline]
#[must_use]
pub fn with_transparent(mut self, transparent: bool) -> Self
{
self.transparent = transparent;
self
}
}
pub type KeyScancode = u32;