fix: Lazy widget

This commit is contained in:
Nick Senger 2023-01-10 16:09:15 -08:00
parent 7ccd87c36b
commit 2e3a69be31

View file

@ -9,16 +9,17 @@ use iced_native::Element;
use iced_native::{Clipboard, Hasher, Length, Point, Rectangle, Shell, Size}; use iced_native::{Clipboard, Hasher, Length, Point, Rectangle, Shell, Size};
use ouroboros::self_referencing; use ouroboros::self_referencing;
use std::cell::{Ref, RefCell, RefMut}; use std::cell::RefCell;
use std::hash::{Hash, Hasher as H}; use std::hash::{Hash, Hasher as H};
use std::marker::PhantomData;
use std::rc::Rc; use std::rc::Rc;
#[allow(missing_debug_implementations)] #[allow(missing_debug_implementations)]
pub struct Lazy<'a, Message, Renderer, Dependency, View> { pub struct Lazy<'a, Message, Renderer, Dependency, View> {
dependency: Dependency, dependency: Dependency,
view: Box<dyn Fn() -> View + 'a>, view: Box<dyn Fn() -> View + 'a>,
element: RefCell<Option<Rc<RefCell<Element<'static, Message, Renderer>>>>>, element: RefCell<
Option<Rc<RefCell<Option<Element<'static, Message, Renderer>>>>>,
>,
} }
impl<'a, Message, Renderer, Dependency, View> impl<'a, Message, Renderer, Dependency, View>
@ -37,21 +38,35 @@ where
fn with_element<T>( fn with_element<T>(
&self, &self,
f: impl FnOnce(Ref<Element<Message, Renderer>>) -> T, f: impl FnOnce(&Element<Message, Renderer>) -> T,
) -> T { ) -> T {
f(self.element.borrow().as_ref().unwrap().borrow()) f(self
.element
.borrow()
.as_ref()
.unwrap()
.borrow()
.as_ref()
.unwrap())
} }
fn with_element_mut<T>( fn with_element_mut<T>(
&self, &self,
f: impl FnOnce(RefMut<Element<Message, Renderer>>) -> T, f: impl FnOnce(&mut Element<Message, Renderer>) -> T,
) -> T { ) -> T {
f(self.element.borrow().as_ref().unwrap().borrow_mut()) f(self
.element
.borrow()
.as_ref()
.unwrap()
.borrow_mut()
.as_mut()
.unwrap())
} }
} }
struct Internal<Message, Renderer> { struct Internal<Message, Renderer> {
element: Rc<RefCell<Element<'static, Message, Renderer>>>, element: Rc<RefCell<Option<Element<'static, Message, Renderer>>>>,
hash: u64, hash: u64,
} }
@ -73,7 +88,7 @@ where
self.dependency.hash(&mut hasher); self.dependency.hash(&mut hasher);
let hash = hasher.finish(); let hash = hasher.finish();
let element = Rc::new(RefCell::new((self.view)().into())); let element = Rc::new(RefCell::new(Some((self.view)().into())));
(*self.element.borrow_mut()) = Some(element.clone()); (*self.element.borrow_mut()) = Some(element.clone());
@ -81,9 +96,7 @@ where
} }
fn children(&self) -> Vec<Tree> { fn children(&self) -> Vec<Tree> {
vec![Tree::new( self.with_element(|element| vec![Tree::new(element.as_widget())])
self.element.borrow().as_ref().unwrap().borrow().as_widget(),
)]
} }
fn diff(&self, tree: &mut Tree) { fn diff(&self, tree: &mut Tree) {
@ -97,12 +110,12 @@ where
current.hash = new_hash; current.hash = new_hash;
let element = (self.view)().into(); let element = (self.view)().into();
current.element = Rc::new(RefCell::new(element)); current.element = Rc::new(RefCell::new(Some(element)));
(*self.element.borrow_mut()) = Some(current.element.clone()); (*self.element.borrow_mut()) = Some(current.element.clone());
tree.diff_children(std::slice::from_ref( self.with_element(|element| {
&self.element.borrow().as_ref().unwrap().borrow().as_widget(), tree.diff_children(std::slice::from_ref(&element.as_widget()))
)); });
} else { } else {
(*self.element.borrow_mut()) = Some(current.element.clone()); (*self.element.borrow_mut()) = Some(current.element.clone());
} }
@ -153,7 +166,7 @@ where
clipboard: &mut dyn Clipboard, clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>, shell: &mut Shell<'_, Message>,
) -> event::Status { ) -> event::Status {
self.with_element_mut(|mut element| { self.with_element_mut(|element| {
element.as_widget_mut().on_event( element.as_widget_mut().on_event(
&mut tree.children[0], &mut tree.children[0],
event, event,
@ -214,23 +227,27 @@ where
layout: Layout<'_>, layout: Layout<'_>,
renderer: &Renderer, renderer: &Renderer,
) -> Option<overlay::Element<'_, Message, Renderer>> { ) -> Option<overlay::Element<'_, Message, Renderer>> {
let overlay = OverlayBuilder { let overlay = Overlay(Some(
cached: self, InnerBuilder {
tree: &mut tree.children[0], cell: self.element.borrow().as_ref().unwrap().clone(),
types: PhantomData, element: self
overlay_builder: |cached, tree| { .element
Rc::get_mut(cached.element.get_mut().as_mut().unwrap()) .borrow()
.as_ref()
.unwrap() .unwrap()
.get_mut() .borrow_mut()
.as_widget_mut() .take()
.overlay(tree, layout, renderer) .unwrap(),
}, tree: &mut tree.children[0],
} overlay_builder: |element, tree| {
.build(); element.as_widget_mut().overlay(tree, layout, renderer)
},
}
.build(),
));
let has_overlay = overlay.with_overlay(|overlay| { let has_overlay = overlay
overlay.as_ref().map(overlay::Element::position) .with_overlay_maybe(|overlay| overlay::Element::position(overlay));
});
has_overlay has_overlay
.map(|position| overlay::Element::new(position, Box::new(overlay))) .map(|position| overlay::Element::new(position, Box::new(overlay)))
@ -238,37 +255,50 @@ where
} }
#[self_referencing] #[self_referencing]
struct Overlay<'a, 'b, Message, Renderer, Dependency, View> { struct Inner<'a, Message, Renderer>
cached: &'a mut Lazy<'b, Message, Renderer, Dependency, View>, where
Message: 'a,
Renderer: 'a,
{
cell: Rc<RefCell<Option<Element<'static, Message, Renderer>>>>,
element: Element<'static, Message, Renderer>,
tree: &'a mut Tree, tree: &'a mut Tree,
types: PhantomData<(Message, Dependency, View)>,
#[borrows(mut cached, mut tree)] #[borrows(mut element, mut tree)]
#[covariant] #[covariant]
overlay: Option<overlay::Element<'this, Message, Renderer>>, overlay: Option<overlay::Element<'this, Message, Renderer>>,
} }
impl<'a, 'b, Message, Renderer, Dependency, View> struct Overlay<'a, Message, Renderer>(Option<Inner<'a, Message, Renderer>>);
Overlay<'a, 'b, Message, Renderer, Dependency, View>
{ impl<'a, Message, Renderer> Drop for Overlay<'a, Message, Renderer> {
fn drop(&mut self) {
let heads = self.0.take().unwrap().into_heads();
(*heads.cell.borrow_mut()) = Some(heads.element);
}
}
impl<'a, Message, Renderer> Overlay<'a, Message, Renderer> {
fn with_overlay_maybe<T>( fn with_overlay_maybe<T>(
&self, &self,
f: impl FnOnce(&overlay::Element<'_, Message, Renderer>) -> T, f: impl FnOnce(&overlay::Element<'_, Message, Renderer>) -> T,
) -> Option<T> { ) -> Option<T> {
self.borrow_overlay().as_ref().map(f) self.0.as_ref().unwrap().borrow_overlay().as_ref().map(f)
} }
fn with_overlay_mut_maybe<T>( fn with_overlay_mut_maybe<T>(
&mut self, &mut self,
f: impl FnOnce(&mut overlay::Element<'_, Message, Renderer>) -> T, f: impl FnOnce(&mut overlay::Element<'_, Message, Renderer>) -> T,
) -> Option<T> { ) -> Option<T> {
self.with_overlay_mut(|overlay| overlay.as_mut().map(f)) self.0
.as_mut()
.unwrap()
.with_overlay_mut(|overlay| overlay.as_mut().map(f))
} }
} }
impl<'a, 'b, Message, Renderer, Dependency, View> impl<'a, Message, Renderer> overlay::Overlay<Message, Renderer>
overlay::Overlay<Message, Renderer> for Overlay<'a, Message, Renderer>
for Overlay<'a, 'b, Message, Renderer, Dependency, View>
where where
Renderer: iced_native::Renderer, Renderer: iced_native::Renderer,
{ {