Introduce application::State in iced_winit

This commit is contained in:
Héctor Ramón Jiménez 2020-11-04 22:46:32 +01:00
parent ed2b9a91b4
commit fee46fd653
5 changed files with 201 additions and 161 deletions

View File

@ -1,7 +1,7 @@
use crate::{Size, Transformation}; use crate::{Size, Transformation};
/// A viewing region for displaying computer graphics. /// A viewing region for displaying computer graphics.
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct Viewport { pub struct Viewport {
physical_size: Size<u32>, physical_size: Size<u32>,
logical_size: Size<f32>, logical_size: Size<f32>,

View File

@ -1,4 +1,8 @@
//! Create interactive, native cross-platform applications. //! Create interactive, native cross-platform applications.
mod state;
pub use state::State;
use crate::conversion; use crate::conversion;
use crate::mouse; use crate::mouse;
use crate::{ use crate::{
@ -6,7 +10,6 @@ use crate::{
Settings, Size, Subscription, Settings, Size, Subscription,
}; };
use iced_graphics::window; use iced_graphics::window;
use iced_graphics::Viewport;
use iced_native::program::Program; use iced_native::program::Program;
use iced_native::{Cache, UserInterface}; use iced_native::{Cache, UserInterface};
@ -215,19 +218,11 @@ async fn process_events<A, E, C>(
use iced_futures::futures::stream::StreamExt; use iced_futures::futures::stream::StreamExt;
use winit::event; use winit::event;
let mut title = application.title(); let mut state = State::new(&application, &window);
let mut mode = application.mode();
let mut background_color = application.background_color();
let mut scale_factor = application.scale_factor();
let physical_size = window.inner_size();
let mut viewport = Viewport::with_physical_size(
Size::new(physical_size.width, physical_size.height),
window.scale_factor() * scale_factor,
);
let mut resized = false;
let surface = compositor.create_surface(&window); let surface = compositor.create_surface(&window);
let mut physical_size = state.physical_size();
let mut swap_chain = compositor.create_swap_chain( let mut swap_chain = compositor.create_swap_chain(
&surface, &surface,
physical_size.width, physical_size.width,
@ -235,23 +230,19 @@ async fn process_events<A, E, C>(
); );
let clipboard = Clipboard::new(&window); let clipboard = Clipboard::new(&window);
// TODO: Encode cursor availability in the type-system
let mut cursor_position = winit::dpi::PhysicalPosition::new(-1.0, -1.0);
let mut mouse_interaction = mouse::Interaction::default();
let mut modifiers = winit::event::ModifiersState::default();
let mut user_interface = std::mem::ManuallyDrop::new(build_user_interface( let mut user_interface = std::mem::ManuallyDrop::new(build_user_interface(
&mut application, &mut application,
Cache::default(), Cache::default(),
&mut renderer, &mut renderer,
viewport.logical_size(), state.logical_size(),
&mut debug, &mut debug,
)); ));
let mut primitive = user_interface.draw( let mut primitive =
&mut renderer, user_interface.draw(&mut renderer, state.cursor_position());
conversion::cursor_position(cursor_position, viewport.scale_factor()), let mut mouse_interaction = mouse::Interaction::default();
);
let mut events = Vec::new(); let mut events = Vec::new();
let mut external_messages = Vec::new(); let mut external_messages = Vec::new();
@ -267,10 +258,7 @@ async fn process_events<A, E, C>(
debug.event_processing_started(); debug.event_processing_started();
let mut messages = user_interface.update( let mut messages = user_interface.update(
&events, &events,
conversion::cursor_position( state.cursor_position(),
cursor_position,
viewport.scale_factor(),
),
clipboard.as_ref().map(|c| c as _), clipboard.as_ref().map(|c| c as _),
&mut renderer, &mut renderer,
); );
@ -281,13 +269,8 @@ async fn process_events<A, E, C>(
if messages.is_empty() { if messages.is_empty() {
debug.draw_started(); debug.draw_started();
primitive = user_interface.draw( primitive = user_interface
&mut renderer, .draw(&mut renderer, state.cursor_position());
conversion::cursor_position(
cursor_position,
viewport.scale_factor(),
),
);
debug.draw_finished(); debug.draw_finished();
} else { } else {
let cache = let cache =
@ -309,61 +292,21 @@ async fn process_events<A, E, C>(
let subscription = application.subscription(); let subscription = application.subscription();
runtime.track(subscription); runtime.track(subscription);
// Update window title // Update window
let new_title = application.title(); state.synchronize(&application, &window);
if title != new_title {
window.set_title(&new_title);
title = new_title;
}
// Update window mode
let new_mode = application.mode();
if mode != new_mode {
window.set_fullscreen(conversion::fullscreen(
window.current_monitor(),
new_mode,
));
mode = new_mode;
}
// Update background color
background_color = application.background_color();
// Update scale factor
let new_scale_factor = application.scale_factor();
if scale_factor != new_scale_factor {
let size = window.inner_size();
viewport = Viewport::with_physical_size(
Size::new(size.width, size.height),
window.scale_factor() * new_scale_factor,
);
scale_factor = new_scale_factor;
}
user_interface = user_interface =
std::mem::ManuallyDrop::new(build_user_interface( std::mem::ManuallyDrop::new(build_user_interface(
&mut application, &mut application,
cache, cache,
&mut renderer, &mut renderer,
viewport.logical_size(), state.logical_size(),
&mut debug, &mut debug,
)); ));
debug.draw_started(); debug.draw_started();
primitive = user_interface.draw( primitive = user_interface
&mut renderer, .draw(&mut renderer, state.cursor_position());
conversion::cursor_position(
cursor_position,
viewport.scale_factor(),
),
);
debug.draw_finished(); debug.draw_finished();
} }
@ -375,23 +318,23 @@ async fn process_events<A, E, C>(
event::Event::RedrawRequested(_) => { event::Event::RedrawRequested(_) => {
debug.render_started(); debug.render_started();
if resized { let current_physical_size = state.physical_size();
let physical_size = viewport.physical_size();
if physical_size != current_physical_size {
swap_chain = compositor.create_swap_chain( swap_chain = compositor.create_swap_chain(
&surface, &surface,
physical_size.width, physical_size.width,
physical_size.height, physical_size.height,
); );
resized = false; physical_size = current_physical_size;
} }
let new_mouse_interaction = compositor.draw( let new_mouse_interaction = compositor.draw(
&mut renderer, &mut renderer,
&mut swap_chain, &mut swap_chain,
&viewport, state.viewport(),
background_color, state.background_color(),
&primitive, &primitive,
&debug.overlay(), &debug.overlay(),
); );
@ -413,21 +356,12 @@ async fn process_events<A, E, C>(
event: window_event, event: window_event,
.. ..
} => { } => {
handle_window_event( state.update(&window, &window_event, &mut debug);
&window_event,
&window,
scale_factor,
&mut cursor_position,
&mut modifiers,
&mut viewport,
&mut resized,
&mut debug,
);
if let Some(event) = conversion::window_event( if let Some(event) = conversion::window_event(
&window_event, &window_event,
viewport.scale_factor(), state.scale_factor(),
modifiers, state.modifiers(),
) { ) {
events.push(event.clone()); events.push(event.clone());
runtime.broadcast(event); runtime.broadcast(event);
@ -469,64 +403,6 @@ pub fn handle_control_flow(
/// Handles a `WindowEvent` and mutates the keyboard modifiers, viewport, and /// Handles a `WindowEvent` and mutates the keyboard modifiers, viewport, and
/// resized flag accordingly. /// resized flag accordingly.
pub fn handle_window_event(
event: &winit::event::WindowEvent<'_>,
window: &winit::window::Window,
scale_factor: f64,
cursor_position: &mut winit::dpi::PhysicalPosition<f64>,
modifiers: &mut winit::event::ModifiersState,
viewport: &mut Viewport,
resized: &mut bool,
_debug: &mut Debug,
) {
use winit::event::WindowEvent;
match event {
WindowEvent::Resized(new_size) => {
let size = Size::new(new_size.width, new_size.height);
*viewport = Viewport::with_physical_size(
size,
window.scale_factor() * scale_factor,
);
*resized = true;
}
WindowEvent::ScaleFactorChanged {
scale_factor: new_scale_factor,
new_inner_size,
} => {
let size = Size::new(new_inner_size.width, new_inner_size.height);
*viewport = Viewport::with_physical_size(
size,
new_scale_factor * scale_factor,
);
*resized = true;
}
WindowEvent::CursorMoved { position, .. } => {
*cursor_position = *position;
}
WindowEvent::CursorLeft { .. } => {
// TODO: Encode cursor availability in the type-system
*cursor_position = winit::dpi::PhysicalPosition::new(-1.0, -1.0);
}
WindowEvent::ModifiersChanged(new_modifiers) => {
*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(),
_ => {}
}
}
fn build_user_interface<'a, A: Application>( fn build_user_interface<'a, A: Application>(
application: &'a mut A, application: &'a mut A,
cache: Cache, cache: Cache,

View File

@ -0,0 +1,171 @@
use crate::conversion;
use crate::{Application, Color, Debug, Mode, Point, Size, Viewport};
use std::marker::PhantomData;
use winit::event::WindowEvent;
use winit::window::Window;
#[derive(Debug, Clone)]
pub struct State<A: Application> {
title: String,
mode: Mode,
background_color: Color,
scale_factor: f64,
viewport: Viewport,
cursor_position: winit::dpi::PhysicalPosition<f64>,
modifiers: winit::event::ModifiersState,
application: PhantomData<A>,
}
impl<A: Application> State<A> {
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,
// 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,
}
}
pub fn background_color(&self) -> Color {
self.background_color
}
pub fn viewport(&self) -> &Viewport {
&self.viewport
}
pub fn physical_size(&self) -> Size<u32> {
self.viewport.physical_size()
}
pub fn logical_size(&self) -> Size<f32> {
self.viewport.logical_size()
}
pub fn scale_factor(&self) -> f64 {
self.viewport.scale_factor()
}
pub fn cursor_position(&self) -> Point {
conversion::cursor_position(
self.cursor_position,
self.viewport.scale_factor(),
)
}
pub fn modifiers(&self) -> winit::event::ModifiersState {
self.modifiers
}
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,
);
}
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,
);
}
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(),
_ => {}
}
}
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;
}
}
}

View File

@ -1,7 +0,0 @@
use crate::Size;
pub trait Compositor {
fn window(&self) -> &winit::window::Window;
fn resize(&self, new_size: Size<u32>);
}

View File

@ -15,7 +15,7 @@
//! [`winit`]: https://github.com/rust-windowing/winit //! [`winit`]: https://github.com/rust-windowing/winit
//! [`Application`]: trait.Application.html //! [`Application`]: trait.Application.html
//! [`conversion`]: conversion //! [`conversion`]: conversion
#![deny(missing_docs)] //#![deny(missing_docs)]
#![deny(missing_debug_implementations)] #![deny(missing_debug_implementations)]
#![deny(unused_results)] #![deny(unused_results)]
#![forbid(unsafe_code)] #![forbid(unsafe_code)]