Merge pull request #1341 from nicksenger/fix/component-overlay-rebuild

fix: prevent building component overlay with stale layout
This commit is contained in:
Héctor Ramón 2022-05-14 23:52:42 +02:00 committed by GitHub
commit ba33e92818
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 52 additions and 35 deletions

View file

@ -410,9 +410,7 @@ where
Some( Some(
CacheBuilder { CacheBuilder {
element: state.view(), element: state.view(),
overlay_builder: |element| { overlay_builder: |_| None,
element.overlay(layout, renderer)
},
} }
.build(), .build(),
) )

View file

@ -464,16 +464,7 @@ where
instance_ref_builder: |instance| instance.state.borrow(), instance_ref_builder: |instance| instance.state.borrow(),
tree: overlay.tree, tree: overlay.tree,
types: PhantomData, types: PhantomData,
overlay_builder: |instance, tree| { overlay_builder: |_, _| None,
instance
.as_ref()
.unwrap()
.borrow_element()
.as_ref()
.unwrap()
.as_widget()
.overlay(&mut tree.children[0], layout, renderer)
},
} }
.build(), .build(),
); );

View file

@ -31,6 +31,11 @@ impl<'a, Message> Shell<'a, Message> {
} }
} }
/// Returns whether the current layout is invalid or not.
pub fn is_layout_invalid(&self) -> bool {
self.is_layout_invalid
}
/// Publish the given `Message` for an application to process it. /// Publish the given `Message` for an application to process it.
pub fn publish(&mut self, message: Message) { pub fn publish(&mut self, message: Message) {
self.messages.push(message); self.messages.push(message);

View file

@ -177,40 +177,61 @@ where
clipboard: &mut dyn Clipboard, clipboard: &mut dyn Clipboard,
messages: &mut Vec<Message>, messages: &mut Vec<Message>,
) -> (State, Vec<event::Status>) { ) -> (State, Vec<event::Status>) {
use std::mem::ManuallyDrop;
let mut state = State::Updated; let mut state = State::Updated;
let mut manual_overlay = ManuallyDrop::new(
self.root.overlay(Layout::new(&self.base), renderer),
);
let (base_cursor, overlay_statuses) = if let Some(mut overlay) = let (base_cursor, overlay_statuses) = if manual_overlay.is_some() {
self.root.overlay(Layout::new(&self.base), renderer)
{
let bounds = self.bounds; let bounds = self.bounds;
let mut overlay = manual_overlay.as_mut().unwrap();
let mut layout = overlay.layout(renderer, bounds); let mut layout = overlay.layout(renderer, bounds);
let mut event_statuses = Vec::new();
let event_statuses = events for event in events.iter().cloned() {
.iter() let mut shell = Shell::new(messages);
.cloned()
.map(|event| {
let mut shell = Shell::new(messages);
let event_status = overlay.on_event( let event_status = overlay.on_event(
event, event,
Layout::new(&layout), Layout::new(&layout),
cursor_position, cursor_position,
renderer, renderer,
clipboard, clipboard,
&mut shell, &mut shell,
);
event_statuses.push(event_status);
if shell.is_layout_invalid() {
let _ = ManuallyDrop::into_inner(manual_overlay);
self.base = renderer.layout(
&self.root,
&layout::Limits::new(Size::ZERO, self.bounds),
); );
manual_overlay = ManuallyDrop::new(
self.root.overlay(Layout::new(&self.base), renderer),
);
if manual_overlay.is_none() {
break;
}
overlay = manual_overlay.as_mut().unwrap();
shell.revalidate_layout(|| { shell.revalidate_layout(|| {
layout = overlay.layout(renderer, bounds); layout = overlay.layout(renderer, bounds);
}); });
}
if shell.are_widgets_invalid() { if shell.are_widgets_invalid() {
state = State::Outdated; state = State::Outdated;
} }
}
event_status
})
.collect();
let base_cursor = if layout.bounds().contains(cursor_position) { let base_cursor = if layout.bounds().contains(cursor_position) {
// TODO: Type-safe cursor availability // TODO: Type-safe cursor availability
@ -226,6 +247,8 @@ where
(cursor_position, vec![event::Status::Ignored; events.len()]) (cursor_position, vec![event::Status::Ignored; events.len()])
}; };
let _ = ManuallyDrop::into_inner(manual_overlay);
let event_statuses = events let event_statuses = events
.iter() .iter()
.cloned() .cloned()