summaryrefslogtreecommitdiffstats
path: root/widget/src/lazy
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--widget/src/lazy.rs (renamed from lazy/src/lazy.rs)134
-rw-r--r--widget/src/lazy/cache.rs (renamed from lazy/src/cache.rs)4
-rw-r--r--widget/src/lazy/component.rs (renamed from lazy/src/component.rs)356
-rw-r--r--widget/src/lazy/helpers.rs (renamed from lazy/src/lib.rs)45
-rw-r--r--widget/src/lazy/responsive.rs (renamed from lazy/src/responsive.rs)181
5 files changed, 408 insertions, 312 deletions
diff --git a/lazy/src/lazy.rs b/widget/src/lazy.rs
index 5e909a49..da287f06 100644
--- a/lazy/src/lazy.rs
+++ b/widget/src/lazy.rs
@@ -1,18 +1,33 @@
-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::widget::{self, Widget};
-use iced_native::Element;
-use iced_native::{Clipboard, Hasher, Length, Point, Rectangle, Shell, Size};
+#![allow(clippy::await_holding_refcell_ref, clippy::type_complexity)]
+pub(crate) mod helpers;
+
+pub mod component;
+pub mod responsive;
+
+pub use component::Component;
+pub use responsive::Responsive;
+
+mod cache;
+
+use crate::core::event::{self, Event};
+use crate::core::layout::{self, Layout};
+use crate::core::mouse;
+use crate::core::overlay;
+use crate::core::renderer;
+use crate::core::widget::tree::{self, Tree};
+use crate::core::widget::{self, Widget};
+use crate::core::Element;
+use crate::core::{
+ self, Clipboard, Hasher, Length, Point, Rectangle, Shell, Size,
+};
+use crate::runtime::overlay::Nested;
use ouroboros::self_referencing;
use std::cell::RefCell;
use std::hash::{Hash, Hasher as H};
use std::rc::Rc;
+/// A widget that only rebuilds its contents when necessary.
#[allow(missing_debug_implementations)]
pub struct Lazy<'a, Message, Renderer, Dependency, View> {
dependency: Dependency,
@@ -28,6 +43,8 @@ where
Dependency: Hash + 'a,
View: Into<Element<'static, Message, Renderer>>,
{
+ /// Creates a new [`Lazy`] widget with the given data `Dependency` and a
+ /// closure that can turn this data into a widget tree.
pub fn new(
dependency: Dependency,
view: impl Fn(&Dependency) -> View + 'a,
@@ -41,7 +58,7 @@ where
fn with_element<T>(
&self,
- f: impl FnOnce(&Element<Message, Renderer>) -> T,
+ f: impl FnOnce(&Element<'_, Message, Renderer>) -> T,
) -> T {
f(self
.element
@@ -55,7 +72,7 @@ where
fn with_element_mut<T>(
&self,
- f: impl FnOnce(&mut Element<Message, Renderer>) -> T,
+ f: impl FnOnce(&mut Element<'_, Message, Renderer>) -> T,
) -> T {
f(self
.element
@@ -79,7 +96,7 @@ where
View: Into<Element<'static, Message, Renderer>> + 'static,
Dependency: Hash + 'a,
Message: 'static,
- Renderer: iced_native::Renderer + 'static,
+ Renderer: core::Renderer + 'static,
{
fn tag(&self) -> tree::Tag {
struct Tag<T>(T);
@@ -163,9 +180,9 @@ where
fn on_event(
&mut self,
tree: &mut Tree,
- event: iced_native::Event,
+ event: Event,
layout: Layout<'_>,
- cursor_position: Point,
+ cursor: mouse::Cursor,
renderer: &Renderer,
clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>,
@@ -175,7 +192,7 @@ where
&mut tree.children[0],
event,
layout,
- cursor_position,
+ cursor,
renderer,
clipboard,
shell,
@@ -187,7 +204,7 @@ where
&self,
tree: &Tree,
layout: Layout<'_>,
- cursor_position: Point,
+ cursor: mouse::Cursor,
viewport: &Rectangle,
renderer: &Renderer,
) -> mouse::Interaction {
@@ -195,7 +212,7 @@ where
element.as_widget().mouse_interaction(
&tree.children[0],
layout,
- cursor_position,
+ cursor,
viewport,
renderer,
)
@@ -209,7 +226,7 @@ where
theme: &Renderer::Theme,
style: &renderer::Style,
layout: Layout<'_>,
- cursor_position: Point,
+ cursor: mouse::Cursor,
viewport: &Rectangle,
) {
self.with_element(|element| {
@@ -219,7 +236,7 @@ where
theme,
style,
layout,
- cursor_position,
+ cursor,
viewport,
)
})
@@ -244,14 +261,17 @@ where
.unwrap(),
tree: &mut tree.children[0],
overlay_builder: |element, tree| {
- element.as_widget_mut().overlay(tree, layout, renderer)
+ element
+ .as_widget_mut()
+ .overlay(tree, layout, renderer)
+ .map(|overlay| RefCell::new(Nested::new(overlay)))
},
}
.build(),
));
- let has_overlay = overlay
- .with_overlay_maybe(|overlay| overlay::Element::position(overlay));
+ let has_overlay =
+ overlay.with_overlay_maybe(|overlay| overlay.position());
has_overlay
.map(|position| overlay::Element::new(position, Box::new(overlay)))
@@ -259,18 +279,14 @@ where
}
#[self_referencing]
-struct Inner<'a, Message, Renderer>
-where
- Message: 'a,
- Renderer: 'a,
-{
+struct Inner<'a, Message: 'a, Renderer: 'a> {
cell: Rc<RefCell<Option<Element<'static, Message, Renderer>>>>,
element: Element<'static, Message, Renderer>,
tree: &'a mut Tree,
#[borrows(mut element, mut tree)]
- #[covariant]
- overlay: Option<overlay::Element<'this, Message, Renderer>>,
+ #[not_covariant]
+ overlay: Option<RefCell<Nested<'this, Message, Renderer>>>,
}
struct Overlay<'a, Message, Renderer>(Option<Inner<'a, Message, Renderer>>);
@@ -285,26 +301,27 @@ impl<'a, Message, Renderer> Drop for Overlay<'a, Message, Renderer> {
impl<'a, Message, Renderer> Overlay<'a, Message, Renderer> {
fn with_overlay_maybe<T>(
&self,
- f: impl FnOnce(&overlay::Element<'_, Message, Renderer>) -> T,
+ f: impl FnOnce(&mut Nested<'_, Message, Renderer>) -> T,
) -> Option<T> {
- self.0.as_ref().unwrap().borrow_overlay().as_ref().map(f)
+ self.0.as_ref().unwrap().with_overlay(|overlay| {
+ overlay.as_ref().map(|nested| (f)(&mut nested.borrow_mut()))
+ })
}
fn with_overlay_mut_maybe<T>(
&mut self,
- f: impl FnOnce(&mut overlay::Element<'_, Message, Renderer>) -> T,
+ f: impl FnOnce(&mut Nested<'_, Message, Renderer>) -> T,
) -> Option<T> {
- self.0
- .as_mut()
- .unwrap()
- .with_overlay_mut(|overlay| overlay.as_mut().map(f))
+ self.0.as_mut().unwrap().with_overlay_mut(|overlay| {
+ overlay.as_mut().map(|nested| (f)(nested.get_mut()))
+ })
}
}
impl<'a, Message, Renderer> overlay::Overlay<Message, Renderer>
for Overlay<'a, Message, Renderer>
where
- Renderer: iced_native::Renderer,
+ Renderer: core::Renderer,
{
fn layout(
&self,
@@ -313,9 +330,7 @@ where
position: Point,
) -> layout::Node {
self.with_overlay_maybe(|overlay| {
- let translation = position - overlay.position();
-
- overlay.layout(renderer, bounds, translation)
+ overlay.layout(renderer, bounds, position)
})
.unwrap_or_default()
}
@@ -326,56 +341,49 @@ where
theme: &Renderer::Theme,
style: &renderer::Style,
layout: Layout<'_>,
- cursor_position: Point,
+ cursor: mouse::Cursor,
) {
let _ = self.with_overlay_maybe(|overlay| {
- overlay.draw(renderer, theme, style, layout, cursor_position);
+ overlay.draw(renderer, theme, style, layout, cursor);
});
}
fn mouse_interaction(
&self,
layout: Layout<'_>,
- cursor_position: Point,
+ cursor: mouse::Cursor,
viewport: &Rectangle,
renderer: &Renderer,
) -> mouse::Interaction {
self.with_overlay_maybe(|overlay| {
- overlay.mouse_interaction(
- layout,
- cursor_position,
- viewport,
- renderer,
- )
+ overlay.mouse_interaction(layout, cursor, viewport, renderer)
})
.unwrap_or_default()
}
fn on_event(
&mut self,
- event: iced_native::Event,
+ event: Event,
layout: Layout<'_>,
- cursor_position: Point,
+ cursor: mouse::Cursor,
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,
- )
+ overlay.on_event(event, layout, cursor, renderer, clipboard, shell)
})
- .unwrap_or(iced_native::event::Status::Ignored)
+ .unwrap_or(event::Status::Ignored)
}
- fn is_over(&self, layout: Layout<'_>, cursor_position: Point) -> bool {
+ fn is_over(
+ &self,
+ layout: Layout<'_>,
+ renderer: &Renderer,
+ cursor_position: Point,
+ ) -> bool {
self.with_overlay_maybe(|overlay| {
- overlay.is_over(layout, cursor_position)
+ overlay.is_over(layout, renderer, cursor_position)
})
.unwrap_or_default()
}
@@ -386,7 +394,7 @@ impl<'a, Message, Renderer, Dependency, View>
for Element<'a, Message, Renderer>
where
View: Into<Element<'static, Message, Renderer>> + 'static,
- Renderer: iced_native::Renderer + 'static,
+ Renderer: core::Renderer + 'static,
Message: 'static,
Dependency: Hash + 'a,
{
diff --git a/lazy/src/cache.rs b/widget/src/lazy/cache.rs
index 5b4a39f6..e7b87614 100644
--- a/lazy/src/cache.rs
+++ b/widget/src/lazy/cache.rs
@@ -1,5 +1,5 @@
-use iced_native::overlay;
-use iced_native::Element;
+use crate::core::overlay;
+use crate::core::Element;
use ouroboros::self_referencing;
diff --git a/lazy/src/component.rs b/widget/src/lazy/component.rs
index b23da9f7..c7814966 100644
--- a/lazy/src/component.rs
+++ b/widget/src/lazy/component.rs
@@ -1,18 +1,20 @@
//! 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::widget;
-use iced_native::widget::tree::{self, Tree};
-use iced_native::{
- Clipboard, Element, Length, Point, Rectangle, Shell, Size, Widget,
+use crate::core::event;
+use crate::core::layout::{self, Layout};
+use crate::core::mouse;
+use crate::core::overlay;
+use crate::core::renderer;
+use crate::core::widget;
+use crate::core::widget::tree::{self, Tree};
+use crate::core::{
+ self, Clipboard, Element, Length, Point, Rectangle, Shell, Size, Widget,
};
+use crate::runtime::overlay::Nested;
use ouroboros::self_referencing;
use std::cell::RefCell;
use std::marker::PhantomData;
+use std::rc::Rc;
/// A reusable, custom widget that uses The Elm Architecture.
///
@@ -58,6 +60,8 @@ pub trait Component<Message, Renderer> {
}
}
+struct Tag<T>(T);
+
/// Turns an implementor of [`Component`] into an [`Element`] that can be
/// embedded in any application.
pub fn view<'a, C, Message, Renderer>(
@@ -67,7 +71,7 @@ where
C: Component<Message, Renderer> + 'a,
C::State: 'static,
Message: 'a,
- Renderer: iced_native::Renderer + 'a,
+ Renderer: core::Renderer + 'a,
{
Element::new(Instance {
state: RefCell::new(Some(
@@ -79,11 +83,13 @@ where
}
.build(),
)),
+ tree: RefCell::new(Rc::new(RefCell::new(None))),
})
}
struct Instance<'a, Message, Renderer, Event, S> {
state: RefCell<Option<State<'a, Message, Renderer, Event, S>>>,
+ tree: RefCell<Rc<RefCell<Option<Tree>>>>,
}
#[self_referencing]
@@ -100,40 +106,91 @@ struct State<'a, Message: 'a, Renderer: 'a, Event: 'a, S: 'a> {
impl<'a, Message, Renderer, Event, S> Instance<'a, Message, Renderer, Event, S>
where
- S: Default,
+ S: Default + 'static,
+ Renderer: renderer::Renderer,
{
- fn rebuild_element(&self, state: &S) {
- let heads = self.state.borrow_mut().take().unwrap().into_heads();
+ fn diff_self(&self) {
+ self.with_element(|element| {
+ self.tree
+ .borrow_mut()
+ .borrow_mut()
+ .as_mut()
+ .unwrap()
+ .diff_children(std::slice::from_ref(&element));
+ });
+ }
- *self.state.borrow_mut() = Some(
- StateBuilder {
- component: heads.component,
- message: PhantomData,
- state: PhantomData,
- element_builder: |component| Some(component.view(state)),
- }
- .build(),
- );
+ fn rebuild_element_if_necessary(&self) {
+ let inner = self.state.borrow_mut().take().unwrap();
+ if inner.borrow_element().is_none() {
+ let heads = inner.into_heads();
+
+ *self.state.borrow_mut() = Some(
+ StateBuilder {
+ component: heads.component,
+ message: PhantomData,
+ state: PhantomData,
+ element_builder: |component| {
+ Some(
+ component.view(
+ self.tree
+ .borrow()
+ .borrow()
+ .as_ref()
+ .unwrap()
+ .state
+ .downcast_ref::<S>(),
+ ),
+ )
+ },
+ }
+ .build(),
+ );
+ self.diff_self();
+ } else {
+ *self.state.borrow_mut() = Some(inner);
+ }
}
fn rebuild_element_with_operation(
&self,
- state: &mut S,
operation: &mut dyn widget::Operation<Message>,
) {
let heads = self.state.borrow_mut().take().unwrap().into_heads();
- heads.component.operate(state, operation);
+ heads.component.operate(
+ self.tree
+ .borrow_mut()
+ .borrow_mut()
+ .as_mut()
+ .unwrap()
+ .state
+ .downcast_mut(),
+ operation,
+ );
*self.state.borrow_mut() = Some(
StateBuilder {
component: heads.component,
message: PhantomData,
state: PhantomData,
- element_builder: |component| Some(component.view(state)),
+ element_builder: |component| {
+ Some(
+ component.view(
+ self.tree
+ .borrow()
+ .borrow()
+ .as_ref()
+ .unwrap()
+ .state
+ .downcast_ref(),
+ ),
+ )
+ },
}
.build(),
);
+ self.diff_self();
}
fn with_element<T>(
@@ -147,6 +204,7 @@ where
&self,
f: impl FnOnce(&mut Element<'_, Event, Renderer>) -> T,
) -> T {
+ self.rebuild_element_if_necessary();
self.state
.borrow_mut()
.as_mut()
@@ -159,27 +217,30 @@ impl<'a, Message, Renderer, Event, S> Widget<Message, Renderer>
for Instance<'a, Message, Renderer, Event, S>
where
S: 'static + Default,
- Renderer: iced_native::Renderer,
+ Renderer: core::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())
+ let state = Rc::new(RefCell::new(Some(Tree {
+ tag: tree::Tag::of::<Tag<S>>(),
+ state: tree::State::new(S::default()),
+ children: vec![Tree::empty()],
+ })));
+ *self.tree.borrow_mut() = state.clone();
+ tree::State::new(state)
}
fn children(&self) -> Vec<Tree> {
- self.rebuild_element(&S::default());
- self.with_element(|element| vec![Tree::new(element)])
+ vec![]
}
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))
- })
+ let tree = tree.state.downcast_ref::<Rc<RefCell<Option<Tree>>>>();
+ *self.tree.borrow_mut() = tree.clone();
+ self.rebuild_element_if_necessary();
}
fn width(&self) -> Length {
@@ -203,9 +264,9 @@ where
fn on_event(
&mut self,
tree: &mut Tree,
- event: iced_native::Event,
+ event: core::Event,
layout: Layout<'_>,
- cursor_position: Point,
+ cursor: mouse::Cursor,
renderer: &Renderer,
clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>,
@@ -213,12 +274,13 @@ where
let mut local_messages = Vec::new();
let mut local_shell = Shell::new(&mut local_messages);
+ let t = tree.state.downcast_mut::<Rc<RefCell<Option<Tree>>>>();
let event_status = self.with_element_mut(|element| {
element.as_widget_mut().on_event(
- &mut tree.children[0],
+ &mut t.borrow_mut().as_mut().unwrap().children[0],
event,
layout,
- cursor_position,
+ cursor,
renderer,
clipboard,
&mut local_shell,
@@ -235,9 +297,10 @@ where
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)
+ heads.component.update(
+ t.borrow_mut().as_mut().unwrap().state.downcast_mut(),
+ message,
+ )
}) {
shell.publish(message);
}
@@ -247,17 +310,11 @@ where
component: heads.component,
message: PhantomData,
state: PhantomData,
- element_builder: |state| {
- Some(state.view(tree.state.downcast_ref::<S>()))
- },
+ element_builder: |_| None,
}
.build(),
));
- self.with_element(|element| {
- tree.diff_children(std::slice::from_ref(&element))
- });
-
shell.invalidate_layout();
}
@@ -271,10 +328,7 @@ where
renderer: &Renderer,
operation: &mut dyn widget::Operation<Message>,
) {
- self.rebuild_element_with_operation(
- tree.state.downcast_mut(),
- operation,
- );
+ self.rebuild_element_with_operation(operation);
struct MapOperation<'a, B> {
operation: &'a mut dyn widget::Operation<B>,
@@ -308,13 +362,28 @@ where
) {
self.operation.text_input(state, id);
}
+
+ fn scrollable(
+ &mut self,
+ state: &mut dyn widget::operation::Scrollable,
+ id: Option<&widget::Id>,
+ ) {
+ self.operation.scrollable(state, id);
+ }
+
+ fn custom(
+ &mut self,
+ state: &mut dyn std::any::Any,
+ id: Option<&widget::Id>,
+ ) {
+ self.operation.custom(state, id);
+ }
}
+ let tree = tree.state.downcast_mut::<Rc<RefCell<Option<Tree>>>>();
self.with_element(|element| {
- tree.diff_children(std::slice::from_ref(&element));
-
element.as_widget().operate(
- &mut tree.children[0],
+ &mut tree.borrow_mut().as_mut().unwrap().children[0],
layout,
renderer,
&mut MapOperation { operation },
@@ -329,17 +398,18 @@ where
theme: &Renderer::Theme,
style: &renderer::Style,
layout: Layout<'_>,
- cursor_position: Point,
+ cursor: mouse::Cursor,
viewport: &Rectangle,
) {
+ let tree = tree.state.downcast_ref::<Rc<RefCell<Option<Tree>>>>();
self.with_element(|element| {
element.as_widget().draw(
- &tree.children[0],
+ &tree.borrow().as_ref().unwrap().children[0],
renderer,
theme,
style,
layout,
- cursor_position,
+ cursor,
viewport,
);
});
@@ -349,15 +419,16 @@ where
&self,
tree: &Tree,
layout: Layout<'_>,
- cursor_position: Point,
+ cursor: mouse::Cursor,
viewport: &Rectangle,
renderer: &Renderer,
) -> mouse::Interaction {
+ let tree = tree.state.downcast_ref::<Rc<RefCell<Option<Tree>>>>();
self.with_element(|element| {
element.as_widget().mouse_interaction(
- &tree.children[0],
+ &tree.borrow().as_ref().unwrap().children[0],
layout,
- cursor_position,
+ cursor,
viewport,
renderer,
)
@@ -370,26 +441,42 @@ where
layout: Layout<'_>,
renderer: &Renderer,
) -> Option<overlay::Element<'b, Message, Renderer>> {
- let overlay = OverlayBuilder {
- instance: self,
- tree,
- types: PhantomData,
- overlay_builder: |instance, tree| {
- instance.state.get_mut().as_mut().unwrap().with_element_mut(
- move |element| {
- element.as_mut().unwrap().as_widget_mut().overlay(
- &mut tree.children[0],
- layout,
- renderer,
- )
- },
- )
- },
- }
- .build();
+ self.rebuild_element_if_necessary();
+ let tree = tree
+ .state
+ .downcast_mut::<Rc<RefCell<Option<Tree>>>>()
+ .borrow_mut()
+ .take()
+ .unwrap();
+ let overlay = Overlay(Some(
+ InnerBuilder {
+ instance: self,
+ tree,
+ types: PhantomData,
+ overlay_builder: |instance, tree| {
+ instance.state.get_mut().as_mut().unwrap().with_element_mut(
+ move |element| {
+ element
+ .as_mut()
+ .unwrap()
+ .as_widget_mut()
+ .overlay(
+ &mut tree.children[0],
+ layout,
+ renderer,
+ )
+ .map(|overlay| {
+ RefCell::new(Nested::new(overlay))
+ })
+ },
+ )
+ },
+ }
+ .build(),
+ ));
- let has_overlay = overlay.with_overlay(|overlay| {
- overlay.as_ref().map(overlay::Element::position)
+ let has_overlay = overlay.0.as_ref().unwrap().with_overlay(|overlay| {
+ overlay.as_ref().map(|nested| nested.borrow().position())
});
has_overlay.map(|position| {
@@ -403,15 +490,29 @@ where
}
}
+struct Overlay<'a, 'b, Message, Renderer, Event, S>(
+ Option<Inner<'a, 'b, Message, Renderer, Event, S>>,
+);
+
+impl<'a, 'b, Message, Renderer, Event, S> Drop
+ for Overlay<'a, 'b, Message, Renderer, Event, S>
+{
+ fn drop(&mut self) {
+ if let Some(heads) = self.0.take().map(|inner| inner.into_heads()) {
+ *heads.instance.tree.borrow_mut().borrow_mut() = Some(heads.tree);
+ }
+ }
+}
+
#[self_referencing]
-struct Overlay<'a, 'b, Message, Renderer, Event, S> {
+struct Inner<'a, 'b, Message, Renderer, Event, S> {
instance: &'a mut Instance<'b, Message, Renderer, Event, S>,
- tree: &'a mut Tree,
+ tree: Tree,
types: PhantomData<(Message, Event, S)>,
#[borrows(mut instance, mut tree)]
- #[covariant]
- overlay: Option<overlay::Element<'this, Event, Renderer>>,
+ #[not_covariant]
+ overlay: Option<RefCell<Nested<'this, Event, Renderer>>>,
}
struct OverlayInstance<'a, 'b, Message, Renderer, Event, S> {
@@ -423,31 +524,39 @@ impl<'a, 'b, Message, Renderer, Event, S>
{
fn with_overlay_maybe<T>(
&self,
- f: impl FnOnce(&overlay::Element<'_, Event, Renderer>) -> T,
+ f: impl FnOnce(&mut Nested<'_, Event, Renderer>) -> T,
) -> Option<T> {
self.overlay
.as_ref()
.unwrap()
- .borrow_overlay()
+ .0
.as_ref()
- .map(f)
+ .unwrap()
+ .with_overlay(|overlay| {
+ overlay.as_ref().map(|nested| (f)(&mut nested.borrow_mut()))
+ })
}
fn with_overlay_mut_maybe<T>(
&mut self,
- f: impl FnOnce(&mut overlay::Element<'_, Event, Renderer>) -> T,
+ f: impl FnOnce(&mut Nested<'_, Event, Renderer>) -> T,
) -> Option<T> {
self.overlay
.as_mut()
.unwrap()
- .with_overlay_mut(|overlay| overlay.as_mut().map(f))
+ .0
+ .as_mut()
+ .unwrap()
+ .with_overlay_mut(|overlay| {
+ overlay.as_mut().map(|nested| (f)(nested.get_mut()))
+ })
}
}
impl<'a, 'b, Message, Renderer, Event, S> overlay::Overlay<Message, Renderer>
for OverlayInstance<'a, 'b, Message, Renderer, Event, S>
where
- Renderer: iced_native::Renderer,
+ Renderer: core::Renderer,
S: 'static + Default,
{
fn layout(
@@ -457,9 +566,7 @@ where
position: Point,
) -> layout::Node {
self.with_overlay_maybe(|overlay| {
- let translation = position - overlay.position();
-
- overlay.layout(renderer, bounds, translation)
+ overlay.layout(renderer, bounds, position)
})
.unwrap_or_default()
}
@@ -470,40 +577,35 @@ where
theme: &Renderer::Theme,
style: &renderer::Style,
layout: Layout<'_>,
- cursor_position: Point,
+ cursor: mouse::Cursor,
) {
let _ = self.with_overlay_maybe(|overlay| {
- overlay.draw(renderer, theme, style, layout, cursor_position);
+ overlay.draw(renderer, theme, style, layout, cursor);
});
}
fn mouse_interaction(
&self,
layout: Layout<'_>,
- cursor_position: Point,
+ cursor: mouse::Cursor,
viewport: &Rectangle,
renderer: &Renderer,
) -> mouse::Interaction {
self.with_overlay_maybe(|overlay| {
- overlay.mouse_interaction(
- layout,
- cursor_position,
- viewport,
- renderer,
- )
+ overlay.mouse_interaction(layout, cursor, viewport, renderer)
})
.unwrap_or_default()
}
fn on_event(
&mut self,
- event: iced_native::Event,
+ event: core::Event,
layout: Layout<'_>,
- cursor_position: Point,
+ cursor: mouse::Cursor,
renderer: &Renderer,
clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>,
- ) -> iced_native::event::Status {
+ ) -> event::Status {
let mut local_messages = Vec::new();
let mut local_shell = Shell::new(&mut local_messages);
@@ -512,53 +614,52 @@ where
overlay.on_event(
event,
layout,
- cursor_position,
+ cursor,
renderer,
clipboard,
&mut local_shell,
)
})
- .unwrap_or(iced_native::event::Status::Ignored);
+ .unwrap_or(event::Status::Ignored);
local_shell.revalidate_layout(|| shell.invalidate_layout());
+ if let Some(redraw_request) = local_shell.redraw_request() {
+ shell.request_redraw(redraw_request);
+ }
+
if !local_messages.is_empty() {
- let overlay = self.overlay.take().unwrap().into_heads();
- let mut heads = overlay.instance.state.take().unwrap().into_heads();
+ let mut inner =
+ self.overlay.take().unwrap().0.take().unwrap().into_heads();
+ let mut heads = inner.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)
+ .update(inner.tree.state.downcast_mut(), message)
}) {
shell.publish(message);
}
- *overlay.instance.state.borrow_mut() = Some(
+ *inner.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>()))
- },
+ element_builder: |_| None,
}
.build(),
);
- overlay.instance.with_element(|element| {
- overlay.tree.diff_children(std::slice::from_ref(&element))
- });
-
- self.overlay = Some(
- OverlayBuilder {
- instance: overlay.instance,
- tree: overlay.tree,
+ self.overlay = Some(Overlay(Some(
+ InnerBuilder {
+ instance: inner.instance,
+ tree: inner.tree,
types: PhantomData,
overlay_builder: |_, _| None,
}
.build(),
- );
+ )));
shell.invalidate_layout();
}
@@ -566,9 +667,14 @@ where
event_status
}
- fn is_over(&self, layout: Layout<'_>, cursor_position: Point) -> bool {
+ fn is_over(
+ &self,
+ layout: Layout<'_>,
+ renderer: &Renderer,
+ cursor_position: Point,
+ ) -> bool {
self.with_overlay_maybe(|overlay| {
- overlay.is_over(layout, cursor_position)
+ overlay.is_over(layout, renderer, cursor_position)
})
.unwrap_or_default()
}
diff --git a/lazy/src/lib.rs b/widget/src/lazy/helpers.rs
index 41a28773..8ca9cb86 100644
--- a/lazy/src/lib.rs
+++ b/widget/src/lazy/helpers.rs
@@ -1,36 +1,11 @@
-#![doc(
- html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg"
-)]
-#![deny(
- missing_debug_implementations,
- unused_results,
- clippy::extra_unused_lifetimes,
- clippy::from_over_into,
- clippy::needless_borrow,
- clippy::new_without_default,
- clippy::useless_conversion
-)]
-#![forbid(unsafe_code)]
-#![allow(
- clippy::await_holding_refcell_ref,
- clippy::inherent_to_string,
- clippy::type_complexity
-)]
-#![cfg_attr(docsrs, feature(doc_cfg))]
-mod lazy;
+use crate::core::{self, Element, Size};
+use crate::lazy::component::{self, Component};
+use crate::lazy::{Lazy, Responsive};
-pub mod component;
-pub mod responsive;
-
-pub use component::Component;
-pub use lazy::Lazy;
-pub use responsive::Responsive;
-
-mod cache;
-
-use iced_native::{Element, Size};
use std::hash::Hash;
+/// Creates a new [`Lazy`] widget with the given data `Dependency` and a
+/// closure that can turn this data into a widget tree.
pub fn lazy<'a, Message, Renderer, Dependency, View>(
dependency: Dependency,
view: impl Fn(&Dependency) -> View + 'a,
@@ -51,16 +26,22 @@ where
C: Component<Message, Renderer> + 'a,
C::State: 'static,
Message: 'a,
- Renderer: iced_native::Renderer + 'a,
+ Renderer: core::Renderer + 'a,
{
component::view(component)
}
+/// 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 responsive<'a, Message, Renderer>(
f: impl Fn(Size) -> Element<'a, Message, Renderer> + 'a,
) -> Responsive<'a, Message, Renderer>
where
- Renderer: iced_native::Renderer,
+ Renderer: core::Renderer,
{
Responsive::new(f)
}
diff --git a/lazy/src/responsive.rs b/widget/src/lazy/responsive.rs
index 57c07de1..07300857 100644
--- a/lazy/src/responsive.rs
+++ b/widget/src/lazy/responsive.rs
@@ -1,13 +1,15 @@
-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::widget::{self, horizontal_space};
-use iced_native::{
- Clipboard, Element, Length, Point, Rectangle, Shell, Size, Widget,
+use crate::core::event::{self, Event};
+use crate::core::layout::{self, Layout};
+use crate::core::mouse;
+use crate::core::overlay;
+use crate::core::renderer;
+use crate::core::widget;
+use crate::core::widget::tree::{self, Tree};
+use crate::core::{
+ self, Clipboard, Element, Length, Point, Rectangle, Shell, Size, Widget,
};
+use crate::horizontal_space;
+use crate::runtime::overlay::Nested;
use ouroboros::self_referencing;
use std::cell::{RefCell, RefMut};
@@ -19,14 +21,14 @@ use std::ops::Deref;
/// 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> {
+pub struct Responsive<'a, Message, Renderer = crate::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,
+ Renderer: core::Renderer,
{
/// Creates a new [`Responsive`] widget with a closure that produces its
/// contents.
@@ -41,7 +43,7 @@ where
view: Box::new(view),
content: RefCell::new(Content {
size: Size::ZERO,
- layout: layout::Node::new(Size::ZERO),
+ layout: None,
element: Element::new(horizontal_space(0)),
}),
}
@@ -50,18 +52,27 @@ where
struct Content<'a, Message, Renderer> {
size: Size,
- layout: layout::Node,
+ layout: Option<layout::Node>,
element: Element<'a, Message, Renderer>,
}
impl<'a, Message, Renderer> Content<'a, Message, Renderer>
where
- Renderer: iced_native::Renderer,
+ Renderer: core::Renderer,
{
+ fn layout(&mut self, renderer: &Renderer) {
+ if self.layout.is_none() {
+ self.layout =
+ Some(self.element.as_widget().layout(
+ renderer,
+ &layout::Limits::new(Size::ZERO, self.size),
+ ));
+ }
+ }
+
fn update(
&mut self,
tree: &mut Tree,
- renderer: &Renderer,
new_size: Size,
view: &dyn Fn(Size) -> Element<'a, Message, Renderer>,
) {
@@ -71,13 +82,9 @@ where
self.element = view(new_size);
self.size = new_size;
+ self.layout = None;
tree.diff(&self.element);
-
- self.layout = self
- .element
- .as_widget()
- .layout(renderer, &layout::Limits::new(Size::ZERO, self.size));
}
fn resolve<R, T>(
@@ -96,11 +103,12 @@ where
where
R: Deref<Target = Renderer>,
{
- self.update(tree, renderer.deref(), layout.bounds().size(), view);
+ self.update(tree, layout.bounds().size(), view);
+ self.layout(renderer.deref());
let content_layout = Layout::with_offset(
layout.position() - Point::ORIGIN,
- &self.layout,
+ self.layout.as_ref().unwrap(),
);
f(tree, renderer, content_layout, &mut self.element)
@@ -114,7 +122,7 @@ struct State {
impl<'a, Message, Renderer> Widget<Message, Renderer>
for Responsive<'a, Message, Renderer>
where
- Renderer: iced_native::Renderer,
+ Renderer: core::Renderer,
{
fn tag(&self) -> tree::Tag {
tree::Tag::of::<State>()
@@ -168,9 +176,9 @@ where
fn on_event(
&mut self,
tree: &mut Tree,
- event: iced_native::Event,
+ event: Event,
layout: Layout<'_>,
- cursor_position: Point,
+ cursor: mouse::Cursor,
renderer: &Renderer,
clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>,
@@ -178,7 +186,10 @@ where
let state = tree.state.downcast_mut::<State>();
let mut content = self.content.borrow_mut();
- content.resolve(
+ let mut local_messages = vec![];
+ let mut local_shell = Shell::new(&mut local_messages);
+
+ let status = content.resolve(
&mut state.tree.borrow_mut(),
renderer,
layout,
@@ -188,13 +199,21 @@ where
tree,
event,
layout,
- cursor_position,
+ cursor,
renderer,
clipboard,
- shell,
+ &mut local_shell,
)
},
- )
+ );
+
+ if local_shell.is_layout_invalid() {
+ content.layout = None;
+ }
+
+ shell.merge(local_shell, std::convert::identity);
+
+ status
}
fn draw(
@@ -204,7 +223,7 @@ where
theme: &Renderer::Theme,
style: &renderer::Style,
layout: Layout<'_>,
- cursor_position: Point,
+ cursor: mouse::Cursor,
viewport: &Rectangle,
) {
let state = tree.state.downcast_ref::<State>();
@@ -217,13 +236,7 @@ where
&self.view,
|tree, renderer, layout, element| {
element.as_widget().draw(
- tree,
- renderer,
- theme,
- style,
- layout,
- cursor_position,
- viewport,
+ tree, renderer, theme, style, layout, cursor, viewport,
)
},
)
@@ -233,7 +246,7 @@ where
&self,
tree: &Tree,
layout: Layout<'_>,
- cursor_position: Point,
+ cursor: mouse::Cursor,
viewport: &Rectangle,
renderer: &Renderer,
) -> mouse::Interaction {
@@ -246,13 +259,9 @@ where
layout,
&self.view,
|tree, renderer, layout, element| {
- element.as_widget().mouse_interaction(
- tree,
- layout,
- cursor_position,
- viewport,
- renderer,
- )
+ element
+ .as_widget()
+ .mouse_interaction(tree, layout, cursor, viewport, renderer)
},
)
}
@@ -271,35 +280,32 @@ where
content: self.content.borrow_mut(),
tree: state.tree.borrow_mut(),
types: PhantomData,
- overlay_builder: |content: &mut RefMut<Content<_, _>>, tree| {
- content.update(
- tree,
- renderer,
- layout.bounds().size(),
- &self.view,
- );
+ overlay_builder: |content: &mut RefMut<'_, Content<'_, _, _>>,
+ tree| {
+ content.update(tree, layout.bounds().size(), &self.view);
+ content.layout(renderer);
let Content {
element,
- layout: content_layout,
+ layout: content_layout_node,
..
} = content.deref_mut();
let content_layout = Layout::with_offset(
layout.bounds().position() - Point::ORIGIN,
- content_layout,
+ content_layout_node.as_ref().unwrap(),
);
element
.as_widget_mut()
.overlay(tree, content_layout, renderer)
+ .map(|overlay| RefCell::new(Nested::new(overlay)))
},
}
.build();
- let has_overlay = overlay.with_overlay(|overlay| {
- overlay.as_ref().map(overlay::Element::position)
- });
+ let has_overlay =
+ overlay.with_overlay_maybe(|overlay| overlay.position());
has_overlay
.map(|position| overlay::Element::new(position, Box::new(overlay)))
@@ -309,7 +315,7 @@ where
impl<'a, Message, Renderer> From<Responsive<'a, Message, Renderer>>
for Element<'a, Message, Renderer>
where
- Renderer: iced_native::Renderer + 'a,
+ Renderer: core::Renderer + 'a,
Message: 'a,
{
fn from(responsive: Responsive<'a, Message, Renderer>) -> Self {
@@ -324,30 +330,34 @@ struct Overlay<'a, 'b, Message, Renderer> {
types: PhantomData<Message>,
#[borrows(mut content, mut tree)]
- #[covariant]
- overlay: Option<overlay::Element<'this, Message, Renderer>>,
+ #[not_covariant]
+ overlay: Option<RefCell<Nested<'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,
+ f: impl FnOnce(&mut Nested<'_, Message, Renderer>) -> T,
) -> Option<T> {
- self.borrow_overlay().as_ref().map(f)
+ self.with_overlay(|overlay| {
+ overlay.as_ref().map(|nested| (f)(&mut nested.borrow_mut()))
+ })
}
fn with_overlay_mut_maybe<T>(
&mut self,
- f: impl FnOnce(&mut overlay::Element<'_, Message, Renderer>) -> T,
+ f: impl FnOnce(&mut Nested<'_, Message, Renderer>) -> T,
) -> Option<T> {
- self.with_overlay_mut(|overlay| overlay.as_mut().map(f))
+ self.with_overlay_mut(|overlay| {
+ overlay.as_mut().map(|nested| (f)(nested.get_mut()))
+ })
}
}
impl<'a, 'b, Message, Renderer> overlay::Overlay<Message, Renderer>
for Overlay<'a, 'b, Message, Renderer>
where
- Renderer: iced_native::Renderer,
+ Renderer: core::Renderer,
{
fn layout(
&self,
@@ -356,9 +366,7 @@ where
position: Point,
) -> layout::Node {
self.with_overlay_maybe(|overlay| {
- let translation = position - overlay.position();
-
- overlay.layout(renderer, bounds, translation)
+ overlay.layout(renderer, bounds, position)
})
.unwrap_or_default()
}
@@ -369,56 +377,49 @@ where
theme: &Renderer::Theme,
style: &renderer::Style,
layout: Layout<'_>,
- cursor_position: Point,
+ cursor: mouse::Cursor,
) {
let _ = self.with_overlay_maybe(|overlay| {
- overlay.draw(renderer, theme, style, layout, cursor_position);
+ overlay.draw(renderer, theme, style, layout, cursor);
});
}
fn mouse_interaction(
&self,
layout: Layout<'_>,
- cursor_position: Point,
+ cursor: mouse::Cursor,
viewport: &Rectangle,
renderer: &Renderer,
) -> mouse::Interaction {
self.with_overlay_maybe(|overlay| {
- overlay.mouse_interaction(
- layout,
- cursor_position,
- viewport,
- renderer,
- )
+ overlay.mouse_interaction(layout, cursor, viewport, renderer)
})
.unwrap_or_default()
}
fn on_event(
&mut self,
- event: iced_native::Event,
+ event: Event,
layout: Layout<'_>,
- cursor_position: Point,
+ cursor: mouse::Cursor,
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,
- )
+ overlay.on_event(event, layout, cursor, renderer, clipboard, shell)
})
- .unwrap_or(iced_native::event::Status::Ignored)
+ .unwrap_or(event::Status::Ignored)
}
- fn is_over(&self, layout: Layout<'_>, cursor_position: Point) -> bool {
+ fn is_over(
+ &self,
+ layout: Layout<'_>,
+ renderer: &Renderer,
+ cursor_position: Point,
+ ) -> bool {
self.with_overlay_maybe(|overlay| {
- overlay.is_over(layout, cursor_position)
+ overlay.is_over(layout, renderer, cursor_position)
})
.unwrap_or_default()
}