use iced_native::{event, mouse, Clipboard, Event, Layout, Length, Point, Rectangle, Shell};
use iced_native::{widget::Tree, Element, Widget};
use super::overlay::modal::ModalOverlay;
pub use crate::style::modal::StyleSheet;
#[allow(missing_debug_implementations)]
pub struct Modal<'a, Content, Message, Renderer>
where
Content: Fn() -> Element<'a, Message, Renderer>,
Message: Clone,
Renderer: iced_native::Renderer,
Renderer::Theme: StyleSheet,
{
show_modal: bool,
underlay: Element<'a, Message, Renderer>,
content: Content,
backdrop: Option<Message>,
esc: Option<Message>,
style: <Renderer::Theme as StyleSheet>::Style,
}
impl<'a, Content, Message, Renderer> Modal<'a, Content, Message, Renderer>
where
Content: Fn() -> Element<'a, Message, Renderer>,
Message: Clone,
Renderer: iced_native::Renderer,
Renderer::Theme: StyleSheet,
{
pub fn new<U>(show_modal: bool, underlay: U, content: Content) -> Self
where
U: Into<Element<'a, Message, Renderer>>,
{
Modal {
show_modal,
underlay: underlay.into(),
content,
backdrop: None,
esc: None,
style: <Renderer::Theme as StyleSheet>::Style::default(),
}
}
#[must_use]
pub fn backdrop(mut self, message: Message) -> Self {
self.backdrop = Some(message);
self
}
#[must_use]
pub fn on_esc(mut self, message: Message) -> Self {
self.esc = Some(message);
self
}
#[must_use]
pub fn style(mut self, style: <Renderer::Theme as StyleSheet>::Style) -> Self {
self.style = style;
self
}
}
impl<'a, Content, Message, Renderer> Widget<Message, Renderer>
for Modal<'a, Content, Message, Renderer>
where
Content: 'a + Fn() -> Element<'a, Message, Renderer>,
Message: 'a + Clone,
Renderer: 'a + iced_native::Renderer,
Renderer::Theme: StyleSheet,
{
fn children(&self) -> Vec<iced_native::widget::Tree> {
vec![Tree::new(&self.underlay), Tree::new(&(self.content)())]
}
fn diff(&self, tree: &mut Tree) {
tree.diff_children(&[&self.underlay, &(self.content)()]);
}
fn width(&self) -> Length {
self.underlay.as_widget().width()
}
fn height(&self) -> Length {
self.underlay.as_widget().height()
}
fn layout(
&self,
renderer: &Renderer,
limits: &iced_native::layout::Limits,
) -> iced_native::layout::Node {
self.underlay.as_widget().layout(renderer, limits)
}
fn on_event(
&mut self,
state: &mut Tree,
event: Event,
layout: Layout<'_>,
cursor_position: Point,
renderer: &Renderer,
clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>,
) -> event::Status {
self.underlay.as_widget_mut().on_event(
&mut state.children[0],
event,
layout,
cursor_position,
renderer,
clipboard,
shell,
)
}
fn mouse_interaction(
&self,
state: &Tree,
layout: Layout<'_>,
cursor_position: Point,
viewport: &Rectangle,
renderer: &Renderer,
) -> mouse::Interaction {
self.underlay.as_widget().mouse_interaction(
&state.children[0],
layout,
cursor_position,
viewport,
renderer,
)
}
fn draw(
&self,
state: &iced_native::widget::Tree,
renderer: &mut Renderer,
theme: &Renderer::Theme,
style: &iced_native::renderer::Style,
layout: Layout<'_>,
cursor_position: Point,
viewport: &Rectangle,
) {
self.underlay.as_widget().draw(
&state.children[0],
renderer,
theme,
style,
layout,
cursor_position,
viewport,
);
}
fn overlay<'b>(
&'b mut self,
state: &'b mut Tree,
layout: Layout<'_>,
renderer: &Renderer,
) -> Option<iced_native::overlay::Element<'b, Message, Renderer>> {
if !self.show_modal {
return self
.underlay
.as_widget_mut()
.overlay(&mut state.children[0], layout, renderer);
}
let bounds = layout.bounds();
let position = Point::new(bounds.x, bounds.y);
Some(
ModalOverlay::new(
&mut state.children[1],
(self.content)(),
self.backdrop.clone(),
self.esc.clone(),
self.style,
)
.overlay(position),
)
}
}
impl<'a, Content, Message, Renderer> From<Modal<'a, Content, Message, Renderer>>
for Element<'a, Message, Renderer>
where
Content: 'a + Fn() -> Element<'a, Message, Renderer>,
Message: 'a + Clone,
Renderer: 'a + iced_native::Renderer,
Renderer::Theme: StyleSheet,
{
fn from(modal: Modal<'a, Content, Message, Renderer>) -> Self {
Element::new(modal)
}
}
#[derive(Debug, Default)]
pub struct State<S> {
show: bool,
state: S,
}
impl<S> State<S> {
pub const fn new(s: S) -> Self {
Self {
show: false,
state: s,
}
}
pub fn show(&mut self, b: bool) {
self.show = b;
}
pub const fn is_shown(&self) -> bool {
self.show
}
pub fn inner_mut(&mut self) -> &mut S {
&mut self.state
}
pub const fn inner(&self) -> &S {
&self.state
}
}