diff options
-rw-r--r-- | glutin/src/application.rs | 14 | ||||
-rw-r--r-- | lazy/src/component.rs | 4 | ||||
-rw-r--r-- | native/src/lib.rs | 4 | ||||
-rw-r--r-- | native/src/program/state.rs | 12 | ||||
-rw-r--r-- | native/src/shell.rs | 20 | ||||
-rw-r--r-- | native/src/user_interface.rs | 45 | ||||
-rw-r--r-- | native/src/widget/responsive.rs | 4 | ||||
-rw-r--r-- | winit/src/application.rs | 15 |
8 files changed, 85 insertions, 33 deletions
diff --git a/glutin/src/application.rs b/glutin/src/application.rs index a1165de3..437c17ee 100644 --- a/glutin/src/application.rs +++ b/glutin/src/application.rs @@ -9,7 +9,8 @@ use iced_winit::application; use iced_winit::conversion; use iced_winit::futures; use iced_winit::futures::channel::mpsc; -use iced_winit::{Cache, Clipboard, Debug, Proxy, Settings}; +use iced_winit::user_interface; +use iced_winit::{Clipboard, Debug, Proxy, Settings}; use glutin::window::Window; use std::mem::ManuallyDrop; @@ -177,7 +178,7 @@ async fn run_instance<A, E, C>( let mut user_interface = ManuallyDrop::new(application::build_user_interface( &mut application, - Cache::default(), + user_interface::Cache::default(), &mut renderer, state.logical_size(), &mut debug, @@ -198,7 +199,7 @@ async fn run_instance<A, E, C>( debug.event_processing_started(); - let statuses = user_interface.update( + let (interface_state, statuses) = user_interface.update( &events, state.cursor_position(), &mut renderer, @@ -212,7 +213,12 @@ async fn run_instance<A, E, C>( runtime.broadcast(event); } - if !messages.is_empty() { + if !messages.is_empty() + || matches!( + interface_state, + user_interface::State::Outdated + ) + { let cache = ManuallyDrop::into_inner(user_interface).into_cache(); diff --git a/lazy/src/component.rs b/lazy/src/component.rs index fd3f6ff7..48ee1d87 100644 --- a/lazy/src/component.rs +++ b/lazy/src/component.rs @@ -149,7 +149,7 @@ where ) }); - local_shell.with_invalid_layout(|| shell.invalidate_layout()); + local_shell.revalidate_layout(|| shell.invalidate_layout()); if !local_messages.is_empty() { let mut component = self @@ -375,7 +375,7 @@ where }) .unwrap_or_else(|| iced_native::event::Status::Ignored); - local_shell.with_invalid_layout(|| shell.invalidate_layout()); + local_shell.revalidate_layout(|| shell.invalidate_layout()); if !local_messages.is_empty() { let mut component = diff --git a/native/src/lib.rs b/native/src/lib.rs index 4211995f..c527a69a 100644 --- a/native/src/lib.rs +++ b/native/src/lib.rs @@ -50,6 +50,7 @@ pub mod subscription; pub mod svg; pub mod text; pub mod touch; +pub mod user_interface; pub mod widget; pub mod window; @@ -57,7 +58,6 @@ mod element; mod hasher; mod runtime; mod shell; -mod user_interface; // We disable debug capabilities on release builds unless the `debug` feature // is explicitly enabled. @@ -91,5 +91,5 @@ pub use renderer::Renderer; pub use runtime::Runtime; pub use shell::Shell; pub use subscription::Subscription; -pub use user_interface::{Cache, UserInterface}; +pub use user_interface::UserInterface; pub use widget::Widget; diff --git a/native/src/program/state.rs b/native/src/program/state.rs index 26c0eb21..cb87a628 100644 --- a/native/src/program/state.rs +++ b/native/src/program/state.rs @@ -1,8 +1,6 @@ use crate::mouse; -use crate::{ - Cache, Clipboard, Command, Debug, Event, Point, Program, Size, - UserInterface, -}; +use crate::user_interface::{self, UserInterface}; +use crate::{Clipboard, Command, Debug, Event, Point, Program, Size}; /// The execution state of a [`Program`]. It leverages caching, event /// processing, and rendering primitive storage. @@ -12,7 +10,7 @@ where P: Program + 'static, { program: P, - cache: Option<Cache>, + cache: Option<user_interface::Cache>, queued_events: Vec<Event>, queued_messages: Vec<P::Message>, mouse_interaction: mouse::Interaction, @@ -32,7 +30,7 @@ where ) -> Self { let user_interface = build_user_interface( &mut program, - Cache::default(), + user_interface::Cache::default(), renderer, bounds, debug, @@ -161,7 +159,7 @@ where fn build_user_interface<'a, P: Program>( program: &'a mut P, - cache: Cache, + cache: user_interface::Cache, renderer: &mut P::Renderer, size: Size, debug: &mut Debug, diff --git a/native/src/shell.rs b/native/src/shell.rs index e916f52d..4a0aa9c6 100644 --- a/native/src/shell.rs +++ b/native/src/shell.rs @@ -8,6 +8,7 @@ pub struct Shell<'a, Message> { messages: &'a mut Vec<Message>, is_layout_invalid: bool, + are_widgets_invalid: bool, } impl<'a, Message> Shell<'a, Message> { @@ -16,12 +17,13 @@ impl<'a, Message> Shell<'a, Message> { Self { messages, is_layout_invalid: false, + are_widgets_invalid: false, } } /// Triggers the given function if the layout is invalid, cleaning it in the /// process. - pub fn with_invalid_layout(&mut self, f: impl FnOnce()) { + pub fn revalidate_layout(&mut self, f: impl FnOnce()) { if self.is_layout_invalid { self.is_layout_invalid = false; @@ -41,6 +43,13 @@ impl<'a, Message> Shell<'a, Message> { self.is_layout_invalid = true; } + /// Invalidates the current application widgets. + /// + /// The shell will rebuild and relayout the widget tree. + pub fn invalidate_widgets(&mut self) { + self.are_widgets_invalid = true; + } + /// Merges the current [`Shell`] with another one by applying the given /// function to the messages of the latter. /// @@ -50,5 +59,14 @@ impl<'a, Message> Shell<'a, Message> { self.is_layout_invalid = self.is_layout_invalid || other.is_layout_invalid; + + self.are_widgets_invalid = + self.are_widgets_invalid || other.are_widgets_invalid; + } + + /// Returns whether the widgets of the current application have been + /// invalidated. + pub fn are_widgets_invalid(&self) -> bool { + self.are_widgets_invalid } } diff --git a/native/src/user_interface.rs b/native/src/user_interface.rs index 40f7a204..1c78b754 100644 --- a/native/src/user_interface.rs +++ b/native/src/user_interface.rs @@ -42,7 +42,8 @@ where /// is naive way to set up our application loop: /// /// ```no_run - /// use iced_native::{UserInterface, Cache, Size}; + /// use iced_native::Size; + /// use iced_native::user_interface::{self, UserInterface}; /// use iced_wgpu::Renderer; /// /// # mod iced_wgpu { @@ -61,7 +62,7 @@ where /// # } /// // Initialization /// let mut counter = Counter::new(); - /// let mut cache = Cache::new(); + /// let mut cache = user_interface::Cache::new(); /// let mut renderer = Renderer::new(); /// let mut window_size = Size::new(1024.0, 768.0); /// @@ -136,7 +137,8 @@ where /// completing [the previous example](#example): /// /// ```no_run - /// use iced_native::{clipboard, UserInterface, Cache, Size, Point}; + /// use iced_native::{clipboard, Size, Point}; + /// use iced_native::user_interface::{self, UserInterface}; /// use iced_wgpu::Renderer; /// /// # mod iced_wgpu { @@ -155,7 +157,7 @@ where /// # pub fn update(&mut self, message: ()) {} /// # } /// let mut counter = Counter::new(); - /// let mut cache = Cache::new(); + /// let mut cache = user_interface::Cache::new(); /// let mut renderer = Renderer::new(); /// let mut window_size = Size::new(1024.0, 768.0); /// let mut cursor_position = Point::default(); @@ -176,7 +178,7 @@ where /// ); /// /// // Update the user interface - /// let event_statuses = user_interface.update( + /// let (state, event_statuses) = user_interface.update( /// &events, /// cursor_position, /// &mut renderer, @@ -199,7 +201,9 @@ where renderer: &mut Renderer, clipboard: &mut dyn Clipboard, messages: &mut Vec<Message>, - ) -> Vec<event::Status> { + ) -> (State, Vec<event::Status>) { + let mut state = State::Updated; + let (base_cursor, overlay_statuses) = if let Some(mut overlay) = self.root.overlay(Layout::new(&self.base.layout)) { @@ -227,7 +231,7 @@ where &mut shell, ); - shell.with_invalid_layout(|| { + shell.revalidate_layout(|| { layer = Self::overlay_layer( None, bounds, @@ -236,6 +240,10 @@ where ); }); + if shell.are_widgets_invalid() { + state = State::Outdated; + } + event_status }) .collect(); @@ -255,7 +263,7 @@ where (cursor_position, vec![event::Status::Ignored; events.len()]) }; - events + let event_statuses = events .iter() .cloned() .zip(overlay_statuses.into_iter()) @@ -271,7 +279,7 @@ where &mut shell, ); - shell.with_invalid_layout(|| { + shell.revalidate_layout(|| { let hash = { let hasher = &mut crate::Hasher::default(); self.root.hash_layout(hasher); @@ -288,9 +296,15 @@ where self.overlay = None; }); + if shell.are_widgets_invalid() { + state = State::Outdated; + } + event_status.merge(overlay_status) }) - .collect() + .collect(); + + (state, event_statuses) } /// Draws the [`UserInterface`] with the provided [`Renderer`]. @@ -306,7 +320,8 @@ where /// [completing the last example](#example-1): /// /// ```no_run - /// use iced_native::{clipboard, UserInterface, Cache, Size, Point}; + /// use iced_native::{clipboard, Size, Point}; + /// use iced_native::user_interface::{self, UserInterface}; /// use iced_wgpu::Renderer; /// /// # mod iced_wgpu { @@ -325,7 +340,7 @@ where /// # pub fn update(&mut self, message: ()) {} /// # } /// let mut counter = Counter::new(); - /// let mut cache = Cache::new(); + /// let mut cache = user_interface::Cache::new(); /// let mut renderer = Renderer::new(); /// let mut window_size = Size::new(1024.0, 768.0); /// let mut cursor_position = Point::default(); @@ -548,3 +563,9 @@ impl Default for Cache { Cache::new() } } + +#[derive(Debug, Clone, Copy)] +pub enum State { + Outdated, + Updated, +} diff --git a/native/src/widget/responsive.rs b/native/src/widget/responsive.rs index 0cb85d45..becaa980 100644 --- a/native/src/widget/responsive.rs +++ b/native/src/widget/responsive.rs @@ -80,6 +80,10 @@ where let Internal { content, state } = internal.deref_mut(); + if state.last_size != Some(state.last_layout.size()) { + shell.invalidate_widgets(); + } + let content = content.resolve(state, renderer); let content_layout = Layout::with_offset( diff --git a/winit/src/application.rs b/winit/src/application.rs index 32423e80..e9212b5e 100644 --- a/winit/src/application.rs +++ b/winit/src/application.rs @@ -15,7 +15,7 @@ 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_native::user_interface::{self, UserInterface}; use std::mem::ManuallyDrop; @@ -250,7 +250,7 @@ async fn run_instance<A, E, C>( let mut user_interface = ManuallyDrop::new(build_user_interface( &mut application, - Cache::default(), + user_interface::Cache::default(), &mut renderer, state.logical_size(), &mut debug, @@ -271,7 +271,7 @@ async fn run_instance<A, E, C>( debug.event_processing_started(); - let statuses = user_interface.update( + let (interface_state, statuses) = user_interface.update( &events, state.cursor_position(), &mut renderer, @@ -285,7 +285,12 @@ async fn run_instance<A, E, C>( runtime.broadcast(event); } - if !messages.is_empty() { + if !messages.is_empty() + || matches!( + interface_state, + user_interface::State::Outdated, + ) + { let cache = ManuallyDrop::into_inner(user_interface).into_cache(); @@ -471,7 +476,7 @@ pub fn requests_exit( /// [`struct@Debug`] information accordingly. pub fn build_user_interface<'a, A: Application>( application: &'a mut A, - cache: Cache, + cache: user_interface::Cache, renderer: &mut A::Renderer, size: Size, debug: &mut Debug, |