use crate::core::event; use crate::core::layout; use crate::core::mouse; use crate::core::overlay; use crate::core::renderer; use crate::core::widget; use crate::core::{ Clipboard, Event, Layout, Overlay, Point, Rectangle, Shell, Size, }; use std::cell::RefCell; /// An [`Overlay`] container that displays nested overlays #[allow(missing_debug_implementations)] pub struct Nested<'a, Message, Renderer> { overlay: Inner<'a, Message, Renderer>, } impl<'a, Message, Renderer> Nested<'a, Message, Renderer> { /// Creates a nested overlay from the provided [`overlay::Element`] pub fn new(element: overlay::Element<'a, Message, Renderer>) -> Self { Self { overlay: Inner(RefCell::new(element)), } } } struct Inner<'a, Message, Renderer>( RefCell>, ); impl<'a, Message, Renderer> Inner<'a, Message, Renderer> { fn with_element_mut( &self, mut f: impl FnMut(&mut overlay::Element<'_, Message, Renderer>) -> T, ) -> T { (f)(&mut self.0.borrow_mut()) } } impl<'a, Message, Renderer> Overlay for Nested<'a, Message, Renderer> where Renderer: renderer::Renderer, { fn layout( &self, renderer: &Renderer, bounds: Size, position: Point, ) -> layout::Node { fn recurse( element: &mut overlay::Element<'_, Message, Renderer>, renderer: &Renderer, bounds: Size, position: Point, ) -> layout::Node where Renderer: renderer::Renderer, { let translation = position - Point::ORIGIN; let node = element.layout(renderer, bounds, translation); if let Some(mut nested) = element.overlay(Layout::new(&node), renderer) { layout::Node::with_children( node.size(), vec![ node, recurse(&mut nested, renderer, bounds, position), ], ) } else { layout::Node::with_children(node.size(), vec![node]) } } self.overlay.with_element_mut(|element| { recurse(element, renderer, bounds, position) }) } fn draw( &self, renderer: &mut Renderer, theme: &::Theme, style: &renderer::Style, layout: Layout<'_>, cursor: mouse::Cursor, ) { fn recurse( element: &mut overlay::Element<'_, Message, Renderer>, layout: Layout<'_>, renderer: &mut Renderer, theme: &::Theme, style: &renderer::Style, cursor: mouse::Cursor, ) where Renderer: renderer::Renderer, { let mut layouts = layout.children(); if let Some(layout) = layouts.next() { let nested_layout = layouts.next(); let is_over = cursor .position() .zip(nested_layout) .and_then(|(cursor_position, nested_layout)| { element.overlay(layout, renderer).map(|nested| { nested.is_over( nested_layout, renderer, cursor_position, ) }) }) .unwrap_or_default(); renderer.with_layer(layout.bounds(), |renderer| { element.draw( renderer, theme, style, layout, if is_over { mouse::Cursor::Unavailable } else { cursor }, ); }); if let Some((mut nested, nested_layout)) = element.overlay(layout, renderer).zip(nested_layout) { recurse( &mut nested, nested_layout, renderer, theme, style, cursor, ); } } } self.overlay.with_element_mut(|element| { recurse(element, layout, renderer, theme, style, cursor); }) } fn operate( &mut self, layout: Layout<'_>, renderer: &Renderer, operation: &mut dyn widget::Operation, ) { fn recurse( element: &mut overlay::Element<'_, Message, Renderer>, layout: Layout<'_>, renderer: &Renderer, operation: &mut dyn widget::Operation, ) where Renderer: renderer::Renderer, { let mut layouts = layout.children(); if let Some(layout) = layouts.next() { element.operate(layout, renderer, operation); if let Some((mut nested, nested_layout)) = element.overlay(layout, renderer).zip(layouts.next()) { recurse(&mut nested, nested_layout, renderer, operation); } } } recurse(self.overlay.0.get_mut(), layout, renderer, operation) } fn on_event( &mut self, event: Event, layout: Layout<'_>, cursor: mouse::Cursor, renderer: &Renderer, clipboard: &mut dyn Clipboard, shell: &mut Shell<'_, Message>, ) -> event::Status { fn recurse( element: &mut overlay::Element<'_, Message, Renderer>, layout: Layout<'_>, event: Event, cursor: mouse::Cursor, renderer: &Renderer, clipboard: &mut dyn Clipboard, shell: &mut Shell<'_, Message>, ) -> event::Status where Renderer: renderer::Renderer, { let mut layouts = layout.children(); if let Some(layout) = layouts.next() { let status = if let Some((mut nested, nested_layout)) = element.overlay(layout, renderer).zip(layouts.next()) { recurse( &mut nested, nested_layout, event.clone(), cursor, renderer, clipboard, shell, ) } else { event::Status::Ignored }; if matches!(status, event::Status::Ignored) { element.on_event( event, layout, cursor, renderer, clipboard, shell, ) } else { status } } else { event::Status::Ignored } } recurse( self.overlay.0.get_mut(), layout, event, cursor, renderer, clipboard, shell, ) } fn mouse_interaction( &self, layout: Layout<'_>, cursor: mouse::Cursor, viewport: &Rectangle, renderer: &Renderer, ) -> mouse::Interaction { fn recurse( element: &mut overlay::Element<'_, Message, Renderer>, layout: Layout<'_>, cursor: mouse::Cursor, viewport: &Rectangle, renderer: &Renderer, ) -> Option where Renderer: renderer::Renderer, { let mut layouts = layout.children(); let layout = layouts.next()?; let cursor_position = cursor.position()?; if !element.is_over(layout, renderer, cursor_position) { return None; } Some( element .overlay(layout, renderer) .zip(layouts.next()) .and_then(|(mut overlay, layout)| { recurse( &mut overlay, layout, cursor, viewport, renderer, ) }) .unwrap_or_else(|| { element.mouse_interaction( layout, cursor, viewport, renderer, ) }), ) } self.overlay .with_element_mut(|element| { recurse(element, layout, cursor, viewport, renderer) }) .unwrap_or_default() } fn is_over( &self, layout: Layout<'_>, renderer: &Renderer, cursor_position: Point, ) -> bool { fn recurse( element: &mut overlay::Element<'_, Message, Renderer>, layout: Layout<'_>, renderer: &Renderer, cursor_position: Point, ) -> bool where Renderer: renderer::Renderer, { let mut layouts = layout.children(); if let Some(layout) = layouts.next() { if element.is_over(layout, renderer, cursor_position) { return true; } if let Some((mut nested, nested_layout)) = element.overlay(layout, renderer).zip(layouts.next()) { recurse( &mut nested, nested_layout, renderer, cursor_position, ) } else { false } } else { false } } self.overlay.with_element_mut(|element| { recurse(element, layout, renderer, cursor_position) }) } fn overlay<'b>( &'b mut self, _layout: Layout<'_>, _renderer: &Renderer, ) -> Option> { None } }