use crate::core::layout::{self, Layout}; use crate::core::mouse; use crate::core::overlay; use crate::core::renderer; use crate::core::widget; use crate::core::widget::Tree; use crate::core::{ self, Clipboard, Element, Event, Length, Rectangle, Shell, Size, Vector, Widget, }; use crate::space; /// A widget that is aware of its dimensions. /// /// A [`Responsive`] widget will always try to fill all the available space of /// its parent. pub struct Responsive< 'a, Message, Theme = crate::Theme, Renderer = crate::Renderer, > { view: Box Element<'a, Message, Theme, Renderer> + 'a>, width: Length, height: Length, content: Element<'a, Message, Theme, Renderer>, } impl<'a, Message, Theme, Renderer> Responsive<'a, Message, Theme, Renderer> where Renderer: core::Renderer, { /// Creates a new [`Responsive`] widget with a closure that produces its /// contents. /// /// The `view` closure will receive the maximum available space for /// the [`Responsive`] during layout. You can use this [`Size`] to /// conditionally build the contents. pub fn new( view: impl Fn(Size) -> Element<'a, Message, Theme, Renderer> + 'a, ) -> Self { Self { view: Box::new(view), width: Length::Fill, height: Length::Fill, content: Element::new(space()), } } /// Sets the width of the [`Responsive`]. pub fn width(mut self, width: impl Into) -> Self { self.width = width.into(); self } /// Sets the height of the [`Responsive`]. pub fn height(mut self, height: impl Into) -> Self { self.height = height.into(); self } } impl Widget for Responsive<'_, Message, Theme, Renderer> where Renderer: core::Renderer, { fn diff(&self, _tree: &mut Tree) { // Diff is deferred to layout } fn size(&self) -> Size { Size { width: self.width, height: self.height, } } fn layout( &mut self, tree: &mut Tree, renderer: &Renderer, limits: &layout::Limits, ) -> layout::Node { let limits = limits.width(self.width).height(self.height); let size = limits.max(); self.content = (self.view)(size); tree.diff_children(std::slice::from_ref(&self.content)); let node = self.content.as_widget_mut().layout( &mut tree.children[0], renderer, &limits.loose(), ); let size = limits.resolve(self.width, self.height, node.size()); layout::Node::with_children(size, vec![node]) } fn update( &mut self, tree: &mut Tree, event: &Event, layout: Layout<'_>, cursor: mouse::Cursor, renderer: &Renderer, clipboard: &mut dyn Clipboard, shell: &mut Shell<'_, Message>, viewport: &Rectangle, ) { self.content.as_widget_mut().update( &mut tree.children[0], event, layout.children().next().unwrap(), cursor, renderer, clipboard, shell, viewport, ); } fn draw( &self, tree: &Tree, renderer: &mut Renderer, theme: &Theme, style: &renderer::Style, layout: Layout<'_>, cursor: mouse::Cursor, viewport: &Rectangle, ) { self.content.as_widget().draw( &tree.children[0], renderer, theme, style, layout.children().next().unwrap(), cursor, viewport, ); } fn mouse_interaction( &self, tree: &Tree, layout: Layout<'_>, cursor: mouse::Cursor, viewport: &Rectangle, renderer: &Renderer, ) -> mouse::Interaction { self.content.as_widget().mouse_interaction( &tree.children[0], layout.children().next().unwrap(), cursor, viewport, renderer, ) } fn operate( &mut self, tree: &mut Tree, layout: Layout<'_>, renderer: &Renderer, operation: &mut dyn widget::Operation, ) { self.content.as_widget_mut().operate( &mut tree.children[0], layout.children().next().unwrap(), renderer, operation, ); } fn overlay<'a>( &'a mut self, tree: &'a mut Tree, layout: Layout<'a>, renderer: &Renderer, viewport: &Rectangle, translation: Vector, ) -> Option> { self.content.as_widget_mut().overlay( &mut tree.children[0], layout.children().next().unwrap(), renderer, viewport, translation, ) } } impl<'a, Message, Theme, Renderer> From> for Element<'a, Message, Theme, Renderer> where Message: 'a, Theme: 'a, Renderer: core::Renderer + 'a, { fn from(responsive: Responsive<'a, Message, Theme, Renderer>) -> Self { Self::new(responsive) } }