Merge pull request #3038 from iced-rs/mutable-widget

Mutable `Widget` Methods
This commit is contained in:
Héctor 2025-08-21 03:42:37 +02:00 committed by GitHub
commit 0e226f6f39
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
60 changed files with 600 additions and 775 deletions

View file

@ -9,7 +9,7 @@ use crate::{
Vector, Widget, Vector, Widget,
}; };
use std::borrow::Borrow; use std::borrow::{Borrow, BorrowMut};
/// A generic [`Widget`]. /// A generic [`Widget`].
/// ///
@ -239,6 +239,37 @@ impl<'a, Message, Theme, Renderer>
} }
} }
impl<'a, Message, Theme, Renderer>
Borrow<dyn Widget<Message, Theme, Renderer> + 'a>
for &mut Element<'a, Message, Theme, Renderer>
{
fn borrow(&self) -> &(dyn Widget<Message, Theme, Renderer> + 'a) {
self.widget.borrow()
}
}
impl<'a, Message, Theme, Renderer>
BorrowMut<dyn Widget<Message, Theme, Renderer> + 'a>
for Element<'a, Message, Theme, Renderer>
{
fn borrow_mut(
&mut self,
) -> &mut (dyn Widget<Message, Theme, Renderer> + 'a) {
self.widget.borrow_mut()
}
}
impl<'a, Message, Theme, Renderer>
BorrowMut<dyn Widget<Message, Theme, Renderer> + 'a>
for &mut Element<'a, Message, Theme, Renderer>
{
fn borrow_mut(
&mut self,
) -> &mut (dyn Widget<Message, Theme, Renderer> + 'a) {
self.widget.borrow_mut()
}
}
struct Map<'a, A, B, Theme, Renderer> { struct Map<'a, A, B, Theme, Renderer> {
widget: Box<dyn Widget<A, Theme, Renderer> + 'a>, widget: Box<dyn Widget<A, Theme, Renderer> + 'a>,
mapper: Box<dyn Fn(A) -> B + 'a>, mapper: Box<dyn Fn(A) -> B + 'a>,
@ -278,7 +309,7 @@ where
self.widget.children() self.widget.children()
} }
fn diff(&self, tree: &mut Tree) { fn diff(&mut self, tree: &mut Tree) {
self.widget.diff(tree); self.widget.diff(tree);
} }
@ -291,7 +322,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
@ -300,7 +331,7 @@ where
} }
fn operate( fn operate(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &Renderer, renderer: &Renderer,
@ -421,12 +452,12 @@ where
self.element.widget.children() self.element.widget.children()
} }
fn diff(&self, tree: &mut Tree) { fn diff(&mut self, tree: &mut Tree) {
self.element.widget.diff(tree); self.element.widget.diff(tree);
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
@ -435,7 +466,7 @@ where
} }
fn operate( fn operate(
&self, &mut self,
state: &mut Tree, state: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &Renderer, renderer: &Renderer,
@ -554,7 +585,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
_tree: &mut Tree, _tree: &mut Tree,
_renderer: &Renderer, _renderer: &Renderer,
_limits: &layout::Limits, _limits: &layout::Limits,

View file

@ -68,7 +68,7 @@ pub fn resolve<Message, Theme, Renderer>(
padding: Padding, padding: Padding,
spacing: f32, spacing: f32,
align_items: Alignment, align_items: Alignment,
items: &[Element<'_, Message, Theme, Renderer>], items: &mut [Element<'_, Message, Theme, Renderer>],
trees: &mut [widget::Tree], trees: &mut [widget::Tree],
) -> Node ) -> Node
where where
@ -95,7 +95,8 @@ where
// We lay out non-fluid elements in the main axis. // We lay out non-fluid elements in the main axis.
// If we need to compress the cross axis, then we skip any of these elements // If we need to compress the cross axis, then we skip any of these elements
// that are also fluid in the cross axis. // that are also fluid in the cross axis.
for (i, (child, tree)) in items.iter().zip(trees.iter_mut()).enumerate() { for (i, (child, tree)) in items.iter_mut().zip(trees.iter_mut()).enumerate()
{
let (fill_main_factor, fill_cross_factor) = { let (fill_main_factor, fill_cross_factor) = {
let size = child.as_widget().size(); let size = child.as_widget().size();
@ -117,7 +118,7 @@ where
Limits::new(Size::ZERO, Size::new(max_width, max_height)); Limits::new(Size::ZERO, Size::new(max_width, max_height));
let layout = let layout =
child.as_widget().layout(tree, renderer, &child_limits); child.as_widget_mut().layout(tree, renderer, &child_limits);
let size = layout.size(); let size = layout.size();
available -= axis.main(size); available -= axis.main(size);
@ -141,7 +142,8 @@ where
// We can defer the layout of any elements that have a fixed size in the main axis, // We can defer the layout of any elements that have a fixed size in the main axis,
// allowing them to use the cross calculations of the next pass. // allowing them to use the cross calculations of the next pass.
if cross_compress && some_fill_cross { if cross_compress && some_fill_cross {
for (i, (child, tree)) in items.iter().zip(trees.iter_mut()).enumerate() for (i, (child, tree)) in
items.iter_mut().zip(trees.iter_mut()).enumerate()
{ {
let (main_size, cross_size) = { let (main_size, cross_size) = {
let size = child.as_widget().size(); let size = child.as_widget().size();
@ -161,7 +163,7 @@ where
Limits::new(Size::ZERO, Size::new(max_width, max_height)); Limits::new(Size::ZERO, Size::new(max_width, max_height));
let layout = let layout =
child.as_widget().layout(tree, renderer, &child_limits); child.as_widget_mut().layout(tree, renderer, &child_limits);
let size = layout.size(); let size = layout.size();
available -= axis.main(size); available -= axis.main(size);
@ -186,7 +188,8 @@ where
// THIRD PASS // THIRD PASS
// We lay out the elements that are fluid in the main axis. // We lay out the elements that are fluid in the main axis.
// We use the remaining space to evenly allocate space based on fill factors. // We use the remaining space to evenly allocate space based on fill factors.
for (i, (child, tree)) in items.iter().zip(trees.iter_mut()).enumerate() { for (i, (child, tree)) in items.iter_mut().zip(trees.iter_mut()).enumerate()
{
let (fill_main_factor, fill_cross_factor) = { let (fill_main_factor, fill_cross_factor) = {
let size = child.as_widget().size(); let size = child.as_widget().size();
@ -225,7 +228,7 @@ where
); );
let layout = let layout =
child.as_widget().layout(tree, renderer, &child_limits); child.as_widget_mut().layout(tree, renderer, &child_limits);
cross = cross.max(axis.cross(layout.size())); cross = cross.max(axis.cross(layout.size()));
nodes[i] = layout; nodes[i] = layout;
@ -237,7 +240,7 @@ where
// These are elements that must be compressed in their cross axis and have // These are elements that must be compressed in their cross axis and have
// a fixed length in the main axis. // a fixed length in the main axis.
if cross_compress && some_fill_cross { if cross_compress && some_fill_cross {
for (i, (child, tree)) in items.iter().zip(trees).enumerate() { for (i, (child, tree)) in items.iter_mut().zip(trees).enumerate() {
let (main_size, cross_size) = { let (main_size, cross_size) = {
let size = child.as_widget().size(); let size = child.as_widget().size();
@ -255,7 +258,7 @@ where
Limits::new(Size::ZERO, Size::new(max_width, max_height)); Limits::new(Size::ZERO, Size::new(max_width, max_height));
let layout = let layout =
child.as_widget().layout(tree, renderer, &child_limits); child.as_widget_mut().layout(tree, renderer, &child_limits);
let size = layout.size(); let size = layout.size();
cross = cross.max(axis.cross(size)); cross = cross.max(axis.cross(size));

View file

@ -6,6 +6,7 @@ use crate::{Length, Size};
pub struct Limits { pub struct Limits {
min: Size, min: Size,
max: Size, max: Size,
compress: Size<bool>,
} }
impl Limits { impl Limits {
@ -13,11 +14,16 @@ impl Limits {
pub const NONE: Limits = Limits { pub const NONE: Limits = Limits {
min: Size::ZERO, min: Size::ZERO,
max: Size::INFINITE, max: Size::INFINITE,
compress: Size::new(false, false),
}; };
/// Creates new [`Limits`] with the given minimum and maximum [`Size`]. /// Creates new [`Limits`] with the given minimum and maximum [`Size`].
pub const fn new(min: Size, max: Size) -> Limits { pub const fn new(min: Size, max: Size) -> Limits {
Limits { min, max } Limits {
min,
max,
compress: Size::new(false, false),
}
} }
/// Returns the minimum [`Size`] of the [`Limits`]. /// Returns the minimum [`Size`] of the [`Limits`].
@ -33,13 +39,17 @@ impl Limits {
/// Applies a width constraint to the current [`Limits`]. /// Applies a width constraint to the current [`Limits`].
pub fn width(mut self, width: impl Into<Length>) -> Limits { pub fn width(mut self, width: impl Into<Length>) -> Limits {
match width.into() { match width.into() {
Length::Shrink | Length::Fill | Length::FillPortion(_) => {} Length::Shrink => {
self.compress.width = true;
}
Length::Fixed(amount) => { Length::Fixed(amount) => {
let new_width = amount.min(self.max.width).max(self.min.width); let new_width = amount.min(self.max.width).max(self.min.width);
self.min.width = new_width; self.min.width = new_width;
self.max.width = new_width; self.max.width = new_width;
self.compress.width = false;
} }
Length::Fill | Length::FillPortion(_) => {}
} }
self self
@ -48,14 +58,18 @@ impl Limits {
/// Applies a height constraint to the current [`Limits`]. /// Applies a height constraint to the current [`Limits`].
pub fn height(mut self, height: impl Into<Length>) -> Limits { pub fn height(mut self, height: impl Into<Length>) -> Limits {
match height.into() { match height.into() {
Length::Shrink | Length::Fill | Length::FillPortion(_) => {} Length::Shrink => {
self.compress.height = true;
}
Length::Fixed(amount) => { Length::Fixed(amount) => {
let new_height = let new_height =
amount.min(self.max.height).max(self.min.height); amount.min(self.max.height).max(self.min.height);
self.min.height = new_height; self.min.height = new_height;
self.max.height = new_height; self.max.height = new_height;
self.compress.height = false;
} }
Length::Fill | Length::FillPortion(_) => {}
} }
self self
@ -103,7 +117,11 @@ impl Limits {
(self.max().height - size.height).max(0.0), (self.max().height - size.height).max(0.0),
); );
Limits { min, max } Limits {
min,
max,
compress: self.compress,
}
} }
/// Removes the minimum width constraint for the current [`Limits`]. /// Removes the minimum width constraint for the current [`Limits`].
@ -111,6 +129,7 @@ impl Limits {
Limits { Limits {
min: Size::ZERO, min: Size::ZERO,
max: self.max, max: self.max,
compress: self.compress,
} }
} }
@ -124,21 +143,23 @@ impl Limits {
intrinsic_size: Size, intrinsic_size: Size,
) -> Size { ) -> Size {
let width = match width.into() { let width = match width.into() {
Length::Fill | Length::FillPortion(_) => self.max.width, Length::Fill | Length::FillPortion(_) if !self.compress.width => {
self.max.width
}
Length::Fixed(amount) => { Length::Fixed(amount) => {
amount.min(self.max.width).max(self.min.width) amount.min(self.max.width).max(self.min.width)
} }
Length::Shrink => { _ => intrinsic_size.width.min(self.max.width).max(self.min.width),
intrinsic_size.width.min(self.max.width).max(self.min.width)
}
}; };
let height = match height.into() { let height = match height.into() {
Length::Fill | Length::FillPortion(_) => self.max.height, Length::Fill | Length::FillPortion(_) if !self.compress.height => {
self.max.height
}
Length::Fixed(amount) => { Length::Fixed(amount) => {
amount.min(self.max.height).max(self.min.height) amount.min(self.max.height).max(self.min.height)
} }
Length::Shrink => intrinsic_size _ => intrinsic_size
.height .height
.min(self.max.height) .min(self.max.height)
.max(self.min.height), .max(self.min.height),

View file

@ -58,7 +58,7 @@ where
/// This [`layout::Node`] is used by the runtime to compute the [`Layout`] of the /// This [`layout::Node`] is used by the runtime to compute the [`Layout`] of the
/// user interface. /// user interface.
fn layout( fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
@ -96,13 +96,13 @@ where
} }
/// Reconciles the [`Widget`] with the provided [`Tree`]. /// Reconciles the [`Widget`] with the provided [`Tree`].
fn diff(&self, tree: &mut Tree) { fn diff(&mut self, tree: &mut Tree) {
tree.children.clear(); tree.children.clear();
} }
/// Applies an [`Operation`] to the [`Widget`]. /// Applies an [`Operation`] to the [`Widget`].
fn operate( fn operate(
&self, &mut self,
_state: &mut Tree, _state: &mut Tree,
_layout: Layout<'_>, _layout: Layout<'_>,
_renderer: &Renderer, _renderer: &Renderer,

View file

@ -207,7 +207,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
@ -245,7 +245,7 @@ where
} }
fn operate( fn operate(
&self, &mut self,
_state: &mut Tree, _state: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
_renderer: &Renderer, _renderer: &Renderer,

View file

@ -2,7 +2,7 @@
use crate::Widget; use crate::Widget;
use std::any::{self, Any}; use std::any::{self, Any};
use std::borrow::Borrow; use std::borrow::{Borrow, BorrowMut};
use std::fmt; use std::fmt;
/// A persistent state widget tree. /// A persistent state widget tree.
@ -56,12 +56,12 @@ impl Tree {
/// [`Widget::diff`]: crate::Widget::diff /// [`Widget::diff`]: crate::Widget::diff
pub fn diff<'a, Message, Theme, Renderer>( pub fn diff<'a, Message, Theme, Renderer>(
&mut self, &mut self,
new: impl Borrow<dyn Widget<Message, Theme, Renderer> + 'a>, mut new: impl BorrowMut<dyn Widget<Message, Theme, Renderer> + 'a>,
) where ) where
Renderer: crate::Renderer, Renderer: crate::Renderer,
{ {
if self.tag == new.borrow().tag() { if self.tag == new.borrow_mut().tag() {
new.borrow().diff(self); new.borrow_mut().diff(self);
} else { } else {
*self = Self::new(new); *self = Self::new(new);
} }
@ -70,13 +70,15 @@ impl Tree {
/// Reconciles the children of the tree with the provided list of widgets. /// Reconciles the children of the tree with the provided list of widgets.
pub fn diff_children<'a, Message, Theme, Renderer>( pub fn diff_children<'a, Message, Theme, Renderer>(
&mut self, &mut self,
new_children: &[impl Borrow<dyn Widget<Message, Theme, Renderer> + 'a>], new_children: &mut [impl BorrowMut<
dyn Widget<Message, Theme, Renderer> + 'a,
>],
) where ) where
Renderer: crate::Renderer, Renderer: crate::Renderer,
{ {
self.diff_children_custom( self.diff_children_custom(
new_children, new_children,
|tree, widget| tree.diff(widget.borrow()), |tree, widget| tree.diff(widget.borrow_mut()),
|widget| Self::new(widget.borrow()), |widget| Self::new(widget.borrow()),
); );
} }
@ -85,8 +87,8 @@ impl Tree {
/// logic both for diffing and creating new widget state. /// logic both for diffing and creating new widget state.
pub fn diff_children_custom<T>( pub fn diff_children_custom<T>(
&mut self, &mut self,
new_children: &[T], new_children: &mut [T],
diff: impl Fn(&mut Tree, &T), diff: impl Fn(&mut Tree, &mut T),
new_state: impl Fn(&T) -> Self, new_state: impl Fn(&T) -> Self,
) { ) {
if self.children.len() > new_children.len() { if self.children.len() > new_children.len() {
@ -94,7 +96,7 @@ impl Tree {
} }
for (child_state, new) in for (child_state, new) in
self.children.iter_mut().zip(new_children.iter()) self.children.iter_mut().zip(new_children.iter_mut())
{ {
diff(child_state, new); diff(child_state, new);
} }
@ -114,8 +116,8 @@ impl Tree {
/// `maybe_changed` closure. /// `maybe_changed` closure.
pub fn diff_children_custom_with_search<T>( pub fn diff_children_custom_with_search<T>(
current_children: &mut Vec<Tree>, current_children: &mut Vec<Tree>,
new_children: &[T], new_children: &mut [T],
diff: impl Fn(&mut Tree, &T), diff: impl Fn(&mut Tree, &mut T),
maybe_changed: impl Fn(usize) -> bool, maybe_changed: impl Fn(usize) -> bool,
new_state: impl Fn(&T) -> Tree, new_state: impl Fn(&T) -> Tree,
) { ) {
@ -183,7 +185,7 @@ pub fn diff_children_custom_with_search<T>(
// TODO: Merge loop with extend logic (?) // TODO: Merge loop with extend logic (?)
for (child_state, new) in for (child_state, new) in
current_children.iter_mut().zip(new_children.iter()) current_children.iter_mut().zip(new_children.iter_mut())
{ {
diff(child_state, new); diff(child_state, new);
} }

View file

@ -175,7 +175,7 @@ mod quad {
} }
fn layout( fn layout(
&self, &mut self,
_tree: &mut widget::Tree, _tree: &mut widget::Tree,
_renderer: &Renderer, _renderer: &Renderer,
_limits: &layout::Limits, _limits: &layout::Limits,

View file

@ -33,7 +33,7 @@ mod circle {
} }
fn layout( fn layout(
&self, &mut self,
_tree: &mut widget::Tree, _tree: &mut widget::Tree,
_renderer: &Renderer, _renderer: &Renderer,
_limits: &layout::Limits, _limits: &layout::Limits,

View file

@ -27,7 +27,7 @@ mod rainbow {
} }
fn layout( fn layout(
&self, &mut self,
_tree: &mut widget::Tree, _tree: &mut widget::Tree,
_renderer: &Renderer, _renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,

View file

@ -253,7 +253,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
_tree: &mut Tree, _tree: &mut Tree,
_renderer: &Renderer, _renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,

View file

@ -167,7 +167,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
_tree: &mut Tree, _tree: &mut Tree,
_renderer: &Renderer, _renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,

View file

@ -87,8 +87,8 @@ mod loupe {
self.content.as_widget().children() self.content.as_widget().children()
} }
fn diff(&self, tree: &mut widget::Tree) { fn diff(&mut self, tree: &mut widget::Tree) {
self.content.as_widget().diff(tree); self.content.as_widget_mut().diff(tree);
} }
fn size(&self) -> Size<Length> { fn size(&self) -> Size<Length> {
@ -96,12 +96,12 @@ mod loupe {
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut widget::Tree, tree: &mut widget::Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
) -> layout::Node { ) -> layout::Node {
self.content.as_widget().layout(tree, renderer, limits) self.content.as_widget_mut().layout(tree, renderer, limits)
} }
fn draw( fn draw(

View file

@ -7,4 +7,4 @@ publish = false
[dependencies] [dependencies]
iced.workspace = true iced.workspace = true
iced.features = ["debug", "lazy"] iced.features = ["debug"]

View file

@ -287,12 +287,12 @@ mod toast {
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
) -> layout::Node { ) -> layout::Node {
self.content.as_widget().layout( self.content.as_widget_mut().layout(
&mut tree.children[0], &mut tree.children[0],
renderer, renderer,
limits, limits,
@ -314,7 +314,7 @@ mod toast {
.collect() .collect()
} }
fn diff(&self, tree: &mut Tree) { fn diff(&mut self, tree: &mut Tree) {
let instants = tree.state.downcast_mut::<Vec<Option<Instant>>>(); let instants = tree.state.downcast_mut::<Vec<Option<Instant>>>();
// Invalidating removed instants to None allows us to remove // Invalidating removed instants to None allows us to remove
@ -336,21 +336,21 @@ mod toast {
} }
tree.diff_children( tree.diff_children(
&std::iter::once(&self.content) &mut std::iter::once(&mut self.content)
.chain(self.toasts.iter()) .chain(self.toasts.iter_mut())
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
); );
} }
fn operate( fn operate(
&self, &mut self,
state: &mut Tree, state: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &Renderer, renderer: &Renderer,
operation: &mut dyn Operation, operation: &mut dyn Operation,
) { ) {
operation.container(None, layout.bounds(), &mut |operation| { operation.container(None, layout.bounds(), &mut |operation| {
self.content.as_widget().operate( self.content.as_widget_mut().operate(
&mut state.children[0], &mut state.children[0],
layout, layout,
renderer, renderer,
@ -582,12 +582,12 @@ mod toast {
) { ) {
operation.container(None, layout.bounds(), &mut |operation| { operation.container(None, layout.bounds(), &mut |operation| {
self.toasts self.toasts
.iter() .iter_mut()
.zip(self.state.iter_mut()) .zip(self.state.iter_mut())
.zip(layout.children()) .zip(layout.children())
.for_each(|((child, state), layout)| { .for_each(|((child, state), layout)| {
child child
.as_widget() .as_widget_mut()
.operate(state, layout, renderer, operation); .operate(state, layout, renderer, operation);
}); });
}); });

View file

@ -97,12 +97,12 @@ where
cache: Cache, cache: Cache,
renderer: &mut Renderer, renderer: &mut Renderer,
) -> Self { ) -> Self {
let root = root.into(); let mut root = root.into();
let Cache { mut state } = cache; let Cache { mut state } = cache;
state.diff(root.as_widget()); state.diff(root.as_widget_mut());
let base = root.as_widget().layout( let base = root.as_widget_mut().layout(
&mut state, &mut state,
renderer, renderer,
&layout::Limits::new(Size::ZERO, bounds), &layout::Limits::new(Size::ZERO, bounds),
@ -234,7 +234,7 @@ where
if shell.is_layout_invalid() { if shell.is_layout_invalid() {
drop(maybe_overlay); drop(maybe_overlay);
self.base = self.root.as_widget().layout( self.base = self.root.as_widget_mut().layout(
&mut self.state, &mut self.state,
renderer, renderer,
&layout::Limits::new(Size::ZERO, self.bounds), &layout::Limits::new(Size::ZERO, self.bounds),
@ -335,7 +335,7 @@ where
input_method.merge(shell.input_method()); input_method.merge(shell.input_method());
shell.revalidate_layout(|| { shell.revalidate_layout(|| {
self.base = self.root.as_widget().layout( self.base = self.root.as_widget_mut().layout(
&mut self.state, &mut self.state,
renderer, renderer,
&layout::Limits::new(Size::ZERO, self.bounds), &layout::Limits::new(Size::ZERO, self.bounds),
@ -539,7 +539,7 @@ where
) { ) {
let viewport = Rectangle::with_size(self.bounds); let viewport = Rectangle::with_size(self.bounds);
self.root.as_widget().operate( self.root.as_widget_mut().operate(
&mut self.state, &mut self.state,
Layout::new(&self.base), Layout::new(&self.base),
renderer, renderer,

View file

@ -223,8 +223,8 @@ where
vec![Tree::new(&self.content)] vec![Tree::new(&self.content)]
} }
fn diff(&self, tree: &mut Tree) { fn diff(&mut self, tree: &mut Tree) {
tree.diff_children(std::slice::from_ref(&self.content)); tree.diff_children(std::slice::from_mut(&mut self.content));
} }
fn size(&self) -> Size<Length> { fn size(&self) -> Size<Length> {
@ -235,7 +235,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
@ -246,7 +246,7 @@ where
self.height, self.height,
self.padding, self.padding,
|limits| { |limits| {
self.content.as_widget().layout( self.content.as_widget_mut().layout(
&mut tree.children[0], &mut tree.children[0],
renderer, renderer,
limits, limits,
@ -256,14 +256,14 @@ where
} }
fn operate( fn operate(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &Renderer, renderer: &Renderer,
operation: &mut dyn Operation, operation: &mut dyn Operation,
) { ) {
operation.container(None, layout.bounds(), &mut |operation| { operation.container(None, layout.bounds(), &mut |operation| {
self.content.as_widget().operate( self.content.as_widget_mut().operate(
&mut tree.children[0], &mut tree.children[0],
layout.children().next().unwrap(), layout.children().next().unwrap(),
renderer, renderer,

View file

@ -207,7 +207,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
_tree: &mut Tree, _tree: &mut Tree,
_renderer: &Renderer, _renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,

View file

@ -269,7 +269,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
@ -447,7 +447,7 @@ where
} }
fn operate( fn operate(
&self, &mut self,
_state: &mut Tree, _state: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
_renderer: &Renderer, _renderer: &Renderer,

View file

@ -194,8 +194,8 @@ where
self.children.iter().map(Tree::new).collect() self.children.iter().map(Tree::new).collect()
} }
fn diff(&self, tree: &mut Tree) { fn diff(&mut self, tree: &mut Tree) {
tree.diff_children(&self.children); tree.diff_children(&mut self.children);
} }
fn size(&self) -> Size<Length> { fn size(&self) -> Size<Length> {
@ -206,7 +206,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
@ -222,13 +222,13 @@ where
self.padding, self.padding,
self.spacing, self.spacing,
self.align, self.align,
&self.children, &mut self.children,
&mut tree.children, &mut tree.children,
) )
} }
fn operate( fn operate(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &Renderer, renderer: &Renderer,
@ -236,12 +236,12 @@ where
) { ) {
operation.container(None, layout.bounds(), &mut |operation| { operation.container(None, layout.bounds(), &mut |operation| {
self.children self.children
.iter() .iter_mut()
.zip(&mut tree.children) .zip(&mut tree.children)
.zip(layout.children()) .zip(layout.children())
.for_each(|((child, state), layout)| { .for_each(|((child, state), layout)| {
child child
.as_widget() .as_widget_mut()
.operate(state, layout, renderer, operation); .operate(state, layout, renderer, operation);
}); });
}); });

View file

@ -471,7 +471,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut widget::Tree, tree: &mut widget::Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
@ -509,7 +509,7 @@ where
vec![widget::Tree::new(&self.text_input as &dyn Widget<_, _, _>)] vec![widget::Tree::new(&self.text_input as &dyn Widget<_, _, _>)]
} }
fn diff(&self, _tree: &mut widget::Tree) { fn diff(&mut self, _tree: &mut widget::Tree) {
// do nothing so the children don't get cleared // do nothing so the children don't get cleared
} }

View file

@ -247,8 +247,8 @@ where
self.content.as_widget().children() self.content.as_widget().children()
} }
fn diff(&self, tree: &mut Tree) { fn diff(&mut self, tree: &mut Tree) {
self.content.as_widget().diff(tree); self.content.as_widget_mut().diff(tree);
} }
fn size(&self) -> Size<Length> { fn size(&self) -> Size<Length> {
@ -259,7 +259,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
@ -273,12 +273,14 @@ where
self.padding, self.padding,
self.horizontal_alignment, self.horizontal_alignment,
self.vertical_alignment, self.vertical_alignment,
|limits| self.content.as_widget().layout(tree, renderer, limits), |limits| {
self.content.as_widget_mut().layout(tree, renderer, limits)
},
) )
} }
fn operate( fn operate(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &Renderer, renderer: &Renderer,
@ -288,7 +290,7 @@ where
self.id.as_ref().map(|id| &id.0), self.id.as_ref().map(|id| &id.0),
layout.bounds(), layout.bounds(),
&mut |operation| { &mut |operation| {
self.content.as_widget().operate( self.content.as_widget_mut().operate(
tree, tree,
layout.children().next().unwrap(), layout.children().next().unwrap(),
renderer, renderer,

View file

@ -103,8 +103,8 @@ where
self.content.as_widget().children() self.content.as_widget().children()
} }
fn diff(&self, tree: &mut widget::Tree) { fn diff(&mut self, tree: &mut widget::Tree) {
self.content.as_widget().diff(tree); self.content.as_widget_mut().diff(tree);
} }
fn size(&self) -> Size<Length> { fn size(&self) -> Size<Length> {
@ -116,12 +116,12 @@ where
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut widget::Tree, tree: &mut widget::Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
) -> layout::Node { ) -> layout::Node {
self.content.as_widget().layout(tree, renderer, limits) self.content.as_widget_mut().layout(tree, renderer, limits)
} }
fn update( fn update(
@ -197,14 +197,14 @@ where
} }
fn operate( fn operate(
&self, &mut self,
state: &mut widget::Tree, state: &mut widget::Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &Renderer, renderer: &Renderer,
operation: &mut dyn widget::Operation, operation: &mut dyn widget::Operation,
) { ) {
self.content self.content
.as_widget() .as_widget_mut()
.operate(state, layout, renderer, operation); .operate(state, layout, renderer, operation);
} }

View file

@ -158,8 +158,8 @@ where
self.children.iter().map(Tree::new).collect() self.children.iter().map(Tree::new).collect()
} }
fn diff(&self, tree: &mut Tree) { fn diff(&mut self, tree: &mut Tree) {
tree.diff_children(&self.children); tree.diff_children(&mut self.children);
} }
fn size(&self) -> Size<Length> { fn size(&self) -> Size<Length> {
@ -176,7 +176,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
@ -220,10 +220,10 @@ where
let mut row_height = 0.0f32; let mut row_height = 0.0f32;
for (i, (child, tree)) in for (i, (child, tree)) in
self.children.iter().zip(&mut tree.children).enumerate() self.children.iter_mut().zip(&mut tree.children).enumerate()
{ {
let node = child let node = child
.as_widget() .as_widget_mut()
.layout(tree, renderer, &cell_limits) .layout(tree, renderer, &cell_limits)
.move_to((x, y)); .move_to((x, y));
@ -251,7 +251,7 @@ where
} }
fn operate( fn operate(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &Renderer, renderer: &Renderer,
@ -259,12 +259,12 @@ where
) { ) {
operation.container(None, layout.bounds(), &mut |operation| { operation.container(None, layout.bounds(), &mut |operation| {
self.children self.children
.iter() .iter_mut()
.zip(&mut tree.children) .zip(&mut tree.children)
.zip(layout.children()) .zip(layout.children())
.for_each(|((child, state), layout)| { .for_each(|((child, state), layout)| {
child child
.as_widget() .as_widget_mut()
.operate(state, layout, renderer, operation); .operate(state, layout, renderer, operation);
}); });
}); });

View file

@ -6,7 +6,7 @@ use crate::container::{self, Container};
use crate::core; use crate::core;
use crate::core::widget::operation::{self, Operation}; use crate::core::widget::operation::{self, Operation};
use crate::core::window; use crate::core::window;
use crate::core::{Element, Length, Pixels, Widget}; use crate::core::{Element, Length, Pixels, Size, Widget};
use crate::float::{self, Float}; use crate::float::{self, Float};
use crate::keyed; use crate::keyed;
use crate::overlay; use crate::overlay;
@ -25,7 +25,9 @@ use crate::text_input::{self, TextInput};
use crate::toggler::{self, Toggler}; use crate::toggler::{self, Toggler};
use crate::tooltip::{self, Tooltip}; use crate::tooltip::{self, Tooltip};
use crate::vertical_slider::{self, VerticalSlider}; use crate::vertical_slider::{self, VerticalSlider};
use crate::{Column, Grid, MouseArea, Pin, Row, Sensor, Space, Stack, Themer}; use crate::{
Column, Grid, MouseArea, Pin, Responsive, Row, Sensor, Space, Stack, Themer,
};
use std::borrow::Borrow; use std::borrow::Borrow;
use std::ops::RangeInclusive; use std::ops::RangeInclusive;
@ -596,8 +598,8 @@ where
self.content.as_widget().children() self.content.as_widget().children()
} }
fn diff(&self, tree: &mut Tree) { fn diff(&mut self, tree: &mut Tree) {
self.content.as_widget().diff(tree); self.content.as_widget_mut().diff(tree);
} }
fn size(&self) -> Size<Length> { fn size(&self) -> Size<Length> {
@ -609,12 +611,12 @@ where
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
) -> layout::Node { ) -> layout::Node {
self.content.as_widget().layout(tree, renderer, limits) self.content.as_widget_mut().layout(tree, renderer, limits)
} }
fn draw( fn draw(
@ -633,14 +635,14 @@ where
} }
fn operate( fn operate(
&self, &mut self,
state: &mut Tree, state: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &Renderer, renderer: &Renderer,
operation: &mut dyn operation::Operation, operation: &mut dyn operation::Operation,
) { ) {
self.content self.content
.as_widget() .as_widget_mut()
.operate(state, layout, renderer, operation); .operate(state, layout, renderer, operation);
} }
@ -759,8 +761,8 @@ where
vec![Tree::new(&self.base), Tree::new(&self.top)] vec![Tree::new(&self.base), Tree::new(&self.top)]
} }
fn diff(&self, tree: &mut Tree) { fn diff(&mut self, tree: &mut Tree) {
tree.diff_children(&[&self.base, &self.top]); tree.diff_children(&mut [&mut self.base, &mut self.top]);
} }
fn size(&self) -> Size<Length> { fn size(&self) -> Size<Length> {
@ -772,18 +774,18 @@ where
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
) -> layout::Node { ) -> layout::Node {
let base = self.base.as_widget().layout( let base = self.base.as_widget_mut().layout(
&mut tree.children[0], &mut tree.children[0],
renderer, renderer,
limits, limits,
); );
let top = self.top.as_widget().layout( let top = self.top.as_widget_mut().layout(
&mut tree.children[1], &mut tree.children[1],
renderer, renderer,
&layout::Limits::new(Size::ZERO, base.size()), &layout::Limits::new(Size::ZERO, base.size()),
@ -834,18 +836,20 @@ where
} }
fn operate( fn operate(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &Renderer, renderer: &Renderer,
operation: &mut dyn operation::Operation, operation: &mut dyn operation::Operation,
) { ) {
let children = [&self.base, &self.top] let children = [&mut self.base, &mut self.top]
.into_iter() .into_iter()
.zip(layout.children().zip(&mut tree.children)); .zip(layout.children().zip(&mut tree.children));
for (child, (layout, tree)) in children { for (child, (layout, tree)) in children {
child.as_widget().operate(tree, layout, renderer, operation); child
.as_widget_mut()
.operate(tree, layout, renderer, operation);
} }
} }
@ -2138,3 +2142,18 @@ where
{ {
Float::new(content) Float::new(content)
} }
/// Creates a new [`Responsive`] widget with a closure that produces its
/// contents.
///
/// The `view` closure will receive the maximum available space for
/// the [`Responsive`] during layout. You can use this [`Size`] to
/// conditionally build the contents.
pub fn responsive<'a, Message, Theme, Renderer>(
f: impl Fn(Size) -> Element<'a, Message, Theme, Renderer> + 'a,
) -> Responsive<'a, Message, Theme, Renderer>
where
Renderer: core::Renderer,
{
Responsive::new(f)
}

View file

@ -386,7 +386,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
_tree: &mut Tree, _tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,

View file

@ -117,7 +117,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
_tree: &mut Tree, _tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,

View file

@ -222,7 +222,7 @@ where
self.children.iter().map(Tree::new).collect() self.children.iter().map(Tree::new).collect()
} }
fn diff(&self, tree: &mut Tree) { fn diff(&mut self, tree: &mut Tree) {
let Tree { let Tree {
state, children, .. state, children, ..
} = tree; } = tree;
@ -231,8 +231,8 @@ where
tree::diff_children_custom_with_search( tree::diff_children_custom_with_search(
children, children,
&self.children, &mut self.children,
|tree, child| child.as_widget().diff(tree), |tree, child| child.as_widget_mut().diff(tree),
|index| { |index| {
self.keys.get(index).or_else(|| self.keys.last()).copied() self.keys.get(index).or_else(|| self.keys.last()).copied()
!= Some(state.keys[index]) != Some(state.keys[index])
@ -253,7 +253,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
@ -272,13 +272,13 @@ where
self.padding, self.padding,
self.spacing, self.spacing,
self.align_items, self.align_items,
&self.children, &mut self.children,
&mut tree.children, &mut tree.children,
) )
} }
fn operate( fn operate(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &Renderer, renderer: &Renderer,
@ -286,12 +286,12 @@ where
) { ) {
operation.container(None, layout.bounds(), &mut |operation| { operation.container(None, layout.bounds(), &mut |operation| {
self.children self.children
.iter() .iter_mut()
.zip(&mut tree.children) .zip(&mut tree.children)
.zip(layout.children()) .zip(layout.children())
.for_each(|((child, state), layout)| { .for_each(|((child, state), layout)| {
child child
.as_widget() .as_widget_mut()
.operate(state, layout, renderer, operation); .operate(state, layout, renderer, operation);
}); });
}); });

View file

@ -2,11 +2,9 @@
pub(crate) mod helpers; pub(crate) mod helpers;
pub mod component; pub mod component;
pub mod responsive;
#[allow(deprecated)] #[allow(deprecated)]
pub use component::Component; pub use component::Component;
pub use responsive::Responsive;
mod cache; mod cache;
@ -127,7 +125,7 @@ where
self.with_element(|element| vec![Tree::new(element.as_widget())]) self.with_element(|element| vec![Tree::new(element.as_widget())])
} }
fn diff(&self, tree: &mut Tree) { fn diff(&mut self, tree: &mut Tree) {
let current = tree let current = tree
.state .state
.downcast_mut::<Internal<Message, Theme, Renderer>>(); .downcast_mut::<Internal<Message, Theme, Renderer>>();
@ -146,8 +144,8 @@ where
current.element = Rc::new(RefCell::new(Some(element))); current.element = Rc::new(RefCell::new(Some(element)));
(*self.element.borrow_mut()) = Some(current.element.clone()); (*self.element.borrow_mut()) = Some(current.element.clone());
self.with_element(|element| { self.with_element_mut(|element| {
tree.diff_children(std::slice::from_ref(&element.as_widget())); tree.diff_children(std::slice::from_mut(element));
}); });
} else { } else {
(*self.element.borrow_mut()) = Some(current.element.clone()); (*self.element.borrow_mut()) = Some(current.element.clone());
@ -166,27 +164,29 @@ where
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
) -> layout::Node { ) -> layout::Node {
self.with_element(|element| { self.with_element_mut(|element| {
element element.as_widget_mut().layout(
.as_widget() &mut tree.children[0],
.layout(&mut tree.children[0], renderer, limits) renderer,
limits,
)
}) })
} }
fn operate( fn operate(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &Renderer, renderer: &Renderer,
operation: &mut dyn widget::Operation, operation: &mut dyn widget::Operation,
) { ) {
self.with_element(|element| { self.with_element_mut(|element| {
element.as_widget().operate( element.as_widget_mut().operate(
&mut tree.children[0], &mut tree.children[0],
layout, layout,
renderer, renderer,

View file

@ -147,13 +147,13 @@ where
Renderer: renderer::Renderer, Renderer: renderer::Renderer,
{ {
fn diff_self(&self) { fn diff_self(&self) {
self.with_element(|element| { self.with_element_mut(|element| {
self.tree self.tree
.borrow_mut() .borrow_mut()
.borrow_mut() .borrow_mut()
.as_mut() .as_mut()
.unwrap() .unwrap()
.diff_children(std::slice::from_ref(&element)); .diff_children(std::slice::from_mut(element));
}); });
} }
@ -279,7 +279,7 @@ where
vec![] vec![]
} }
fn diff(&self, tree: &mut Tree) { fn diff(&mut self, tree: &mut Tree) {
let tree = tree.state.downcast_ref::<Rc<RefCell<Option<Tree>>>>(); let tree = tree.state.downcast_ref::<Rc<RefCell<Option<Tree>>>>();
*self.tree.borrow_mut() = tree.clone(); *self.tree.borrow_mut() = tree.clone();
self.rebuild_element_if_necessary(); self.rebuild_element_if_necessary();
@ -299,15 +299,15 @@ where
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
) -> layout::Node { ) -> layout::Node {
let t = tree.state.downcast_mut::<Rc<RefCell<Option<Tree>>>>(); let t = tree.state.downcast_mut::<Rc<RefCell<Option<Tree>>>>();
self.with_element(|element| { self.with_element_mut(|element| {
element.as_widget().layout( element.as_widget_mut().layout(
&mut t.borrow_mut().as_mut().unwrap().children[0], &mut t.borrow_mut().as_mut().unwrap().children[0],
renderer, renderer,
limits, limits,
@ -378,7 +378,7 @@ where
} }
fn operate( fn operate(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &Renderer, renderer: &Renderer,
@ -387,8 +387,8 @@ where
self.rebuild_element_with_operation(layout, operation); self.rebuild_element_with_operation(layout, operation);
let tree = tree.state.downcast_mut::<Rc<RefCell<Option<Tree>>>>(); let tree = tree.state.downcast_mut::<Rc<RefCell<Option<Tree>>>>();
self.with_element(|element| { self.with_element_mut(|element| {
element.as_widget().operate( element.as_widget_mut().operate(
&mut tree.borrow_mut().as_mut().unwrap().children[0], &mut tree.borrow_mut().as_mut().unwrap().children[0],
layout, layout,
renderer, renderer,

View file

@ -1,10 +1,10 @@
use crate::core::{self, Element, Size}; use crate::core::{self, Element};
use crate::lazy::component; use crate::lazy::component;
use std::hash::Hash; use std::hash::Hash;
#[allow(deprecated)] #[allow(deprecated)]
pub use crate::lazy::{Component, Lazy, Responsive}; pub use crate::lazy::{Component, Lazy};
/// Creates a new [`Lazy`] widget with the given data `Dependency` and a /// Creates a new [`Lazy`] widget with the given data `Dependency` and a
/// closure that can turn this data into a widget tree. /// closure that can turn this data into a widget tree.
@ -41,19 +41,3 @@ where
{ {
component::view(component) 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.
#[cfg(feature = "lazy")]
pub fn responsive<'a, Message, Theme, Renderer>(
f: impl Fn(Size) -> Element<'a, Message, Theme, Renderer> + 'a,
) -> Responsive<'a, Message, Theme, Renderer>
where
Renderer: core::Renderer,
{
Responsive::new(f)
}

View file

@ -1,461 +0,0 @@
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, Event, Length, Point, Rectangle, Shell, Size,
Vector, Widget,
};
use crate::horizontal_space;
use crate::runtime::overlay::Nested;
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.
#[cfg(feature = "lazy")]
#[allow(missing_debug_implementations)]
pub struct Responsive<
'a,
Message,
Theme = crate::Theme,
Renderer = crate::Renderer,
> {
view: Box<dyn Fn(Size) -> Element<'a, Message, Theme, Renderer> + 'a>,
content: RefCell<Content<'a, Message, Theme, Renderer>>,
}
impl<'a, Message, Theme, Renderer> Responsive<'a, Message, Theme, Renderer>
where
Renderer: core::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, Theme, Renderer> + 'a,
) -> Self {
Self {
view: Box::new(view),
content: RefCell::new(Content {
size: Size::ZERO,
layout: None,
is_layout_invalid: true,
element: Element::new(horizontal_space().width(0)),
}),
}
}
}
struct Content<'a, Message, Theme, Renderer> {
size: Size,
layout: Option<layout::Node>,
is_layout_invalid: bool,
element: Element<'a, Message, Theme, Renderer>,
}
impl<'a, Message, Theme, Renderer> Content<'a, Message, Theme, Renderer>
where
Renderer: core::Renderer,
{
fn layout(&mut self, tree: &mut Tree, renderer: &Renderer) {
if self.layout.is_none() || self.is_layout_invalid {
self.layout = Some(self.element.as_widget().layout(
tree,
renderer,
&layout::Limits::new(Size::ZERO, self.size),
));
self.is_layout_invalid = false;
}
}
fn update(
&mut self,
tree: &mut Tree,
new_size: Size,
view: &dyn Fn(Size) -> Element<'a, Message, Theme, Renderer>,
) {
if self.size != new_size {
self.element = view(new_size);
self.size = new_size;
self.layout = None;
tree.diff(&self.element);
} else {
let is_tree_empty =
tree.tag == tree::Tag::stateless() && tree.children.is_empty();
if is_tree_empty {
self.layout = None;
tree.diff(&self.element);
}
}
}
fn resolve<R, T>(
&mut self,
tree: &mut Tree,
renderer: R,
layout: Layout<'_>,
view: &dyn Fn(Size) -> Element<'a, Message, Theme, Renderer>,
f: impl FnOnce(
&mut Tree,
R,
Layout<'_>,
&mut Element<'a, Message, Theme, Renderer>,
) -> T,
) -> T
where
R: Deref<Target = Renderer>,
{
self.update(tree, layout.bounds().size(), view);
self.layout(tree, renderer.deref());
let content_layout = Layout::with_offset(
layout.position() - Point::ORIGIN,
self.layout.as_ref().unwrap(),
);
f(tree, renderer, content_layout, &mut self.element)
}
}
struct State {
tree: RefCell<Tree>,
}
impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>
for Responsive<'_, Message, Theme, Renderer>
where
Renderer: core::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 size(&self) -> Size<Length> {
Size {
width: Length::Fill,
height: Length::Fill,
}
}
fn layout(
&self,
_tree: &mut Tree,
_renderer: &Renderer,
limits: &layout::Limits,
) -> layout::Node {
layout::Node::new(limits.max())
}
fn operate(
&self,
tree: &mut Tree,
layout: Layout<'_>,
renderer: &Renderer,
operation: &mut dyn widget::Operation,
) {
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()
.operate(tree, layout, renderer, operation);
},
);
}
fn update(
&mut self,
tree: &mut Tree,
event: &Event,
layout: Layout<'_>,
cursor: mouse::Cursor,
renderer: &Renderer,
clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>,
viewport: &Rectangle,
) {
let state = tree.state.downcast_mut::<State>();
let mut content = self.content.borrow_mut();
let mut local_messages = vec![];
let mut local_shell = Shell::new(&mut local_messages);
content.resolve(
&mut state.tree.borrow_mut(),
renderer,
layout,
&self.view,
|tree, renderer, layout, element| {
element.as_widget_mut().update(
tree,
event,
layout,
cursor,
renderer,
clipboard,
&mut local_shell,
viewport,
);
},
);
if local_shell.is_layout_invalid() {
content.layout = None;
}
shell.merge(local_shell, std::convert::identity);
}
fn draw(
&self,
tree: &Tree,
renderer: &mut Renderer,
theme: &Theme,
style: &renderer::Style,
layout: Layout<'_>,
cursor: mouse::Cursor,
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, viewport,
);
},
);
}
fn mouse_interaction(
&self,
tree: &Tree,
layout: Layout<'_>,
cursor: mouse::Cursor,
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, viewport, renderer)
},
)
}
fn overlay<'b>(
&'b mut self,
tree: &'b mut Tree,
layout: Layout<'b>,
renderer: &Renderer,
viewport: &Rectangle,
translation: Vector,
) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
use std::ops::DerefMut;
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: &mut RefMut<
'_,
Content<'_, _, _, _>,
>,
tree| {
content.update(tree, layout.bounds().size(), &self.view);
content.layout(tree, renderer);
let Content {
element,
layout: content_layout_node,
is_layout_invalid,
..
} = content.deref_mut();
let content_layout = Layout::with_offset(
layout.bounds().position() - Point::ORIGIN,
content_layout_node.as_ref().unwrap(),
);
(
element
.as_widget_mut()
.overlay(
tree,
content_layout,
renderer,
viewport,
translation,
)
.map(|overlay| RefCell::new(Nested::new(overlay))),
is_layout_invalid,
)
},
}
.build();
if overlay.with_overlay(|(overlay, _layout)| overlay.is_some()) {
Some(overlay::Element::new(Box::new(overlay)))
} else {
None
}
}
}
impl<'a, Message, Theme, Renderer>
From<Responsive<'a, Message, Theme, Renderer>>
for Element<'a, Message, Theme, Renderer>
where
Message: 'a,
Theme: 'a,
Renderer: core::Renderer + 'a,
{
fn from(responsive: Responsive<'a, Message, Theme, Renderer>) -> Self {
Self::new(responsive)
}
}
#[self_referencing]
struct Overlay<'a, 'b, Message, Theme, Renderer> {
content: RefMut<'a, Content<'b, Message, Theme, Renderer>>,
tree: RefMut<'a, Tree>,
types: PhantomData<Message>,
#[borrows(mut content, mut tree)]
#[not_covariant]
overlay: (
Option<RefCell<Nested<'this, Message, Theme, Renderer>>>,
&'this mut bool,
),
}
impl<Message, Theme, Renderer> Overlay<'_, '_, Message, Theme, Renderer> {
fn with_overlay_maybe<T>(
&self,
f: impl FnOnce(&mut Nested<'_, Message, Theme, Renderer>) -> T,
) -> Option<T> {
self.with_overlay(|(overlay, _layout)| {
overlay.as_ref().map(|nested| (f)(&mut nested.borrow_mut()))
})
}
fn with_overlay_mut_maybe<T>(
&mut self,
f: impl FnOnce(&mut Nested<'_, Message, Theme, Renderer>) -> T,
) -> Option<T> {
self.with_overlay_mut(|(overlay, _layout)| {
overlay.as_mut().map(|nested| (f)(nested.get_mut()))
})
}
}
impl<Message, Theme, Renderer> overlay::Overlay<Message, Theme, Renderer>
for Overlay<'_, '_, Message, Theme, Renderer>
where
Renderer: core::Renderer,
{
fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node {
self.with_overlay_maybe(|overlay| overlay.layout(renderer, bounds))
.unwrap_or_default()
}
fn draw(
&self,
renderer: &mut Renderer,
theme: &Theme,
style: &renderer::Style,
layout: Layout<'_>,
cursor: mouse::Cursor,
) {
let _ = self.with_overlay_maybe(|overlay| {
overlay.draw(renderer, theme, style, layout, cursor);
});
}
fn mouse_interaction(
&self,
layout: Layout<'_>,
cursor: mouse::Cursor,
renderer: &Renderer,
) -> mouse::Interaction {
self.with_overlay_maybe(|overlay| {
overlay.mouse_interaction(layout, cursor, renderer)
})
.unwrap_or_default()
}
fn update(
&mut self,
event: &Event,
layout: Layout<'_>,
cursor: mouse::Cursor,
renderer: &Renderer,
clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>,
) {
let mut is_layout_invalid = false;
let _ = self.with_overlay_mut_maybe(|overlay| {
overlay.update(event, layout, cursor, renderer, clipboard, shell);
is_layout_invalid = shell.is_layout_invalid();
});
if is_layout_invalid {
self.with_overlay_mut(|(_overlay, layout)| {
**layout = true;
});
}
}
fn operate(
&mut self,
layout: Layout<'_>,
renderer: &Renderer,
operation: &mut dyn widget::Operation,
) {
let _ = self.with_overlay_mut_maybe(|overlay| {
overlay.operate(layout, renderer, operation);
});
}
}

View file

@ -12,6 +12,7 @@ mod action;
mod column; mod column;
mod mouse_area; mod mouse_area;
mod pin; mod pin;
mod responsive;
mod space; mod space;
mod stack; mod stack;
mod themer; mod themer;
@ -78,6 +79,8 @@ pub use progress_bar::ProgressBar;
#[doc(no_inline)] #[doc(no_inline)]
pub use radio::Radio; pub use radio::Radio;
#[doc(no_inline)] #[doc(no_inline)]
pub use responsive::Responsive;
#[doc(no_inline)]
pub use row::Row; pub use row::Row;
#[doc(no_inline)] #[doc(no_inline)]
pub use rule::Rule; pub use rule::Rule;

View file

@ -181,8 +181,8 @@ where
vec![Tree::new(&self.content)] vec![Tree::new(&self.content)]
} }
fn diff(&self, tree: &mut Tree) { fn diff(&mut self, tree: &mut Tree) {
tree.diff_children(std::slice::from_ref(&self.content)); tree.diff_children(std::slice::from_mut(&mut self.content));
} }
fn size(&self) -> Size<Length> { fn size(&self) -> Size<Length> {
@ -190,24 +190,26 @@ where
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
) -> layout::Node { ) -> layout::Node {
self.content self.content.as_widget_mut().layout(
.as_widget() &mut tree.children[0],
.layout(&mut tree.children[0], renderer, limits) renderer,
limits,
)
} }
fn operate( fn operate(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &Renderer, renderer: &Renderer,
operation: &mut dyn Operation, operation: &mut dyn Operation,
) { ) {
self.content.as_widget().operate( self.content.as_widget_mut().operate(
&mut tree.children[0], &mut tree.children[0],
layout, layout,
renderer, renderer,

View file

@ -205,7 +205,7 @@ where
class, class,
} = menu; } = menu;
let list = Scrollable::new(List { let mut list = Scrollable::new(List {
options, options,
hovered_option, hovered_option,
on_selected, on_selected,
@ -218,7 +218,7 @@ where
class, class,
}); });
state.tree.diff(&list as &dyn Widget<_, _, _>); state.tree.diff(&mut list as &mut dyn Widget<_, _, _>);
Self { Self {
position, position,
@ -369,7 +369,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
_tree: &mut Tree, _tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,

View file

@ -378,7 +378,7 @@ where
self.contents.iter().map(Content::state).collect() self.contents.iter().map(Content::state).collect()
} }
fn diff(&self, tree: &mut Tree) { fn diff(&mut self, tree: &mut Tree) {
let Memory { order, .. } = tree.state.downcast_ref(); let Memory { order, .. } = tree.state.downcast_ref();
// `Pane` always increments and is iterated by Ord so new // `Pane` always increments and is iterated by Ord so new
@ -401,7 +401,7 @@ where
}); });
tree.diff_children_custom( tree.diff_children_custom(
&self.contents, &mut self.contents,
|state, content| content.diff(state), |state, content| content.diff(state),
Content::state, Content::state,
); );
@ -418,7 +418,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
@ -432,20 +432,19 @@ where
let children = self let children = self
.panes .panes
.iter() .iter_mut()
.copied() .zip(&mut self.contents)
.zip(&self.contents)
.zip(tree.children.iter_mut()) .zip(tree.children.iter_mut())
.filter_map(|((pane, content), tree)| { .filter_map(|((pane, content), tree)| {
if self if self
.internal .internal
.maximized() .maximized()
.is_some_and(|maximized| maximized != pane) .is_some_and(|maximized| maximized != *pane)
{ {
return Some(layout::Node::new(Size::ZERO)); return Some(layout::Node::new(Size::ZERO));
} }
let region = regions.get(&pane)?; let region = regions.get(pane)?;
let size = Size::new(region.width, region.height); let size = Size::new(region.width, region.height);
let node = content.layout( let node = content.layout(
@ -462,7 +461,7 @@ where
} }
fn operate( fn operate(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &Renderer, renderer: &Renderer,
@ -470,15 +469,14 @@ where
) { ) {
operation.container(None, layout.bounds(), &mut |operation| { operation.container(None, layout.bounds(), &mut |operation| {
self.panes self.panes
.iter() .iter_mut()
.copied() .zip(&mut self.contents)
.zip(&self.contents)
.zip(&mut tree.children) .zip(&mut tree.children)
.zip(layout.children()) .zip(layout.children())
.filter(|(((pane, _), _), _)| { .filter(|(((pane, _), _), _)| {
self.internal self.internal
.maximized() .maximized()
.is_none_or(|maximized| *pane == maximized) .is_none_or(|maximized| **pane == maximized)
}) })
.for_each(|(((_, content), state), layout)| { .for_each(|(((_, content), state), layout)| {
content.operate(state, layout, renderer, operation); content.operate(state, layout, renderer, operation);

View file

@ -91,13 +91,13 @@ where
} }
} }
pub(super) fn diff(&self, tree: &mut Tree) { pub(super) fn diff(&mut self, tree: &mut Tree) {
if tree.children.len() == 2 { if tree.children.len() == 2 {
if let Some(title_bar) = self.title_bar.as_ref() { if let Some(title_bar) = self.title_bar.as_mut() {
title_bar.diff(&mut tree.children[1]); title_bar.diff(&mut tree.children[1]);
} }
tree.children[0].diff(&self.body); tree.children[0].diff(&mut self.body);
} else { } else {
*tree = self.state(); *tree = self.state();
} }
@ -165,12 +165,12 @@ where
} }
pub(crate) fn layout( pub(crate) fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
) -> layout::Node { ) -> layout::Node {
if let Some(title_bar) = &self.title_bar { if let Some(title_bar) = &mut self.title_bar {
let max_size = limits.max(); let max_size = limits.max();
let title_bar_layout = title_bar.layout( let title_bar_layout = title_bar.layout(
@ -181,7 +181,7 @@ where
let title_bar_size = title_bar_layout.size(); let title_bar_size = title_bar_layout.size();
let body_layout = self.body.as_widget().layout( let body_layout = self.body.as_widget_mut().layout(
&mut tree.children[0], &mut tree.children[0],
renderer, renderer,
&layout::Limits::new( &layout::Limits::new(
@ -201,7 +201,7 @@ where
], ],
) )
} else { } else {
self.body.as_widget().layout( self.body.as_widget_mut().layout(
&mut tree.children[0], &mut tree.children[0],
renderer, renderer,
limits, limits,
@ -210,13 +210,13 @@ where
} }
pub(crate) fn operate( pub(crate) fn operate(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &Renderer, renderer: &Renderer,
operation: &mut dyn widget::Operation, operation: &mut dyn widget::Operation,
) { ) {
let body_layout = if let Some(title_bar) = &self.title_bar { let body_layout = if let Some(title_bar) = &mut self.title_bar {
let mut children = layout.children(); let mut children = layout.children();
title_bar.operate( title_bar.operate(
@ -231,7 +231,7 @@ where
layout layout
}; };
self.body.as_widget().operate( self.body.as_widget_mut().operate(
&mut tree.children[0], &mut tree.children[0],
body_layout, body_layout,
renderer, renderer,

View file

@ -128,17 +128,17 @@ where
} }
} }
pub(super) fn diff(&self, tree: &mut Tree) { pub(super) fn diff(&mut self, tree: &mut Tree) {
if tree.children.len() == 3 { if tree.children.len() == 3 {
if let Some(controls) = self.controls.as_ref() { if let Some(controls) = self.controls.as_mut() {
if let Some(compact) = controls.compact.as_ref() { if let Some(compact) = controls.compact.as_mut() {
tree.children[2].diff(compact); tree.children[2].diff(compact);
} }
tree.children[1].diff(&controls.full); tree.children[1].diff(&mut controls.full);
} }
tree.children[0].diff(&self.content); tree.children[0].diff(&mut self.content);
} else { } else {
*tree = self.state(); *tree = self.state();
} }
@ -274,7 +274,7 @@ where
} }
pub(crate) fn layout( pub(crate) fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
@ -282,7 +282,7 @@ where
let limits = limits.shrink(self.padding); let limits = limits.shrink(self.padding);
let max_size = limits.max(); let max_size = limits.max();
let title_layout = self.content.as_widget().layout( let title_layout = self.content.as_widget_mut().layout(
&mut tree.children[0], &mut tree.children[0],
renderer, renderer,
&layout::Limits::new(Size::ZERO, max_size), &layout::Limits::new(Size::ZERO, max_size),
@ -290,8 +290,8 @@ where
let title_size = title_layout.size(); let title_size = title_layout.size();
let node = if let Some(controls) = &self.controls { let node = if let Some(controls) = &mut self.controls {
let controls_layout = controls.full.as_widget().layout( let controls_layout = controls.full.as_widget_mut().layout(
&mut tree.children[1], &mut tree.children[1],
renderer, renderer,
&layout::Limits::new(Size::ZERO, max_size), &layout::Limits::new(Size::ZERO, max_size),
@ -300,8 +300,8 @@ where
if title_layout.bounds().width + controls_layout.bounds().width if title_layout.bounds().width + controls_layout.bounds().width
> max_size.width > max_size.width
{ {
if let Some(compact) = controls.compact.as_ref() { if let Some(compact) = controls.compact.as_mut() {
let compact_layout = compact.as_widget().layout( let compact_layout = compact.as_widget_mut().layout(
&mut tree.children[2], &mut tree.children[2],
renderer, renderer,
&layout::Limits::new(Size::ZERO, max_size), &layout::Limits::new(Size::ZERO, max_size),
@ -369,7 +369,7 @@ where
} }
pub(crate) fn operate( pub(crate) fn operate(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &Renderer, renderer: &Renderer,
@ -382,16 +382,16 @@ where
let title_layout = children.next().unwrap(); let title_layout = children.next().unwrap();
let mut show_title = true; let mut show_title = true;
if let Some(controls) = &self.controls { if let Some(controls) = &mut self.controls {
let controls_layout = children.next().unwrap(); let controls_layout = children.next().unwrap();
if title_layout.bounds().width + controls_layout.bounds().width if title_layout.bounds().width + controls_layout.bounds().width
> padded.bounds().width > padded.bounds().width
{ {
if let Some(compact) = controls.compact.as_ref() { if let Some(compact) = controls.compact.as_mut() {
let compact_layout = children.next().unwrap(); let compact_layout = children.next().unwrap();
compact.as_widget().operate( compact.as_widget_mut().operate(
&mut tree.children[2], &mut tree.children[2],
compact_layout, compact_layout,
renderer, renderer,
@ -400,7 +400,7 @@ where
} else { } else {
show_title = false; show_title = false;
controls.full.as_widget().operate( controls.full.as_widget_mut().operate(
&mut tree.children[1], &mut tree.children[1],
controls_layout, controls_layout,
renderer, renderer,
@ -408,7 +408,7 @@ where
); );
} }
} else { } else {
controls.full.as_widget().operate( controls.full.as_widget_mut().operate(
&mut tree.children[1], &mut tree.children[1],
controls_layout, controls_layout,
renderer, renderer,
@ -418,7 +418,7 @@ where
}; };
if show_title { if show_title {
self.content.as_widget().operate( self.content.as_widget_mut().operate(
&mut tree.children[0], &mut tree.children[0],
title_layout, title_layout,
renderer, renderer,

View file

@ -348,7 +348,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,

View file

@ -127,8 +127,8 @@ where
self.content.as_widget().children() self.content.as_widget().children()
} }
fn diff(&self, tree: &mut widget::Tree) { fn diff(&mut self, tree: &mut widget::Tree) {
self.content.as_widget().diff(tree); self.content.as_widget_mut().diff(tree);
} }
fn size(&self) -> Size<Length> { fn size(&self) -> Size<Length> {
@ -139,7 +139,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut widget::Tree, tree: &mut widget::Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
@ -151,7 +151,7 @@ where
let node = self let node = self
.content .content
.as_widget() .as_widget_mut()
.layout(tree, renderer, &layout::Limits::new(Size::ZERO, available)) .layout(tree, renderer, &layout::Limits::new(Size::ZERO, available))
.move_to(self.position); .move_to(self.position);
@ -160,13 +160,13 @@ where
} }
fn operate( fn operate(
&self, &mut self,
tree: &mut widget::Tree, tree: &mut widget::Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &Renderer, renderer: &Renderer,
operation: &mut dyn widget::Operation, operation: &mut dyn widget::Operation,
) { ) {
self.content.as_widget().operate( self.content.as_widget_mut().operate(
tree, tree,
layout.children().next().unwrap(), layout.children().next().unwrap(),
renderer, renderer,

View file

@ -157,7 +157,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
_tree: &mut Tree, _tree: &mut Tree,
_renderer: &Renderer, _renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,

View file

@ -136,7 +136,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
_tree: &mut Tree, _tree: &mut Tree,
_renderer: &Renderer, _renderer: &Renderer,
_limits: &layout::Limits, _limits: &layout::Limits,

View file

@ -290,7 +290,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,

213
widget/src/responsive.rs Normal file
View file

@ -0,0 +1,213 @@
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, Event, Length, Rectangle, Shell, Size, Vector,
Widget,
};
use crate::horizontal_space;
/// 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,
Theme = crate::Theme,
Renderer = crate::Renderer,
> {
view: Box<dyn Fn(Size) -> Element<'a, Message, Theme, Renderer> + 'a>,
width: Length,
height: Length,
content: Element<'a, Message, Theme, Renderer>,
}
impl<'a, Message, Theme, Renderer> Responsive<'a, Message, Theme, Renderer>
where
Renderer: core::Renderer,
{
/// Creates a new [`Responsive`] widget with a closure that produces its
/// contents.
///
/// The `view` closure will receive the maximum available space for
/// the [`Responsive`] during layout. You can use this [`Size`] to
/// conditionally build the contents.
pub fn new(
view: impl Fn(Size) -> Element<'a, Message, Theme, Renderer> + 'a,
) -> Self {
Self {
view: Box::new(view),
width: Length::Fill,
height: Length::Fill,
content: Element::new(horizontal_space().width(0)),
}
}
/// Sets the width of the [`Responsive`].
pub fn width(mut self, width: impl Into<Length>) -> Self {
self.width = width.into();
self
}
/// Sets the height of the [`Responsive`].
pub fn height(mut self, height: impl Into<Length>) -> Self {
self.height = height.into();
self
}
}
impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>
for Responsive<'_, Message, Theme, Renderer>
where
Renderer: core::Renderer,
{
fn tag(&self) -> tree::Tag {
struct Marker;
tree::Tag::of::<Marker>()
}
fn diff(&mut self, _tree: &mut Tree) {
// Diff is deferred to layout
}
fn size(&self) -> Size<Length> {
Size {
width: self.width,
height: self.height,
}
}
fn layout(
&mut self,
tree: &mut Tree,
renderer: &Renderer,
limits: &layout::Limits,
) -> layout::Node {
let limits = limits.width(self.width).height(self.height);
let size = limits.max();
self.content = (self.view)(size);
tree.diff_children(std::slice::from_mut(&mut self.content));
let node = self.content.as_widget_mut().layout(
&mut tree.children[0],
renderer,
&limits.loose(),
);
let size = limits.resolve(self.width, self.height, node.size());
layout::Node::with_children(size, vec![node])
}
fn update(
&mut self,
tree: &mut Tree,
event: &Event,
layout: Layout<'_>,
cursor: mouse::Cursor,
renderer: &Renderer,
clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>,
viewport: &Rectangle,
) {
self.content.as_widget_mut().update(
&mut tree.children[0],
event,
layout.children().next().unwrap(),
cursor,
renderer,
clipboard,
shell,
viewport,
);
}
fn draw(
&self,
tree: &Tree,
renderer: &mut Renderer,
theme: &Theme,
style: &renderer::Style,
layout: Layout<'_>,
cursor: mouse::Cursor,
viewport: &Rectangle,
) {
self.content.as_widget().draw(
&tree.children[0],
renderer,
theme,
style,
layout.children().next().unwrap(),
cursor,
viewport,
);
}
fn mouse_interaction(
&self,
tree: &Tree,
layout: Layout<'_>,
cursor: mouse::Cursor,
viewport: &Rectangle,
renderer: &Renderer,
) -> mouse::Interaction {
self.content.as_widget().mouse_interaction(
&tree.children[0],
layout.children().next().unwrap(),
cursor,
viewport,
renderer,
)
}
fn operate(
&mut self,
tree: &mut Tree,
layout: Layout<'_>,
renderer: &Renderer,
operation: &mut dyn widget::Operation,
) {
self.content.as_widget_mut().operate(
&mut tree.children[0],
layout.children().next().unwrap(),
renderer,
operation,
);
}
fn overlay<'a>(
&'a mut self,
tree: &'a mut Tree,
layout: Layout<'a>,
renderer: &Renderer,
viewport: &Rectangle,
translation: Vector,
) -> Option<overlay::Element<'a, Message, Theme, Renderer>> {
self.content.as_widget_mut().overlay(
&mut tree.children[0],
layout.children().next().unwrap(),
renderer,
viewport,
translation,
)
}
}
impl<'a, Message, Theme, Renderer>
From<Responsive<'a, Message, Theme, Renderer>>
for Element<'a, Message, Theme, Renderer>
where
Message: 'a,
Theme: 'a,
Renderer: core::Renderer + 'a,
{
fn from(responsive: Responsive<'a, Message, Theme, Renderer>) -> Self {
Self::new(responsive)
}
}

View file

@ -196,8 +196,8 @@ where
self.children.iter().map(Tree::new).collect() self.children.iter().map(Tree::new).collect()
} }
fn diff(&self, tree: &mut Tree) { fn diff(&mut self, tree: &mut Tree) {
tree.diff_children(&self.children); tree.diff_children(&mut self.children);
} }
fn size(&self) -> Size<Length> { fn size(&self) -> Size<Length> {
@ -208,7 +208,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
@ -222,13 +222,13 @@ where
self.padding, self.padding,
self.spacing, self.spacing,
self.align, self.align,
&self.children, &mut self.children,
&mut tree.children, &mut tree.children,
) )
} }
fn operate( fn operate(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &Renderer, renderer: &Renderer,
@ -236,12 +236,12 @@ where
) { ) {
operation.container(None, layout.bounds(), &mut |operation| { operation.container(None, layout.bounds(), &mut |operation| {
self.children self.children
.iter() .iter_mut()
.zip(&mut tree.children) .zip(&mut tree.children)
.zip(layout.children()) .zip(layout.children())
.for_each(|((child, state), layout)| { .for_each(|((child, state), layout)| {
child child
.as_widget() .as_widget_mut()
.operate(state, layout, renderer, operation); .operate(state, layout, renderer, operation);
}); });
}); });
@ -398,7 +398,7 @@ where
self.row.children() self.row.children()
} }
fn diff(&self, tree: &mut Tree) { fn diff(&mut self, tree: &mut Tree) {
self.row.diff(tree); self.row.diff(tree);
} }
@ -407,7 +407,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
@ -449,8 +449,8 @@ where
} }
}; };
for (i, child) in self.row.children.iter().enumerate() { for (i, child) in self.row.children.iter_mut().enumerate() {
let node = child.as_widget().layout( let node = child.as_widget_mut().layout(
&mut tree.children[i], &mut tree.children[i],
renderer, renderer,
&limits, &limits,
@ -528,7 +528,7 @@ where
} }
fn operate( fn operate(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &Renderer, renderer: &Renderer,

View file

@ -112,7 +112,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
_tree: &mut Tree, _tree: &mut Tree,
_renderer: &Renderer, _renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,

View file

@ -409,8 +409,8 @@ where
vec![Tree::new(&self.content)] vec![Tree::new(&self.content)]
} }
fn diff(&self, tree: &mut Tree) { fn diff(&mut self, tree: &mut Tree) {
tree.diff_children(std::slice::from_ref(&self.content)); tree.diff_children(std::slice::from_mut(&mut self.content));
} }
fn size(&self) -> Size<Length> { fn size(&self) -> Size<Length> {
@ -421,7 +421,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
@ -453,7 +453,7 @@ where
), ),
); );
self.content.as_widget().layout( self.content.as_widget_mut().layout(
&mut tree.children[0], &mut tree.children[0],
renderer, renderer,
&child_limits, &child_limits,
@ -527,7 +527,7 @@ where
} }
fn operate( fn operate(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &Renderer, renderer: &Renderer,
@ -553,7 +553,7 @@ where
self.id.as_ref().map(|id| &id.0), self.id.as_ref().map(|id| &id.0),
bounds, bounds,
&mut |operation| { &mut |operation| {
self.content.as_widget().operate( self.content.as_widget_mut().operate(
&mut tree.children[0], &mut tree.children[0],
layout.children().next().unwrap(), layout.children().next().unwrap(),
renderer, renderer,

View file

@ -184,8 +184,8 @@ where
vec![Tree::new(&self.content)] vec![Tree::new(&self.content)]
} }
fn diff(&self, tree: &mut Tree) { fn diff(&mut self, tree: &mut Tree) {
tree.diff_children(&[&self.content]); tree.diff_children(std::slice::from_mut(&mut self.content));
} }
fn update( fn update(
@ -287,14 +287,16 @@ where
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
) -> layout::Node { ) -> layout::Node {
self.content self.content.as_widget_mut().layout(
.as_widget() &mut tree.children[0],
.layout(&mut tree.children[0], renderer, limits) renderer,
limits,
)
} }
fn draw( fn draw(
@ -319,13 +321,13 @@ where
} }
fn operate( fn operate(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
layout: core::Layout<'_>, layout: core::Layout<'_>,
renderer: &Renderer, renderer: &Renderer,
operation: &mut dyn widget::Operation, operation: &mut dyn widget::Operation,
) { ) {
self.content.as_widget().operate( self.content.as_widget_mut().operate(
&mut tree.children[0], &mut tree.children[0],
layout, layout,
renderer, renderer,

View file

@ -77,7 +77,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
_tree: &mut Tree, _tree: &mut Tree,
_renderer: &Renderer, _renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,

View file

@ -234,7 +234,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
_tree: &mut Tree, _tree: &mut Tree,
_renderer: &Renderer, _renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,

View file

@ -65,7 +65,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
_tree: &mut Tree, _tree: &mut Tree,
_renderer: &Renderer, _renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,

View file

@ -146,8 +146,8 @@ where
self.children.iter().map(Tree::new).collect() self.children.iter().map(Tree::new).collect()
} }
fn diff(&self, tree: &mut Tree) { fn diff(&mut self, tree: &mut Tree) {
tree.diff_children(&self.children); tree.diff_children(&mut self.children);
} }
fn size(&self) -> Size<Length> { fn size(&self) -> Size<Length> {
@ -158,7 +158,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
@ -173,7 +173,7 @@ where
)); ));
} }
let base = self.children[0].as_widget().layout( let base = self.children[0].as_widget_mut().layout(
&mut tree.children[0], &mut tree.children[0],
renderer, renderer,
&limits, &limits,
@ -183,18 +183,21 @@ where
let limits = layout::Limits::new(Size::ZERO, size); let limits = layout::Limits::new(Size::ZERO, size);
let nodes = std::iter::once(base) let nodes = std::iter::once(base)
.chain(self.children[1..].iter().zip(&mut tree.children[1..]).map( .chain(
|(layer, tree)| { self.children[1..]
layer.as_widget().layout(tree, renderer, &limits) .iter_mut()
}, .zip(&mut tree.children[1..])
)) .map(|(layer, tree)| {
layer.as_widget_mut().layout(tree, renderer, &limits)
}),
)
.collect(); .collect();
layout::Node::with_children(size, nodes) layout::Node::with_children(size, nodes)
} }
fn operate( fn operate(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &Renderer, renderer: &Renderer,
@ -202,12 +205,12 @@ where
) { ) {
operation.container(None, layout.bounds(), &mut |operation| { operation.container(None, layout.bounds(), &mut |operation| {
self.children self.children
.iter() .iter_mut()
.zip(&mut tree.children) .zip(&mut tree.children)
.zip(layout.children()) .zip(layout.children())
.for_each(|((child, state), layout)| { .for_each(|((child, state), layout)| {
child child
.as_widget() .as_widget_mut()
.operate(state, layout, renderer, operation); .operate(state, layout, renderer, operation);
}); });
}); });

View file

@ -162,7 +162,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
_tree: &mut Tree, _tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,

View file

@ -227,12 +227,12 @@ where
.collect() .collect()
} }
fn diff(&self, state: &mut widget::Tree) { fn diff(&mut self, state: &mut widget::Tree) {
state.diff_children(&self.cells); state.diff_children(&mut self.cells);
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut widget::Tree, tree: &mut widget::Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
@ -265,7 +265,7 @@ where
let mut y = self.padding_y; let mut y = self.padding_y;
for (i, (cell, state)) in for (i, (cell, state)) in
self.cells.iter().zip(&mut tree.children).enumerate() self.cells.iter_mut().zip(&mut tree.children).enumerate()
{ {
let row = i / columns; let row = i / columns;
let column = i % columns; let column = i % columns;
@ -306,7 +306,7 @@ where
) )
.width(width); .width(width);
let layout = cell.as_widget().layout(state, renderer, &limits); let layout = cell.as_widget_mut().layout(state, renderer, &limits);
let size = limits.resolve(width, Length::Shrink, layout.size()); let size = limits.resolve(width, Length::Shrink, layout.size());
metrics.columns[column] = metrics.columns[column].max(size.width); metrics.columns[column] = metrics.columns[column].max(size.width);
@ -344,7 +344,7 @@ where
let mut y = self.padding_y; let mut y = self.padding_y;
for (i, (cell, state)) in for (i, (cell, state)) in
self.cells.iter().zip(&mut tree.children).enumerate() self.cells.iter_mut().zip(&mut tree.children).enumerate()
{ {
let row = i / columns; let row = i / columns;
let column = i % columns; let column = i % columns;
@ -396,7 +396,7 @@ where
) )
.width(width); .width(width);
let layout = cell.as_widget().layout(state, renderer, &limits); let layout = cell.as_widget_mut().layout(state, renderer, &limits);
let size = limits.resolve( let size = limits.resolve(
if let Length::Fixed(_) = width { if let Length::Fixed(_) = width {
width width
@ -581,7 +581,7 @@ where
} }
fn operate( fn operate(
&self, &mut self,
tree: &mut widget::Tree, tree: &mut widget::Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &Renderer, renderer: &Renderer,
@ -589,11 +589,12 @@ where
) { ) {
for ((cell, state), layout) in self for ((cell, state), layout) in self
.cells .cells
.iter() .iter_mut()
.zip(&mut tree.children) .zip(&mut tree.children)
.zip(layout.children()) .zip(layout.children())
{ {
cell.as_widget().operate(state, layout, renderer, operation); cell.as_widget_mut()
.operate(state, layout, renderer, operation);
} }
} }

View file

@ -225,7 +225,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,

View file

@ -597,7 +597,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut widget::Tree, tree: &mut widget::Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
@ -1051,7 +1051,7 @@ where
} }
fn operate( fn operate(
&self, &mut self,
tree: &mut widget::Tree, tree: &mut widget::Tree,
layout: Layout<'_>, layout: Layout<'_>,
_renderer: &Renderer, _renderer: &Renderer,

View file

@ -297,7 +297,7 @@ where
/// ///
/// [`Renderer`]: text::Renderer /// [`Renderer`]: text::Renderer
pub fn layout( pub fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
@ -654,7 +654,7 @@ where
tree::State::new(State::<Renderer::Paragraph>::new()) tree::State::new(State::<Renderer::Paragraph>::new())
} }
fn diff(&self, tree: &mut Tree) { fn diff(&mut self, tree: &mut Tree) {
let state = tree.state.downcast_mut::<State<Renderer::Paragraph>>(); let state = tree.state.downcast_mut::<State<Renderer::Paragraph>>();
// Stop pasting if input becomes disabled // Stop pasting if input becomes disabled
@ -671,7 +671,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
@ -680,7 +680,7 @@ where
} }
fn operate( fn operate(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
_renderer: &Renderer, _renderer: &Renderer,

View file

@ -81,8 +81,8 @@ where
self.content.as_widget().children() self.content.as_widget().children()
} }
fn diff(&self, tree: &mut Tree) { fn diff(&mut self, tree: &mut Tree) {
self.content.as_widget().diff(tree); self.content.as_widget_mut().diff(tree);
} }
fn size(&self) -> Size<Length> { fn size(&self) -> Size<Length> {
@ -90,23 +90,23 @@ where
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
) -> layout::Node { ) -> layout::Node {
self.content.as_widget().layout(tree, renderer, limits) self.content.as_widget_mut().layout(tree, renderer, limits)
} }
fn operate( fn operate(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &Renderer, renderer: &Renderer,
operation: &mut dyn Operation, operation: &mut dyn Operation,
) { ) {
self.content self.content
.as_widget() .as_widget_mut()
.operate(tree, layout, renderer, operation); .operate(tree, layout, renderer, operation);
} }

View file

@ -270,7 +270,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut Tree, tree: &mut Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,

View file

@ -155,10 +155,10 @@ where
] ]
} }
fn diff(&self, tree: &mut widget::Tree) { fn diff(&mut self, tree: &mut widget::Tree) {
tree.diff_children(&[ tree.diff_children(&mut [
self.content.as_widget(), self.content.as_widget_mut(),
self.tooltip.as_widget(), self.tooltip.as_widget_mut(),
]); ]);
} }
@ -179,14 +179,16 @@ where
} }
fn layout( fn layout(
&self, &mut self,
tree: &mut widget::Tree, tree: &mut widget::Tree,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
) -> layout::Node { ) -> layout::Node {
self.content self.content.as_widget_mut().layout(
.as_widget() &mut tree.children[0],
.layout(&mut tree.children[0], renderer, limits) renderer,
limits,
)
} }
fn update( fn update(
@ -294,7 +296,7 @@ where
let tooltip = if let State::Hovered { cursor_position } = *state { let tooltip = if let State::Hovered { cursor_position } = *state {
Some(overlay::Element::new(Box::new(Overlay { Some(overlay::Element::new(Box::new(Overlay {
position: layout.position() + translation, position: layout.position() + translation,
tooltip: &self.tooltip, tooltip: &mut self.tooltip,
state: children.next().unwrap(), state: children.next().unwrap(),
cursor_position, cursor_position,
content_bounds: layout.bounds(), content_bounds: layout.bounds(),
@ -366,7 +368,7 @@ where
Renderer: text::Renderer, Renderer: text::Renderer,
{ {
position: Point, position: Point,
tooltip: &'b Element<'a, Message, Theme, Renderer>, tooltip: &'b mut Element<'a, Message, Theme, Renderer>,
state: &'b mut widget::Tree, state: &'b mut widget::Tree,
cursor_position: Point, cursor_position: Point,
content_bounds: Rectangle, content_bounds: Rectangle,
@ -386,7 +388,7 @@ where
fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node { fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node {
let viewport = Rectangle::with_size(bounds); let viewport = Rectangle::with_size(bounds);
let tooltip_layout = self.tooltip.as_widget().layout( let tooltip_layout = self.tooltip.as_widget_mut().layout(
self.state, self.state,
renderer, renderer,
&layout::Limits::new( &layout::Limits::new(

View file

@ -238,7 +238,7 @@ where
} }
fn layout( fn layout(
&self, &mut self,
_tree: &mut Tree, _tree: &mut Tree,
_renderer: &Renderer, _renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,