diff --git a/native/src/user_interface.rs b/native/src/user_interface.rs index 59d91f42..504dbe0f 100644 --- a/native/src/user_interface.rs +++ b/native/src/user_interface.rs @@ -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 /// process. /// diff --git a/winit/src/application.rs b/winit/src/application.rs index dcc5a282..96438d73 100644 --- a/winit/src/application.rs +++ b/winit/src/application.rs @@ -9,12 +9,14 @@ use crate::{ Clipboard, Color, Command, Debug, Error, Executor, Mode, Proxy, Runtime, Settings, Size, Subscription, }; + +use iced_futures::futures; +use iced_futures::futures::channel::mpsc; use iced_graphics::window; use iced_native::program::Program; use iced_native::{Cache, UserInterface}; -use iced_futures::futures; -use iced_futures::futures::channel::mpsc; +use std::mem::ManuallyDrop; /// An interactive, native cross-platform application. /// @@ -214,8 +216,9 @@ async fn run_instance( let mut state = State::new(&application, &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( &surface, physical_size.width, @@ -224,7 +227,7 @@ async fn run_instance( 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, Cache::default(), &mut renderer, @@ -267,8 +270,7 @@ async fn run_instance( debug.draw_finished(); } else { let cache = - std::mem::ManuallyDrop::into_inner(user_interface) - .into_cache(); + ManuallyDrop::into_inner(user_interface).into_cache(); for message in messages.drain(..) { debug.log_message(&message); @@ -288,14 +290,13 @@ async fn run_instance( // Update window state.synchronize(&application, &window); - user_interface = - std::mem::ManuallyDrop::new(build_user_interface( - &mut application, - cache, - &mut renderer, - state.logical_size(), - &mut debug, - )); + user_interface = ManuallyDrop::new(build_user_interface( + &mut application, + cache, + &mut renderer, + state.logical_size(), + &mut debug, + )); debug.draw_started(); primitive = user_interface @@ -310,17 +311,31 @@ async fn run_instance( } event::Event::RedrawRequested(_) => { 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( &surface, physical_size.width, physical_size.height, ); - physical_size = current_physical_size; + viewport_version = current_viewport_version; } let new_mouse_interaction = compositor.draw( diff --git a/winit/src/application/state.rs b/winit/src/application/state.rs index 7de3ecef..1f3c77a0 100644 --- a/winit/src/application/state.rs +++ b/winit/src/application/state.rs @@ -12,6 +12,7 @@ pub struct State { background_color: Color, scale_factor: f64, viewport: Viewport, + viewport_version: usize, cursor_position: winit::dpi::PhysicalPosition, modifiers: winit::event::ModifiersState, application: PhantomData, @@ -39,6 +40,7 @@ impl State { 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(), @@ -54,6 +56,10 @@ impl State { &self.viewport } + pub fn viewport_version(&self) -> usize { + self.viewport_version + } + pub fn physical_size(&self) -> Size { self.viewport.physical_size() } @@ -91,6 +97,8 @@ impl State { size, window.scale_factor() * self.scale_factor, ); + + self.viewport_version = self.viewport_version.wrapping_add(1); } WindowEvent::ScaleFactorChanged { scale_factor: new_scale_factor, @@ -103,6 +111,8 @@ impl State { size, new_scale_factor * self.scale_factor, ); + + self.viewport_version = self.viewport_version.wrapping_add(1); } WindowEvent::CursorMoved { position, .. } => { self.cursor_position = *position;