Implement From<Option<T>> for Element

This commit is contained in:
Héctor Ramón Jiménez 2025-07-18 03:53:59 +02:00
parent dcea10f707
commit e0d9078334
No known key found for this signature in database
GPG key ID: 7CC46565708259A7
9 changed files with 110 additions and 74 deletions

View file

@ -532,3 +532,49 @@ where
) )
} }
} }
impl<'a, T, Message, Theme, Renderer> From<Option<T>>
for Element<'a, Message, Theme, Renderer>
where
T: Into<Self>,
Renderer: crate::Renderer,
{
fn from(element: Option<T>) -> Self {
struct Void;
impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer> for Void
where
Renderer: crate::Renderer,
{
fn size(&self) -> Size<Length> {
Size {
width: Length::Fixed(0.0),
height: Length::Fixed(0.0),
}
}
fn layout(
&self,
_tree: &mut Tree,
_renderer: &Renderer,
_limits: &layout::Limits,
) -> layout::Node {
layout::Node::new(Size::ZERO)
}
fn draw(
&self,
_tree: &Tree,
_renderer: &mut Renderer,
_theme: &Theme,
_style: &renderer::Style,
_layout: Layout<'_>,
_cursor: mouse::Cursor,
_viewport: &Rectangle,
) {
}
}
element.map(T::into).unwrap_or_else(|| Element::new(Void))
}
}

View file

@ -57,6 +57,7 @@ impl Length {
/// Adapts the [`Length`] so it can contain the other [`Length`] and /// Adapts the [`Length`] so it can contain the other [`Length`] and
/// match its fluidity. /// match its fluidity.
#[inline]
pub fn enclose(self, other: Length) -> Self { pub fn enclose(self, other: Length) -> Self {
match (self, other) { match (self, other) {
(Length::Shrink, Length::Fill | Length::FillPortion(_)) => other, (Length::Shrink, Length::Fill | Length::FillPortion(_)) => other,

View file

@ -1,4 +1,4 @@
use crate::{Radians, Vector}; use crate::{Length, Radians, Vector};
/// An amount of space in 2 dimensions. /// An amount of space in 2 dimensions.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
@ -66,6 +66,15 @@ impl Size {
} }
} }
impl Size<Length> {
/// Returns true if either `width` or `height` are 0-sized.
#[inline]
pub fn is_void(&self) -> bool {
matches!(self.width, Length::Fixed(0.0))
|| matches!(self.height, Length::Fixed(0.0))
}
}
impl<T> From<[T; 2]> for Size<T> { impl<T> From<[T; 2]> for Size<T> {
fn from([width, height]: [T; 2]) -> Self { fn from([width, height]: [T; 2]) -> Self {
Size { width, height } Size { width, height }

View file

@ -276,13 +276,13 @@ fn view_content<'a>(
button( button(
"Split vertically", "Split vertically",
Message::Split(pane_grid::Axis::Vertical, pane), Message::Split(pane_grid::Axis::Vertical, pane),
) ),
if total_panes > 1 && !is_pinned {
Some(button("Close", Message::Close(pane)).style(button::danger))
} else {
None
}
] ]
.push_maybe(if total_panes > 1 && !is_pinned {
Some(button("Close", Message::Close(pane)).style(button::danger))
} else {
None
})
.spacing(5) .spacing(5)
.max_width(160); .max_width(160);
@ -300,7 +300,7 @@ fn view_controls<'a>(
is_pinned: bool, is_pinned: bool,
is_maximized: bool, is_maximized: bool,
) -> Element<'a, Message> { ) -> Element<'a, Message> {
let row = row![].spacing(5).push_maybe(if total_panes > 1 { let maximize = if total_panes > 1 {
let (content, message) = if is_maximized { let (content, message) = if is_maximized {
("Restore", Message::Restore) ("Restore", Message::Restore)
} else { } else {
@ -315,7 +315,7 @@ fn view_controls<'a>(
) )
} else { } else {
None None
}); };
let close = button(text("Close").size(14)) let close = button(text("Close").size(14))
.style(button::danger) .style(button::danger)
@ -326,7 +326,7 @@ fn view_controls<'a>(
None None
}); });
row.push(close).into() row![maximize, close].spacing(5).into()
} }
mod style { mod style {

View file

@ -88,18 +88,18 @@ impl QRGenerator {
input, input,
row![toggle_total_size, choose_theme] row![toggle_total_size, choose_theme]
.spacing(20) .spacing(20)
.align_y(Center) .align_y(Center),
self.total_size.map(|total_size| {
slider(Self::SIZE_RANGE, total_size, Message::TotalSizeChanged)
}),
self.qr_code.as_ref().map(|data| {
if let Some(total_size) = self.total_size {
qr_code(data).total_size(total_size)
} else {
qr_code(data).cell_size(10.0)
}
})
] ]
.push_maybe(self.total_size.map(|total_size| {
slider(Self::SIZE_RANGE, total_size, Message::TotalSizeChanged)
}))
.push_maybe(self.qr_code.as_ref().map(|data| {
if let Some(total_size) = self.total_size {
qr_code(data).total_size(total_size)
} else {
qr_code(data).cell_size(10.0)
}
}))
.width(700) .width(700)
.spacing(20) .spacing(20)
.align_x(Center); .align_x(Center);

View file

@ -158,15 +158,15 @@ impl Example {
.spacing(10) .spacing(10)
.align_y(Center); .align_y(Center);
let crop_controls = let crop_controls = column![
column![crop_origin_controls, crop_dimension_controls] crop_origin_controls,
.push_maybe( crop_dimension_controls,
self.crop_error self.crop_error
.as_ref() .as_ref()
.map(|error| text!("Crop error! \n{error}")), .map(|error| text!("Crop error! \n{error}")),
) ]
.spacing(10) .spacing(10)
.align_x(Center); .align_x(Center);
let controls = { let controls = {
let save_result = let save_result =
@ -208,8 +208,8 @@ impl Example {
] ]
.spacing(10) .spacing(10)
.align_x(Center), .align_x(Center),
save_result.map(text)
] ]
.push_maybe(save_result.map(text))
.spacing(40) .spacing(40)
}; };

