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(); -}  | 
