🏡 index : ~doyle/shalom.git

use iced::{
    advanced::{
        layout::{Limits, Node},
        overlay,
        overlay::Element,
        renderer::{Quad, Style},
        widget::{
            tree::{State, Tag},
            Operation, Tree,
        },
        Clipboard, Layout, Renderer, Shell, Widget,
    },
    event::Status,
    mouse::{Cursor, Interaction},
    Background, Color, Event, Length, Point, Rectangle, Size,
};

pub fn forced_rounded<'a, M: 'a, R>(
    element: impl Into<iced::Element<'a, M, R>>,
) -> ForcedRounded<'a, M, R> {
    ForcedRounded {
        element: element.into(),
    }
}

pub struct ForcedRounded<'a, M, R> {
    element: iced::Element<'a, M, R>,
}

impl<'a, M, R: Renderer> Widget<M, R> for ForcedRounded<'a, M, R> {
    fn width(&self) -> Length {
        self.element.as_widget().width()
    }

    fn height(&self) -> Length {
        self.element.as_widget().height()
    }

    fn layout(&self, renderer: &R, limits: &Limits) -> Node {
        self.element.as_widget().layout(renderer, limits)
    }

    fn draw(
        &self,
        state: &Tree,
        renderer: &mut R,
        theme: &R::Theme,
        style: &Style,
        layout: Layout<'_>,
        cursor: Cursor,
        viewport: &Rectangle,
    ) {
        self.element
            .as_widget()
            .draw(state, renderer, theme, style, layout, cursor, viewport);
    }

    fn tag(&self) -> Tag {
        self.element.as_widget().tag()
    }

    fn children(&self) -> Vec<Tree> {
        self.element.as_widget().children()
    }

    fn diff(&self, tree: &mut Tree) {
        self.element.as_widget().diff(tree);
    }

    fn mouse_interaction(
        &self,
        state: &Tree,
        layout: Layout<'_>,
        cursor: Cursor,
        viewport: &Rectangle,
        renderer: &R,
    ) -> Interaction {
        self.element
            .as_widget()
            .mouse_interaction(state, layout, cursor, viewport, renderer)
    }

    fn on_event(
        &mut self,
        state: &mut Tree,
        event: Event,
        layout: Layout<'_>,
        cursor: Cursor,
        renderer: &R,
        clipboard: &mut dyn Clipboard,
        shell: &mut Shell<'_, M>,
        viewport: &Rectangle,
    ) -> Status {
        self.element.as_widget_mut().on_event(
            state, event, layout, cursor, renderer, clipboard, shell, viewport,
        )
    }

    fn operate(
        &self,
        state: &mut Tree,
        layout: Layout<'_>,
        renderer: &R,
        operation: &mut dyn Operation<M>,
    ) {
        self.element
            .as_widget()
            .operate(state, layout, renderer, operation);
    }

    fn state(&self) -> State {
        self.element.as_widget().state()
    }

    fn overlay<'b>(
        &'b mut self,
        _state: &'b mut Tree,
        layout: Layout<'_>,
        _renderer: &R,
    ) -> Option<Element<'b, M, R>> {
        Some(overlay::Element::new(
            layout.position(),
            Box::new(Overlay {
                size: layout.bounds().size(),
                position: Some(layout.bounds().position()),
            }),
        ))
    }
}

impl<'a, M, R> From<ForcedRounded<'a, M, R>> for iced::Element<'a, M, R>
where
    M: 'a + Clone,
    R: 'a + Renderer,
{
    fn from(e: ForcedRounded<'a, M, R>) -> Self {
        iced::Element::new(e)
    }
}

pub struct Overlay {
    pub size: Size,
    pub position: Option<Point>,
}

impl<M, R: Renderer> overlay::Overlay<M, R> for Overlay {
    fn layout(&self, _renderer: &R, _bounds: Size, position: Point) -> Node {
        let mut node = Node::new(self.size);
        node.move_to(self.position.unwrap_or(position));

        node
    }

    fn draw(
        &self,
        renderer: &mut R,
        _theme: &R::Theme,
        _style: &Style,
        layout: Layout<'_>,
        _cursor: Cursor,
    ) {
        renderer.with_layer(layout.bounds(), |renderer| {
            renderer.fill_quad(
                Quad {
                    bounds: Rectangle {
                        height: self.size.height + 12.,
                        width: self.size.width + 12.,
                        x: layout.bounds().x - 6.,
                        y: layout.bounds().y - 6.,
                    },
                    border_radius: [20., 20., 20., 20.].into(),
                    border_width: 10.,
                    border_color: Color::WHITE,
                },
                Background::Color(Color::TRANSPARENT),
            );
        });
    }

    fn is_over(&self, _layout: Layout<'_>, _renderer: &R, _cursor_position: Point) -> bool {
        false
    }
}