diff options
Diffstat (limited to 'lazy')
| -rw-r--r-- | lazy/Cargo.toml | 8 | ||||
| -rw-r--r-- | lazy/src/component.rs | 308 | ||||
| -rw-r--r-- | lazy/src/lib.rs | 29 | ||||
| -rw-r--r-- | lazy/src/pure.rs | 31 | ||||
| -rw-r--r-- | lazy/src/pure/component.rs | 479 | ||||
| -rw-r--r-- | lazy/src/pure/responsive.rs | 388 | ||||
| -rw-r--r-- | lazy/src/responsive.rs | 433 | 
7 files changed, 406 insertions, 1270 deletions
| diff --git a/lazy/Cargo.toml b/lazy/Cargo.toml index 9a184dd1..12e4e313 100644 --- a/lazy/Cargo.toml +++ b/lazy/Cargo.toml @@ -10,17 +10,9 @@ documentation = "https://docs.rs/iced_lazy"  keywords = ["gui", "ui", "graphics", "interface", "widgets"]  categories = ["gui"] -[features] -pure = ["iced_pure"] -  [dependencies]  ouroboros = "0.13"  [dependencies.iced_native]  version = "0.5"  path = "../native" - -[dependencies.iced_pure] -version = "0.2" -path = "../pure" -optional = true diff --git a/lazy/src/component.rs b/lazy/src/component.rs index eac7e8ee..ea4d7311 100644 --- a/lazy/src/component.rs +++ b/lazy/src/component.rs @@ -1,17 +1,16 @@  //! Build and reuse custom widgets using The Elm Architecture. -use crate::{Cache, CacheBuilder}; -  use iced_native::event;  use iced_native::layout::{self, Layout};  use iced_native::mouse;  use iced_native::overlay;  use iced_native::renderer; +use iced_native::widget::tree::{self, Tree};  use iced_native::{      Clipboard, Element, Length, Point, Rectangle, Shell, Size, Widget,  };  use ouroboros::self_referencing; -use std::cell::RefCell; +use std::cell::{Ref, RefCell};  use std::marker::PhantomData;  /// A reusable, custom widget that uses The Elm Architecture. @@ -28,17 +27,24 @@ use std::marker::PhantomData;  /// Additionally, a [`Component`] is capable of producing a `Message` to notify  /// the parent application of any relevant interactions.  pub trait Component<Message, Renderer> { +    /// The internal state of this [`Component`]. +    type State: Default; +      /// The type of event this [`Component`] handles internally.      type Event;      /// Processes an [`Event`](Component::Event) and updates the [`Component`] state accordingly.      ///      /// It can produce a `Message` for the parent application. -    fn update(&mut self, event: Self::Event) -> Option<Message>; +    fn update( +        &mut self, +        state: &mut Self::State, +        event: Self::Event, +    ) -> Option<Message>;      /// Produces the widgets of the [`Component`], which may trigger an [`Event`](Component::Event)      /// on user interaction. -    fn view(&mut self) -> Element<'_, Self::Event, Renderer>; +    fn view(&self, state: &Self::State) -> Element<'_, Self::Event, Renderer>;  }  /// Turns an implementor of [`Component`] into an [`Element`] that can be @@ -48,6 +54,7 @@ pub fn view<'a, C, Message, Renderer>(  ) -> Element<'a, Message, Renderer>  where      C: Component<Message, Renderer> + 'a, +    C::State: 'static,      Message: 'a,      Renderer: iced_native::Renderer + 'a,  { @@ -56,36 +63,48 @@ where              StateBuilder {                  component: Box::new(component),                  message: PhantomData, -                cache_builder: |state| { -                    Some( -                        CacheBuilder { -                            element: state.view(), -                            overlay_builder: |_| None, -                        } -                        .build(), -                    ) -                }, +                state: PhantomData, +                element_builder: |_| None,              }              .build(),          )),      })  } -struct Instance<'a, Message, Renderer, Event> { -    state: RefCell<Option<State<'a, Message, Renderer, Event>>>, +struct Instance<'a, Message, Renderer, Event, S> { +    state: RefCell<Option<State<'a, Message, Renderer, Event, S>>>,  }  #[self_referencing] -struct State<'a, Message: 'a, Renderer: 'a, Event: 'a> { -    component: Box<dyn Component<Message, Renderer, Event = Event> + 'a>, +struct State<'a, Message: 'a, Renderer: 'a, Event: 'a, S: 'a> { +    component: +        Box<dyn Component<Message, Renderer, Event = Event, State = S> + 'a>,      message: PhantomData<Message>, +    state: PhantomData<S>, -    #[borrows(mut component)] +    #[borrows(component)]      #[covariant] -    cache: Option<Cache<'this, Event, Renderer>>, +    element: Option<Element<'this, Event, Renderer>>,  } -impl<'a, Message, Renderer, Event> Instance<'a, Message, Renderer, Event> { +impl<'a, Message, Renderer, Event, S> Instance<'a, Message, Renderer, Event, S> +where +    S: Default, +{ +    fn rebuild_element(&self, state: &S) { +        let heads = self.state.borrow_mut().take().unwrap().into_heads(); + +        *self.state.borrow_mut() = Some( +            StateBuilder { +                component: heads.component, +                message: PhantomData, +                state: PhantomData, +                element_builder: |component| Some(component.view(state)), +            } +            .build(), +        ); +    } +      fn with_element<T>(          &self,          f: impl FnOnce(&Element<'_, Event, Renderer>) -> T, @@ -101,34 +120,43 @@ impl<'a, Message, Renderer, Event> Instance<'a, Message, Renderer, Event> {              .borrow_mut()              .as_mut()              .unwrap() -            .with_cache_mut(|cache| { -                let mut element = cache.take().unwrap().into_heads().element; -                let result = f(&mut element); - -                *cache = Some( -                    CacheBuilder { -                        element, -                        overlay_builder: |_| None, -                    } -                    .build(), -                ); - -                result -            }) +            .with_element_mut(|element| f(element.as_mut().unwrap()))      }  } -impl<'a, Message, Renderer, Event> Widget<Message, Renderer> -    for Instance<'a, Message, Renderer, Event> +impl<'a, Message, Renderer, Event, S> Widget<Message, Renderer> +    for Instance<'a, Message, Renderer, Event, S>  where +    S: 'static + Default,      Renderer: iced_native::Renderer,  { +    fn tag(&self) -> tree::Tag { +        struct Tag<T>(T); +        tree::Tag::of::<Tag<S>>() +    } + +    fn state(&self) -> tree::State { +        tree::State::new(S::default()) +    } + +    fn children(&self) -> Vec<Tree> { +        self.rebuild_element(&S::default()); +        self.with_element(|element| vec![Tree::new(element)]) +    } + +    fn diff(&self, tree: &mut Tree) { +        self.rebuild_element(tree.state.downcast_ref()); +        self.with_element(|element| { +            tree.diff_children(std::slice::from_ref(&element)) +        }) +    } +      fn width(&self) -> Length { -        self.with_element(|element| element.width()) +        self.with_element(|element| element.as_widget().width())      }      fn height(&self) -> Length { -        self.with_element(|element| element.height()) +        self.with_element(|element| element.as_widget().height())      }      fn layout( @@ -136,11 +164,14 @@ where          renderer: &Renderer,          limits: &layout::Limits,      ) -> layout::Node { -        self.with_element(|element| element.layout(renderer, limits)) +        self.with_element(|element| { +            element.as_widget().layout(renderer, limits) +        })      }      fn on_event(          &mut self, +        tree: &mut Tree,          event: iced_native::Event,          layout: Layout<'_>,          cursor_position: Point, @@ -152,7 +183,8 @@ where          let mut local_shell = Shell::new(&mut local_messages);          let event_status = self.with_element_mut(|element| { -            element.on_event( +            element.as_widget_mut().on_event( +                &mut tree.children[0],                  event,                  layout,                  cursor_position, @@ -165,37 +197,31 @@ where          local_shell.revalidate_layout(|| shell.invalidate_layout());          if !local_messages.is_empty() { -            let mut component = self -                .state -                .borrow_mut() -                .take() -                .unwrap() -                .into_heads() -                .component; - -            for message in local_messages -                .into_iter() -                .filter_map(|message| component.update(message)) -            { +            let mut heads = self.state.take().unwrap().into_heads(); + +            for message in local_messages.into_iter().filter_map(|message| { +                heads +                    .component +                    .update(tree.state.downcast_mut::<S>(), message) +            }) {                  shell.publish(message);              } -            *self.state.borrow_mut() = Some( +            self.state = RefCell::new(Some(                  StateBuilder { -                    component, +                    component: heads.component,                      message: PhantomData, -                    cache_builder: |state| { -                        Some( -                            CacheBuilder { -                                element: state.view(), -                                overlay_builder: |_| None, -                            } -                            .build(), -                        ) +                    state: PhantomData, +                    element_builder: |state| { +                        Some(state.view(tree.state.downcast_ref::<S>()))                      },                  }                  .build(), -            ); +            )); + +            self.with_element(|element| { +                tree.diff_children(std::slice::from_ref(&element)) +            });              shell.invalidate_layout();          } @@ -205,6 +231,7 @@ where      fn draw(          &self, +        tree: &Tree,          renderer: &mut Renderer,          theme: &Renderer::Theme,          style: &renderer::Style, @@ -213,7 +240,8 @@ where          viewport: &Rectangle,      ) {          self.with_element(|element| { -            element.draw( +            element.as_widget().draw( +                &tree.children[0],                  renderer,                  theme,                  style, @@ -226,13 +254,15 @@ where      fn mouse_interaction(          &self, +        tree: &Tree,          layout: Layout<'_>,          cursor_position: Point,          viewport: &Rectangle,          renderer: &Renderer,      ) -> mouse::Interaction {          self.with_element(|element| { -            element.mouse_interaction( +            element.as_widget().mouse_interaction( +                &tree.children[0],                  layout,                  cursor_position,                  viewport, @@ -241,63 +271,72 @@ where          })      } -    fn overlay( -        &mut self, +    fn overlay<'b>( +        &'b self, +        tree: &'b mut Tree,          layout: Layout<'_>,          renderer: &Renderer, -    ) -> Option<overlay::Element<'_, Message, Renderer>> { -        let has_overlay = self -            .state -            .borrow_mut() -            .as_mut() -            .unwrap() -            .with_cache_mut(|cache| { -                let element = cache.take().unwrap().into_heads().element; - -                *cache = Some( -                    CacheBuilder { -                        element, -                        overlay_builder: |element| { -                            element.overlay(layout, renderer) -                        }, -                    } -                    .build(), -                ); - -                cache +    ) -> Option<overlay::Element<'b, Message, Renderer>> { +        let overlay = OverlayBuilder { +            instance: self, +            instance_ref_builder: |instance| instance.state.borrow(), +            tree, +            types: PhantomData, +            overlay_builder: |instance, tree| { +                instance                      .as_ref()                      .unwrap() -                    .borrow_overlay() +                    .borrow_element()                      .as_ref() -                    .map(|overlay| overlay.position()) -            }); +                    .unwrap() +                    .as_widget() +                    .overlay(&mut tree.children[0], layout, renderer) +            }, +        } +        .build(); + +        let has_overlay = overlay.with_overlay(|overlay| { +            overlay.as_ref().map(overlay::Element::position) +        });          has_overlay.map(|position| {              overlay::Element::new(                  position, -                Box::new(Overlay { instance: self }), +                Box::new(OverlayInstance { +                    overlay: Some(overlay), +                }),              )          })      }  } -struct Overlay<'a, 'b, Message, Renderer, Event> { -    instance: &'b mut Instance<'a, Message, Renderer, Event>, +#[self_referencing] +struct Overlay<'a, 'b, Message, Renderer, Event, S> { +    instance: &'a Instance<'b, Message, Renderer, Event, S>, +    tree: &'a mut Tree, +    types: PhantomData<(Message, Event, S)>, + +    #[borrows(instance)] +    #[covariant] +    instance_ref: Ref<'this, Option<State<'a, Message, Renderer, Event, S>>>, + +    #[borrows(instance_ref, mut tree)] +    #[covariant] +    overlay: Option<overlay::Element<'this, Event, Renderer>>, +} + +struct OverlayInstance<'a, 'b, Message, Renderer, Event, S> { +    overlay: Option<Overlay<'a, 'b, Message, Renderer, Event, S>>,  } -impl<'a, 'b, Message, Renderer, Event> -    Overlay<'a, 'b, Message, Renderer, Event> +impl<'a, 'b, Message, Renderer, Event, S> +    OverlayInstance<'a, 'b, Message, Renderer, Event, S>  {      fn with_overlay_maybe<T>(          &self,          f: impl FnOnce(&overlay::Element<'_, Event, Renderer>) -> T,      ) -> Option<T> { -        self.instance -            .state -            .borrow() -            .as_ref() -            .unwrap() -            .borrow_cache() +        self.overlay              .as_ref()              .unwrap()              .borrow_overlay() @@ -306,27 +345,21 @@ impl<'a, 'b, Message, Renderer, Event>      }      fn with_overlay_mut_maybe<T>( -        &self, +        &mut self,          f: impl FnOnce(&mut overlay::Element<'_, Event, Renderer>) -> T,      ) -> Option<T> { -        self.instance -            .state -            .borrow_mut() +        self.overlay              .as_mut()              .unwrap() -            .with_cache_mut(|cache| { -                cache -                    .as_mut() -                    .unwrap() -                    .with_overlay_mut(|overlay| overlay.as_mut().map(f)) -            }) +            .with_overlay_mut(|overlay| overlay.as_mut().map(f))      }  } -impl<'a, 'b, Message, Renderer, Event> overlay::Overlay<Message, Renderer> -    for Overlay<'a, 'b, Message, Renderer, Event> +impl<'a, 'b, Message, Renderer, Event, S> overlay::Overlay<Message, Renderer> +    for OverlayInstance<'a, 'b, Message, Renderer, Event, S>  where      Renderer: iced_native::Renderer, +    S: 'static + Default,  {      fn layout(          &self, @@ -401,32 +434,43 @@ where          local_shell.revalidate_layout(|| shell.invalidate_layout());          if !local_messages.is_empty() { -            let mut component = -                self.instance.state.take().unwrap().into_heads().component; - -            for message in local_messages -                .into_iter() -                .filter_map(|message| component.update(message)) -            { +            let overlay = self.overlay.take().unwrap().into_heads(); +            let mut heads = overlay.instance.state.take().unwrap().into_heads(); + +            for message in local_messages.into_iter().filter_map(|message| { +                heads +                    .component +                    .update(overlay.tree.state.downcast_mut::<S>(), message) +            }) {                  shell.publish(message);              } -            self.instance.state = RefCell::new(Some( +            *overlay.instance.state.borrow_mut() = Some(                  StateBuilder { -                    component, +                    component: heads.component,                      message: PhantomData, -                    cache_builder: |state| { -                        Some( -                            CacheBuilder { -                                element: state.view(), -                                overlay_builder: |_| None, -                            } -                            .build(), -                        ) +                    state: PhantomData, +                    element_builder: |state| { +                        Some(state.view(overlay.tree.state.downcast_ref::<S>()))                      },                  }                  .build(), -            )); +            ); + +            overlay.instance.with_element(|element| { +                overlay.tree.diff_children(std::slice::from_ref(&element)) +            }); + +            self.overlay = Some( +                OverlayBuilder { +                    instance: overlay.instance, +                    instance_ref_builder: |instance| instance.state.borrow(), +                    tree: overlay.tree, +                    types: PhantomData, +                    overlay_builder: |_, _| None, +                } +                .build(), +            );              shell.invalidate_layout();          } diff --git a/lazy/src/lib.rs b/lazy/src/lib.rs index aed11e9f..3827746c 100644 --- a/lazy/src/lib.rs +++ b/lazy/src/lib.rs @@ -20,13 +20,32 @@  pub mod component;  pub mod responsive; -#[cfg(feature = "pure")] -#[cfg_attr(docsrs, doc(cfg(feature = "pure")))] -pub mod pure; -  pub use component::Component;  pub use responsive::Responsive;  mod cache; -use cache::{Cache, CacheBuilder}; +use iced_native::{Element, Size}; + +/// Turns an implementor of [`Component`] into an [`Element`] that can be +/// embedded in any application. +pub fn component<'a, C, Message, Renderer>( +    component: C, +) -> Element<'a, Message, Renderer> +where +    C: Component<Message, Renderer> + 'a, +    C::State: 'static, +    Message: 'a, +    Renderer: iced_native::Renderer + 'a, +{ +    component::view(component) +} + +pub fn responsive<'a, Message, Renderer>( +    f: impl Fn(Size) -> Element<'a, Message, Renderer> + 'a, +) -> Responsive<'a, Message, Renderer> +where +    Renderer: iced_native::Renderer, +{ +    Responsive::new(f) +} diff --git a/lazy/src/pure.rs b/lazy/src/pure.rs deleted file mode 100644 index dc500e5e..00000000 --- a/lazy/src/pure.rs +++ /dev/null @@ -1,31 +0,0 @@ -mod component; -mod responsive; - -pub use component::Component; -pub use responsive::Responsive; - -use iced_native::Size; -use iced_pure::Element; - -/// Turns an implementor of [`Component`] into an [`Element`] that can be -/// embedded in any application. -pub fn component<'a, C, Message, Renderer>( -    component: C, -) -> Element<'a, Message, Renderer> -where -    C: Component<Message, Renderer> + 'a, -    C::State: 'static, -    Message: 'a, -    Renderer: iced_native::Renderer + 'a, -{ -    component::view(component) -} - -pub fn responsive<'a, Message, Renderer>( -    f: impl Fn(Size) -> Element<'a, Message, Renderer> + 'a, -) -> Responsive<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer, -{ -    Responsive::new(f) -} diff --git a/lazy/src/pure/component.rs b/lazy/src/pure/component.rs deleted file mode 100644 index b414a149..00000000 --- a/lazy/src/pure/component.rs +++ /dev/null @@ -1,479 +0,0 @@ -//! Build and reuse custom widgets using The Elm Architecture. -use iced_native::event; -use iced_native::layout::{self, Layout}; -use iced_native::mouse; -use iced_native::overlay; -use iced_native::renderer; -use iced_native::{Clipboard, Length, Point, Rectangle, Shell, Size}; -use iced_pure::widget::tree::{self, Tree}; -use iced_pure::{Element, Widget}; - -use ouroboros::self_referencing; -use std::cell::{Ref, RefCell}; -use std::marker::PhantomData; - -/// A reusable, custom widget that uses The Elm Architecture. -/// -/// A [`Component`] allows you to implement custom widgets as if they were -/// `iced` applications with encapsulated state. -/// -/// In other words, a [`Component`] allows you to turn `iced` applications into -/// custom widgets and embed them without cumbersome wiring. -/// -/// A [`Component`] produces widgets that may fire an [`Event`](Component::Event) -/// and update the internal state of the [`Component`]. -/// -/// Additionally, a [`Component`] is capable of producing a `Message` to notify -/// the parent application of any relevant interactions. -pub trait Component<Message, Renderer> { -    /// The internal state of this [`Component`]. -    type State: Default; - -    /// The type of event this [`Component`] handles internally. -    type Event; - -    /// Processes an [`Event`](Component::Event) and updates the [`Component`] state accordingly. -    /// -    /// It can produce a `Message` for the parent application. -    fn update( -        &mut self, -        state: &mut Self::State, -        event: Self::Event, -    ) -> Option<Message>; - -    /// Produces the widgets of the [`Component`], which may trigger an [`Event`](Component::Event) -    /// on user interaction. -    fn view(&self, state: &Self::State) -> Element<'_, Self::Event, Renderer>; -} - -/// Turns an implementor of [`Component`] into an [`Element`] that can be -/// embedded in any application. -pub fn view<'a, C, Message, Renderer>( -    component: C, -) -> Element<'a, Message, Renderer> -where -    C: Component<Message, Renderer> + 'a, -    C::State: 'static, -    Message: 'a, -    Renderer: iced_native::Renderer + 'a, -{ -    Element::new(Instance { -        state: RefCell::new(Some( -            StateBuilder { -                component: Box::new(component), -                message: PhantomData, -                state: PhantomData, -                element_builder: |_| None, -            } -            .build(), -        )), -    }) -} - -struct Instance<'a, Message, Renderer, Event, S> { -    state: RefCell<Option<State<'a, Message, Renderer, Event, S>>>, -} - -#[self_referencing] -struct State<'a, Message: 'a, Renderer: 'a, Event: 'a, S: 'a> { -    component: -        Box<dyn Component<Message, Renderer, Event = Event, State = S> + 'a>, -    message: PhantomData<Message>, -    state: PhantomData<S>, - -    #[borrows(component)] -    #[covariant] -    element: Option<Element<'this, Event, Renderer>>, -} - -impl<'a, Message, Renderer, Event, S> Instance<'a, Message, Renderer, Event, S> -where -    S: Default, -{ -    fn rebuild_element(&self, state: &S) { -        let heads = self.state.borrow_mut().take().unwrap().into_heads(); - -        *self.state.borrow_mut() = Some( -            StateBuilder { -                component: heads.component, -                message: PhantomData, -                state: PhantomData, -                element_builder: |component| Some(component.view(state)), -            } -            .build(), -        ); -    } - -    fn with_element<T>( -        &self, -        f: impl FnOnce(&Element<'_, Event, Renderer>) -> T, -    ) -> T { -        self.with_element_mut(|element| f(element)) -    } - -    fn with_element_mut<T>( -        &self, -        f: impl FnOnce(&mut Element<'_, Event, Renderer>) -> T, -    ) -> T { -        self.state -            .borrow_mut() -            .as_mut() -            .unwrap() -            .with_element_mut(|element| f(element.as_mut().unwrap())) -    } -} - -impl<'a, Message, Renderer, Event, S> Widget<Message, Renderer> -    for Instance<'a, Message, Renderer, Event, S> -where -    S: 'static + Default, -    Renderer: iced_native::Renderer, -{ -    fn tag(&self) -> tree::Tag { -        struct Tag<T>(T); -        tree::Tag::of::<Tag<S>>() -    } - -    fn state(&self) -> tree::State { -        tree::State::new(S::default()) -    } - -    fn children(&self) -> Vec<Tree> { -        self.rebuild_element(&S::default()); -        self.with_element(|element| vec![Tree::new(element)]) -    } - -    fn diff(&self, tree: &mut Tree) { -        self.rebuild_element(tree.state.downcast_ref()); -        self.with_element(|element| { -            tree.diff_children(std::slice::from_ref(&element)) -        }) -    } - -    fn width(&self) -> Length { -        self.with_element(|element| element.as_widget().width()) -    } - -    fn height(&self) -> Length { -        self.with_element(|element| element.as_widget().height()) -    } - -    fn layout( -        &self, -        renderer: &Renderer, -        limits: &layout::Limits, -    ) -> layout::Node { -        self.with_element(|element| { -            element.as_widget().layout(renderer, limits) -        }) -    } - -    fn on_event( -        &mut self, -        tree: &mut Tree, -        event: iced_native::Event, -        layout: Layout<'_>, -        cursor_position: Point, -        renderer: &Renderer, -        clipboard: &mut dyn Clipboard, -        shell: &mut Shell<'_, Message>, -    ) -> event::Status { -        let mut local_messages = Vec::new(); -        let mut local_shell = Shell::new(&mut local_messages); - -        let event_status = self.with_element_mut(|element| { -            element.as_widget_mut().on_event( -                &mut tree.children[0], -                event, -                layout, -                cursor_position, -                renderer, -                clipboard, -                &mut local_shell, -            ) -        }); - -        local_shell.revalidate_layout(|| shell.invalidate_layout()); - -        if !local_messages.is_empty() { -            let mut heads = self.state.take().unwrap().into_heads(); - -            for message in local_messages.into_iter().filter_map(|message| { -                heads -                    .component -                    .update(tree.state.downcast_mut::<S>(), message) -            }) { -                shell.publish(message); -            } - -            self.state = RefCell::new(Some( -                StateBuilder { -                    component: heads.component, -                    message: PhantomData, -                    state: PhantomData, -                    element_builder: |state| { -                        Some(state.view(tree.state.downcast_ref::<S>())) -                    }, -                } -                .build(), -            )); - -            self.with_element(|element| { -                tree.diff_children(std::slice::from_ref(&element)) -            }); - -            shell.invalidate_layout(); -        } - -        event_status -    } - -    fn draw( -        &self, -        tree: &Tree, -        renderer: &mut Renderer, -        theme: &Renderer::Theme, -        style: &renderer::Style, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -    ) { -        self.with_element(|element| { -            element.as_widget().draw( -                &tree.children[0], -                renderer, -                theme, -                style, -                layout, -                cursor_position, -                viewport, -            ); -        }); -    } - -    fn mouse_interaction( -        &self, -        tree: &Tree, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -        renderer: &Renderer, -    ) -> mouse::Interaction { -        self.with_element(|element| { -            element.as_widget().mouse_interaction( -                &tree.children[0], -                layout, -                cursor_position, -                viewport, -                renderer, -            ) -        }) -    } - -    fn overlay<'b>( -        &'b self, -        tree: &'b mut Tree, -        layout: Layout<'_>, -        renderer: &Renderer, -    ) -> Option<overlay::Element<'b, Message, Renderer>> { -        let overlay = OverlayBuilder { -            instance: self, -            instance_ref_builder: |instance| instance.state.borrow(), -            tree, -            types: PhantomData, -            overlay_builder: |instance, tree| { -                instance -                    .as_ref() -                    .unwrap() -                    .borrow_element() -                    .as_ref() -                    .unwrap() -                    .as_widget() -                    .overlay(&mut tree.children[0], layout, renderer) -            }, -        } -        .build(); - -        let has_overlay = overlay.with_overlay(|overlay| { -            overlay.as_ref().map(overlay::Element::position) -        }); - -        has_overlay.map(|position| { -            overlay::Element::new( -                position, -                Box::new(OverlayInstance { -                    overlay: Some(overlay), -                }), -            ) -        }) -    } -} - -#[self_referencing] -struct Overlay<'a, 'b, Message, Renderer, Event, S> { -    instance: &'a Instance<'b, Message, Renderer, Event, S>, -    tree: &'a mut Tree, -    types: PhantomData<(Message, Event, S)>, - -    #[borrows(instance)] -    #[covariant] -    instance_ref: Ref<'this, Option<State<'a, Message, Renderer, Event, S>>>, - -    #[borrows(instance_ref, mut tree)] -    #[covariant] -    overlay: Option<overlay::Element<'this, Event, Renderer>>, -} - -struct OverlayInstance<'a, 'b, Message, Renderer, Event, S> { -    overlay: Option<Overlay<'a, 'b, Message, Renderer, Event, S>>, -} - -impl<'a, 'b, Message, Renderer, Event, S> -    OverlayInstance<'a, 'b, Message, Renderer, Event, S> -{ -    fn with_overlay_maybe<T>( -        &self, -        f: impl FnOnce(&overlay::Element<'_, Event, Renderer>) -> T, -    ) -> Option<T> { -        self.overlay -            .as_ref() -            .unwrap() -            .borrow_overlay() -            .as_ref() -            .map(f) -    } - -    fn with_overlay_mut_maybe<T>( -        &mut self, -        f: impl FnOnce(&mut overlay::Element<'_, Event, Renderer>) -> T, -    ) -> Option<T> { -        self.overlay -            .as_mut() -            .unwrap() -            .with_overlay_mut(|overlay| overlay.as_mut().map(f)) -    } -} - -impl<'a, 'b, Message, Renderer, Event, S> overlay::Overlay<Message, Renderer> -    for OverlayInstance<'a, 'b, Message, Renderer, Event, S> -where -    Renderer: iced_native::Renderer, -    S: 'static + Default, -{ -    fn layout( -        &self, -        renderer: &Renderer, -        bounds: Size, -        position: Point, -    ) -> layout::Node { -        self.with_overlay_maybe(|overlay| { -            let vector = position - overlay.position(); - -            overlay.layout(renderer, bounds).translate(vector) -        }) -        .unwrap_or_default() -    } - -    fn draw( -        &self, -        renderer: &mut Renderer, -        theme: &Renderer::Theme, -        style: &renderer::Style, -        layout: Layout<'_>, -        cursor_position: Point, -    ) { -        let _ = self.with_overlay_maybe(|overlay| { -            overlay.draw(renderer, theme, style, layout, cursor_position); -        }); -    } - -    fn mouse_interaction( -        &self, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -        renderer: &Renderer, -    ) -> mouse::Interaction { -        self.with_overlay_maybe(|overlay| { -            overlay.mouse_interaction( -                layout, -                cursor_position, -                viewport, -                renderer, -            ) -        }) -        .unwrap_or_default() -    } - -    fn on_event( -        &mut self, -        event: iced_native::Event, -        layout: Layout<'_>, -        cursor_position: Point, -        renderer: &Renderer, -        clipboard: &mut dyn Clipboard, -        shell: &mut Shell<'_, Message>, -    ) -> iced_native::event::Status { -        let mut local_messages = Vec::new(); -        let mut local_shell = Shell::new(&mut local_messages); - -        let event_status = self -            .with_overlay_mut_maybe(|overlay| { -                overlay.on_event( -                    event, -                    layout, -                    cursor_position, -                    renderer, -                    clipboard, -                    &mut local_shell, -                ) -            }) -            .unwrap_or(iced_native::event::Status::Ignored); - -        local_shell.revalidate_layout(|| shell.invalidate_layout()); - -        if !local_messages.is_empty() { -            let overlay = self.overlay.take().unwrap().into_heads(); -            let mut heads = overlay.instance.state.take().unwrap().into_heads(); - -            for message in local_messages.into_iter().filter_map(|message| { -                heads -                    .component -                    .update(overlay.tree.state.downcast_mut::<S>(), message) -            }) { -                shell.publish(message); -            } - -            *overlay.instance.state.borrow_mut() = Some( -                StateBuilder { -                    component: heads.component, -                    message: PhantomData, -                    state: PhantomData, -                    element_builder: |state| { -                        Some(state.view(overlay.tree.state.downcast_ref::<S>())) -                    }, -                } -                .build(), -            ); - -            overlay.instance.with_element(|element| { -                overlay.tree.diff_children(std::slice::from_ref(&element)) -            }); - -            self.overlay = Some( -                OverlayBuilder { -                    instance: overlay.instance, -                    instance_ref_builder: |instance| instance.state.borrow(), -                    tree: overlay.tree, -                    types: PhantomData, -                    overlay_builder: |_, _| None, -                } -                .build(), -            ); - -            shell.invalidate_layout(); -        } - -        event_status -    } -} diff --git a/lazy/src/pure/responsive.rs b/lazy/src/pure/responsive.rs deleted file mode 100644 index 0964ebc8..00000000 --- a/lazy/src/pure/responsive.rs +++ /dev/null @@ -1,388 +0,0 @@ -use iced_native::event; -use iced_native::layout::{self, Layout}; -use iced_native::mouse; -use iced_native::renderer; -use iced_native::{Clipboard, Length, Point, Rectangle, Shell, Size}; -use iced_pure::horizontal_space; -use iced_pure::overlay; -use iced_pure::widget::tree::{self, Tree}; -use iced_pure::{Element, Widget}; - -use ouroboros::self_referencing; -use std::cell::{RefCell, RefMut}; -use std::marker::PhantomData; -use std::ops::Deref; - -/// A widget that is aware of its dimensions. -/// -/// A [`Responsive`] widget will always try to fill all the available space of -/// its parent. -#[allow(missing_debug_implementations)] -pub struct Responsive<'a, Message, Renderer> { -    view: Box<dyn Fn(Size) -> Element<'a, Message, Renderer> + 'a>, -    content: RefCell<Content<'a, Message, Renderer>>, -} - -impl<'a, Message, Renderer> Responsive<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer, -{ -    /// Creates a new [`Responsive`] widget with a closure that produces its -    /// contents. -    /// -    /// The `view` closure will be provided with the current [`Size`] of -    /// the [`Responsive`] widget and, therefore, can be used to build the -    /// contents of the widget in a responsive way. -    pub fn new( -        view: impl Fn(Size) -> Element<'a, Message, Renderer> + 'a, -    ) -> Self { -        Self { -            view: Box::new(view), -            content: RefCell::new(Content { -                size: Size::ZERO, -                layout: layout::Node::new(Size::ZERO), -                element: Element::new(horizontal_space(Length::Units(0))), -            }), -        } -    } -} - -struct Content<'a, Message, Renderer> { -    size: Size, -    layout: layout::Node, -    element: Element<'a, Message, Renderer>, -} - -impl<'a, Message, Renderer> Content<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer, -{ -    fn update( -        &mut self, -        tree: &mut Tree, -        renderer: &Renderer, -        new_size: Size, -        view: &dyn Fn(Size) -> Element<'a, Message, Renderer>, -    ) { -        if self.size == new_size { -            return; -        } - -        self.element = view(new_size); -        self.size = new_size; - -        tree.diff(&self.element); - -        self.layout = self -            .element -            .as_widget() -            .layout(renderer, &layout::Limits::new(Size::ZERO, self.size)); -    } - -    fn resolve<R, T>( -        &mut self, -        tree: &mut Tree, -        renderer: R, -        layout: Layout<'_>, -        view: &dyn Fn(Size) -> Element<'a, Message, Renderer>, -        f: impl FnOnce( -            &mut Tree, -            R, -            Layout<'_>, -            &mut Element<'a, Message, Renderer>, -        ) -> T, -    ) -> T -    where -        R: Deref<Target = Renderer>, -    { -        self.update(tree, renderer.deref(), layout.bounds().size(), view); - -        let content_layout = Layout::with_offset( -            layout.position() - Point::ORIGIN, -            &self.layout, -        ); - -        f(tree, renderer, content_layout, &mut self.element) -    } -} - -struct State { -    tree: RefCell<Tree>, -} - -impl<'a, Message, Renderer> Widget<Message, Renderer> -    for Responsive<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer, -{ -    fn tag(&self) -> tree::Tag { -        tree::Tag::of::<State>() -    } - -    fn state(&self) -> tree::State { -        tree::State::new(State { -            tree: RefCell::new(Tree::empty()), -        }) -    } - -    fn width(&self) -> Length { -        Length::Fill -    } - -    fn height(&self) -> Length { -        Length::Fill -    } - -    fn layout( -        &self, -        _renderer: &Renderer, -        limits: &layout::Limits, -    ) -> layout::Node { -        layout::Node::new(limits.max()) -    } - -    fn on_event( -        &mut self, -        tree: &mut Tree, -        event: iced_native::Event, -        layout: Layout<'_>, -        cursor_position: Point, -        renderer: &Renderer, -        clipboard: &mut dyn Clipboard, -        shell: &mut Shell<'_, Message>, -    ) -> event::Status { -        let state = tree.state.downcast_mut::<State>(); -        let mut content = self.content.borrow_mut(); - -        content.resolve( -            &mut state.tree.borrow_mut(), -            renderer, -            layout, -            &self.view, -            |tree, renderer, layout, element| { -                element.as_widget_mut().on_event( -                    tree, -                    event, -                    layout, -                    cursor_position, -                    renderer, -                    clipboard, -                    shell, -                ) -            }, -        ) -    } - -    fn draw( -        &self, -        tree: &Tree, -        renderer: &mut Renderer, -        theme: &Renderer::Theme, -        style: &renderer::Style, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -    ) { -        let state = tree.state.downcast_ref::<State>(); -        let mut content = self.content.borrow_mut(); - -        content.resolve( -            &mut state.tree.borrow_mut(), -            renderer, -            layout, -            &self.view, -            |tree, renderer, layout, element| { -                element.as_widget().draw( -                    tree, -                    renderer, -                    theme, -                    style, -                    layout, -                    cursor_position, -                    viewport, -                ) -            }, -        ) -    } - -    fn mouse_interaction( -        &self, -        tree: &Tree, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -        renderer: &Renderer, -    ) -> mouse::Interaction { -        let state = tree.state.downcast_ref::<State>(); -        let mut content = self.content.borrow_mut(); - -        content.resolve( -            &mut state.tree.borrow_mut(), -            renderer, -            layout, -            &self.view, -            |tree, renderer, layout, element| { -                element.as_widget().mouse_interaction( -                    tree, -                    layout, -                    cursor_position, -                    viewport, -                    renderer, -                ) -            }, -        ) -    } - -    fn overlay<'b>( -        &'b self, -        tree: &'b mut Tree, -        layout: Layout<'_>, -        renderer: &Renderer, -    ) -> Option<overlay::Element<'b, Message, Renderer>> { -        let state = tree.state.downcast_ref::<State>(); - -        let overlay = OverlayBuilder { -            content: self.content.borrow_mut(), -            tree: state.tree.borrow_mut(), -            types: PhantomData, -            overlay_builder: |content, tree| { -                content.update( -                    tree, -                    renderer, -                    layout.bounds().size(), -                    &self.view, -                ); - -                let content_layout = Layout::with_offset( -                    layout.position() - Point::ORIGIN, -                    &content.layout, -                ); - -                content.element.as_widget().overlay( -                    tree, -                    content_layout, -                    renderer, -                ) -            }, -        } -        .build(); - -        let has_overlay = overlay.with_overlay(|overlay| { -            overlay.as_ref().map(overlay::Element::position) -        }); - -        has_overlay -            .map(|position| overlay::Element::new(position, Box::new(overlay))) -    } -} - -impl<'a, Message, Renderer> From<Responsive<'a, Message, Renderer>> -    for Element<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer + 'a, -    Message: 'a, -{ -    fn from(responsive: Responsive<'a, Message, Renderer>) -> Self { -        Self::new(responsive) -    } -} - -#[self_referencing] -struct Overlay<'a, 'b, Message, Renderer> { -    content: RefMut<'a, Content<'b, Message, Renderer>>, -    tree: RefMut<'a, Tree>, -    types: PhantomData<Message>, - -    #[borrows(mut content, mut tree)] -    #[covariant] -    overlay: Option<overlay::Element<'this, Message, Renderer>>, -} - -impl<'a, 'b, Message, Renderer> Overlay<'a, 'b, Message, Renderer> { -    fn with_overlay_maybe<T>( -        &self, -        f: impl FnOnce(&overlay::Element<'_, Message, Renderer>) -> T, -    ) -> Option<T> { -        self.borrow_overlay().as_ref().map(f) -    } - -    fn with_overlay_mut_maybe<T>( -        &mut self, -        f: impl FnOnce(&mut overlay::Element<'_, Message, Renderer>) -> T, -    ) -> Option<T> { -        self.with_overlay_mut(|overlay| overlay.as_mut().map(f)) -    } -} - -impl<'a, 'b, Message, Renderer> overlay::Overlay<Message, Renderer> -    for Overlay<'a, 'b, Message, Renderer> -where -    Renderer: iced_native::Renderer, -{ -    fn layout( -        &self, -        renderer: &Renderer, -        bounds: Size, -        position: Point, -    ) -> layout::Node { -        self.with_overlay_maybe(|overlay| { -            let vector = position - overlay.position(); - -            overlay.layout(renderer, bounds).translate(vector) -        }) -        .unwrap_or_default() -    } - -    fn draw( -        &self, -        renderer: &mut Renderer, -        theme: &Renderer::Theme, -        style: &renderer::Style, -        layout: Layout<'_>, -        cursor_position: Point, -    ) { -        let _ = self.with_overlay_maybe(|overlay| { -            overlay.draw(renderer, theme, style, layout, cursor_position); -        }); -    } - -    fn mouse_interaction( -        &self, -        layout: Layout<'_>, -        cursor_position: Point, -        viewport: &Rectangle, -        renderer: &Renderer, -    ) -> mouse::Interaction { -        self.with_overlay_maybe(|overlay| { -            overlay.mouse_interaction( -                layout, -                cursor_position, -                viewport, -                renderer, -            ) -        }) -        .unwrap_or_default() -    } - -    fn on_event( -        &mut self, -        event: iced_native::Event, -        layout: Layout<'_>, -        cursor_position: Point, -        renderer: &Renderer, -        clipboard: &mut dyn Clipboard, -        shell: &mut Shell<'_, Message>, -    ) -> event::Status { -        self.with_overlay_mut_maybe(|overlay| { -            overlay.on_event( -                event, -                layout, -                cursor_position, -                renderer, -                clipboard, -                shell, -            ) -        }) -        .unwrap_or(iced_native::event::Status::Ignored) -    } -} diff --git a/lazy/src/responsive.rs b/lazy/src/responsive.rs index 4a3eb5c6..0b7ae6de 100644 --- a/lazy/src/responsive.rs +++ b/lazy/src/responsive.rs @@ -1,71 +1,131 @@ -//! Build responsive widgets. -use crate::{Cache, CacheBuilder}; - -use iced_native::event::{self, Event}; +use iced_native::event;  use iced_native::layout::{self, Layout};  use iced_native::mouse;  use iced_native::overlay;  use iced_native::renderer; -use iced_native::window; +use iced_native::widget::horizontal_space; +use iced_native::widget::tree::{self, Tree};  use iced_native::{      Clipboard, Element, Length, Point, Rectangle, Shell, Size, Widget,  }; -use std::cell::RefCell; +use ouroboros::self_referencing; +use std::cell::{RefCell, RefMut}; +use std::marker::PhantomData;  use std::ops::Deref; -/// The state of a [`Responsive`] widget. -#[derive(Debug, Clone, Default)] -pub struct State { -    last_size: Option<Size>, -    last_layout: layout::Node, -} - -impl State { -    pub fn new() -> State { -        State::default() -    } - -    fn layout(&self, parent: Layout<'_>) -> Layout<'_> { -        Layout::with_offset( -            parent.position() - Point::ORIGIN, -            &self.last_layout, -        ) -    } -} -  /// A widget that is aware of its dimensions.  ///  /// A [`Responsive`] widget will always try to fill all the available space of  /// its parent.  #[allow(missing_debug_implementations)] -pub struct Responsive<'a, Message, Renderer>( -    RefCell<Internal<'a, Message, Renderer>>, -); +pub struct Responsive<'a, Message, Renderer> { +    view: Box<dyn Fn(Size) -> Element<'a, Message, Renderer> + 'a>, +    content: RefCell<Content<'a, Message, Renderer>>, +} -impl<'a, Message, Renderer> Responsive<'a, Message, Renderer> { -    /// Creates a new [`Responsive`] widget with the given [`State`] and a -    /// closure that produces its contents. +impl<'a, Message, Renderer> Responsive<'a, Message, Renderer> +where +    Renderer: iced_native::Renderer, +{ +    /// Creates a new [`Responsive`] widget with a closure that produces its +    /// contents.      ///      /// The `view` closure will be provided with the current [`Size`] of      /// the [`Responsive`] widget and, therefore, can be used to build the      /// contents of the widget in a responsive way.      pub fn new( -        state: &'a mut State, -        view: impl FnOnce(Size) -> Element<'a, Message, Renderer> + 'a, +        view: impl Fn(Size) -> Element<'a, Message, Renderer> + 'a,      ) -> Self { -        Self(RefCell::new(Internal { -            state, -            content: Content::Pending(Some(Box::new(view))), -        })) +        Self { +            view: Box::new(view), +            content: RefCell::new(Content { +                size: Size::ZERO, +                layout: layout::Node::new(Size::ZERO), +                element: Element::new(horizontal_space(Length::Units(0))), +            }), +        }      }  } +struct Content<'a, Message, Renderer> { +    size: Size, +    layout: layout::Node, +    element: Element<'a, Message, Renderer>, +} + +impl<'a, Message, Renderer> Content<'a, Message, Renderer> +where +    Renderer: iced_native::Renderer, +{ +    fn update( +        &mut self, +        tree: &mut Tree, +        renderer: &Renderer, +        new_size: Size, +        view: &dyn Fn(Size) -> Element<'a, Message, Renderer>, +    ) { +        if self.size == new_size { +            return; +        } + +        self.element = view(new_size); +        self.size = new_size; + +        tree.diff(&self.element); + +        self.layout = self +            .element +            .as_widget() +            .layout(renderer, &layout::Limits::new(Size::ZERO, self.size)); +    } + +    fn resolve<R, T>( +        &mut self, +        tree: &mut Tree, +        renderer: R, +        layout: Layout<'_>, +        view: &dyn Fn(Size) -> Element<'a, Message, Renderer>, +        f: impl FnOnce( +            &mut Tree, +            R, +            Layout<'_>, +            &mut Element<'a, Message, Renderer>, +        ) -> T, +    ) -> T +    where +        R: Deref<Target = Renderer>, +    { +        self.update(tree, renderer.deref(), layout.bounds().size(), view); + +        let content_layout = Layout::with_offset( +            layout.position() - Point::ORIGIN, +            &self.layout, +        ); + +        f(tree, renderer, content_layout, &mut self.element) +    } +} + +struct State { +    tree: RefCell<Tree>, +} +  impl<'a, Message, Renderer> Widget<Message, Renderer>      for Responsive<'a, Message, Renderer>  where      Renderer: iced_native::Renderer,  { +    fn tag(&self) -> tree::Tag { +        tree::Tag::of::<State>() +    } + +    fn state(&self) -> tree::State { +        tree::State::new(State { +            tree: RefCell::new(Tree::empty()), +        }) +    } +      fn width(&self) -> Length {          Length::Fill      } @@ -79,45 +139,44 @@ where          _renderer: &Renderer,          limits: &layout::Limits,      ) -> layout::Node { -        let size = limits.max(); - -        self.0.borrow_mut().state.last_size = Some(size); - -        layout::Node::new(size) +        layout::Node::new(limits.max())      }      fn on_event(          &mut self, -        event: Event, +        tree: &mut Tree, +        event: iced_native::Event,          layout: Layout<'_>,          cursor_position: Point,          renderer: &Renderer,          clipboard: &mut dyn Clipboard,          shell: &mut Shell<'_, Message>,      ) -> event::Status { -        let mut internal = self.0.borrow_mut(); - -        if matches!(event, Event::Window(window::Event::Resized { .. })) -            || internal.state.last_size -                != Some(internal.state.last_layout.size()) -        { -            shell.invalidate_widgets(); -        } - -        internal.resolve(renderer, |state, renderer, content| { -            content.on_event( -                event, -                state.layout(layout), -                cursor_position, -                renderer, -                clipboard, -                shell, -            ) -        }) +        let state = tree.state.downcast_mut::<State>(); +        let mut content = self.content.borrow_mut(); + +        content.resolve( +            &mut state.tree.borrow_mut(), +            renderer, +            layout, +            &self.view, +            |tree, renderer, layout, element| { +                element.as_widget_mut().on_event( +                    tree, +                    event, +                    layout, +                    cursor_position, +                    renderer, +                    clipboard, +                    shell, +                ) +            }, +        )      }      fn draw(          &self, +        tree: &Tree,          renderer: &mut Renderer,          theme: &Renderer::Theme,          style: &renderer::Style, @@ -125,168 +184,96 @@ where          cursor_position: Point,          viewport: &Rectangle,      ) { -        let mut internal = self.0.borrow_mut(); - -        internal.resolve(renderer, |state, renderer, content| { -            content.draw( -                renderer, -                theme, -                style, -                state.layout(layout), -                cursor_position, -                viewport, -            ) -        }) +        let state = tree.state.downcast_ref::<State>(); +        let mut content = self.content.borrow_mut(); + +        content.resolve( +            &mut state.tree.borrow_mut(), +            renderer, +            layout, +            &self.view, +            |tree, renderer, layout, element| { +                element.as_widget().draw( +                    tree, +                    renderer, +                    theme, +                    style, +                    layout, +                    cursor_position, +                    viewport, +                ) +            }, +        )      }      fn mouse_interaction(          &self, +        tree: &Tree,          layout: Layout<'_>,          cursor_position: Point,          viewport: &Rectangle,          renderer: &Renderer,      ) -> mouse::Interaction { -        let mut internal = self.0.borrow_mut(); - -        internal.resolve(renderer, |state, renderer, content| { -            content.mouse_interaction( -                state.layout(layout), -                cursor_position, -                viewport, -                renderer, -            ) -        }) +        let state = tree.state.downcast_ref::<State>(); +        let mut content = self.content.borrow_mut(); + +        content.resolve( +            &mut state.tree.borrow_mut(), +            renderer, +            layout, +            &self.view, +            |tree, renderer, layout, element| { +                element.as_widget().mouse_interaction( +                    tree, +                    layout, +                    cursor_position, +                    viewport, +                    renderer, +                ) +            }, +        )      } -    fn overlay( -        &mut self, +    fn overlay<'b>( +        &'b self, +        tree: &'b mut Tree,          layout: Layout<'_>,          renderer: &Renderer, -    ) -> Option<overlay::Element<'_, Message, Renderer>> { -        let has_overlay = { -            use std::ops::DerefMut; - -            let mut internal = self.0.borrow_mut(); - -            let _ = -                internal.resolve(renderer, |_state, _renderer, _content| {}); - -            let Internal { content, state } = internal.deref_mut(); - -            let content_layout = state.layout(layout); - -            match content { -                Content::Pending(_) => None, -                Content::Ready(cache) => { -                    *cache = Some( -                        CacheBuilder { -                            element: cache.take().unwrap().into_heads().element, -                            overlay_builder: |element| { -                                element.overlay(content_layout, renderer) -                            }, -                        } -                        .build(), -                    ); - -                    cache -                        .as_ref() -                        .unwrap() -                        .borrow_overlay() -                        .as_ref() -                        .map(|overlay| overlay.position()) -                } -            } -        }; - -        has_overlay.map(|position| { -            overlay::Element::new( -                position, -                Box::new(Overlay { instance: self }), -            ) -        }) -    } -} - -struct Internal<'a, Message, Renderer> { -    state: &'a mut State, -    content: Content<'a, Message, Renderer>, -} - -impl<'a, Message, Renderer> Internal<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer, -{ -    fn resolve<R, T>( -        &mut self, -        renderer: R, -        f: impl FnOnce(&State, R, &mut Element<'a, Message, Renderer>) -> T, -    ) -> T -    where -        R: Deref<Target = Renderer>, -    { -        self.content.resolve(self.state, renderer, f) -    } -} - -enum Content<'a, Message, Renderer> { -    Pending( -        Option<Box<dyn FnOnce(Size) -> Element<'a, Message, Renderer> + 'a>>, -    ), -    Ready(Option<Cache<'a, Message, Renderer>>), -} - -impl<'a, Message, Renderer> Content<'a, Message, Renderer> -where -    Renderer: iced_native::Renderer, -{ -    fn resolve<R, T>( -        &mut self, -        state: &mut State, -        renderer: R, -        f: impl FnOnce(&State, R, &mut Element<'a, Message, Renderer>) -> T, -    ) -> T -    where -        R: Deref<Target = Renderer>, -    { -        match self { -            Content::Ready(cache) => { -                let mut heads = cache.take().unwrap().into_heads(); - -                let result = f(state, renderer, &mut heads.element); - -                *cache = Some( -                    CacheBuilder { -                        element: heads.element, -                        overlay_builder: |_| None, -                    } -                    .build(), +    ) -> Option<overlay::Element<'b, Message, Renderer>> { +        let state = tree.state.downcast_ref::<State>(); + +        let overlay = OverlayBuilder { +            content: self.content.borrow_mut(), +            tree: state.tree.borrow_mut(), +            types: PhantomData, +            overlay_builder: |content, tree| { +                content.update( +                    tree, +                    renderer, +                    layout.bounds().size(), +                    &self.view,                  ); -                result -            } -            Content::Pending(view) => { -                let element = -                    view.take().unwrap()(state.last_size.unwrap_or(Size::ZERO)); - -                state.last_layout = element.layout( -                    renderer.deref(), -                    &layout::Limits::new( -                        Size::ZERO, -                        state.last_size.unwrap_or(Size::ZERO), -                    ), +                let content_layout = Layout::with_offset( +                    layout.position() - Point::ORIGIN, +                    &content.layout,                  ); -                *self = Content::Ready(Some( -                    CacheBuilder { -                        element, -                        overlay_builder: |_| None, -                    } -                    .build(), -                )); - -                self.resolve(state, renderer, f) -            } +                content.element.as_widget().overlay( +                    tree, +                    content_layout, +                    renderer, +                ) +            },          } +        .build(); + +        let has_overlay = overlay.with_overlay(|overlay| { +            overlay.as_ref().map(overlay::Element::position) +        }); + +        has_overlay +            .map(|position| overlay::Element::new(position, Box::new(overlay)))      }  } @@ -301,8 +288,15 @@ where      }  } +#[self_referencing]  struct Overlay<'a, 'b, Message, Renderer> { -    instance: &'b mut Responsive<'a, Message, Renderer>, +    content: RefMut<'a, Content<'b, Message, Renderer>>, +    tree: RefMut<'a, Tree>, +    types: PhantomData<Message>, + +    #[borrows(mut content, mut tree)] +    #[covariant] +    overlay: Option<overlay::Element<'this, Message, Renderer>>,  }  impl<'a, 'b, Message, Renderer> Overlay<'a, 'b, Message, Renderer> { @@ -310,29 +304,14 @@ impl<'a, 'b, Message, Renderer> Overlay<'a, 'b, Message, Renderer> {          &self,          f: impl FnOnce(&overlay::Element<'_, Message, Renderer>) -> T,      ) -> Option<T> { -        let internal = self.instance.0.borrow(); - -        match &internal.content { -            Content::Pending(_) => None, -            Content::Ready(cache) => { -                cache.as_ref().unwrap().borrow_overlay().as_ref().map(f) -            } -        } +        self.borrow_overlay().as_ref().map(f)      }      fn with_overlay_mut_maybe<T>( -        &self, +        &mut self,          f: impl FnOnce(&mut overlay::Element<'_, Message, Renderer>) -> T,      ) -> Option<T> { -        let mut internal = self.instance.0.borrow_mut(); - -        match &mut internal.content { -            Content::Pending(_) => None, -            Content::Ready(cache) => cache -                .as_mut() -                .unwrap() -                .with_overlay_mut(|overlay| overlay.as_mut().map(f)), -        } +        self.with_overlay_mut(|overlay| overlay.as_mut().map(f))      }  } @@ -394,7 +373,7 @@ where          renderer: &Renderer,          clipboard: &mut dyn Clipboard,          shell: &mut Shell<'_, Message>, -    ) -> iced_native::event::Status { +    ) -> event::Status {          self.with_overlay_mut_maybe(|overlay| {              overlay.on_event(                  event, | 
