Introduce application::State
in iced_winit
This commit is contained in:
parent
ed2b9a91b4
commit
fee46fd653
@ -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>,
|
||||||
|
@ -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,
|
||||||
|
171
winit/src/application/state.rs
Normal file
171
winit/src/application/state.rs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +0,0 @@
|
|||||||
use crate::Size;
|
|
||||||
|
|
||||||
pub trait Compositor {
|
|
||||||
fn window(&self) -> &winit::window::Window;
|
|
||||||
|
|
||||||
fn resize(&self, new_size: Size<u32>);
|
|
||||||
}
|
|
@ -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)]
|
||||||
|
Loading…
Reference in New Issue
Block a user