use iced::widget::{center, container, mouse_area, opaque, stack};
use iced::{Color, Element, Length};
pub fn modal<'a, Message>(
base: impl Into<Element<'a, Message>>,
content: impl Into<Element<'a, Message>>,
on_blur: Message,
) -> Element<'a, Message>
where
Message: Clone + 'a,
{
modal_with_opacity(base, content, on_blur, 0.8)
}
pub fn modal_with_opacity<'a, Message>(
base: impl Into<Element<'a, Message>>,
content: impl Into<Element<'a, Message>>,
on_blur: Message,
opacity: f32,
) -> Element<'a, Message>
where
Message: Clone + 'a,
{
let opacity = opacity.clamp(0.0, 1.0);
stack![
base.into(),
opaque(
mouse_area(
center(opaque(content))
.style(move |_theme| {
container::Style {
background: Some(
Color {
a: opacity,
..Color::BLACK
}
.into(),
),
..container::Style::default()
}
})
)
.on_press(on_blur)
)
]
.into()
}
pub struct Modal<'a, Message> {
base: Element<'a, Message>,
content: Element<'a, Message>,
backdrop_opacity: f32,
on_backdrop_press: Option<Message>,
}
impl<'a, Message> Modal<'a, Message>
where
Message: Clone + 'a,
{
pub fn new(
base: impl Into<Element<'a, Message>>,
content: impl Into<Element<'a, Message>>,
) -> Self {
Self {
base: base.into(),
content: content.into(),
backdrop_opacity: 0.8,
on_backdrop_press: None,
}
}
#[must_use]
pub fn backdrop_opacity(mut self, opacity: f32) -> Self {
self.backdrop_opacity = opacity.clamp(0.0, 1.0);
self
}
#[must_use]
pub fn on_backdrop_press(mut self, message: Message) -> Self {
self.on_backdrop_press = Some(message);
self
}
}
impl<'a, Message> From<Modal<'a, Message>> for Element<'a, Message>
where
Message: Clone + 'a,
{
fn from(modal: Modal<'a, Message>) -> Self {
let opacity = modal.backdrop_opacity;
let backdrop_content: Element<'a, Message> = center(opaque(modal.content))
.style(move |_theme| container::Style {
background: Some(
Color {
a: opacity,
..Color::BLACK
}
.into(),
),
..container::Style::default()
})
.into();
let overlay: Element<'a, Message> = if let Some(on_blur) = modal.on_backdrop_press {
opaque(mouse_area(backdrop_content).on_press(on_blur)).into()
} else {
opaque(backdrop_content).into()
};
stack![modal.base, overlay].into()
}
}
pub fn drawer<'a, Message>(
base: impl Into<Element<'a, Message>>,
content: impl Into<Element<'a, Message>>,
on_close: Message,
) -> Element<'a, Message>
where
Message: Clone + 'a,
{
drawer_left(base, content, on_close, 280.0)
}
pub fn drawer_left<'a, Message>(
base: impl Into<Element<'a, Message>>,
content: impl Into<Element<'a, Message>>,
on_close: Message,
width: f32,
) -> Element<'a, Message>
where
Message: Clone + 'a,
{
use iced::widget::row;
let drawer_content: Element<'a, Message> = container(content)
.width(Length::Fixed(width))
.height(Length::Fill)
.style(|theme: &iced::Theme| {
let palette = theme.extended_palette();
container::Style {
background: Some(palette.background.base.color.into()),
..container::Style::default()
}
})
.into();
let backdrop: Element<'a, Message> = mouse_area(
container(iced::widget::Space::new(Length::Fill, Length::Fill)).style(|_theme| {
container::Style {
background: Some(
Color {
a: 0.5,
..Color::BLACK
}
.into(),
),
..container::Style::default()
}
}),
)
.on_press(on_close)
.into();
let overlay: Element<'a, Message> = row![opaque(drawer_content), backdrop]
.width(Length::Fill)
.height(Length::Fill)
.into();
stack![base.into(), overlay].into()
}
pub fn drawer_right<'a, Message>(
base: impl Into<Element<'a, Message>>,
content: impl Into<Element<'a, Message>>,
on_close: Message,
width: f32,
) -> Element<'a, Message>
where
Message: Clone + 'a,
{
use iced::widget::row;
let drawer_content: Element<'a, Message> = container(content)
.width(Length::Fixed(width))
.height(Length::Fill)
.style(|theme: &iced::Theme| {
let palette = theme.extended_palette();
container::Style {
background: Some(palette.background.base.color.into()),
..container::Style::default()
}
})
.into();
let backdrop: Element<'a, Message> = mouse_area(
container(iced::widget::Space::new(Length::Fill, Length::Fill)).style(|_theme| {
container::Style {
background: Some(
Color {
a: 0.5,
..Color::BLACK
}
.into(),
),
..container::Style::default()
}
}),
)
.on_press(on_close)
.into();
let overlay: Element<'a, Message> = row![backdrop, opaque(drawer_content)]
.width(Length::Fill)
.height(Length::Fill)
.into();
stack![base.into(), overlay].into()
}