From 9d24307ad29a2934a23f27d0cdba1b64e0ea664e Mon Sep 17 00:00:00 2001 From: Zoxc Date: Fri, 10 Nov 2023 12:04:18 +0100 Subject: [PATCH] Add `request_compute_layout_recursive` to let scrolling bypass layout (#164) --- src/context.rs | 7 +++++ src/views/scroll.rs | 3 +- src/views/virtual_list.rs | 64 +++++++++++++++++++++------------------ src/window_handle.rs | 11 +++++++ 4 files changed, 54 insertions(+), 31 deletions(-) diff --git a/src/context.rs b/src/context.rs index c6c870b6..598a6da0 100644 --- a/src/context.rs +++ b/src/context.rs @@ -225,6 +225,7 @@ pub struct AppState { pub(crate) view_states: HashMap, stale_view_state: ViewState, pub(crate) scheduled_updates: Vec, + pub(crate) request_compute_layout: bool, pub(crate) request_paint: bool, pub(crate) disabled: HashSet, pub(crate) keyboard_navigable: HashSet, @@ -270,6 +271,7 @@ impl AppState { view_states: HashMap::new(), scheduled_updates: Vec::new(), request_paint: false, + request_compute_layout: false, disabled: HashSet::new(), keyboard_navigable: HashSet::new(), draggable: HashSet::new(), @@ -491,6 +493,11 @@ impl AppState { self.request_changes(id, ChangeFlags::LAYOUT) } + /// Requests that `compute_layout` will run for `_id` and all direct and indirect children. + pub fn request_compute_layout_recursive(&mut self, _id: Id) { + self.request_compute_layout = true; + } + // `Id` is unused currently, but could be used to calculate damage regions. pub fn request_paint(&mut self, _id: Id) { self.request_paint = true; diff --git a/src/views/scroll.rs b/src/views/scroll.rs index 2b3b294f..74e183c8 100644 --- a/src/views/scroll.rs +++ b/src/views/scroll.rs @@ -304,7 +304,8 @@ impl Scroll { if child_viewport != self.child_viewport { app_state.set_viewport(self.child.id(), child_viewport); - app_state.request_layout(self.id); + app_state.request_compute_layout_recursive(self.id); + app_state.request_paint(self.id); self.child_viewport = child_viewport; if let Some(onscroll) = &self.onscroll { onscroll(child_viewport); diff --git a/src/views/virtual_list.rs b/src/views/virtual_list.rs index 744b53ef..81e433cf 100644 --- a/src/views/virtual_list.rs +++ b/src/views/virtual_list.rs @@ -83,7 +83,7 @@ where let (viewport, set_viewport) = create_signal(Rect::ZERO); - create_effect(move |prev_hash_run| { + create_effect(move |prev| { let mut items_vector = each_fn(); let viewport = viewport.get(); let min = match direction { @@ -148,35 +148,39 @@ where }; let hashed_items = items.iter().map(&key_fn).collect::>(); - let diff = if let Some(HashRun(prev_hash_run)) = prev_hash_run { - let mut diff = diff(&prev_hash_run, &hashed_items); - let mut items = items - .into_iter() - .map(|i| Some(i)) - .collect::; 128]>>(); - for added in &mut diff.added { - added.view = Some(items[added.at].take().unwrap()); - } - diff - } else { - let mut diff = Diff::default(); - for (i, item) in items.into_iter().enumerate() { - diff.added.push(DiffOpAdd { - at: i, - view: Some(item), - }); - } - diff - }; - id.update_state( - VirtualListState { - diff, - before_size, - after_size, - }, - false, - ); - HashRun(hashed_items) + let (prev_before_size, prev_after_size, diff) = + if let Some((prev_before_size, prev_after_size, HashRun(prev_hash_run))) = prev { + let mut diff = diff(&prev_hash_run, &hashed_items); + let mut items = items + .into_iter() + .map(|i| Some(i)) + .collect::; 128]>>(); + for added in &mut diff.added { + added.view = Some(items[added.at].take().unwrap()); + } + (prev_before_size, prev_after_size, diff) + } else { + let mut diff = Diff::default(); + for (i, item) in items.into_iter().enumerate() { + diff.added.push(DiffOpAdd { + at: i, + view: Some(item), + }); + } + (0.0, 0.0, diff) + }; + + if !diff.is_empty() || prev_before_size != before_size || prev_after_size != after_size { + id.update_state( + VirtualListState { + diff, + before_size, + after_size, + }, + false, + ); + } + (before_size, after_size, HashRun(hashed_items)) }); let view_fn = Box::new(as_child_of_current_scope(view_fn)); diff --git a/src/window_handle.rs b/src/window_handle.rs index 4cae2dc6..1c2c305b 100644 --- a/src/window_handle.rs +++ b/src/window_handle.rs @@ -493,10 +493,16 @@ impl WindowHandle { cx.clear(); cx.compute_view_layout(&mut self.view); + self.app_state.request_compute_layout = false; taffy_duration } + fn compute_layout(&mut self) { + let mut cx = LayoutCx::new(&mut self.app_state); + cx.compute_view_layout(&mut self.view); + } + pub fn render_frame(&mut self) { // Processes updates scheduled on this frame. for update in mem::take(&mut self.app_state.scheduled_updates) { @@ -636,6 +642,7 @@ impl WindowHandle { && !self.needs_style() && !self.has_deferred_update_messages() && !self.has_anim_update_messages() + && !self.app_state.request_compute_layout { break; } @@ -650,6 +657,10 @@ impl WindowHandle { self.layout(); } + if mem::take(&mut self.app_state.request_compute_layout) { + self.compute_layout(); + } + self.process_deferred_update_messages(); self.process_anim_update_messages(); }