From d76911c294caaa480f884f9c290d563d6d3a21aa Mon Sep 17 00:00:00 2001 From: wiiznokes <78230769+wiiznokes@users.noreply.github.com> Date: Thu, 27 Jun 2024 02:05:14 +0200 Subject: [PATCH] add widget impl --- src/widget/toaster/mod.rs | 40 +++---- src/widget/toaster/widget.rs | 208 +++++++++++++++++++++++++++++++---- 2 files changed, 204 insertions(+), 44 deletions(-) diff --git a/src/widget/toaster/mod.rs b/src/widget/toaster/mod.rs index 9d7cc7d1..134fcbb8 100644 --- a/src/widget/toaster/mod.rs +++ b/src/widget/toaster/mod.rs @@ -3,47 +3,39 @@ use std::time::Duration; -use iced::{Command, Length}; -use iced_core::{Element}; use crate::widget::container; use crate::widget::Column; +use iced::{Command, Length}; +use iced_core::Element; use widget::Toaster; use crate::ext::CollectionWidget; use super::{button, row, text}; - mod widget; -pub fn toaster<'a, Message: Clone + 'a, Theme, Renderer>( +pub fn toaster<'a, Message>( toasts: &'a Toasts, - content: impl Into>, -) -> Element<'a, Message, Theme, Renderer> + content: impl Into>, +) -> Element<'a, Message, crate::Theme, iced::Renderer> where - Renderer: iced_core::Renderer, + Message: Clone + 'a, { + let make_toast = |toast: &'a Toast| { + let row = row().push(text(&toast.message)).push_maybe( + toast + .action + .as_ref() + .map(|t| button(text(t.0.clone())).on_press(t.1.clone())), + ); - - let make_toast = |toast: &Toast| { - - let row = row() - .push(text(toast.message)) - .push_maybe(toast.action.map(|t| button(text(t.0)).on_press(t.1))); - - container(row) - .into() - + container(row).into() }; + let col = Column::with_children(toasts.toasts.iter().map(make_toast)); - let col = Column::with_children(toasts.toasts.iter().map(|t| { - make_toast(t) - })); - - - - Toaster::new(col.into(), content.into()).into() + Toaster::new(col.into(), content.into(), toasts.toasts.is_empty()).into() } pub enum ToastDuration { diff --git a/src/widget/toaster/widget.rs b/src/widget/toaster/widget.rs index ec52b221..da3e898d 100644 --- a/src/widget/toaster/widget.rs +++ b/src/widget/toaster/widget.rs @@ -1,41 +1,41 @@ // Copyright 2024 wiiznokes // SPDX-License-Identifier: MIT -use iced::Size; +use iced::{Limits, Size}; +use iced_core::layout::Node; use iced_runtime::core::widget::Id; use iced_runtime::{keyboard, Command}; use iced_core::event::{self, Event}; use iced_core::renderer::{self, Quad, Renderer}; -use iced_core::touch; use iced_core::widget::tree::{self, Tree}; use iced_core::widget::Operation; use iced_core::Element; use iced_core::{layout, svg}; use iced_core::{mouse, Border}; use iced_core::{overlay, Shadow}; +use iced_core::{touch, Overlay}; use iced_core::{ Background, Clipboard, Color, Layout, Length, Padding, Point, Rectangle, Shell, Vector, Widget, }; use iced_renderer::core::widget::{operation, OperationOutputWrapper}; - - -use super::Toasts; - pub struct Toaster<'a, Message, Theme, Renderer> { toasts: Element<'a, Message, Theme, Renderer>, content: Element<'a, Message, Theme, Renderer>, + is_empty: bool, } impl<'a, Message, Theme, Renderer> Toaster<'a, Message, Theme, Renderer> { pub fn new( toasts: Element<'a, Message, Theme, Renderer>, content: Element<'a, Message, Theme, Renderer>, + is_empty: bool, ) -> Self { Self { toasts, content, + is_empty, } } } @@ -46,7 +46,7 @@ where Renderer: iced_core::Renderer, { fn size(&self) -> Size { - todo!() + self.content.as_widget().size() } fn layout( @@ -55,18 +55,9 @@ where renderer: &Renderer, limits: &layout::Limits, ) -> layout::Node { - todo!() - } - - fn mouse_interaction( - &self, - _state: &Tree, - _layout: Layout<'_>, - _cursor: mouse::Cursor, - _viewport: &Rectangle, - _renderer: &Renderer, - ) -> mouse::Interaction { - todo!() + self.content + .as_widget() + .layout(&mut tree.children[0], renderer, limits) } fn draw( @@ -79,6 +70,183 @@ where cursor: mouse::Cursor, viewport: &Rectangle, ) { + self.content.as_widget().draw( + &tree.children[0], + renderer, + theme, + style, + layout, + cursor, + viewport, + ); + } + + fn children(&self) -> Vec { + vec![Tree::new(&self.content), Tree::new(&self.toasts)] + } + + fn diff(&mut self, tree: &mut Tree) { + tree.diff_children(&mut [&mut self.content, &mut self.toasts]); + } + + fn operate<'b>( + &'b self, + state: &'b mut Tree, + layout: Layout<'_>, + renderer: &Renderer, + operation: &mut dyn Operation>, + ) { + self.content + .as_widget() + .operate(&mut state.children[0], layout, renderer, operation); + } + + fn on_event( + &mut self, + state: &mut Tree, + event: Event, + layout: Layout<'_>, + cursor: mouse::Cursor, + renderer: &Renderer, + clipboard: &mut dyn Clipboard, + shell: &mut Shell<'_, Message>, + viewport: &Rectangle, + ) -> event::Status { + self.content.as_widget_mut().on_event( + &mut state.children[0], + event, + layout, + cursor, + renderer, + clipboard, + shell, + viewport, + ) + } + + fn mouse_interaction( + &self, + state: &Tree, + layout: Layout<'_>, + cursor: mouse::Cursor, + viewport: &Rectangle, + renderer: &Renderer, + ) -> mouse::Interaction { + self.content.as_widget().mouse_interaction( + &state.children[0], + layout, + cursor, + viewport, + renderer, + ) + } + + fn overlay<'b>( + &'b mut self, + state: &'b mut Tree, + layout: Layout<'_>, + renderer: &Renderer, + ) -> Option> { + if self.is_empty { + None + } else { + let bounds = layout.bounds(); + + Some(overlay::Element::new( + bounds.position(), + Box::new(ToasterOverlay::new( + &mut state.children[1], + &mut self.toasts, + )), + )) + } + } +} + +struct ToasterOverlay<'a, 'b, Message, Theme = iced::Theme, Renderer = iced::Renderer> { + state: &'b mut Tree, + element: &'b mut Element<'a, Message, Theme, Renderer>, +} + +impl<'a, 'b, Message, Theme, Renderer> ToasterOverlay<'a, 'b, Message, Theme, Renderer> +where + Renderer: renderer::Renderer, +{ + fn new(state: &'b mut Tree, element: &'b mut Element<'a, Message, Theme, Renderer>) -> Self { + Self { state, element } + } +} + +impl<'a, 'b, Message, Theme, Renderer> Overlay + for ToasterOverlay<'a, 'b, Message, Theme, Renderer> +where + Renderer: renderer::Renderer, +{ + fn layout( + &mut self, + renderer: &Renderer, + bounds: Size, + position: Point, + _translation: Vector, + ) -> Node { + todo!() + } + + fn draw( + &self, + renderer: &mut Renderer, + theme: &Theme, + style: &renderer::Style, + layout: Layout<'_>, + cursor: mouse::Cursor, + ) { + let bounds = layout.bounds(); + self.element + .as_widget() + .draw(self.state, renderer, theme, style, layout, cursor, &bounds); + } + + fn on_event( + &mut self, + event: Event, + layout: Layout<'_>, + cursor: mouse::Cursor, + renderer: &Renderer, + clipboard: &mut dyn Clipboard, + shell: &mut Shell, + ) -> event::Status { + self.element.as_widget_mut().on_event( + self.state, + event, + layout, + cursor, + renderer, + clipboard, + shell, + &layout.bounds(), + ) + } + + fn mouse_interaction( + &self, + layout: Layout<'_>, + cursor: mouse::Cursor, + viewport: &Rectangle, + renderer: &Renderer, + ) -> mouse::Interaction { + self.element + .as_widget() + .mouse_interaction(self.state, layout, cursor, viewport, renderer) + } + + fn overlay<'c>( + &'c mut self, + layout: Layout<'_>, + renderer: &Renderer, + ) -> Option> { + self.element + .as_widget_mut() + .overlay(self.state, layout, renderer) } } @@ -87,7 +255,7 @@ impl<'a, Message, Theme, Renderer> From> where Renderer: renderer::Renderer + 'a, Theme: 'a, - Message: 'a + Message: 'a, { fn from( toggler: Toaster<'a, Message, Theme, Renderer>,