Merge branch 'master' into feature/test-recorder
This commit is contained in:
commit
9e81c2b9e8
88 changed files with 1225 additions and 1158 deletions
376
Cargo.lock
generated
376
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -263,3 +263,16 @@ impl From<Radius> for [f32; 4] {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::ops::Mul<f32> for Radius {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(self, scale: f32) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
top_left: self.top_left * scale,
|
||||||
|
top_right: self.top_right * scale,
|
||||||
|
bottom_right: self.bottom_right * scale,
|
||||||
|
bottom_left: self.bottom_left * scale,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -197,7 +197,7 @@ impl Color {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the relative luminance of the [`Color`].
|
/// Returns the relative luminance of the [`Color`].
|
||||||
/// https://www.w3.org/TR/WCAG21/#dfn-relative-luminance
|
/// <https://www.w3.org/TR/WCAG21/#dfn-relative-luminance>
|
||||||
pub fn relative_luminance(self) -> f32 {
|
pub fn relative_luminance(self) -> f32 {
|
||||||
let linear = self.into_linear();
|
let linear = self.into_linear();
|
||||||
0.2126 * linear[0] + 0.7152 * linear[1] + 0.0722 * linear[2]
|
0.2126 * linear[0] + 0.7152 * linear[1] + 0.0722 * linear[2]
|
||||||
|
|
|
||||||
|
|
@ -291,7 +291,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 +300,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn operate(
|
fn operate(
|
||||||
&self,
|
&mut self,
|
||||||
tree: &mut Tree,
|
tree: &mut Tree,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
|
|
@ -426,7 +426,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,
|
||||||
|
|
@ -435,7 +435,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 +554,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,
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ impl<'a> Layout<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over the [`Layout`] of the children of a [`Node`].
|
/// Returns an iterator over the children of this [`Layout`].
|
||||||
pub fn children(self) -> impl DoubleEndedIterator<Item = Layout<'a>> {
|
pub fn children(self) -> impl DoubleEndedIterator<Item = Layout<'a>> {
|
||||||
self.node.children().iter().map(move |node| {
|
self.node.children().iter().map(move |node| {
|
||||||
Layout::with_offset(
|
Layout::with_offset(
|
||||||
|
|
@ -62,6 +62,19 @@ impl<'a> Layout<'a> {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the [`Layout`] of the child at the given index.
|
||||||
|
///
|
||||||
|
/// This can be useful if you ever need to access children out of order
|
||||||
|
/// for layering purposes.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
/// Panics if index is out of bounds.
|
||||||
|
pub fn child(self, index: usize) -> Layout<'a> {
|
||||||
|
let node = &self.node.children()[index];
|
||||||
|
|
||||||
|
Layout::with_offset(Vector::new(self.position.x, self.position.y), node)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Produces a [`Node`] with two children nodes one right next to each other.
|
/// Produces a [`Node`] with two children nodes one right next to each other.
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -78,13 +78,13 @@ where
|
||||||
let total_spacing = spacing * items.len().saturating_sub(1) as f32;
|
let total_spacing = spacing * items.len().saturating_sub(1) as f32;
|
||||||
let max_cross = axis.cross(limits.max());
|
let max_cross = axis.cross(limits.max());
|
||||||
|
|
||||||
|
let compression = limits.compression();
|
||||||
|
let (main_compress, cross_compress) =
|
||||||
|
axis.pack(compression.width, compression.height);
|
||||||
|
|
||||||
let mut fill_main_sum = 0;
|
let mut fill_main_sum = 0;
|
||||||
let mut some_fill_cross = false;
|
let mut some_fill_cross = false;
|
||||||
let (mut cross, cross_compress) = match axis {
|
let mut cross = if cross_compress { 0.0 } else { max_cross };
|
||||||
Axis::Vertical if width == Length::Shrink => (0.0, true),
|
|
||||||
Axis::Horizontal if height == Length::Shrink => (0.0, true),
|
|
||||||
_ => (max_cross, false),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut available = axis.main(limits.max()) - total_spacing;
|
let mut available = axis.main(limits.max()) - total_spacing;
|
||||||
|
|
||||||
|
|
@ -95,14 +95,16 @@ 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();
|
||||||
|
|
||||||
axis.pack(size.width.fill_factor(), size.height.fill_factor())
|
axis.pack(size.width.fill_factor(), size.height.fill_factor())
|
||||||
};
|
};
|
||||||
|
|
||||||
if fill_main_factor == 0 && (!cross_compress || fill_cross_factor == 0)
|
if (main_compress || fill_main_factor == 0)
|
||||||
|
&& (!cross_compress || fill_cross_factor == 0)
|
||||||
{
|
{
|
||||||
let (max_width, max_height) = axis.pack(
|
let (max_width, max_height) = axis.pack(
|
||||||
available,
|
available,
|
||||||
|
|
@ -113,11 +115,14 @@ where
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
let child_limits =
|
let child_limits = Limits::with_compression(
|
||||||
Limits::new(Size::ZERO, Size::new(max_width, max_height));
|
Size::ZERO,
|
||||||
|
Size::new(max_width, max_height),
|
||||||
|
compression,
|
||||||
|
);
|
||||||
|
|
||||||
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 +146,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();
|
||||||
|
|
@ -149,7 +155,9 @@ where
|
||||||
axis.pack(size.width, size.height)
|
axis.pack(size.width, size.height)
|
||||||
};
|
};
|
||||||
|
|
||||||
if main_size.fill_factor() == 0 && cross_size.fill_factor() != 0 {
|
if (main_compress || main_size.fill_factor() == 0)
|
||||||
|
&& cross_size.fill_factor() != 0
|
||||||
|
{
|
||||||
if let Length::Fixed(main) = main_size {
|
if let Length::Fixed(main) = main_size {
|
||||||
available -= main;
|
available -= main;
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -157,11 +165,14 @@ where
|
||||||
|
|
||||||
let (max_width, max_height) = axis.pack(available, cross);
|
let (max_width, max_height) = axis.pack(available, cross);
|
||||||
|
|
||||||
let child_limits =
|
let child_limits = Limits::with_compression(
|
||||||
Limits::new(Size::ZERO, Size::new(max_width, max_height));
|
Size::ZERO,
|
||||||
|
Size::new(max_width, max_height),
|
||||||
|
compression,
|
||||||
|
);
|
||||||
|
|
||||||
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);
|
||||||
|
|
@ -172,63 +183,59 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let remaining = match axis {
|
let remaining = available.max(0.0);
|
||||||
Axis::Horizontal => match width {
|
|
||||||
Length::Shrink => 0.0,
|
|
||||||
_ => available.max(0.0),
|
|
||||||
},
|
|
||||||
Axis::Vertical => match height {
|
|
||||||
Length::Shrink => 0.0,
|
|
||||||
_ => available.max(0.0),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// THIRD PASS
|
// THIRD PASS (conditional)
|
||||||
// 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() {
|
if !main_compress {
|
||||||
let (fill_main_factor, fill_cross_factor) = {
|
for (i, (child, tree)) in
|
||||||
let size = child.as_widget().size();
|
items.iter_mut().zip(trees.iter_mut()).enumerate()
|
||||||
|
{
|
||||||
|
let (fill_main_factor, fill_cross_factor) = {
|
||||||
|
let size = child.as_widget().size();
|
||||||
|
|
||||||
axis.pack(size.width.fill_factor(), size.height.fill_factor())
|
axis.pack(size.width.fill_factor(), size.height.fill_factor())
|
||||||
};
|
|
||||||
|
|
||||||
if fill_main_factor != 0 {
|
|
||||||
let max_main =
|
|
||||||
remaining * fill_main_factor as f32 / fill_main_sum as f32;
|
|
||||||
|
|
||||||
let max_main = if max_main.is_nan() {
|
|
||||||
f32::INFINITY
|
|
||||||
} else {
|
|
||||||
max_main
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let min_main = if max_main.is_infinite() {
|
if fill_main_factor != 0 {
|
||||||
0.0
|
let max_main =
|
||||||
} else {
|
remaining * fill_main_factor as f32 / fill_main_sum as f32;
|
||||||
max_main
|
|
||||||
};
|
|
||||||
|
|
||||||
let (min_width, min_height) = axis.pack(min_main, 0.0);
|
let max_main = if max_main.is_nan() {
|
||||||
let (max_width, max_height) = axis.pack(
|
f32::INFINITY
|
||||||
max_main,
|
|
||||||
if fill_cross_factor == 0 {
|
|
||||||
max_cross
|
|
||||||
} else {
|
} else {
|
||||||
cross
|
max_main
|
||||||
},
|
};
|
||||||
);
|
|
||||||
|
|
||||||
let child_limits = Limits::new(
|
let min_main = if max_main.is_infinite() {
|
||||||
Size::new(min_width, min_height),
|
0.0
|
||||||
Size::new(max_width, max_height),
|
} else {
|
||||||
);
|
max_main
|
||||||
|
};
|
||||||
|
|
||||||
let layout =
|
let (min_width, min_height) = axis.pack(min_main, 0.0);
|
||||||
child.as_widget().layout(tree, renderer, &child_limits);
|
let (max_width, max_height) = axis.pack(
|
||||||
cross = cross.max(axis.cross(layout.size()));
|
max_main,
|
||||||
|
if fill_cross_factor == 0 {
|
||||||
|
max_cross
|
||||||
|
} else {
|
||||||
|
cross
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
nodes[i] = layout;
|
let child_limits = Limits::with_compression(
|
||||||
|
Size::new(min_width, min_height),
|
||||||
|
Size::new(max_width, max_height),
|
||||||
|
compression,
|
||||||
|
);
|
||||||
|
|
||||||
|
let layout =
|
||||||
|
child.as_widget_mut().layout(tree, renderer, &child_limits);
|
||||||
|
cross = cross.max(axis.cross(layout.size()));
|
||||||
|
|
||||||
|
nodes[i] = layout;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -237,7 +244,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 +262,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));
|
||||||
|
|
|
||||||
|
|
@ -6,18 +6,34 @@ use crate::{Length, Size};
|
||||||
pub struct Limits {
|
pub struct Limits {
|
||||||
min: Size,
|
min: Size,
|
||||||
max: Size,
|
max: Size,
|
||||||
|
compression: Size<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Limits {
|
impl Limits {
|
||||||
/// No limits
|
/// No limits
|
||||||
pub const NONE: Limits = Limits {
|
pub const NONE: Limits = Limits {
|
||||||
min: Size::ZERO,
|
min: Size::ZERO,
|
||||||
max: Size::INFINITY,
|
max: Size::INFINITE,
|
||||||
|
compression: 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::with_compression(min, max, Size::new(false, false))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates new [`Limits`] with the given minimun and maximum [`Size`], and
|
||||||
|
/// whether fluid lengths should be compressed to intrinsic dimensions.
|
||||||
|
pub const fn with_compression(
|
||||||
|
min: Size,
|
||||||
|
max: Size,
|
||||||
|
compress: Size<bool>,
|
||||||
|
) -> Self {
|
||||||
|
Limits {
|
||||||
|
min,
|
||||||
|
max,
|
||||||
|
compression: compress,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the minimum [`Size`] of the [`Limits`].
|
/// Returns the minimum [`Size`] of the [`Limits`].
|
||||||
|
|
@ -30,16 +46,25 @@ impl Limits {
|
||||||
self.max
|
self.max
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the compression of the [`Limits`].
|
||||||
|
pub fn compression(&self) -> Size<bool> {
|
||||||
|
self.compression
|
||||||
|
}
|
||||||
|
|
||||||
/// 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.compression.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.compression.width = false;
|
||||||
}
|
}
|
||||||
|
Length::Fill | Length::FillPortion(_) => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
self
|
self
|
||||||
|
|
@ -48,14 +73,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.compression.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.compression.height = false;
|
||||||
}
|
}
|
||||||
|
Length::Fill | Length::FillPortion(_) => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
self
|
self
|
||||||
|
|
@ -103,7 +132,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,
|
||||||
|
compression: self.compression,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes the minimum width constraint for the current [`Limits`].
|
/// Removes the minimum width constraint for the current [`Limits`].
|
||||||
|
|
@ -111,6 +144,7 @@ impl Limits {
|
||||||
Limits {
|
Limits {
|
||||||
min: Size::ZERO,
|
min: Size::ZERO,
|
||||||
max: self.max,
|
max: self.max,
|
||||||
|
compression: self.compression,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -124,21 +158,27 @@ 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.compression.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.compression.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),
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,11 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Rectangle<f32> {
|
impl Rectangle<f32> {
|
||||||
/// A rectangle starting at [`Point::ORIGIN`] with infinite width and height.
|
/// A rectangle starting at negative infinity and with infinite width and height.
|
||||||
pub const INFINITE: Self = Self::new(Point::ORIGIN, Size::INFINITY);
|
pub const INFINITE: Self = Self::new(
|
||||||
|
Point::new(f32::NEG_INFINITY, f32::NEG_INFINITY),
|
||||||
|
Size::INFINITE,
|
||||||
|
);
|
||||||
|
|
||||||
/// Creates a new [`Rectangle`] with its top-left corner in the given
|
/// Creates a new [`Rectangle`] with its top-left corner in the given
|
||||||
/// [`Point`] and with the provided [`Size`].
|
/// [`Point`] and with the provided [`Size`].
|
||||||
|
|
|
||||||
|
|
@ -60,8 +60,8 @@ pub trait Renderer {
|
||||||
/// Fills a [`Quad`] with the provided [`Background`].
|
/// Fills a [`Quad`] with the provided [`Background`].
|
||||||
fn fill_quad(&mut self, quad: Quad, background: impl Into<Background>);
|
fn fill_quad(&mut self, quad: Quad, background: impl Into<Background>);
|
||||||
|
|
||||||
/// Clears all of the recorded primitives in the [`Renderer`].
|
/// Resets the [`Renderer`] to start drawing in the `new_bounds` from scratch.
|
||||||
fn clear(&mut self);
|
fn reset(&mut self, new_bounds: Rectangle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A polygon with four sides.
|
/// A polygon with four sides.
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ impl Renderer for () {
|
||||||
|
|
||||||
fn end_transformation(&mut self) {}
|
fn end_transformation(&mut self) {}
|
||||||
|
|
||||||
fn clear(&mut self) {}
|
fn reset(&mut self, _new_bounds: Rectangle) {}
|
||||||
|
|
||||||
fn fill_quad(
|
fn fill_quad(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ impl Size {
|
||||||
pub const UNIT: Size = Size::new(1., 1.);
|
pub const UNIT: Size = Size::new(1., 1.);
|
||||||
|
|
||||||
/// A [`Size`] with infinite width and height.
|
/// A [`Size`] with infinite width and height.
|
||||||
pub const INFINITY: Size = Size::new(f32::INFINITY, f32::INFINITY);
|
pub const INFINITE: Size = Size::new(f32::INFINITY, f32::INFINITY);
|
||||||
|
|
||||||
/// Returns the minimum of each component of this size and another.
|
/// Returns the minimum of each component of this size and another.
|
||||||
pub fn min(self, other: Self) -> Self {
|
pub fn min(self, other: Self) -> Self {
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
@ -102,7 +102,7 @@ where
|
||||||
|
|
||||||
/// 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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ pub fn from_rgba(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An window icon normally used for the titlebar or taskbar.
|
/// An window icon normally used for the titlebar or taskbar.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Icon {
|
pub struct Icon {
|
||||||
rgba: Vec<u8>,
|
rgba: Vec<u8>,
|
||||||
size: Size<u32>,
|
size: Size<u32>,
|
||||||
|
|
@ -48,6 +48,15 @@ impl Icon {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for Icon {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct("Icon")
|
||||||
|
.field("rgba", &format!("{} pixels", self.rgba.len() / 4))
|
||||||
|
.field("size", &self.size)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
/// An error produced when using [`from_rgba`] with invalid arguments.
|
/// An error produced when using [`from_rgba`] with invalid arguments.
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
|
|
||||||
|
|
@ -134,14 +134,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 draw(
|
fn draw(
|
||||||
|
|
@ -201,13 +203,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(
|
||||||
&mut tree.children[0],
|
&mut tree.children[0],
|
||||||
layout,
|
layout,
|
||||||
renderer,
|
renderer,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -94,14 +94,14 @@ impl Layout {
|
||||||
|
|
||||||
let controls = row([
|
let controls = row([
|
||||||
(!self.example.is_first()).then_some(
|
(!self.example.is_first()).then_some(
|
||||||
button("← Previous")
|
button(text("← Previous").shaping(text::Shaping::Advanced))
|
||||||
.padding([5, 10])
|
.padding([5, 10])
|
||||||
.on_press(Message::Previous)
|
.on_press(Message::Previous)
|
||||||
.into(),
|
.into(),
|
||||||
),
|
),
|
||||||
Some(horizontal_space().into()),
|
Some(horizontal_space().into()),
|
||||||
(!self.example.is_last()).then_some(
|
(!self.example.is_last()).then_some(
|
||||||
button("Next →")
|
button(text("Next →").shaping(text::Shaping::Advanced))
|
||||||
.padding([5, 10])
|
.padding([5, 10])
|
||||||
.on_press(Message::Next)
|
.on_press(Message::Next)
|
||||||
.into(),
|
.into(),
|
||||||
|
|
@ -294,7 +294,7 @@ fn quotes<'a>() -> Element<'a, Message> {
|
||||||
fn quote<'a>(
|
fn quote<'a>(
|
||||||
content: impl Into<Element<'a, Message>>,
|
content: impl Into<Element<'a, Message>>,
|
||||||
) -> Element<'a, Message> {
|
) -> Element<'a, Message> {
|
||||||
row![vertical_rule(2), content.into()]
|
row![vertical_rule(1), content.into()]
|
||||||
.spacing(10)
|
.spacing(10)
|
||||||
.height(Shrink)
|
.height(Shrink)
|
||||||
.into()
|
.into()
|
||||||
|
|
@ -313,7 +313,7 @@ fn quotes<'a>() -> Element<'a, Message> {
|
||||||
"This is another reply",
|
"This is another reply",
|
||||||
),
|
),
|
||||||
horizontal_rule(1),
|
horizontal_rule(1),
|
||||||
"A separator ↑",
|
text("A separator ↑").shaping(text::Shaping::Advanced),
|
||||||
]
|
]
|
||||||
.width(Shrink)
|
.width(Shrink)
|
||||||
.spacing(10)
|
.spacing(10)
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -7,4 +7,4 @@ publish = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
iced.workspace = true
|
iced.workspace = true
|
||||||
iced.features = ["debug", "lazy"]
|
iced.features = ["debug"]
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
@ -343,7 +343,7 @@ mod toast {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn operate(
|
fn operate(
|
||||||
&self,
|
&mut self,
|
||||||
state: &mut Tree,
|
state: &mut Tree,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
|
|
@ -351,7 +351,7 @@ mod toast {
|
||||||
) {
|
) {
|
||||||
operation.container(None, layout.bounds());
|
operation.container(None, layout.bounds());
|
||||||
operation.traverse(&mut |operation| {
|
operation.traverse(&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,
|
||||||
|
|
@ -584,12 +584,12 @@ mod toast {
|
||||||
operation.container(None, layout.bounds());
|
operation.container(None, layout.bounds());
|
||||||
operation.traverse(&mut |operation| {
|
operation.traverse(&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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ pub use crate::core::{Image, Svg};
|
||||||
pub use crate::gradient::{self, Gradient};
|
pub use crate::gradient::{self, Gradient};
|
||||||
|
|
||||||
use crate::cache::Cached;
|
use crate::cache::Cached;
|
||||||
use crate::core::{self, Size};
|
use crate::core::{self, Rectangle};
|
||||||
|
|
||||||
/// A renderer capable of drawing some [`Self::Geometry`].
|
/// A renderer capable of drawing some [`Self::Geometry`].
|
||||||
pub trait Renderer: core::Renderer {
|
pub trait Renderer: core::Renderer {
|
||||||
|
|
@ -31,7 +31,7 @@ pub trait Renderer: core::Renderer {
|
||||||
type Frame: frame::Backend<Geometry = Self::Geometry>;
|
type Frame: frame::Backend<Geometry = Self::Geometry>;
|
||||||
|
|
||||||
/// Creates a new [`Self::Frame`].
|
/// Creates a new [`Self::Frame`].
|
||||||
fn new_frame(&self, size: Size) -> Self::Frame;
|
fn new_frame(&self, bounds: Rectangle) -> Self::Frame;
|
||||||
|
|
||||||
/// Draws the given [`Self::Geometry`].
|
/// Draws the given [`Self::Geometry`].
|
||||||
fn draw_geometry(&mut self, geometry: Self::Geometry);
|
fn draw_geometry(&mut self, geometry: Self::Geometry);
|
||||||
|
|
@ -42,7 +42,7 @@ impl Renderer for () {
|
||||||
type Geometry = ();
|
type Geometry = ();
|
||||||
type Frame = ();
|
type Frame = ();
|
||||||
|
|
||||||
fn new_frame(&self, _size: Size) -> Self::Frame {}
|
fn new_frame(&self, _bounds: Rectangle) -> Self::Frame {}
|
||||||
|
|
||||||
fn draw_geometry(&mut self, _geometry: Self::Geometry) {}
|
fn draw_geometry(&mut self, _geometry: Self::Geometry) {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::cache::{self, Cached};
|
use crate::cache::{self, Cached};
|
||||||
use crate::core::Size;
|
use crate::core::{Rectangle, Size};
|
||||||
use crate::geometry::{self, Frame};
|
use crate::geometry::{self, Frame};
|
||||||
|
|
||||||
pub use cache::Group;
|
pub use cache::Group;
|
||||||
|
|
@ -17,7 +17,7 @@ where
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct Data<T> {
|
struct Data<T> {
|
||||||
bounds: Size,
|
bounds: Rectangle,
|
||||||
geometry: T,
|
geometry: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -53,7 +53,7 @@ where
|
||||||
/// [`Cache`].
|
/// [`Cache`].
|
||||||
///
|
///
|
||||||
/// The closure will only be called when
|
/// The closure will only be called when
|
||||||
/// - the bounds have changed since the previous draw call.
|
/// - the size has changed since the previous draw call.
|
||||||
/// - the [`Cache`] is empty or has been explicitly cleared.
|
/// - the [`Cache`] is empty or has been explicitly cleared.
|
||||||
///
|
///
|
||||||
/// Otherwise, the previously stored geometry will be returned. The
|
/// Otherwise, the previously stored geometry will be returned. The
|
||||||
|
|
@ -62,7 +62,21 @@ where
|
||||||
pub fn draw(
|
pub fn draw(
|
||||||
&self,
|
&self,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
bounds: Size,
|
size: Size,
|
||||||
|
draw_fn: impl FnOnce(&mut Frame<Renderer>),
|
||||||
|
) -> Renderer::Geometry {
|
||||||
|
self.draw_with_bounds(renderer, Rectangle::with_size(size), draw_fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draws geometry using the provided closure and stores it in the
|
||||||
|
/// [`Cache`].
|
||||||
|
///
|
||||||
|
/// Analogous to [`draw`](Self::draw), but takes a clipping [`Rectangle`] instead of
|
||||||
|
/// a [`Size`].
|
||||||
|
pub fn draw_with_bounds(
|
||||||
|
&self,
|
||||||
|
renderer: &Renderer,
|
||||||
|
bounds: Rectangle,
|
||||||
draw_fn: impl FnOnce(&mut Frame<Renderer>),
|
draw_fn: impl FnOnce(&mut Frame<Renderer>),
|
||||||
) -> Renderer::Geometry {
|
) -> Renderer::Geometry {
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
@ -82,7 +96,7 @@ where
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut frame = Frame::new(renderer, bounds);
|
let mut frame = Frame::with_bounds(renderer, bounds);
|
||||||
draw_fn(&mut frame);
|
draw_fn(&mut frame);
|
||||||
|
|
||||||
let geometry = frame.into_geometry().cache(self.raw.group(), previous);
|
let geometry = frame.into_geometry().cache(self.raw.group(), previous);
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,17 @@ where
|
||||||
Renderer: geometry::Renderer,
|
Renderer: geometry::Renderer,
|
||||||
{
|
{
|
||||||
/// Creates a new [`Frame`] with the given dimensions.
|
/// Creates a new [`Frame`] with the given dimensions.
|
||||||
|
///
|
||||||
|
/// Any geometry drawn outside of the dimensions will be clipped.
|
||||||
|
/// If you need further control, use [`with_bounds`](Self::with_bounds).
|
||||||
pub fn new(renderer: &Renderer, size: Size) -> Self {
|
pub fn new(renderer: &Renderer, size: Size) -> Self {
|
||||||
|
Self::with_bounds(renderer, Rectangle::with_size(size))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new [`Frame`] with the given clip bounds.
|
||||||
|
pub fn with_bounds(renderer: &Renderer, bounds: Rectangle) -> Self {
|
||||||
Self {
|
Self {
|
||||||
raw: renderer.new_frame(size),
|
raw: renderer.new_frame(bounds),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,9 @@ pub trait Layer: Default {
|
||||||
/// Creates a new [`Layer`] with the given bounds.
|
/// Creates a new [`Layer`] with the given bounds.
|
||||||
fn with_bounds(bounds: Rectangle) -> Self;
|
fn with_bounds(bounds: Rectangle) -> Self;
|
||||||
|
|
||||||
|
/// Returns the current bounds of the [`Layer`].
|
||||||
|
fn bounds(&self) -> Rectangle;
|
||||||
|
|
||||||
/// Flushes and settles any pending group of primitives in the [`Layer`].
|
/// Flushes and settles any pending group of primitives in the [`Layer`].
|
||||||
///
|
///
|
||||||
/// This will be called when a [`Layer`] is finished. It allows layers to efficiently
|
/// This will be called when a [`Layer`] is finished. It allows layers to efficiently
|
||||||
|
|
@ -20,6 +23,24 @@ pub trait Layer: Default {
|
||||||
|
|
||||||
/// Clears all the layers contents and resets its bounds.
|
/// Clears all the layers contents and resets its bounds.
|
||||||
fn reset(&mut self);
|
fn reset(&mut self);
|
||||||
|
|
||||||
|
/// Returns the start level of the [`Layer`].
|
||||||
|
///
|
||||||
|
/// A level is a "sublayer" index inside of a [`Layer`].
|
||||||
|
///
|
||||||
|
/// A [`Layer`] may draw multiple primitive types in a certain order.
|
||||||
|
/// The level represents the lowest index of the primitive types it
|
||||||
|
/// contains.
|
||||||
|
///
|
||||||
|
/// Two layers A and B can therefore be merged if they have the same bounds,
|
||||||
|
/// and the end level of A is lower or equal than the start level of B.
|
||||||
|
fn start(&self) -> usize;
|
||||||
|
|
||||||
|
/// Returns the end level of the [`Layer`].
|
||||||
|
fn end(&self) -> usize;
|
||||||
|
|
||||||
|
/// Merges a [`Layer`] with the current one.
|
||||||
|
fn merge(&mut self, _layer: &mut Self);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A stack of layers used for drawing.
|
/// A stack of layers used for drawing.
|
||||||
|
|
@ -101,13 +122,6 @@ impl<T: Layer> Stack<T> {
|
||||||
let _ = self.transformations.pop();
|
let _ = self.transformations.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over mutable references to the layers in the [`Stack`].
|
|
||||||
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
|
|
||||||
self.flush();
|
|
||||||
|
|
||||||
self.layers[..self.active_count].iter_mut()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an iterator over immutable references to the layers in the [`Stack`].
|
/// Returns an iterator over immutable references to the layers in the [`Stack`].
|
||||||
pub fn iter(&self) -> impl Iterator<Item = &T> {
|
pub fn iter(&self) -> impl Iterator<Item = &T> {
|
||||||
self.layers[..self.active_count].iter()
|
self.layers[..self.active_count].iter()
|
||||||
|
|
@ -118,19 +132,82 @@ impl<T: Layer> Stack<T> {
|
||||||
&self.layers[..self.active_count]
|
&self.layers[..self.active_count]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Flushes and settles any primitives in the current layer of the [`Stack`].
|
/// Flushes and settles any primitives in the [`Stack`].
|
||||||
pub fn flush(&mut self) {
|
pub fn flush(&mut self) {
|
||||||
self.layers[self.current].flush();
|
self.layers[self.current].flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Performs layer merging wherever possible.
|
||||||
|
///
|
||||||
|
/// Flushes and settles any primitives in the [`Stack`].
|
||||||
|
pub fn merge(&mut self) {
|
||||||
|
self.flush();
|
||||||
|
|
||||||
|
// These are the layers left to process
|
||||||
|
let mut left = self.active_count;
|
||||||
|
|
||||||
|
// There must be at least 2 or more layers to merge
|
||||||
|
while left > 1 {
|
||||||
|
// We set our target as the topmost layer left to process
|
||||||
|
let mut current = left - 1;
|
||||||
|
let mut target = &self.layers[current];
|
||||||
|
let mut target_start = target.start();
|
||||||
|
let mut target_index = current;
|
||||||
|
|
||||||
|
// We scan downwards for a contiguous block of mergeable layer candidates
|
||||||
|
while current > 0 {
|
||||||
|
let candidate = &self.layers[current - 1];
|
||||||
|
let start = candidate.start();
|
||||||
|
let end = candidate.end();
|
||||||
|
|
||||||
|
// We skip empty layers
|
||||||
|
if end == 0 {
|
||||||
|
current -= 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Candidate can be merged if primitive sublayers do not overlap with
|
||||||
|
// previous targets and the clipping bounds match
|
||||||
|
if end > target_start || candidate.bounds() != target.bounds() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Candidate is not empty and can be merged into
|
||||||
|
target = candidate;
|
||||||
|
target_start = start;
|
||||||
|
target_index = current;
|
||||||
|
current -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We merge all the layers scanned into the target
|
||||||
|
//
|
||||||
|
// Since we use `target_index` instead of `current`, we
|
||||||
|
// deliberately avoid merging into empty layers.
|
||||||
|
//
|
||||||
|
// If no candidates were mergeable, this is a no-op.
|
||||||
|
let (head, tail) = self.layers.split_at_mut(target_index + 1);
|
||||||
|
let layer = &mut head[target_index];
|
||||||
|
|
||||||
|
for middle in &mut tail[0..left - target_index - 1] {
|
||||||
|
layer.merge(middle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empty layers found after the target can be skipped
|
||||||
|
left = current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Clears the layers of the [`Stack`], allowing reuse.
|
/// Clears the layers of the [`Stack`], allowing reuse.
|
||||||
///
|
///
|
||||||
|
/// It resizes the base layer bounds to the `new_bounds`.
|
||||||
|
///
|
||||||
/// This will normally keep layer allocations for future drawing operations.
|
/// This will normally keep layer allocations for future drawing operations.
|
||||||
pub fn clear(&mut self) {
|
pub fn reset(&mut self, new_bounds: Rectangle) {
|
||||||
for layer in self.layers[..self.active_count].iter_mut() {
|
for layer in self.layers[..self.active_count].iter_mut() {
|
||||||
layer.reset();
|
layer.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.layers[0].resize(new_bounds);
|
||||||
self.current = 0;
|
self.current = 0;
|
||||||
self.active_count = 1;
|
self.active_count = 1;
|
||||||
self.previous.clear();
|
self.previous.clear();
|
||||||
|
|
|
||||||
|
|
@ -46,8 +46,8 @@ where
|
||||||
delegate!(self, renderer, renderer.fill_quad(quad, background.into()));
|
delegate!(self, renderer, renderer.fill_quad(quad, background.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear(&mut self) {
|
fn reset(&mut self, new_bounds: Rectangle) {
|
||||||
delegate!(self, renderer, renderer.clear());
|
delegate!(self, renderer, renderer.reset(new_bounds));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_layer(&mut self, bounds: Rectangle) {
|
fn start_layer(&mut self, bounds: Rectangle) {
|
||||||
|
|
@ -408,13 +408,13 @@ mod geometry {
|
||||||
type Geometry = Geometry<A::Geometry, B::Geometry>;
|
type Geometry = Geometry<A::Geometry, B::Geometry>;
|
||||||
type Frame = Frame<A::Frame, B::Frame>;
|
type Frame = Frame<A::Frame, B::Frame>;
|
||||||
|
|
||||||
fn new_frame(&self, size: iced_graphics::core::Size) -> Self::Frame {
|
fn new_frame(&self, bounds: Rectangle) -> Self::Frame {
|
||||||
match self {
|
match self {
|
||||||
Self::Primary(renderer) => {
|
Self::Primary(renderer) => {
|
||||||
Frame::Primary(renderer.new_frame(size))
|
Frame::Primary(renderer.new_frame(bounds))
|
||||||
}
|
}
|
||||||
Self::Secondary(renderer) => {
|
Self::Secondary(renderer) => {
|
||||||
Frame::Secondary(renderer.new_frame(size))
|
Frame::Secondary(renderer.new_frame(bounds))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -383,6 +383,12 @@ impl<T, E> Task<Result<T, E>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> Default for Task<T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::none()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> From<()> for Task<T> {
|
impl<T> From<()> for Task<T> {
|
||||||
fn from(_value: ()) -> Self {
|
fn from(_value: ()) -> Self {
|
||||||
Self::none()
|
Self::none()
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
|
|
||||||
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),
|
||||||
|
|
@ -482,10 +482,8 @@ where
|
||||||
style: &renderer::Style,
|
style: &renderer::Style,
|
||||||
cursor: mouse::Cursor,
|
cursor: mouse::Cursor,
|
||||||
) {
|
) {
|
||||||
// TODO: Move to shell level (?)
|
|
||||||
renderer.clear();
|
|
||||||
|
|
||||||
let viewport = Rectangle::with_size(self.bounds);
|
let viewport = Rectangle::with_size(self.bounds);
|
||||||
|
renderer.reset(viewport);
|
||||||
|
|
||||||
let base_cursor = match &self.overlay {
|
let base_cursor = match &self.overlay {
|
||||||
None
|
None
|
||||||
|
|
@ -541,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,
|
||||||
|
|
|
||||||
|
|
@ -64,21 +64,14 @@ pub struct Frame {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Frame {
|
impl Frame {
|
||||||
pub fn new(size: Size) -> Self {
|
pub fn new(bounds: Rectangle) -> Self {
|
||||||
Self::with_clip(Rectangle::with_size(size))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_clip(clip_bounds: Rectangle) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
clip_bounds,
|
clip_bounds: bounds,
|
||||||
stack: Vec::new(),
|
stack: Vec::new(),
|
||||||
primitives: Vec::new(),
|
primitives: Vec::new(),
|
||||||
images: Vec::new(),
|
images: Vec::new(),
|
||||||
text: Vec::new(),
|
text: Vec::new(),
|
||||||
transform: tiny_skia::Transform::from_translate(
|
transform: tiny_skia::Transform::identity(),
|
||||||
clip_bounds.x,
|
|
||||||
clip_bounds.y,
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -238,7 +231,7 @@ impl geometry::frame::Backend for Frame {
|
||||||
align_x: text.align_x,
|
align_x: text.align_x,
|
||||||
align_y: text.align_y,
|
align_y: text.align_y,
|
||||||
shaping: text.shaping,
|
shaping: text.shaping,
|
||||||
clip_bounds: Rectangle::with_size(Size::INFINITY),
|
clip_bounds: Rectangle::with_size(Size::INFINITE),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
text.draw_with(|path, color| self.fill(&path, color));
|
text.draw_with(|path, color| self.fill(&path, color));
|
||||||
|
|
@ -265,7 +258,7 @@ impl geometry::frame::Backend for Frame {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draft(&mut self, clip_bounds: Rectangle) -> Self {
|
fn draft(&mut self, clip_bounds: Rectangle) -> Self {
|
||||||
Self::with_clip(clip_bounds)
|
Self::new(clip_bounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paste(&mut self, frame: Self) {
|
fn paste(&mut self, frame: Self) {
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ pub struct Layer {
|
||||||
pub bounds: Rectangle,
|
pub bounds: Rectangle,
|
||||||
pub quads: Vec<(Quad, Background)>,
|
pub quads: Vec<(Quad, Background)>,
|
||||||
pub primitives: Vec<Item<Primitive>>,
|
pub primitives: Vec<Item<Primitive>>,
|
||||||
pub text: Vec<Item<Text>>,
|
|
||||||
pub images: Vec<Image>,
|
pub images: Vec<Image>,
|
||||||
|
pub text: Vec<Item<Text>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Layer {
|
impl Layer {
|
||||||
|
|
@ -284,6 +284,10 @@ impl graphics::Layer for Layer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn bounds(&self) -> Rectangle {
|
||||||
|
self.bounds
|
||||||
|
}
|
||||||
|
|
||||||
fn flush(&mut self) {}
|
fn flush(&mut self) {}
|
||||||
|
|
||||||
fn resize(&mut self, bounds: Rectangle) {
|
fn resize(&mut self, bounds: Rectangle) {
|
||||||
|
|
@ -298,6 +302,53 @@ impl graphics::Layer for Layer {
|
||||||
self.text.clear();
|
self.text.clear();
|
||||||
self.images.clear();
|
self.images.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn start(&self) -> usize {
|
||||||
|
if !self.quads.is_empty() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.primitives.is_empty() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.images.is_empty() {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.text.is_empty() {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
usize::MAX
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(&self) -> usize {
|
||||||
|
if !self.text.is_empty() {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.images.is_empty() {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.primitives.is_empty() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.quads.is_empty() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn merge(&mut self, layer: &mut Self) {
|
||||||
|
self.quads.append(&mut layer.quads);
|
||||||
|
self.primitives.append(&mut layer.primitives);
|
||||||
|
self.text.append(&mut layer.text);
|
||||||
|
self.images.append(&mut layer.images);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
|
||||||
|
|
@ -225,8 +225,8 @@ impl core::Renderer for Renderer {
|
||||||
layer.draw_quad(quad, background.into(), transformation);
|
layer.draw_quad(quad, background.into(), transformation);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear(&mut self) {
|
fn reset(&mut self, new_bounds: Rectangle) {
|
||||||
self.layers.clear();
|
self.layers.reset(new_bounds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -293,8 +293,8 @@ impl graphics::geometry::Renderer for Renderer {
|
||||||
type Geometry = Geometry;
|
type Geometry = Geometry;
|
||||||
type Frame = geometry::Frame;
|
type Frame = geometry::Frame;
|
||||||
|
|
||||||
fn new_frame(&self, size: core::Size) -> Self::Frame {
|
fn new_frame(&self, bounds: Rectangle) -> Self::Frame {
|
||||||
geometry::Frame::new(size)
|
geometry::Frame::new(bounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_geometry(&mut self, geometry: Self::Geometry) {
|
fn draw_geometry(&mut self, geometry: Self::Geometry) {
|
||||||
|
|
|
||||||
|
|
@ -105,13 +105,8 @@ pub struct Frame {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Frame {
|
impl Frame {
|
||||||
/// Creates a new [`Frame`] with the given [`Size`].
|
|
||||||
pub fn new(size: Size) -> Frame {
|
|
||||||
Self::with_clip(Rectangle::with_size(size))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new [`Frame`] with the given clip bounds.
|
/// Creates a new [`Frame`] with the given clip bounds.
|
||||||
pub fn with_clip(bounds: Rectangle) -> Frame {
|
pub fn new(bounds: Rectangle) -> Frame {
|
||||||
Frame {
|
Frame {
|
||||||
clip_bounds: bounds,
|
clip_bounds: bounds,
|
||||||
buffers: BufferStack::new(),
|
buffers: BufferStack::new(),
|
||||||
|
|
@ -120,9 +115,7 @@ impl Frame {
|
||||||
text: Vec::new(),
|
text: Vec::new(),
|
||||||
transforms: Transforms {
|
transforms: Transforms {
|
||||||
previous: Vec::new(),
|
previous: Vec::new(),
|
||||||
current: Transform(lyon::math::Transform::translation(
|
current: Transform(lyon::math::Transform::identity()),
|
||||||
bounds.x, bounds.y,
|
|
||||||
)),
|
|
||||||
},
|
},
|
||||||
fill_tessellator: tessellation::FillTessellator::new(),
|
fill_tessellator: tessellation::FillTessellator::new(),
|
||||||
stroke_tessellator: tessellation::StrokeTessellator::new(),
|
stroke_tessellator: tessellation::StrokeTessellator::new(),
|
||||||
|
|
@ -409,7 +402,7 @@ impl geometry::frame::Backend for Frame {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draft(&mut self, clip_bounds: Rectangle) -> Frame {
|
fn draft(&mut self, clip_bounds: Rectangle) -> Frame {
|
||||||
Frame::with_clip(clip_bounds)
|
Frame::new(clip_bounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paste(&mut self, frame: Frame) {
|
fn paste(&mut self, frame: Frame) {
|
||||||
|
|
|
||||||
|
|
@ -11,4 +11,6 @@ impl Batch {
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn append(&mut self, _batch: &mut Self) {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,11 +49,14 @@ impl Layer {
|
||||||
position: [bounds.x, bounds.y],
|
position: [bounds.x, bounds.y],
|
||||||
size: [bounds.width, bounds.height],
|
size: [bounds.width, bounds.height],
|
||||||
border_color: color::pack(quad.border.color),
|
border_color: color::pack(quad.border.color),
|
||||||
border_radius: quad.border.radius.into(),
|
border_radius: (quad.border.radius * transformation.scale_factor())
|
||||||
border_width: quad.border.width,
|
.into(),
|
||||||
|
border_width: quad.border.width * transformation.scale_factor(),
|
||||||
shadow_color: color::pack(quad.shadow.color),
|
shadow_color: color::pack(quad.shadow.color),
|
||||||
shadow_offset: quad.shadow.offset.into(),
|
shadow_offset: (quad.shadow.offset * transformation.scale_factor())
|
||||||
shadow_blur_radius: quad.shadow.blur_radius,
|
.into(),
|
||||||
|
shadow_blur_radius: quad.shadow.blur_radius
|
||||||
|
* transformation.scale_factor(),
|
||||||
snap: quad.snap as u32,
|
snap: quad.snap as u32,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -268,6 +271,10 @@ impl graphics::Layer for Layer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn bounds(&self) -> Rectangle {
|
||||||
|
self.bounds
|
||||||
|
}
|
||||||
|
|
||||||
fn flush(&mut self) {
|
fn flush(&mut self) {
|
||||||
self.flush_meshes();
|
self.flush_meshes();
|
||||||
self.flush_text();
|
self.flush_text();
|
||||||
|
|
@ -288,6 +295,62 @@ impl graphics::Layer for Layer {
|
||||||
self.pending_meshes.clear();
|
self.pending_meshes.clear();
|
||||||
self.pending_text.clear();
|
self.pending_text.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn start(&self) -> usize {
|
||||||
|
if !self.quads.is_empty() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.triangles.is_empty() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.primitives.is_empty() {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.images.is_empty() {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.text.is_empty() {
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
usize::MAX
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(&self) -> usize {
|
||||||
|
if !self.text.is_empty() {
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.images.is_empty() {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.primitives.is_empty() {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.triangles.is_empty() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.quads.is_empty() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn merge(&mut self, layer: &mut Self) {
|
||||||
|
self.quads.append(&mut layer.quads);
|
||||||
|
self.triangles.append(&mut layer.triangles);
|
||||||
|
self.primitives.append(&mut layer.primitives);
|
||||||
|
self.images.append(&mut layer.images);
|
||||||
|
self.text.append(&mut layer.text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Layer {
|
impl Default for Layer {
|
||||||
|
|
|
||||||
|
|
@ -311,7 +311,9 @@ impl Renderer {
|
||||||
viewport.physical_size(),
|
viewport.physical_size(),
|
||||||
));
|
));
|
||||||
|
|
||||||
for layer in self.layers.iter_mut() {
|
self.layers.merge();
|
||||||
|
|
||||||
|
for layer in self.layers.iter() {
|
||||||
if physical_bounds
|
if physical_bounds
|
||||||
.intersection(&(layer.bounds * scale_factor))
|
.intersection(&(layer.bounds * scale_factor))
|
||||||
.and_then(Rectangle::snap)
|
.and_then(Rectangle::snap)
|
||||||
|
|
@ -648,8 +650,8 @@ impl core::Renderer for Renderer {
|
||||||
layer.draw_quad(quad, background.into(), transformation);
|
layer.draw_quad(quad, background.into(), transformation);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear(&mut self) {
|
fn reset(&mut self, new_bounds: Rectangle) {
|
||||||
self.layers.clear();
|
self.layers.reset(new_bounds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -759,8 +761,8 @@ impl graphics::geometry::Renderer for Renderer {
|
||||||
type Geometry = Geometry;
|
type Geometry = Geometry;
|
||||||
type Frame = geometry::Frame;
|
type Frame = geometry::Frame;
|
||||||
|
|
||||||
fn new_frame(&self, size: core::Size) -> Self::Frame {
|
fn new_frame(&self, bounds: Rectangle) -> Self::Frame {
|
||||||
geometry::Frame::new(size)
|
geometry::Frame::new(bounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_geometry(&mut self, geometry: Self::Geometry) {
|
fn draw_geometry(&mut self, geometry: Self::Geometry) {
|
||||||
|
|
|
||||||
|
|
@ -304,6 +304,12 @@ impl Batch {
|
||||||
self.gradients.clear();
|
self.gradients.clear();
|
||||||
self.order.clear();
|
self.order.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn append(&mut self, batch: &mut Batch) {
|
||||||
|
self.solids.append(&mut batch.solids);
|
||||||
|
self.gradients.append(&mut batch.gradients);
|
||||||
|
self.order.append(&mut batch.order);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
|
|
||||||
|
|
@ -72,8 +72,6 @@ impl Pipeline {
|
||||||
) -> Self {
|
) -> Self {
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
{
|
{
|
||||||
use crate::graphics::color;
|
|
||||||
|
|
||||||
let layout = device.create_pipeline_layout(
|
let layout = device.create_pipeline_layout(
|
||||||
&wgpu::PipelineLayoutDescriptor {
|
&wgpu::PipelineLayoutDescriptor {
|
||||||
label: Some("iced_wgpu.quad.gradient.pipeline"),
|
label: Some("iced_wgpu.quad.gradient.pipeline"),
|
||||||
|
|
@ -86,39 +84,17 @@ impl Pipeline {
|
||||||
device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||||
label: Some("iced_wgpu.quad.gradient.shader"),
|
label: Some("iced_wgpu.quad.gradient.shader"),
|
||||||
source: wgpu::ShaderSource::Wgsl(
|
source: wgpu::ShaderSource::Wgsl(
|
||||||
std::borrow::Cow::Borrowed(
|
std::borrow::Cow::Borrowed(concat!(
|
||||||
if color::GAMMA_CORRECTION {
|
include_str!("../shader/quad.wgsl"),
|
||||||
concat!(
|
"\n",
|
||||||
include_str!("../shader/quad.wgsl"),
|
include_str!("../shader/vertex.wgsl"),
|
||||||
"\n",
|
"\n",
|
||||||
include_str!("../shader/vertex.wgsl"),
|
include_str!("../shader/quad/gradient.wgsl"),
|
||||||
"\n",
|
"\n",
|
||||||
include_str!(
|
include_str!("../shader/color.wgsl"),
|
||||||
"../shader/quad/gradient.wgsl"
|
"\n",
|
||||||
),
|
include_str!("../shader/color/linear_rgb.wgsl")
|
||||||
"\n",
|
)),
|
||||||
include_str!("../shader/color.wgsl"),
|
|
||||||
"\n",
|
|
||||||
include_str!("../shader/color/oklab.wgsl")
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
concat!(
|
|
||||||
include_str!("../shader/quad.wgsl"),
|
|
||||||
"\n",
|
|
||||||
include_str!("../shader/vertex.wgsl"),
|
|
||||||
"\n",
|
|
||||||
include_str!(
|
|
||||||
"../shader/quad/gradient.wgsl"
|
|
||||||
),
|
|
||||||
"\n",
|
|
||||||
include_str!("../shader/color.wgsl"),
|
|
||||||
"\n",
|
|
||||||
include_str!(
|
|
||||||
"../shader/color/linear_rgb.wgsl"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
const to_lms = mat3x4<f32>(
|
|
||||||
vec4<f32>(0.4121656120, 0.2118591070, 0.0883097947, 0.0),
|
|
||||||
vec4<f32>(0.5362752080, 0.6807189584, 0.2818474174, 0.0),
|
|
||||||
vec4<f32>(0.0514575653, 0.1074065790, 0.6302613616, 0.0),
|
|
||||||
);
|
|
||||||
|
|
||||||
const to_rgb = mat3x4<f32>(
|
|
||||||
vec4<f32>( 4.0767245293, -3.3072168827, 0.2307590544, 0.0),
|
|
||||||
vec4<f32>(-1.2681437731, 2.6093323231, -0.3411344290, 0.0),
|
|
||||||
vec4<f32>(-0.0041119885, -0.7034763098, 1.7068625689, 0.0),
|
|
||||||
);
|
|
||||||
|
|
||||||
fn interpolate_color(from_: vec4<f32>, to_: vec4<f32>, factor: f32) -> vec4<f32> {
|
|
||||||
// To Oklab
|
|
||||||
let lms_a = pow(from_ * to_lms, vec3<f32>(1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0));
|
|
||||||
let lms_b = pow(to_ * to_lms, vec3<f32>(1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0));
|
|
||||||
let mixed = mix(lms_a, lms_b, factor);
|
|
||||||
|
|
||||||
// Back to linear RGB
|
|
||||||
var color = to_rgb * (mixed * mixed * mixed);
|
|
||||||
|
|
||||||
// Alpha interpolation
|
|
||||||
color.a = mix(from_.a, to_.a, factor);
|
|
||||||
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
@ -827,7 +827,6 @@ mod solid {
|
||||||
mod gradient {
|
mod gradient {
|
||||||
use crate::Buffer;
|
use crate::Buffer;
|
||||||
use crate::graphics::Antialiasing;
|
use crate::graphics::Antialiasing;
|
||||||
use crate::graphics::color;
|
|
||||||
use crate::graphics::mesh;
|
use crate::graphics::mesh;
|
||||||
use crate::triangle;
|
use crate::triangle;
|
||||||
|
|
||||||
|
|
@ -922,35 +921,15 @@ mod gradient {
|
||||||
device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||||
label: Some("iced_wgpu.triangle.gradient.shader"),
|
label: Some("iced_wgpu.triangle.gradient.shader"),
|
||||||
source: wgpu::ShaderSource::Wgsl(
|
source: wgpu::ShaderSource::Wgsl(
|
||||||
std::borrow::Cow::Borrowed(
|
std::borrow::Cow::Borrowed(concat!(
|
||||||
if color::GAMMA_CORRECTION {
|
include_str!("shader/triangle.wgsl"),
|
||||||
concat!(
|
"\n",
|
||||||
include_str!("shader/triangle.wgsl"),
|
include_str!("shader/triangle/gradient.wgsl"),
|
||||||
"\n",
|
"\n",
|
||||||
include_str!(
|
include_str!("shader/color.wgsl"),
|
||||||
"shader/triangle/gradient.wgsl"
|
"\n",
|
||||||
),
|
include_str!("shader/color/linear_rgb.wgsl")
|
||||||
"\n",
|
)),
|
||||||
include_str!("shader/color.wgsl"),
|
|
||||||
"\n",
|
|
||||||
include_str!("shader/color/oklab.wgsl")
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
concat!(
|
|
||||||
include_str!("shader/triangle.wgsl"),
|
|
||||||
"\n",
|
|
||||||
include_str!(
|
|
||||||
"shader/triangle/gradient.wgsl"
|
|
||||||
),
|
|
||||||
"\n",
|
|
||||||
include_str!("shader/color.wgsl"),
|
|
||||||
"\n",
|
|
||||||
include_str!(
|
|
||||||
"shader/color/linear_rgb.wgsl"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,7 +256,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn operate(
|
fn operate(
|
||||||
&self,
|
&mut self,
|
||||||
tree: &mut Tree,
|
tree: &mut Tree,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
|
|
@ -264,7 +264,7 @@ where
|
||||||
) {
|
) {
|
||||||
operation.container(None, layout.bounds());
|
operation.container(None, layout.bounds());
|
||||||
operation.traverse(&mut |operation| {
|
operation.traverse(&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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
@ -237,12 +237,12 @@ where
|
||||||
operation.container(None, layout.bounds());
|
operation.container(None, layout.bounds());
|
||||||
operation.traverse(&mut |operation| {
|
operation.traverse(&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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -474,7 +474,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,
|
||||||
|
|
|
||||||
|
|
@ -258,7 +258,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,12 +272,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,
|
||||||
|
|
@ -285,7 +287,7 @@ where
|
||||||
) {
|
) {
|
||||||
operation.container(self.id.as_ref(), layout.bounds());
|
operation.container(self.id.as_ref(), layout.bounds());
|
||||||
operation.traverse(&mut |operation| {
|
operation.traverse(&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,
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
@ -260,12 +260,12 @@ where
|
||||||
operation.container(None, layout.bounds());
|
operation.container(None, layout.bounds());
|
||||||
operation.traverse(&mut |operation| {
|
operation.traverse(&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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -23,7 +23,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;
|
||||||
|
|
@ -607,12 +609,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(
|
||||||
|
|
@ -631,14 +633,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -770,18 +772,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()),
|
||||||
|
|
@ -832,18 +834,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2117,3 +2121,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)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@ pub struct Image<Handle = image::Handle> {
|
||||||
handle: Handle,
|
handle: Handle,
|
||||||
width: Length,
|
width: Length,
|
||||||
height: Length,
|
height: Length,
|
||||||
|
crop: Option<Rectangle<u32>>,
|
||||||
content_fit: ContentFit,
|
content_fit: ContentFit,
|
||||||
filter_method: FilterMethod,
|
filter_method: FilterMethod,
|
||||||
rotation: Rotation,
|
rotation: Rotation,
|
||||||
|
|
@ -74,6 +75,7 @@ impl<Handle> Image<Handle> {
|
||||||
handle: handle.into(),
|
handle: handle.into(),
|
||||||
width: Length::Shrink,
|
width: Length::Shrink,
|
||||||
height: Length::Shrink,
|
height: Length::Shrink,
|
||||||
|
crop: None,
|
||||||
content_fit: ContentFit::default(),
|
content_fit: ContentFit::default(),
|
||||||
filter_method: FilterMethod::default(),
|
filter_method: FilterMethod::default(),
|
||||||
rotation: Rotation::default(),
|
rotation: Rotation::default(),
|
||||||
|
|
@ -145,6 +147,24 @@ impl<Handle> Image<Handle> {
|
||||||
self.scale = scale.into();
|
self.scale = scale.into();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Crops the [`Image`] to the given region described by the [`Rectangle`] in absolute
|
||||||
|
/// coordinates.
|
||||||
|
///
|
||||||
|
/// Cropping is done before applying any transformation or [`ContentFit`]. In practice,
|
||||||
|
/// this means that cropping an [`Image`] with this method should produce the same result
|
||||||
|
/// as cropping it externally (e.g. with an image editor) and creating a new [`Handle`]
|
||||||
|
/// for the cropped version.
|
||||||
|
///
|
||||||
|
/// However, this method is much more efficient; since it just leverages scissoring during
|
||||||
|
/// rendering and no image cropping actually takes place. Instead, it reuses the existing
|
||||||
|
/// image allocations and should be as efficient as not cropping at all!
|
||||||
|
///
|
||||||
|
/// The `region` coordinates will be clamped to the image dimensions, if necessary.
|
||||||
|
pub fn crop(mut self, region: Rectangle<u32>) -> Self {
|
||||||
|
self.crop = Some(region);
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the layout of an [`Image`].
|
/// Computes the layout of an [`Image`].
|
||||||
|
|
@ -154,6 +174,7 @@ pub fn layout<Renderer, Handle>(
|
||||||
handle: &Handle,
|
handle: &Handle,
|
||||||
width: Length,
|
width: Length,
|
||||||
height: Length,
|
height: Length,
|
||||||
|
region: Option<Rectangle<u32>>,
|
||||||
content_fit: ContentFit,
|
content_fit: ContentFit,
|
||||||
rotation: Rotation,
|
rotation: Rotation,
|
||||||
expand: bool,
|
expand: bool,
|
||||||
|
|
@ -162,16 +183,14 @@ where
|
||||||
Renderer: image::Renderer<Handle = Handle>,
|
Renderer: image::Renderer<Handle = Handle>,
|
||||||
{
|
{
|
||||||
// The raw w/h of the underlying image
|
// The raw w/h of the underlying image
|
||||||
let image_size = renderer.measure_image(handle);
|
let image_size = crop(renderer.measure_image(handle), region);
|
||||||
let image_size =
|
|
||||||
Size::new(image_size.width as f32, image_size.height as f32);
|
|
||||||
|
|
||||||
// The rotated size of the image
|
// The rotated size of the image
|
||||||
let rotated_size = rotation.apply(image_size);
|
let rotated_size = rotation.apply(image_size);
|
||||||
|
|
||||||
// The size to be available to the widget prior to `Shrink`ing
|
// The size to be available to the widget prior to `Shrink`ing
|
||||||
let bounds = if expand {
|
let bounds = if expand {
|
||||||
limits.max()
|
limits.width(width).height(height).max()
|
||||||
} else {
|
} else {
|
||||||
limits.resolve(width, height, rotated_size)
|
limits.resolve(width, height, rotated_size)
|
||||||
};
|
};
|
||||||
|
|
@ -198,6 +217,7 @@ fn drawing_bounds<Renderer, Handle>(
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
bounds: Rectangle,
|
bounds: Rectangle,
|
||||||
handle: &Handle,
|
handle: &Handle,
|
||||||
|
region: Option<Rectangle<u32>>,
|
||||||
content_fit: ContentFit,
|
content_fit: ContentFit,
|
||||||
rotation: Rotation,
|
rotation: Rotation,
|
||||||
scale: f32,
|
scale: f32,
|
||||||
|
|
@ -205,8 +225,8 @@ fn drawing_bounds<Renderer, Handle>(
|
||||||
where
|
where
|
||||||
Renderer: image::Renderer<Handle = Handle>,
|
Renderer: image::Renderer<Handle = Handle>,
|
||||||
{
|
{
|
||||||
let Size { width, height } = renderer.measure_image(handle);
|
let original_size = renderer.measure_image(handle);
|
||||||
let image_size = Size::new(width as f32, height as f32);
|
let image_size = crop(original_size, region);
|
||||||
let rotated_size = rotation.apply(image_size);
|
let rotated_size = rotation.apply(image_size);
|
||||||
let adjusted_fit = content_fit.fit(rotated_size, bounds.size());
|
let adjusted_fit = content_fit.fit(rotated_size, bounds.size());
|
||||||
|
|
||||||
|
|
@ -217,6 +237,37 @@ where
|
||||||
|
|
||||||
let final_size = image_size * fit_scale * scale;
|
let final_size = image_size * fit_scale * scale;
|
||||||
|
|
||||||
|
let (crop_offset, final_size) = if let Some(region) = region {
|
||||||
|
let x = region.x.min(original_size.width) as f32;
|
||||||
|
let y = region.y.min(original_size.height) as f32;
|
||||||
|
let width = image_size.width;
|
||||||
|
let height = image_size.height;
|
||||||
|
|
||||||
|
let ratio = Vector::new(
|
||||||
|
original_size.width as f32 / width,
|
||||||
|
original_size.height as f32 / height,
|
||||||
|
);
|
||||||
|
|
||||||
|
let final_size = final_size * ratio;
|
||||||
|
|
||||||
|
let scale = Vector::new(
|
||||||
|
final_size.width / original_size.width as f32,
|
||||||
|
final_size.height / original_size.height as f32,
|
||||||
|
);
|
||||||
|
|
||||||
|
let offset = match content_fit {
|
||||||
|
ContentFit::None => Vector::new(x * scale.x, y * scale.y),
|
||||||
|
_ => Vector::new(
|
||||||
|
((original_size.width as f32 - width) / 2.0 - x) * scale.x,
|
||||||
|
((original_size.height as f32 - height) / 2.0 - y) * scale.y,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
(offset, final_size)
|
||||||
|
} else {
|
||||||
|
(Vector::ZERO, final_size)
|
||||||
|
};
|
||||||
|
|
||||||
let position = match content_fit {
|
let position = match content_fit {
|
||||||
ContentFit::None => Point::new(
|
ContentFit::None => Point::new(
|
||||||
bounds.x + (rotated_size.width - adjusted_fit.width) / 2.0,
|
bounds.x + (rotated_size.width - adjusted_fit.width) / 2.0,
|
||||||
|
|
@ -228,19 +279,31 @@ where
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
Rectangle::new(position, final_size)
|
Rectangle::new(position + crop_offset, final_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn must_clip(bounds: Rectangle, drawing_bounds: Rectangle) -> bool {
|
fn must_clip(bounds: Rectangle, drawing_bounds: Rectangle) -> bool {
|
||||||
drawing_bounds.width > bounds.width || drawing_bounds.height > bounds.height
|
drawing_bounds.width > bounds.width || drawing_bounds.height > bounds.height
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn crop(size: Size<u32>, region: Option<Rectangle<u32>>) -> Size<f32> {
|
||||||
|
if let Some(region) = region {
|
||||||
|
Size::new(
|
||||||
|
region.width.min(size.width) as f32,
|
||||||
|
region.height.min(size.height) as f32,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Size::new(size.width as f32, size.height as f32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Draws an [`Image`]
|
/// Draws an [`Image`]
|
||||||
pub fn draw<Renderer, Handle>(
|
pub fn draw<Renderer, Handle>(
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
viewport: &Rectangle,
|
viewport: &Rectangle,
|
||||||
handle: &Handle,
|
handle: &Handle,
|
||||||
|
crop: Option<Rectangle<u32>>,
|
||||||
content_fit: ContentFit,
|
content_fit: ContentFit,
|
||||||
filter_method: FilterMethod,
|
filter_method: FilterMethod,
|
||||||
rotation: Rotation,
|
rotation: Rotation,
|
||||||
|
|
@ -251,8 +314,15 @@ pub fn draw<Renderer, Handle>(
|
||||||
Handle: Clone,
|
Handle: Clone,
|
||||||
{
|
{
|
||||||
let bounds = layout.bounds();
|
let bounds = layout.bounds();
|
||||||
let drawing_bounds =
|
let drawing_bounds = drawing_bounds(
|
||||||
drawing_bounds(renderer, bounds, handle, content_fit, rotation, scale);
|
renderer,
|
||||||
|
bounds,
|
||||||
|
handle,
|
||||||
|
crop,
|
||||||
|
content_fit,
|
||||||
|
rotation,
|
||||||
|
scale,
|
||||||
|
);
|
||||||
|
|
||||||
if must_clip(bounds, drawing_bounds) {
|
if must_clip(bounds, drawing_bounds) {
|
||||||
if let Some(bounds) = bounds.intersection(viewport) {
|
if let Some(bounds) = bounds.intersection(viewport) {
|
||||||
|
|
@ -316,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,
|
||||||
|
|
@ -327,6 +397,7 @@ where
|
||||||
&self.handle,
|
&self.handle,
|
||||||
self.width,
|
self.width,
|
||||||
self.height,
|
self.height,
|
||||||
|
self.crop,
|
||||||
self.content_fit,
|
self.content_fit,
|
||||||
self.rotation,
|
self.rotation,
|
||||||
self.expand,
|
self.expand,
|
||||||
|
|
@ -348,6 +419,7 @@ where
|
||||||
layout,
|
layout,
|
||||||
viewport,
|
viewport,
|
||||||
&self.handle,
|
&self.handle,
|
||||||
|
self.crop,
|
||||||
self.content_fit,
|
self.content_fit,
|
||||||
self.filter_method,
|
self.filter_method,
|
||||||
self.rotation,
|
self.rotation,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
@ -287,12 +287,12 @@ where
|
||||||
operation.container(None, layout.bounds());
|
operation.container(None, layout.bounds());
|
||||||
operation.traverse(&mut |operation| {
|
operation.traverse(&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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
@ -165,27 +163,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,
|
||||||
|
|
|
||||||
|
|
@ -298,15 +298,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,
|
||||||
|
|
@ -377,7 +377,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn operate(
|
fn operate(
|
||||||
&self,
|
&mut self,
|
||||||
tree: &mut Tree,
|
tree: &mut Tree,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
|
|
@ -386,8 +386,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,
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,462 +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 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(overlay::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<overlay::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 overlay::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 overlay::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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -13,6 +13,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;
|
||||||
|
|
@ -79,6 +80,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;
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
@ -471,15 +470,14 @@ where
|
||||||
operation.container(None, layout.bounds());
|
operation.container(None, layout.bounds());
|
||||||
operation.traverse(&mut |operation| {
|
operation.traverse(&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);
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
208
widget/src/responsive.rs
Normal file
208
widget/src/responsive.rs
Normal file
|
|
@ -0,0 +1,208 @@
|
||||||
|
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;
|
||||||
|
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 diff(&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_ref(&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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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,
|
||||||
|
|
@ -237,12 +237,12 @@ where
|
||||||
operation.container(None, layout.bounds());
|
operation.container(None, layout.bounds());
|
||||||
operation.traverse(&mut |operation| {
|
operation.traverse(&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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -408,7 +408,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,
|
||||||
|
|
@ -418,6 +418,7 @@ where
|
||||||
.height(self.row.height)
|
.height(self.row.height)
|
||||||
.shrink(self.row.padding);
|
.shrink(self.row.padding);
|
||||||
|
|
||||||
|
let child_limits = limits.loose();
|
||||||
let spacing = self.row.spacing;
|
let spacing = self.row.spacing;
|
||||||
let vertical_spacing = self.vertical_spacing.unwrap_or(spacing);
|
let vertical_spacing = self.vertical_spacing.unwrap_or(spacing);
|
||||||
let max_width = limits.max().width;
|
let max_width = limits.max().width;
|
||||||
|
|
@ -450,11 +451,11 @@ 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,
|
&child_limits,
|
||||||
);
|
);
|
||||||
|
|
||||||
let child_size = node.size();
|
let child_size = node.size();
|
||||||
|
|
@ -529,7 +530,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn operate(
|
fn operate(
|
||||||
&self,
|
&mut self,
|
||||||
tree: &mut Tree,
|
tree: &mut Tree,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -109,22 +109,12 @@ where
|
||||||
class: Theme::default(),
|
class: Theme::default(),
|
||||||
last_status: None,
|
last_status: None,
|
||||||
}
|
}
|
||||||
.validate()
|
.enclose()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate(mut self) -> Self {
|
fn enclose(mut self) -> Self {
|
||||||
let size_hint = self.content.as_widget().size_hint();
|
let size_hint = self.content.as_widget().size_hint();
|
||||||
|
|
||||||
debug_assert!(
|
|
||||||
self.direction.vertical().is_none() || !size_hint.height.is_fill(),
|
|
||||||
"scrollable content must not fill its vertical scrolling axis"
|
|
||||||
);
|
|
||||||
|
|
||||||
debug_assert!(
|
|
||||||
self.direction.horizontal().is_none() || !size_hint.width.is_fill(),
|
|
||||||
"scrollable content must not fill its horizontal scrolling axis"
|
|
||||||
);
|
|
||||||
|
|
||||||
if self.direction.horizontal().is_none() {
|
if self.direction.horizontal().is_none() {
|
||||||
self.width = self.width.enclose(size_hint.width);
|
self.width = self.width.enclose(size_hint.width);
|
||||||
}
|
}
|
||||||
|
|
@ -144,7 +134,7 @@ where
|
||||||
/// Sets the [`Direction`] of the [`Scrollable`].
|
/// Sets the [`Direction`] of the [`Scrollable`].
|
||||||
pub fn direction(mut self, direction: impl Into<Direction>) -> Self {
|
pub fn direction(mut self, direction: impl Into<Direction>) -> Self {
|
||||||
self.direction = direction.into();
|
self.direction = direction.into();
|
||||||
self.validate()
|
self.enclose()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the [`widget::Id`] of the [`Scrollable`].
|
/// Sets the [`widget::Id`] of the [`Scrollable`].
|
||||||
|
|
@ -419,7 +409,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,
|
||||||
|
|
@ -435,23 +425,27 @@ where
|
||||||
..Padding::ZERO
|
..Padding::ZERO
|
||||||
},
|
},
|
||||||
|limits| {
|
|limits| {
|
||||||
let child_limits = layout::Limits::new(
|
let is_horizontal = self.direction.horizontal().is_some();
|
||||||
|
let is_vertical = self.direction.vertical().is_some();
|
||||||
|
|
||||||
|
let child_limits = layout::Limits::with_compression(
|
||||||
limits.min(),
|
limits.min(),
|
||||||
Size::new(
|
Size::new(
|
||||||
if self.direction.horizontal().is_some() {
|
if is_horizontal {
|
||||||
f32::INFINITY
|
f32::INFINITY
|
||||||
} else {
|
} else {
|
||||||
limits.max().width
|
limits.max().width
|
||||||
},
|
},
|
||||||
if self.direction.vertical().is_some() {
|
if is_vertical {
|
||||||
f32::INFINITY
|
f32::INFINITY
|
||||||
} else {
|
} else {
|
||||||
limits.max().height
|
limits.max().height
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
Size::new(is_horizontal, is_vertical),
|
||||||
);
|
);
|
||||||
|
|
||||||
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,
|
||||||
|
|
@ -525,7 +519,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn operate(
|
fn operate(
|
||||||
&self,
|
&mut self,
|
||||||
tree: &mut Tree,
|
tree: &mut Tree,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
|
|
@ -548,7 +542,7 @@ where
|
||||||
);
|
);
|
||||||
|
|
||||||
operation.traverse(&mut |operation| {
|
operation.traverse(&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,
|
||||||
|
|
|
||||||
|
|
@ -284,14 +284,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(
|
||||||
|
|
@ -316,13 +318,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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ pub struct Stack<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer>
|
||||||
width: Length,
|
width: Length,
|
||||||
height: Length,
|
height: Length,
|
||||||
children: Vec<Element<'a, Message, Theme, Renderer>>,
|
children: Vec<Element<'a, Message, Theme, Renderer>>,
|
||||||
|
clip: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message, Theme, Renderer> Stack<'a, Message, Theme, Renderer>
|
impl<'a, Message, Theme, Renderer> Stack<'a, Message, Theme, Renderer>
|
||||||
|
|
@ -62,6 +63,7 @@ where
|
||||||
width: Length::Shrink,
|
width: Length::Shrink,
|
||||||
height: Length::Shrink,
|
height: Length::Shrink,
|
||||||
children,
|
children,
|
||||||
|
clip: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -114,6 +116,16 @@ where
|
||||||
) -> Self {
|
) -> Self {
|
||||||
children.into_iter().fold(self, Self::push)
|
children.into_iter().fold(self, Self::push)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets whether the [`Stack`] should clip overflowing content.
|
||||||
|
///
|
||||||
|
/// It has a slight performance overhead during presentation.
|
||||||
|
///
|
||||||
|
/// By default, it is set to `false`.
|
||||||
|
pub fn clip(mut self, clip: bool) -> Self {
|
||||||
|
self.clip = clip;
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Message, Renderer> Default for Stack<'_, Message, Renderer>
|
impl<Message, Renderer> Default for Stack<'_, Message, Renderer>
|
||||||
|
|
@ -146,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,
|
||||||
|
|
@ -161,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,
|
||||||
|
|
@ -171,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,
|
||||||
|
|
@ -191,12 +206,12 @@ where
|
||||||
operation.container(None, layout.bounds());
|
operation.container(None, layout.bounds());
|
||||||
operation.traverse(&mut |operation| {
|
operation.traverse(&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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -278,6 +293,12 @@ where
|
||||||
viewport: &Rectangle,
|
viewport: &Rectangle,
|
||||||
) {
|
) {
|
||||||
if let Some(clipped_viewport) = layout.bounds().intersection(viewport) {
|
if let Some(clipped_viewport) = layout.bounds().intersection(viewport) {
|
||||||
|
let viewport = if self.clip {
|
||||||
|
&clipped_viewport
|
||||||
|
} else {
|
||||||
|
viewport
|
||||||
|
};
|
||||||
|
|
||||||
let layers_below = if cursor.is_over(layout.bounds()) {
|
let layers_below = if cursor.is_over(layout.bounds()) {
|
||||||
self.children
|
self.children
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -313,26 +334,16 @@ where
|
||||||
layout,
|
layout,
|
||||||
cursor| {
|
cursor| {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
renderer.with_layer(clipped_viewport, |renderer| {
|
renderer.with_layer(*viewport, |renderer| {
|
||||||
layer.as_widget().draw(
|
layer.as_widget().draw(
|
||||||
state,
|
state, renderer, theme, style, layout, cursor,
|
||||||
renderer,
|
viewport,
|
||||||
theme,
|
|
||||||
style,
|
|
||||||
layout,
|
|
||||||
cursor,
|
|
||||||
&clipped_viewport,
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
layer.as_widget().draw(
|
layer.as_widget().draw(
|
||||||
state,
|
state, renderer, theme, style, layout, cursor,
|
||||||
renderer,
|
viewport,
|
||||||
theme,
|
|
||||||
style,
|
|
||||||
layout,
|
|
||||||
cursor,
|
|
||||||
&clipped_viewport,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -232,7 +232,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,
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -295,7 +295,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,
|
||||||
|
|
@ -669,7 +669,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,
|
||||||
|
|
@ -678,7 +678,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn operate(
|
fn operate(
|
||||||
&self,
|
&mut self,
|
||||||
tree: &mut Tree,
|
tree: &mut Tree,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
_renderer: &Renderer,
|
_renderer: &Renderer,
|
||||||
|
|
|
||||||
|
|
@ -82,23 +82,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
@ -202,6 +204,7 @@ where
|
||||||
) {
|
) {
|
||||||
let state = tree.state.downcast_mut::<State>();
|
let state = tree.state.downcast_mut::<State>();
|
||||||
|
|
||||||
|
let previous_state = *state;
|
||||||
let was_idle = *state == State::Idle;
|
let was_idle = *state == State::Idle;
|
||||||
|
|
||||||
*state = cursor
|
*state = cursor
|
||||||
|
|
@ -214,7 +217,9 @@ where
|
||||||
if was_idle != is_idle {
|
if was_idle != is_idle {
|
||||||
shell.invalidate_layout();
|
shell.invalidate_layout();
|
||||||
shell.request_redraw();
|
shell.request_redraw();
|
||||||
} else if !is_idle && self.position == Position::FollowCursor {
|
} else if self.position == Position::FollowCursor
|
||||||
|
&& previous_state != *state
|
||||||
|
{
|
||||||
shell.request_redraw();
|
shell.request_redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -291,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(),
|
||||||
|
|
@ -363,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,
|
||||||
|
|
@ -383,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(
|
||||||
|
|
@ -391,7 +396,7 @@ where
|
||||||
if self.snap_within_viewport {
|
if self.snap_within_viewport {
|
||||||
viewport.size()
|
viewport.size()
|
||||||
} else {
|
} else {
|
||||||
Size::INFINITY
|
Size::INFINITE
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.shrink(Padding::new(self.padding)),
|
.shrink(Padding::new(self.padding)),
|
||||||
|
|
@ -505,7 +510,7 @@ where
|
||||||
&defaults,
|
&defaults,
|
||||||
layout.children().next().unwrap(),
|
layout.children().next().unwrap(),
|
||||||
cursor_position,
|
cursor_position,
|
||||||
&Rectangle::with_size(Size::INFINITY),
|
&Rectangle::with_size(Size::INFINITE),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -346,7 +346,7 @@ where
|
||||||
|
|
||||||
self.content = Renderer::Paragraph::with_spans(Text {
|
self.content = Renderer::Paragraph::with_spans(Text {
|
||||||
content: &spans,
|
content: &spans,
|
||||||
bounds: Size::INFINITY,
|
bounds: Size::INFINITE,
|
||||||
size: preedit
|
size: preedit
|
||||||
.text_size
|
.text_size
|
||||||
.unwrap_or_else(|| renderer.default_size()),
|
.unwrap_or_else(|| renderer.default_size()),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue