Relayout UserInterface on resize in iced_winit

This commit is contained in:
Héctor Ramón Jiménez 2020-11-05 02:11:11 +01:00
parent 86b26f65d6
commit 88993fb092
3 changed files with 59 additions and 17 deletions

View File

@ -388,6 +388,23 @@ where
} }
} }
/// Relayouts and returns a new [`UserInterface`] using the provided
/// bounds.
///
/// [`UserInterface`]: struct.UserInterface.html
pub fn relayout(self, bounds: Size, renderer: &mut Renderer) -> Self {
Self::build(
self.root,
bounds,
Cache {
base: self.base,
overlay: self.overlay,
bounds: self.bounds,
},
renderer,
)
}
/// Extract the [`Cache`] of the [`UserInterface`], consuming it in the /// Extract the [`Cache`] of the [`UserInterface`], consuming it in the
/// process. /// process.
/// ///

View File

@ -9,12 +9,14 @@ use crate::{
Clipboard, Color, Command, Debug, Error, Executor, Mode, Proxy, Runtime, Clipboard, Color, Command, Debug, Error, Executor, Mode, Proxy, Runtime,
Settings, Size, Subscription, Settings, Size, Subscription,
}; };
use iced_futures::futures;
use iced_futures::futures::channel::mpsc;
use iced_graphics::window; use iced_graphics::window;
use iced_native::program::Program; use iced_native::program::Program;
use iced_native::{Cache, UserInterface}; use iced_native::{Cache, UserInterface};
use iced_futures::futures; use std::mem::ManuallyDrop;
use iced_futures::futures::channel::mpsc;
/// An interactive, native cross-platform application. /// An interactive, native cross-platform application.
/// ///
@ -214,8 +216,9 @@ async fn run_instance<A, E, C>(
let mut state = State::new(&application, &window); let mut state = State::new(&application, &window);
let surface = compositor.create_surface(&window); let surface = compositor.create_surface(&window);
let mut physical_size = state.physical_size(); let physical_size = state.physical_size();
let mut viewport_version = state.viewport_version();
let mut swap_chain = compositor.create_swap_chain( let mut swap_chain = compositor.create_swap_chain(
&surface, &surface,
physical_size.width, physical_size.width,
@ -224,7 +227,7 @@ async fn run_instance<A, E, C>(
let clipboard = Clipboard::new(&window); let clipboard = Clipboard::new(&window);
let mut user_interface = std::mem::ManuallyDrop::new(build_user_interface( let mut user_interface = ManuallyDrop::new(build_user_interface(
&mut application, &mut application,
Cache::default(), Cache::default(),
&mut renderer, &mut renderer,
@ -267,8 +270,7 @@ async fn run_instance<A, E, C>(
debug.draw_finished(); debug.draw_finished();
} else { } else {
let cache = let cache =
std::mem::ManuallyDrop::into_inner(user_interface) ManuallyDrop::into_inner(user_interface).into_cache();
.into_cache();
for message in messages.drain(..) { for message in messages.drain(..) {
debug.log_message(&message); debug.log_message(&message);
@ -288,14 +290,13 @@ async fn run_instance<A, E, C>(
// Update window // Update window
state.synchronize(&application, &window); state.synchronize(&application, &window);
user_interface = user_interface = ManuallyDrop::new(build_user_interface(
std::mem::ManuallyDrop::new(build_user_interface( &mut application,
&mut application, cache,
cache, &mut renderer,
&mut renderer, state.logical_size(),
state.logical_size(), &mut debug,
&mut debug, ));
));
debug.draw_started(); debug.draw_started();
primitive = user_interface primitive = user_interface
@ -310,17 +311,31 @@ async fn run_instance<A, E, C>(
} }
event::Event::RedrawRequested(_) => { event::Event::RedrawRequested(_) => {
debug.render_started(); debug.render_started();
let current_viewport_version = state.viewport_version();
let current_physical_size = state.physical_size(); if viewport_version != current_viewport_version {
let physical_size = state.physical_size();
let logical_size = state.logical_size();
debug.layout_started();
user_interface = ManuallyDrop::new(
ManuallyDrop::into_inner(user_interface)
.relayout(logical_size, &mut renderer),
);
debug.layout_finished();
debug.draw_started();
primitive = user_interface
.draw(&mut renderer, state.cursor_position());
debug.draw_finished();
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,
); );
physical_size = current_physical_size; viewport_version = current_viewport_version;
} }
let new_mouse_interaction = compositor.draw( let new_mouse_interaction = compositor.draw(

View File

@ -12,6 +12,7 @@ pub struct State<A: Application> {
background_color: Color, background_color: Color,
scale_factor: f64, scale_factor: f64,
viewport: Viewport, viewport: Viewport,
viewport_version: usize,
cursor_position: winit::dpi::PhysicalPosition<f64>, cursor_position: winit::dpi::PhysicalPosition<f64>,
modifiers: winit::event::ModifiersState, modifiers: winit::event::ModifiersState,
application: PhantomData<A>, application: PhantomData<A>,
@ -39,6 +40,7 @@ impl<A: Application> State<A> {
background_color, background_color,
scale_factor, scale_factor,
viewport, viewport,
viewport_version: 0,
// TODO: Encode cursor availability in the type-system // TODO: Encode cursor availability in the type-system
cursor_position: winit::dpi::PhysicalPosition::new(-1.0, -1.0), cursor_position: winit::dpi::PhysicalPosition::new(-1.0, -1.0),
modifiers: winit::event::ModifiersState::default(), modifiers: winit::event::ModifiersState::default(),
@ -54,6 +56,10 @@ impl<A: Application> State<A> {
&self.viewport &self.viewport
} }
pub fn viewport_version(&self) -> usize {
self.viewport_version
}
pub fn physical_size(&self) -> Size<u32> { pub fn physical_size(&self) -> Size<u32> {
self.viewport.physical_size() self.viewport.physical_size()
} }
@ -91,6 +97,8 @@ impl<A: Application> State<A> {
size, size,
window.scale_factor() * self.scale_factor, window.scale_factor() * self.scale_factor,
); );
self.viewport_version = self.viewport_version.wrapping_add(1);
} }
WindowEvent::ScaleFactorChanged { WindowEvent::ScaleFactorChanged {
scale_factor: new_scale_factor, scale_factor: new_scale_factor,
@ -103,6 +111,8 @@ impl<A: Application> State<A> {
size, size,
new_scale_factor * self.scale_factor, new_scale_factor * self.scale_factor,
); );
self.viewport_version = self.viewport_version.wrapping_add(1);
} }
WindowEvent::CursorMoved { position, .. } => { WindowEvent::CursorMoved { position, .. } => {
self.cursor_position = *position; self.cursor_position = *position;