diff options
Diffstat (limited to 'winit/src/application')
| -rw-r--r-- | winit/src/application/state.rs | 235 | 
1 files changed, 235 insertions, 0 deletions
| diff --git a/winit/src/application/state.rs b/winit/src/application/state.rs new file mode 100644 index 00000000..4c0bfd34 --- /dev/null +++ b/winit/src/application/state.rs @@ -0,0 +1,235 @@ +use crate::conversion; +use crate::{Application, Color, Debug, Mode, Point, Size, Viewport}; + +use std::marker::PhantomData; +use winit::event::WindowEvent; +use winit::window::Window; + +/// The state of a windowed [`Application`]. +/// +/// [`Application`]: ../trait.Application.html +#[derive(Debug, Clone)] +pub struct State<A: Application> { +    title: String, +    mode: Mode, +    background_color: Color, +    scale_factor: f64, +    viewport: Viewport, +    viewport_version: usize, +    cursor_position: winit::dpi::PhysicalPosition<f64>, +    modifiers: winit::event::ModifiersState, +    application: PhantomData<A>, +} + +impl<A: Application> State<A> { +    /// Creates a new [`State`] for the provided [`Application`] and window. +    /// +    /// [`State`]: struct.State.html +    /// [`Application`]: ../trait.Application.html +    pub fn new(application: &A, window: &Window) -> Self { +        let title = application.title(); +        let mode = application.mode(); +        let background_color = application.background_color(); +        let scale_factor = application.scale_factor(); + +        let viewport = { +            let physical_size = window.inner_size(); + +            Viewport::with_physical_size( +                Size::new(physical_size.width, physical_size.height), +                window.scale_factor() * scale_factor, +            ) +        }; + +        Self { +            title, +            mode, +            background_color, +            scale_factor, +            viewport, +            viewport_version: 0, +            // TODO: Encode cursor availability in the type-system +            cursor_position: winit::dpi::PhysicalPosition::new(-1.0, -1.0), +            modifiers: winit::event::ModifiersState::default(), +            application: PhantomData, +        } +    } + +    /// Returns the current background [`Color`] of the [`State`]. +    /// +    /// [`Color`]: ../struct.Color.html +    /// [`State`]: struct.State.html +    pub fn background_color(&self) -> Color { +        self.background_color +    } + +    /// Returns the current [`Viewport`] of the [`State`]. +    /// +    /// [`Viewport`]: ../struct.Viewport.html +    /// [`State`]: struct.State.html +    pub fn viewport(&self) -> &Viewport { +        &self.viewport +    } + +    /// Returns the version of the [`Viewport`] of the [`State`]. +    /// +    /// The version is incremented every time the [`Viewport`] changes. +    /// +    /// [`Viewport`]: ../struct.Viewport.html +    /// [`State`]: struct.State.html +    pub fn viewport_version(&self) -> usize { +        self.viewport_version +    } + +    /// Returns the physical [`Size`] of the [`Viewport`] of the [`State`]. +    /// +    /// [`Size`]: ../struct.Size.html +    /// [`Viewport`]: ../struct.Viewport.html +    /// [`State`]: struct.State.html +    pub fn physical_size(&self) -> Size<u32> { +        self.viewport.physical_size() +    } + +    /// Returns the logical [`Size`] of the [`Viewport`] of the [`State`]. +    /// +    /// [`Size`]: ../struct.Size.html +    /// [`Viewport`]: ../struct.Viewport.html +    /// [`State`]: struct.State.html +    pub fn logical_size(&self) -> Size<f32> { +        self.viewport.logical_size() +    } + +    /// Returns the current scale factor of the [`Viewport`] of the [`State`]. +    /// +    /// [`Viewport`]: ../struct.Viewport.html +    /// [`State`]: struct.State.html +    pub fn scale_factor(&self) -> f64 { +        self.viewport.scale_factor() +    } + +    /// Returns the current cursor position of the [`State`]. +    /// +    /// [`State`]: struct.State.html +    pub fn cursor_position(&self) -> Point { +        conversion::cursor_position( +            self.cursor_position, +            self.viewport.scale_factor(), +        ) +    } + +    /// Returns the current keyboard modifiers of the [`State`]. +    /// +    /// [`State`]: struct.State.html +    pub fn modifiers(&self) -> winit::event::ModifiersState { +        self.modifiers +    } + +    /// Processes the provided window event and updates the [`State`] +    /// accordingly. +    /// +    /// [`State`]: struct.State.html +    pub fn update( +        &mut self, +        window: &Window, +        event: &WindowEvent<'_>, +        _debug: &mut Debug, +    ) { +        match event { +            WindowEvent::Resized(new_size) => { +                let size = Size::new(new_size.width, new_size.height); + +                self.viewport = Viewport::with_physical_size( +                    size, +                    window.scale_factor() * self.scale_factor, +                ); + +                self.viewport_version = self.viewport_version.wrapping_add(1); +            } +            WindowEvent::ScaleFactorChanged { +                scale_factor: new_scale_factor, +                new_inner_size, +            } => { +                let size = +                    Size::new(new_inner_size.width, new_inner_size.height); + +                self.viewport = Viewport::with_physical_size( +                    size, +                    new_scale_factor * self.scale_factor, +                ); + +                self.viewport_version = self.viewport_version.wrapping_add(1); +            } +            WindowEvent::CursorMoved { position, .. } => { +                self.cursor_position = *position; +            } +            WindowEvent::CursorLeft { .. } => { +                // TODO: Encode cursor availability in the type-system +                self.cursor_position = +                    winit::dpi::PhysicalPosition::new(-1.0, -1.0); +            } +            WindowEvent::ModifiersChanged(new_modifiers) => { +                self.modifiers = *new_modifiers; +            } +            #[cfg(feature = "debug")] +            WindowEvent::KeyboardInput { +                input: +                    winit::event::KeyboardInput { +                        virtual_keycode: Some(winit::event::VirtualKeyCode::F12), +                        state: winit::event::ElementState::Pressed, +                        .. +                    }, +                .. +            } => _debug.toggle(), +            _ => {} +        } +    } + +    /// Synchronizes the [`State`] with its [`Application`] and its respective +    /// window. +    /// +    /// Normally an [`Application`] should be synchronized with its [`State`] +    /// and window after calling [`Application::update`]. +    /// +    /// [`State`]: struct.State.html +    /// [`Application`]: ../trait.Application.html +    /// [`Application::update`]: ../trait.Application.html#tymethod.update +    pub fn synchronize(&mut self, application: &A, window: &Window) { +        // Update window title +        let new_title = application.title(); + +        if self.title != new_title { +            window.set_title(&new_title); + +            self.title = new_title; +        } + +        // Update window mode +        let new_mode = application.mode(); + +        if self.mode != new_mode { +            window.set_fullscreen(conversion::fullscreen( +                window.current_monitor(), +                new_mode, +            )); + +            self.mode = new_mode; +        } + +        // Update background color +        self.background_color = application.background_color(); + +        // Update scale factor +        let new_scale_factor = application.scale_factor(); + +        if self.scale_factor != new_scale_factor { +            let size = window.inner_size(); + +            self.viewport = Viewport::with_physical_size( +                Size::new(size.width, size.height), +                window.scale_factor() * new_scale_factor, +            ); + +            self.scale_factor = new_scale_factor; +        } +    } +} | 
