diff options
Diffstat (limited to 'glfw/src/window.rs')
-rw-r--r-- | glfw/src/window.rs | 863 |
1 files changed, 0 insertions, 863 deletions
diff --git a/glfw/src/window.rs b/glfw/src/window.rs deleted file mode 100644 index 1e7e777..0000000 --- a/glfw/src/window.rs +++ /dev/null @@ -1,863 +0,0 @@ -use std::cell::RefCell; -use std::ffi::{c_double, c_int, CString}; -use std::hint::unreachable_unchecked; -use std::io::{stdout, Write}; -use std::ptr::null_mut; - -use bitflags::bitflags; -use util_macros::{FromRepr, VariantArr}; - -use crate::init::{initialize, Glfw}; -use crate::{get_glfw_error, Error}; - -#[derive(Debug)] -pub struct Window -{ - _init: Glfw, - handle: *mut crate::ffi::GLFWwindow, -} - -impl Window -{ - /// Makes the context of the window current for the calling thread. - /// - /// # Errors - /// Will return `Err` if a GLFW platform error occurs or if no OpenGL context is - /// present. - #[cfg(feature = "opengl")] - pub fn make_context_current(&self) -> Result<(), Error> - { - unsafe { crate::ffi::glfwMakeContextCurrent(self.handle) }; - - get_glfw_error()?; - - Ok(()) - } - - /// Returns the address of the specified OpenGL function, if it is supported by the - /// current context. - /// - /// # Errors - /// Will return `Err` if a GLFW platform error occurs or if no current context has - /// been set. - #[cfg(feature = "opengl")] - pub fn get_proc_address( - &self, - proc_name: &std::ffi::CStr, - ) -> Result<unsafe extern "C" fn(), Error> - { - let proc_addr = unsafe { crate::ffi::glfwGetProcAddress(proc_name.as_ptr()) }; - - get_glfw_error()?; - - // SAFETY: Is only None when a error has occured and that case is handled above - Ok(unsafe { proc_addr.unwrap_unchecked() }) - } - - /// Processes all pending events. - /// - /// # Errors - /// Will return `Err` if a GLFW platform error occurs. - pub fn poll_events(&self) -> Result<(), Error> - { - // SAFETY: The initialize function (called when the window is created) makes sure - // the current thread is the main thread - unsafe { crate::ffi::glfwPollEvents() }; - - get_glfw_error()?; - - Ok(()) - } - - /// Swaps the front and back buffers of the window. - /// - /// # Errors - /// Will return `Err` if a GLFW platform error occurs or if no OpenGL window context - /// is present. - pub fn swap_buffers(&self) -> Result<(), Error> - { - unsafe { - crate::ffi::glfwSwapBuffers(self.handle); - }; - - get_glfw_error()?; - - Ok(()) - } - - /// Returns whether or not the window should close. - #[must_use] - pub fn should_close(&self) -> bool - { - let should_close = unsafe { crate::ffi::glfwWindowShouldClose(self.handle) }; - - should_close == crate::ffi::GLFW_TRUE - } - - /// Retrieves the size of the window. - /// - /// # Errors - /// Will return `Err` if a GLFW platform error occurs. - pub fn size(&self) -> Result<Size, Error> - { - let mut width = 0; - let mut height = 0; - - // SAFETY: The initialize function (called when the window is created) makes sure - // the current thread is the main thread - unsafe { crate::ffi::glfwGetWindowSize(self.handle, &mut width, &mut height) }; - - get_glfw_error()?; - - #[allow(clippy::cast_sign_loss)] - Ok(Size { - width: width as u32, - height: height as u32, - }) - } - - /// Sets the callback which is called when the user attempts to close the window. - pub fn set_close_callback(&self, callback: impl Fn() + 'static) - { - CLOSE_CALLBACK.with_borrow_mut(|cb| { - *cb = Some(Box::new(callback)); - }); - - // SAFETY: The initialize function (called when the window is created) makes sure - // the current thread is the main thread - unsafe { - crate::ffi::glfwSetWindowCloseCallback(self.handle, Some(close_callback)); - } - } - - pub fn set_framebuffer_size_callback(&self, callback: impl Fn(Size) + 'static) - { - FRAMEBUFFER_SIZE_CB.with_borrow_mut(|framebuffer_size_cb| { - *framebuffer_size_cb = Some(Box::new(callback)); - }); - - // SAFETY: The initialize function (called when the window is created) makes sure - // the current thread is the main thread - unsafe { - crate::ffi::glfwSetFramebufferSizeCallback( - self.handle, - Some(framebuffer_size_callback), - ); - } - } - - pub fn set_key_callback( - &self, - callback: impl Fn(Key, i32, KeyState, KeyModifiers) + 'static, - ) - { - KEY_CALLBACK.with_borrow_mut(|key_callback| { - *key_callback = Some(Box::new(callback)); - }); - - // SAFETY: The initialize function (called when the window is created) makes sure - // the current thread is the main thread - unsafe { - crate::ffi::glfwSetKeyCallback(self.handle, Some(key_callback)); - } - } - - /// Sets the cursor position callback. - /// - /// The callback is provided with the position, in screen coordinates, relative to the - /// upper-left corner of the content area of the window. - pub fn set_cursor_pos_callback(&self, callback: impl Fn(CursorPosition) + 'static) - { - CURSOR_POS_CALLBACK.with_borrow_mut(|cursor_pos_callback| { - *cursor_pos_callback = Some(Box::new(callback)); - }); - - // SAFETY: The initialize function (called when the window is created) makes sure - // the current thread is the main thread - unsafe { - crate::ffi::glfwSetCursorPosCallback(self.handle, Some(cursor_pos_callback)); - } - } - - /// Sets the mouse button callback. - pub fn set_mouse_button_callback( - &self, - callback: impl Fn(MouseButton, MouseButtonState, KeyModifiers) + 'static, - ) - { - MOUSE_BUTTON_CALLBACK.with_borrow_mut(|mouse_button_callback| { - *mouse_button_callback = Some(Box::new(callback)); - }); - - // SAFETY: The initialize function (called when the window is created) makes sure - // the current thread is the main thread - unsafe { - crate::ffi::glfwSetMouseButtonCallback( - self.handle, - Some(mouse_button_callback), - ); - } - } - - /// Sets the callback called when the window gains or loses input focus. - pub fn set_focus_callback(&self, callback: impl Fn(bool) + 'static) - { - FOCUS_CALLBACK.with_borrow_mut(|focus_cb| { - *focus_cb = Some(Box::new(callback)); - }); - - // SAFETY: The initialize function (called when the window is created) makes sure - // the current thread is the main thread - unsafe { - crate::ffi::glfwSetWindowFocusCallback(self.handle, Some(focus_callback)); - } - } - - /// Returns the last reported state of a keyboard key. - /// - /// # Errors - /// Will return `Err` if a GLFW error occurs. - pub fn get_key(&self, key: Key) -> Result<KeyState, Error> - { - // SAFETY: The initialize function (called when the window is created) makes sure - // the current thread is the main thread - let state = unsafe { crate::ffi::glfwGetKey(self.handle, key as i32) }; - - get_glfw_error()?; - - Ok(match state { - crate::ffi::GLFW_PRESS => KeyState::Pressed, - crate::ffi::GLFW_RELEASE => KeyState::Released, - _ => { - // SAFETY: glfwGetKey can only return GLFW_PRESS or GLFW_RELEASE - unsafe { - unreachable_unchecked(); - } - } - }) - } - - /// Returns the last reported state of a mouse button. - /// - /// # Errors - /// Will return `Err` if a GLFW error occurs. - pub fn get_mouse_button( - &self, - mouse_button: MouseButton, - ) -> Result<MouseButtonState, Error> - { - // SAFETY: The initialize function (called when the window is created) makes sure - // the current thread is the main thread - let state = - unsafe { crate::ffi::glfwGetMouseButton(self.handle, mouse_button as i32) }; - - get_glfw_error()?; - - Ok(match state { - crate::ffi::GLFW_PRESS => MouseButtonState::Pressed, - crate::ffi::GLFW_RELEASE => MouseButtonState::Released, - _ => { - // SAFETY: glfwGetMouseButton can only return GLFW_PRESS or GLFW_RELEASE - unsafe { - unreachable_unchecked(); - } - } - }) - } - - /// Returns the position of the cursor, in screen coordinates, relative to the - /// upper-left corner of the content area of the window. - /// - /// # Errors - /// Will return `Err` if a GLFW error occurs. - pub fn get_cursor_position(&self) -> Result<CursorPosition, Error> - { - let mut x_pos = 0.0; - let mut y_pos = 0.0; - - // SAFETY: The initialize function (called when the window is created) makes sure - // the current thread is the main thread - unsafe { - crate::ffi::glfwGetCursorPos(self.handle, &mut x_pos, &mut y_pos); - } - - get_glfw_error()?; - - Ok(CursorPosition { x: x_pos, y: y_pos }) - } - - /// Sets a input mode option. - /// - /// # Errors - /// Will return `Err` if a GLFW error occurs. - pub fn set_input_mode( - &self, - input_mode: InputMode, - enabled: bool, - ) -> Result<(), Error> - { - // SAFETY: The initialize function (called when the window is created) makes sure - // the current thread is the main thread - unsafe { - crate::ffi::glfwSetInputMode( - self.handle, - input_mode as i32, - i32::from(enabled), - ); - } - - get_glfw_error()?; - - Ok(()) - } - - /// Sets the cursor mode. - /// - /// # Errors - /// Will return `Err` if a GLFW error occurs. - pub fn set_cursor_mode(&self, cursor_mode: CursorMode) -> Result<(), Error> - { - // SAFETY: The initialize function (called when the window is created) makes sure - // the current thread is the main thread - unsafe { - crate::ffi::glfwSetInputMode( - self.handle, - crate::ffi::GLFW_CURSOR, - cursor_mode as i32, - ); - } - - get_glfw_error()?; - - Ok(()) - } - - /// Returns whether or not raw mouse motion is supported. - /// - /// # Errors - /// Will return `Err` if a GLFW error occurs. - pub fn is_raw_mouse_motion_supported(&self) -> Result<bool, Error> - { - // SAFETY: The initialize function (called when the window is created) makes sure - // the current thread is the main thread - let supported = unsafe { crate::ffi::glfwRawMouseMotionSupported() }; - - get_glfw_error()?; - - Ok(supported == crate::ffi::GLFW_TRUE) - } -} - -/// [`Window`] builder. -#[derive(Debug, Clone, Default)] -pub struct Builder -{ - hints: Vec<(Hint, HintValue)>, -} - -impl Builder -{ - #[must_use] - pub fn new() -> Self - { - Self { hints: Vec::new() } - } - - /// Adds a window creation hint to set. - #[must_use] - pub fn hint(mut self, hint: Hint, value: HintValue) -> Self - { - self.hints.push((hint, value)); - - self - } - - /// Sets the window hints to set. - pub fn hints(mut self, hints: impl IntoIterator<Item = (Hint, HintValue)>) - { - self.hints = hints.into_iter().collect(); - } - - /// Creates a new window. - /// - /// # Errors - /// Will return `Err` if - /// - The title contains an internal nul byte - /// - A GLFW error occurs - pub fn create(&self, size: &Size, title: &str) -> Result<Window, Error> - { - let c_title = - CString::new(title).map_err(|_| Error::InternalNulByteInWindowTitle)?; - - let init = initialize()?; - - for (hint, value) in &self.hints { - // SAFETY: The initialize function makes sure the current thread is the main - // thread - // - // Error is not checked for after since the two possible errors - // (GLFW_NOT_INITIALIZED and GLFW_INVALID_ENUM) cannot occur. - unsafe { - crate::ffi::glfwWindowHint( - *hint as i32, - match value { - HintValue::Number(num) => *num, - HintValue::Bool(boolean) => { - if *boolean { - crate::ffi::GLFW_TRUE - } else { - crate::ffi::GLFW_FALSE - } - } - }, - ); - } - } - - // SAFETY: The initialize function makes sure the current thread is the main - // thread - let handle = unsafe { - #[allow(clippy::cast_possible_wrap)] - crate::ffi::glfwCreateWindow( - size.width as i32, - size.height as i32, - c_title.as_ptr(), - null_mut(), - null_mut(), - ) - }; - - get_glfw_error()?; - - Ok(Window { _init: init, handle }) - } -} - -/// Window creation hint -#[derive(Debug, Clone, Copy)] -#[repr(i32)] -#[non_exhaustive] -pub enum Hint -{ - /// Specifies whether the OpenGL context should be created in debug mode, which may - /// provide additional error and diagnostic reporting functionality. - /// - /// Valid values are [`HintValue::Bool`]. - OpenGLDebugContext = crate::ffi::GLFW_OPENGL_DEBUG_CONTEXT, - - /// Specifies the desired number of samples to use for multisampling. Zero disables - /// multisampling. - /// - /// Valid values are: [`HintValue::Number`]. - Samples = crate::ffi::GLFW_SAMPLES, - - /// Specifies whether the framebuffer should be double buffered. You nearly always - /// want to use double buffering. This is a hard constraint. - /// - /// Valid values are [`HintValue::Bool`]. - DoubleBuffer = crate::ffi::GLFW_DOUBLEBUFFER, -} - -/// Window creation hint value. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum HintValue -{ - Number(i32), - Bool(bool), -} - -/// Window size. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Size -{ - pub width: u32, - pub height: u32, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[repr(i32)] -pub enum InputMode -{ - /// When sticky keys mode is enabled, the pollable state of a key will remain - /// [`KeyState::Pressed`] until the state of that key is polled with - /// [`Window::get_key`]. Once it has been polled, if a key release event had been - /// processed in the meantime, the state will reset to [`KeyState::Released`], - /// otherwise it will remain [`KeyState::Pressed`]. - StickyKeys = crate::ffi::GLFW_STICKY_KEYS, - - /// When sticky mouse buttons mode is enabled, the pollable state of a mouse button - /// will remain [`MouseButtonState::Pressed`] until the state of that button is - /// polled with [`Window::get_mouse_button`]. Once it has been polled, if a mouse - /// button release event had been processed in the meantime, the state will reset - /// to [`MouseButtonState::Released`], otherwise it will remain - /// [`MouseButton::Pressed`]. - StickyMouseButtons = crate::ffi::GLFW_STICKY_MOUSE_BUTTONS, - - LockKeyMods = crate::ffi::GLFW_LOCK_KEY_MODS, - - /// When the cursor is disabled, raw (unscaled and unaccelerated) mouse motion can be - /// enabled if available. - /// - /// Raw mouse motion is closer to the actual motion of the mouse across a surface. It - /// is not affected by the scaling and acceleration applied to the motion of the - /// desktop cursor. That processing is suitable for a cursor while raw motion is - /// better for controlling for example a 3D camera. Because of this, raw mouse motion - /// is only provided when the cursor is disabled. - RawMouseMotion = crate::ffi::GLFW_RAW_MOUSE_MOTION, -} - -#[derive(Debug, Clone, Copy)] -#[repr(i32)] -pub enum CursorMode -{ - /// Hides and grabs the cursor, providing virtual and unlimited cursor movement. This - /// is useful for implementing for example 3D camera controls. - Disabled = crate::ffi::GLFW_CURSOR_DISABLED, - - /// Makes the cursor invisible when it is over the content area of the window but - /// does not restrict the cursor from leaving. - Hidden = crate::ffi::GLFW_CURSOR_HIDDEN, - - /// Makes the cursor visible and behaving normally. - Normal = crate::ffi::GLFW_CURSOR_NORMAL, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, FromRepr, VariantArr)] -#[variant_arr(name = KEYS)] -#[repr(i32)] -pub enum Key -{ - // Unknown = crate::ffi::GLFW_KEY_UNKNOWN, - Space = crate::ffi::GLFW_KEY_SPACE, - Apostrophe = crate::ffi::GLFW_KEY_APOSTROPHE, - Comma = crate::ffi::GLFW_KEY_COMMA, - Minus = crate::ffi::GLFW_KEY_MINUS, - Period = crate::ffi::GLFW_KEY_PERIOD, - Slash = crate::ffi::GLFW_KEY_SLASH, - Digit0 = crate::ffi::GLFW_KEY_0, - Digit1 = crate::ffi::GLFW_KEY_1, - Digit2 = crate::ffi::GLFW_KEY_2, - Digit3 = crate::ffi::GLFW_KEY_3, - Digit4 = crate::ffi::GLFW_KEY_4, - Digit5 = crate::ffi::GLFW_KEY_5, - Digit6 = crate::ffi::GLFW_KEY_6, - Digit7 = crate::ffi::GLFW_KEY_7, - Digit8 = crate::ffi::GLFW_KEY_8, - Digit9 = crate::ffi::GLFW_KEY_9, - Semicolon = crate::ffi::GLFW_KEY_SEMICOLON, - Equal = crate::ffi::GLFW_KEY_EQUAL, - A = crate::ffi::GLFW_KEY_A, - B = crate::ffi::GLFW_KEY_B, - C = crate::ffi::GLFW_KEY_C, - D = crate::ffi::GLFW_KEY_D, - E = crate::ffi::GLFW_KEY_E, - F = crate::ffi::GLFW_KEY_F, - G = crate::ffi::GLFW_KEY_G, - H = crate::ffi::GLFW_KEY_H, - I = crate::ffi::GLFW_KEY_I, - J = crate::ffi::GLFW_KEY_J, - K = crate::ffi::GLFW_KEY_K, - L = crate::ffi::GLFW_KEY_L, - M = crate::ffi::GLFW_KEY_M, - N = crate::ffi::GLFW_KEY_N, - O = crate::ffi::GLFW_KEY_O, - P = crate::ffi::GLFW_KEY_P, - Q = crate::ffi::GLFW_KEY_Q, - R = crate::ffi::GLFW_KEY_R, - S = crate::ffi::GLFW_KEY_S, - T = crate::ffi::GLFW_KEY_T, - U = crate::ffi::GLFW_KEY_U, - V = crate::ffi::GLFW_KEY_V, - W = crate::ffi::GLFW_KEY_W, - X = crate::ffi::GLFW_KEY_X, - Y = crate::ffi::GLFW_KEY_Y, - Z = crate::ffi::GLFW_KEY_Z, - LeftBracket = crate::ffi::GLFW_KEY_LEFT_BRACKET, - Backslash = crate::ffi::GLFW_KEY_BACKSLASH, - RightBracket = crate::ffi::GLFW_KEY_RIGHT_BRACKET, - GraveAccent = crate::ffi::GLFW_KEY_GRAVE_ACCENT, - World1 = crate::ffi::GLFW_KEY_WORLD_1, - World2 = crate::ffi::GLFW_KEY_WORLD_2, - Escape = crate::ffi::GLFW_KEY_ESCAPE, - Enter = crate::ffi::GLFW_KEY_ENTER, - Tab = crate::ffi::GLFW_KEY_TAB, - Backspace = crate::ffi::GLFW_KEY_BACKSPACE, - Insert = crate::ffi::GLFW_KEY_INSERT, - Delete = crate::ffi::GLFW_KEY_DELETE, - Right = crate::ffi::GLFW_KEY_RIGHT, - Left = crate::ffi::GLFW_KEY_LEFT, - Down = crate::ffi::GLFW_KEY_DOWN, - Up = crate::ffi::GLFW_KEY_UP, - PageUp = crate::ffi::GLFW_KEY_PAGE_UP, - PageDown = crate::ffi::GLFW_KEY_PAGE_DOWN, - Home = crate::ffi::GLFW_KEY_HOME, - End = crate::ffi::GLFW_KEY_END, - CapsLock = crate::ffi::GLFW_KEY_CAPS_LOCK, - ScrollLock = crate::ffi::GLFW_KEY_SCROLL_LOCK, - NumLock = crate::ffi::GLFW_KEY_NUM_LOCK, - PrintScreen = crate::ffi::GLFW_KEY_PRINT_SCREEN, - Pause = crate::ffi::GLFW_KEY_PAUSE, - F1 = crate::ffi::GLFW_KEY_F1, - F2 = crate::ffi::GLFW_KEY_F2, - F3 = crate::ffi::GLFW_KEY_F3, - F4 = crate::ffi::GLFW_KEY_F4, - F5 = crate::ffi::GLFW_KEY_F5, - F6 = crate::ffi::GLFW_KEY_F6, - F7 = crate::ffi::GLFW_KEY_F7, - F8 = crate::ffi::GLFW_KEY_F8, - F9 = crate::ffi::GLFW_KEY_F9, - F10 = crate::ffi::GLFW_KEY_F10, - F11 = crate::ffi::GLFW_KEY_F11, - F12 = crate::ffi::GLFW_KEY_F12, - F13 = crate::ffi::GLFW_KEY_F13, - F14 = crate::ffi::GLFW_KEY_F14, - F15 = crate::ffi::GLFW_KEY_F15, - F16 = crate::ffi::GLFW_KEY_F16, - F17 = crate::ffi::GLFW_KEY_F17, - F18 = crate::ffi::GLFW_KEY_F18, - F19 = crate::ffi::GLFW_KEY_F19, - F20 = crate::ffi::GLFW_KEY_F20, - F21 = crate::ffi::GLFW_KEY_F21, - F22 = crate::ffi::GLFW_KEY_F22, - F23 = crate::ffi::GLFW_KEY_F23, - F24 = crate::ffi::GLFW_KEY_F24, - F25 = crate::ffi::GLFW_KEY_F25, - Kp0 = crate::ffi::GLFW_KEY_KP_0, - Kp1 = crate::ffi::GLFW_KEY_KP_1, - Kp2 = crate::ffi::GLFW_KEY_KP_2, - Kp3 = crate::ffi::GLFW_KEY_KP_3, - Kp4 = crate::ffi::GLFW_KEY_KP_4, - Kp5 = crate::ffi::GLFW_KEY_KP_5, - Kp6 = crate::ffi::GLFW_KEY_KP_6, - Kp7 = crate::ffi::GLFW_KEY_KP_7, - Kp8 = crate::ffi::GLFW_KEY_KP_8, - Kp9 = crate::ffi::GLFW_KEY_KP_9, - KpDecimal = crate::ffi::GLFW_KEY_KP_DECIMAL, - KpDivide = crate::ffi::GLFW_KEY_KP_DIVIDE, - KpMultiply = crate::ffi::GLFW_KEY_KP_MULTIPLY, - KpSubtract = crate::ffi::GLFW_KEY_KP_SUBTRACT, - KpAdd = crate::ffi::GLFW_KEY_KP_ADD, - KpEnter = crate::ffi::GLFW_KEY_KP_ENTER, - KpEqual = crate::ffi::GLFW_KEY_KP_EQUAL, - LeftShift = crate::ffi::GLFW_KEY_LEFT_SHIFT, - LeftControl = crate::ffi::GLFW_KEY_LEFT_CONTROL, - LeftAlt = crate::ffi::GLFW_KEY_LEFT_ALT, - LeftSuper = crate::ffi::GLFW_KEY_LEFT_SUPER, - RightShift = crate::ffi::GLFW_KEY_RIGHT_SHIFT, - RightControl = crate::ffi::GLFW_KEY_RIGHT_CONTROL, - RightAlt = crate::ffi::GLFW_KEY_RIGHT_ALT, - RightSuper = crate::ffi::GLFW_KEY_RIGHT_SUPER, - Menu = crate::ffi::GLFW_KEY_MENU, -} - -#[derive(Debug, Clone, Copy, FromRepr)] -#[repr(i32)] -pub enum KeyState -{ - Pressed = crate::ffi::GLFW_PRESS, - Released = crate::ffi::GLFW_RELEASE, - Repeat = crate::ffi::GLFW_REPEAT, -} - -bitflags! { - #[derive(Debug, Clone, Copy)] - pub struct KeyModifiers: i32 { - const SHIFT = crate::ffi::GLFW_MOD_SHIFT; - const CONTROL = crate::ffi::GLFW_MOD_CONTROL; - const ALT = crate::ffi::GLFW_MOD_ALT; - const SUPER = crate::ffi::GLFW_MOD_SUPER; - const CAPS_LOCK = crate::ffi::GLFW_MOD_CAPS_LOCK; - const NUM_LOCK = crate::ffi::GLFW_MOD_NUM_LOCK; - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, FromRepr)] -#[repr(i32)] -pub enum MouseButton -{ - One = crate::ffi::GLFW_MOUSE_BUTTON_1, - Two = crate::ffi::GLFW_MOUSE_BUTTON_2, - Three = crate::ffi::GLFW_MOUSE_BUTTON_3, - Four = crate::ffi::GLFW_MOUSE_BUTTON_4, - Five = crate::ffi::GLFW_MOUSE_BUTTON_5, - Six = crate::ffi::GLFW_MOUSE_BUTTON_6, - Seven = crate::ffi::GLFW_MOUSE_BUTTON_7, - Eight = crate::ffi::GLFW_MOUSE_BUTTON_8, -} - -impl MouseButton -{ - pub const LEFT: Self = Self::One; - pub const MIDDLE: Self = Self::Three; - pub const RIGHT: Self = Self::Two; -} - -#[derive(Debug, Clone, Copy, FromRepr)] -#[repr(i32)] -pub enum MouseButtonState -{ - Pressed = crate::ffi::GLFW_PRESS, - Released = crate::ffi::GLFW_RELEASE, -} - -#[derive(Debug, Clone)] -pub struct CursorPosition -{ - pub x: f64, - pub y: f64, -} - -type CloseCallback = Box<dyn Fn()>; -type FramebufferSizeCb = Box<dyn Fn(Size)>; -type KeyCallback = Box<dyn Fn(Key, i32, KeyState, KeyModifiers)>; -type CursorPositionCallback = Box<dyn Fn(CursorPosition)>; -type MouseButtonCallback = Box<dyn Fn(MouseButton, MouseButtonState, KeyModifiers)>; -type FocusCallback = Box<dyn Fn(bool)>; - -thread_local! { -static CLOSE_CALLBACK: RefCell<Option<CloseCallback>> = RefCell::new(None); -static FRAMEBUFFER_SIZE_CB: RefCell<Option<FramebufferSizeCb>> = RefCell::new(None); -static KEY_CALLBACK: RefCell<Option<KeyCallback>> = RefCell::new(None); -static CURSOR_POS_CALLBACK: RefCell<Option<CursorPositionCallback>> = RefCell::new(None); -static MOUSE_BUTTON_CALLBACK: RefCell<Option<MouseButtonCallback>> = RefCell::new(None); -static FOCUS_CALLBACK: RefCell<Option<FocusCallback>> = RefCell::new(None); -} - -extern "C-unwind" fn close_callback(_window: *mut crate::ffi::GLFWwindow) -{ - CLOSE_CALLBACK - .try_with(|close_cb| { - if let Some(cb) = close_cb.borrow().as_deref() { - cb(); - } - }) - .ok(); -} - -extern "C-unwind" fn framebuffer_size_callback( - _window: *mut crate::ffi::GLFWwindow, - c_width: c_int, - c_height: c_int, -) -{ - // Width and height can't possibly have their sign bit set - let width = u32::from_le_bytes(c_width.to_le_bytes()); - let height = u32::from_le_bytes(c_height.to_le_bytes()); - - FRAMEBUFFER_SIZE_CB - .try_with(|framebuffer_size_cb| { - if let Some(cb) = framebuffer_size_cb.borrow().as_deref() { - cb(Size { width, height }); - } - }) - .ok(); -} - -extern "C-unwind" fn key_callback( - _window: *mut crate::ffi::GLFWwindow, - key_raw: c_int, - scancode: c_int, - action_raw: c_int, - mods: c_int, -) -{ - let Some(key) = Key::from_repr(key_raw) else { - write!(stdout(), "Unknown key {key_raw}").ok(); - return; - }; - - let Some(key_state) = KeyState::from_repr(action_raw) else { - write!(stdout(), "Unknown key state {action_raw}").ok(); - return; - }; - - let Some(key_modifiers) = KeyModifiers::from_bits(mods) else { - write!( - stdout(), - "Key modifiers {action_raw} contain one or more unknown bit(s)" - ) - .ok(); - - return; - }; - - KEY_CALLBACK - .try_with(|key_callback| { - if let Some(cb) = key_callback.borrow().as_deref() { - cb(key, scancode, key_state, key_modifiers); - } - }) - .ok(); -} - -extern "C-unwind" fn cursor_pos_callback( - _window: *mut crate::ffi::GLFWwindow, - x_pos: c_double, - y_pos: c_double, -) -{ - CURSOR_POS_CALLBACK - .try_with(|cursor_pos_callback| { - if let Some(cb) = cursor_pos_callback.borrow().as_deref() { - cb(CursorPosition { x: x_pos, y: y_pos }); - } - }) - .ok(); -} - -extern "C-unwind" fn mouse_button_callback( - _window: *mut crate::ffi::GLFWwindow, - mouse_button_raw: c_int, - mouse_action: c_int, - modifier_keys: c_int, -) -{ - let Some(mouse_button) = MouseButton::from_repr(mouse_button_raw) else { - write!(stdout(), "Unknown mouse button {mouse_button_raw}").ok(); - return; - }; - - let Some(mouse_button_state) = MouseButtonState::from_repr(mouse_action) else { - write!(stdout(), "Unknown mouse action {mouse_action}").ok(); - return; - }; - - let Some(key_modifiers) = KeyModifiers::from_bits(modifier_keys) else { - write!( - stdout(), - "Key modifiers {modifier_keys:#b} contain one or more unknown bit(s)" - ) - .ok(); - - return; - }; - - MOUSE_BUTTON_CALLBACK - .try_with(|mouse_button_callback| { - if let Some(cb) = mouse_button_callback.borrow().as_deref() { - cb(mouse_button, mouse_button_state, key_modifiers); - } - }) - .ok(); -} - -extern "C-unwind" fn focus_callback(_window: *mut crate::ffi::GLFWwindow, focused: c_int) -{ - let is_focused = if focused == crate::ffi::GLFW_TRUE { - true - } else if focused == crate::ffi::GLFW_FALSE { - false - } else { - write!(stdout(), "Invalid focus state {focused}").ok(); - return; - }; - - FOCUS_CALLBACK - .try_with(|focus_callback| { - if let Some(cb) = focus_callback.borrow().as_deref() { - cb(is_focused); - } - }) - .ok(); -} |