use iced::{ advanced::{ image::Data, layout::{Limits, Node}, overlay, renderer::Style, widget::{Operation, Tree}, Clipboard, Layout, Shell, Widget, }, event::Status, mouse::{Cursor, Interaction}, widget::{image, image::FilterMethod}, Alignment, ContentFit, Element, Event, Length, Point, Rectangle, Size, Vector, }; pub fn image_background<'a, M: 'a, R>( handle: impl Into, el: Element<'a, M, R>, ) -> ImageBackground<'a, M, R> { let image_handle = handle.into(); ImageBackground { image_handle: image_handle.clone(), el, width: Length::FillPortion(1), height: Length::Fixed(128.0), } } pub struct ImageBackground<'a, M, R> { image_handle: image::Handle, el: Element<'a, M, R>, width: Length, height: Length, } impl<'a, M, R> ImageBackground<'a, M, R> { pub fn height(mut self, height: Length) -> Self { self.height = height; self } pub fn width(mut self, width: Length) -> Self { self.width = width; self } } impl< 'a, M: Clone, R: iced::advanced::Renderer + iced::advanced::image::Renderer, > Widget for ImageBackground<'a, M, R> { fn size(&self) -> Size { Size::new(self.width, self.height) } fn layout(&self, _state: &mut Tree, _renderer: &R, limits: &Limits) -> Node { let limits = limits.width(self.width).height(self.height); let size = limits.resolve(self.width, self.height, Size::ZERO); Node::new(size) } fn draw( &self, _state: &Tree, renderer: &mut R, _theme: &::Theme, _style: &Style, layout: Layout<'_>, _cursor: Cursor, _viewport: &Rectangle, ) { let bounds = layout.bounds(); // The raw w/h of the underlying image, renderer.dimensions is _really_ // slow so enforce the use of preparsed images from `theme`. #[allow(clippy::cast_precision_loss)] let image_size = match self.image_handle.data() { Data::Rgba { width, height, .. } => Size::new(*width as f32, *height as f32), Data::Path(_) | Data::Bytes(_) => panic!("only parsed images are supported"), }; let adjusted_fit = ContentFit::Cover.fit(image_size, bounds.size()); renderer.with_layer(bounds, |renderer| { let offset = Vector::new( (bounds.width - adjusted_fit.width).min(0.0) / 1.5, (bounds.height - adjusted_fit.height).min(0.0) / 1.5, ); let drawing_bounds = Rectangle { width: adjusted_fit.width, height: adjusted_fit.height, ..bounds }; renderer.draw( self.image_handle.clone(), FilterMethod::Linear, drawing_bounds + offset, ); }); } fn children(&self) -> Vec { vec![Tree::new(&self.el)] } fn diff(&self, tree: &mut Tree) { tree.diff_children(&[&self.el]); } fn overlay<'b>( &'b mut self, state: &'b mut Tree, layout: Layout<'_>, _renderer: &R, ) -> Option> { Some(overlay::Element::new( layout.position(), Box::new(Overlay { el: &mut self.el, tree: &mut state.children[0], size: layout.bounds().size(), }), )) } } struct Overlay<'a, 'b, M, R> { el: &'b mut Element<'a, M, R>, tree: &'b mut Tree, size: Size, } impl<'a, 'b, M: Clone, R: iced::advanced::Renderer> overlay::Overlay for Overlay<'a, 'b, M, R> { fn layout( &mut self, renderer: &R, _bounds: Size, position: Point, _translation: Vector, ) -> Node { let limits = Limits::new(Size::ZERO, self.size) .width(Length::Fill) .height(Length::Fill); let child = self .el .as_widget() .layout(self.tree, renderer, &limits) .align(Alignment::Start, Alignment::Start, limits.max()); Node::with_children(self.size, vec![child]).move_to(position) } fn draw( &self, renderer: &mut R, theme: &::Theme, style: &Style, layout: Layout<'_>, cursor: Cursor, ) { self.el.as_widget().draw( self.tree, renderer, theme, style, layout.children().next().unwrap(), cursor, &layout.bounds(), ); } fn on_event( &mut self, event: Event, layout: Layout<'_>, cursor: Cursor, renderer: &R, clipboard: &mut dyn Clipboard, shell: &mut Shell<'_, M>, ) -> Status { self.el.as_widget_mut().on_event( self.tree, event, layout.children().next().unwrap(), cursor, renderer, clipboard, shell, &layout.bounds(), ) } fn mouse_interaction( &self, layout: Layout<'_>, cursor: Cursor, viewport: &Rectangle, renderer: &R, ) -> Interaction { self.el.as_widget().mouse_interaction( self.tree, layout.children().next().unwrap(), cursor, viewport, renderer, ) } fn operate(&mut self, layout: Layout<'_>, renderer: &R, operation: &mut dyn Operation) { self.el.as_widget().operate( self.tree, layout.children().next().unwrap(), renderer, operation, ); } } impl<'a, M, R> From> for Element<'a, M, R> where M: 'a + Clone, R: iced::advanced::Renderer + iced::advanced::image::Renderer + 'a, { fn from(modal: ImageBackground<'a, M, R>) -> Self { Element::new(modal) } }