View file

@ -142,17 +142,17 @@ impl Tour {
} }
fn view(&self) -> Element<'_, Message> { fn view(&self) -> Element<'_, Message> {
let controls = let controls = row![
row![] self.screen.previous().is_some().then(|| {
.push_maybe(self.screen.previous().is_some().then(|| { padded_button("Back")
padded_button("Back") .on_press(Message::BackPressed)
.on_press(Message::BackPressed) .style(button::secondary)
.style(button::secondary) }),
})) horizontal_space(),
.push(horizontal_space()) self.can_continue().then(|| {
.push_maybe(self.can_continue().then(|| { padded_button("Next").on_press(Message::NextPressed)
padded_button("Next").on_press(Message::NextPressed) })
})); ];
let screen = match self.screen { let screen = match self.screen {
Screen::Welcome => self.welcome(), Screen::Welcome => self.welcome(),

View file

@ -145,23 +145,13 @@ where
let child = child.into(); let child = child.into();
let child_size = child.as_widget().size_hint(); let child_size = child.as_widget().size_hint();
self.width = self.width.enclose(child_size.width); if !child_size.is_void() {
self.height = self.height.enclose(child_size.height); self.width = self.width.enclose(child_size.width);
self.height = self.height.enclose(child_size.height);
self.children.push(child); self.children.push(child);
self
}
/// Adds an element to the [`Column`], if `Some`.
pub fn push_maybe(
self,
child: Option<impl Into<Element<'a, Message, Theme, Renderer>>>,
) -> Self {
if let Some(child) = child {
self.push(child)
} else {
self
} }
self
} }
/// Extends the [`Column`] with the given children. /// Extends the [`Column`] with the given children.

View file

@ -136,23 +136,13 @@ where
let child = child.into(); let child = child.into();
let child_size = child.as_widget().size_hint(); let child_size = child.as_widget().size_hint();
self.width = self.width.enclose(child_size.width); if !child_size.is_void() {
self.height = self.height.enclose(child_size.height); self.width = self.width.enclose(child_size.width);
self.height = self.height.enclose(child_size.height);
self.children.push(child); self.children.push(child);
self
}
/// Adds an element to the [`Row`], if `Some`.
pub fn push_maybe(
self,
child: Option<impl Into<Element<'a, Message, Theme, Renderer>>>,
) -> Self {
if let Some(child) = child {
self.push(child)
} else {
self
} }
self
} }
/// Extends the [`Row`] with the given children. /// Extends the [`Row`] with the given children.