From 72db8a013babb9aa53ec9a6c87c80f80428134f2 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Thu, 30 May 2024 15:48:42 -0400 Subject: [PATCH] feat: add id_container --- src/widget/id_container.rs | 207 +++++++++++++++++++++++++++++++++++++ src/widget/mod.rs | 4 + 2 files changed, 211 insertions(+) create mode 100644 src/widget/id_container.rs diff --git a/src/widget/id_container.rs b/src/widget/id_container.rs new file mode 100644 index 00000000..90511ff3 --- /dev/null +++ b/src/widget/id_container.rs @@ -0,0 +1,207 @@ +use iced_core::event::{self, Event}; +use iced_core::layout; +use iced_core::mouse; +use iced_core::overlay; +use iced_core::renderer; +use iced_core::widget::{Id, Tree}; +use iced_core::{Clipboard, Element, Layout, Length, Rectangle, Shell, Widget}; +pub use iced_style::container::{Appearance, StyleSheet}; + +pub fn id_container<'a, Message: 'static, Theme, E>( + content: E, + id: Id, +) -> IdContainer<'a, Message, Theme, crate::Renderer> +where + E: Into>, + Theme: iced_style::container::StyleSheet, + ::Style: From, +{ + IdContainer::new(content, id) +} + +/// An element decorating some content. +/// +/// It is normally used for alignment purposes. +#[allow(missing_debug_implementations)] +pub struct IdContainer<'a, Message, Theme, Renderer> +where + Renderer: iced_core::Renderer, +{ + content: Element<'a, Message, Theme, Renderer>, + id: Id, +} + +impl<'a, Message, Theme, Renderer> IdContainer<'a, Message, Theme, Renderer> +where + Renderer: iced_core::Renderer, +{ + /// Creates an empty [`IdContainer`]. + pub(crate) fn new(content: T, id: Id) -> Self + where + T: Into>, + { + IdContainer { + content: content.into(), + id, + } + } +} + +impl<'a, Message, Theme, Renderer> Widget + for IdContainer<'a, Message, Theme, Renderer> +where + Renderer: iced_core::Renderer, +{ + fn children(&self) -> Vec { + vec![Tree::new(&self.content)] + } + + fn diff(&mut self, tree: &mut Tree) { + tree.children[0].diff(&mut self.content); + } + + fn size(&self) -> iced_core::Size { + self.content.as_widget().size() + } + + fn layout( + &self, + tree: &mut Tree, + renderer: &Renderer, + limits: &layout::Limits, + ) -> layout::Node { + let node = self + .content + .as_widget() + .layout(&mut tree.children[0], renderer, limits); + let size = node.size(); + layout::Node::with_children(size, vec![node]) + } + + fn operate( + &self, + tree: &mut Tree, + layout: Layout<'_>, + renderer: &Renderer, + operation: &mut dyn iced_core::widget::Operation< + iced_core::widget::OperationOutputWrapper, + >, + ) { + self.content.as_widget().operate( + &mut tree.children[0], + layout.children().next().unwrap(), + renderer, + operation, + ); + } + + fn on_event( + &mut self, + tree: &mut Tree, + event: Event, + layout: Layout<'_>, + cursor_position: mouse::Cursor, + renderer: &Renderer, + clipboard: &mut dyn Clipboard, + shell: &mut Shell<'_, Message>, + viewport: &Rectangle, + ) -> event::Status { + self.content.as_widget_mut().on_event( + &mut tree.children[0], + event.clone(), + layout.children().next().unwrap(), + cursor_position, + renderer, + clipboard, + shell, + viewport, + ) + } + + fn mouse_interaction( + &self, + tree: &Tree, + layout: Layout<'_>, + cursor_position: mouse::Cursor, + viewport: &Rectangle, + renderer: &Renderer, + ) -> mouse::Interaction { + let content_layout = layout.children().next().unwrap(); + self.content.as_widget().mouse_interaction( + &tree.children[0], + content_layout, + cursor_position, + viewport, + renderer, + ) + } + + fn draw( + &self, + tree: &Tree, + renderer: &mut Renderer, + theme: &Theme, + renderer_style: &renderer::Style, + layout: Layout<'_>, + cursor_position: mouse::Cursor, + viewport: &Rectangle, + ) { + let content_layout = layout.children().next().unwrap(); + self.content.as_widget().draw( + &tree.children[0], + renderer, + theme, + renderer_style, + content_layout, + cursor_position, + viewport, + ); + } + + fn overlay<'b>( + &'b mut self, + tree: &'b mut Tree, + layout: Layout<'_>, + renderer: &Renderer, + ) -> Option> { + self.content.as_widget_mut().overlay( + &mut tree.children[0], + layout.children().next().unwrap(), + renderer, + ) + } + + fn drag_destinations( + &self, + state: &Tree, + layout: Layout<'_>, + dnd_rectangles: &mut iced_style::core::clipboard::DndDestinationRectangles, + ) { + let content_layout = layout.children().next().unwrap(); + self.content.as_widget().drag_destinations( + &state.children[0], + content_layout, + dnd_rectangles, + ); + } + + fn id(&self) -> Option { + Some(self.id.clone()) + } + + fn set_id(&mut self, id: crate::widget::Id) { + self.id = id; + } +} + +impl<'a, Message, Theme, Renderer> From> + for Element<'a, Message, Theme, Renderer> +where + Message: 'a, + Renderer: 'a + iced_core::Renderer, + Theme: 'a, +{ + fn from(c: IdContainer<'a, Message, Theme, Renderer>) -> Element<'a, Message, Theme, Renderer> { + Element::new(c) + } +} diff --git a/src/widget/mod.rs b/src/widget/mod.rs index 9b922470..a1b6cb51 100644 --- a/src/widget/mod.rs +++ b/src/widget/mod.rs @@ -234,6 +234,10 @@ pub mod icon; #[doc(inline)] pub use icon::{icon, Icon}; +pub mod id_container; +#[doc(inline)] +pub use id_container::{id_container, IdContainer}; + #[cfg(feature = "animated-image")] pub mod frames;