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::{self, Tree}; use crate::core::{ self, Clipboard, Element, Event, Length, Rectangle, Shell, Size, Vector, Widget, }; use crate::horizontal_space; /// A widget that is aware of its dimensions. /// /// A [`Responsive`] widget will always try to fill all the available space of /// its parent. #[cfg(feature = "lazy")] #[allow(missing_debug_implementations)] pub struct Responsive< 'a, Message, Theme = crate::Theme, Renderer = crate::Renderer, > { view: Box Element<'a, Message, Theme, Renderer> + 'a>, 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 be provided with the current [`Size`] of /// the [`Responsive`] widget and, therefore, can be used to build the /// contents of the widget in a responsive way. pub fn new( view: impl Fn(Size) -> Element<'a, Message, Theme, Renderer> + 'a, ) -> Self { Self { view: Box::new(view), content: Element::new(horizontal_space().width(0)), } } } struct State { tree: Tree, } impl Widget for Responsive<'_, Message, Theme, Renderer> where Renderer: core::Renderer, { fn tag(&self) -> tree::Tag { tree::Tag::of::() } fn state(&self) -> tree::State { tree::State::new(State { tree: Tree::empty(), }) } fn size(&self) -> Size { Size { width: Length::Fill, height: Length::Fill, } } fn layout( &mut self, tree: &mut Tree, renderer: &Renderer, limits: &layout::Limits, ) -> layout::Node { let state = tree.state.downcast_mut::(); let size = limits.max(); self.content = (self.view)(size); state.tree.diff(&mut self.content); self.content.as_widget_mut().layout( &mut state.tree, renderer, &limits.loose(), ) } 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, ) { let state = tree.state.downcast_mut::(); self.content.as_widget_mut().update( &mut state.tree, event, layout, 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, ) { let state = tree.state.downcast_ref::(); self.content.as_widget().draw( &state.tree, renderer, theme, style, layout, cursor, viewport, ); } fn mouse_interaction( &self, tree: &Tree, layout: Layout<'_>, cursor: mouse::Cursor, viewport: &Rectangle, renderer: &Renderer, ) -> mouse::Interaction { let state = tree.state.downcast_ref::(); self.content.as_widget().mouse_interaction( &state.tree, layout, cursor, viewport, renderer, ) } fn operate( &mut self, tree: &mut Tree, layout: Layout<'_>, renderer: &Renderer, operation: &mut dyn widget::Operation, ) { let state = tree.state.downcast_mut::(); self.content.as_widget_mut().operate( &mut state.tree, layout, renderer, operation, ); } fn overlay<'a>( &'a mut self, tree: &'a mut Tree, layout: Layout<'a>, renderer: &Renderer, viewport: &Rectangle, translation: Vector, ) -> Option> { let state = tree.state.downcast_mut::(); self.content.as_widget_mut().overlay( &mut state.tree, layout, 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) } }