diff options
author | 2023-02-18 14:31:38 -0800 | |
---|---|---|
committer | 2023-06-14 09:25:30 +0200 | |
commit | 55dc3b5619392f4a20389255708c61082b3d4c1a (patch) | |
tree | c8b523def929a2e44be3535f5ae93ed494168ab7 /runtime/src | |
parent | 329fbc7b2157b84183849b2e0f600eb039435aed (diff) | |
download | iced-55dc3b5619392f4a20389255708c61082b3d4c1a.tar.gz iced-55dc3b5619392f4a20389255708c61082b3d4c1a.tar.bz2 iced-55dc3b5619392f4a20389255708c61082b3d4c1a.zip |
Introduce internal `overlay::Nested` for `UserInterface`
Diffstat (limited to 'runtime/src')
-rw-r--r-- | runtime/src/user_interface.rs | 71 | ||||
-rw-r--r-- | runtime/src/user_interface/overlay.rs | 288 |
2 files changed, 332 insertions, 27 deletions
diff --git a/runtime/src/user_interface.rs b/runtime/src/user_interface.rs index 68ff6158..8ae0363a 100644 --- a/runtime/src/user_interface.rs +++ b/runtime/src/user_interface.rs @@ -1,12 +1,14 @@ //! Implement your own event loop to drive a user interface. +mod overlay; + use crate::core::event::{self, Event}; use crate::core::layout; use crate::core::mouse; use crate::core::renderer; use crate::core::widget; use crate::core::window; -use crate::core::{Clipboard, Rectangle, Size, Vector}; -use crate::core::{Element, Layout, Shell}; +use crate::core::{Clipboard, Point, Rectangle, Size}; +use crate::core::{Element, Layout, Overlay, Shell}; /// A set of interactive graphical elements with a specific [`Layout`]. /// @@ -185,18 +187,18 @@ where let mut outdated = false; let mut redraw_request = None; - let mut manual_overlay = - ManuallyDrop::new(self.root.as_widget_mut().overlay( - &mut self.state, - Layout::new(&self.base), - renderer, - )); + let mut manual_overlay = ManuallyDrop::new( + self.root + .as_widget_mut() + .overlay(&mut self.state, Layout::new(&self.base), renderer) + .map(overlay::Nested::new), + ); let (base_cursor, overlay_statuses) = if manual_overlay.is_some() { let bounds = self.bounds; let mut overlay = manual_overlay.as_mut().unwrap(); - let mut layout = overlay.layout(renderer, bounds, Vector::ZERO); + let mut layout = overlay.layout(renderer, bounds, Point::ORIGIN); let mut event_statuses = Vec::new(); for event in events.iter().cloned() { @@ -231,12 +233,16 @@ where &layout::Limits::new(Size::ZERO, self.bounds), ); - manual_overlay = - ManuallyDrop::new(self.root.as_widget_mut().overlay( - &mut self.state, - Layout::new(&self.base), - renderer, - )); + manual_overlay = ManuallyDrop::new( + self.root + .as_widget_mut() + .overlay( + &mut self.state, + Layout::new(&self.base), + renderer, + ) + .map(overlay::Nested::new), + ); if manual_overlay.is_none() { break; @@ -245,7 +251,8 @@ where overlay = manual_overlay.as_mut().unwrap(); shell.revalidate_layout(|| { - layout = overlay.layout(renderer, bounds, Vector::ZERO); + layout = + overlay.layout(renderer, bounds, Point::ORIGIN); }); } @@ -260,8 +267,11 @@ where cursor .position() .map(|cursor_position| { - overlay - .is_over(Layout::new(&layout), cursor_position) + overlay.is_over( + Layout::new(&layout), + renderer, + cursor_position, + ) }) .unwrap_or_default() }) @@ -428,16 +438,20 @@ where .root .as_widget_mut() .overlay(&mut self.state, Layout::new(&self.base), renderer) + .map(overlay::Nested::new) { let overlay_layout = self.overlay.take().unwrap_or_else(|| { - overlay.layout(renderer, self.bounds, Vector::ZERO) + overlay.layout(renderer, self.bounds, Point::ORIGIN) }); let cursor = if cursor .position() .map(|cursor_position| { - overlay - .is_over(Layout::new(&overlay_layout), cursor_position) + overlay.is_over( + Layout::new(&overlay_layout), + renderer, + cursor_position, + ) }) .unwrap_or_default() { @@ -488,6 +502,7 @@ where .and_then(|layout| { root.as_widget_mut() .overlay(&mut self.state, Layout::new(base), renderer) + .map(overlay::Nested::new) .map(|overlay| { let overlay_interaction = overlay.mouse_interaction( Layout::new(layout), @@ -513,6 +528,7 @@ where .map(|cursor_position| { overlay.is_over( Layout::new(layout), + renderer, cursor_position, ) }) @@ -540,14 +556,15 @@ where operation, ); - if let Some(mut overlay) = self.root.as_widget_mut().overlay( - &mut self.state, - Layout::new(&self.base), - renderer, - ) { + if let Some(mut overlay) = self + .root + .as_widget_mut() + .overlay(&mut self.state, Layout::new(&self.base), renderer) + .map(overlay::Nested::new) + { if self.overlay.is_none() { self.overlay = - Some(overlay.layout(renderer, self.bounds, Vector::ZERO)); + Some(overlay.layout(renderer, self.bounds, Point::ORIGIN)); } overlay.operate( diff --git a/runtime/src/user_interface/overlay.rs b/runtime/src/user_interface/overlay.rs new file mode 100644 index 00000000..6dfed153 --- /dev/null +++ b/runtime/src/user_interface/overlay.rs @@ -0,0 +1,288 @@ +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<overlay::Element<'a, Message, Renderer>>, +); + +impl<'a, Message, Renderer> Inner<'a, Message, Renderer> { + fn with_element_mut<T>( + &self, + mut f: impl FnMut(&mut overlay::Element<'_, Message, Renderer>) -> T, + ) -> T { + (f)(&mut self.0.borrow_mut()) + } +} + +impl<'a, Message, Renderer> Overlay<Message, Renderer> + for Nested<'a, Message, Renderer> +where + Renderer: renderer::Renderer, +{ + fn layout( + &self, + renderer: &Renderer, + bounds: Size, + position: Point, + ) -> layout::Node { + fn recurse<Message, Renderer>( + element: &mut overlay::Element<'_, Message, Renderer>, + renderer: &Renderer, + bounds: Size, + position: Point, + ) -> Vec<layout::Node> + where + Renderer: renderer::Renderer, + { + let translation = position - Point::ORIGIN; + + let node = element.layout(renderer, bounds, translation); + + if let Some(mut overlay) = + element.overlay(Layout::new(&node), renderer) + { + vec![node] + .into_iter() + .chain(recurse(&mut overlay, renderer, bounds, position)) + .collect() + } else { + vec![node] + } + } + + self.overlay.with_element_mut(|element| { + layout::Node::with_children( + bounds, + recurse(element, renderer, bounds, position), + ) + }) + } + + fn draw( + &self, + renderer: &mut Renderer, + theme: &<Renderer as renderer::Renderer>::Theme, + style: &renderer::Style, + layout: Layout<'_>, + cursor: mouse::Cursor, + ) { + fn recurse<'a, Message, Renderer>( + element: &mut overlay::Element<'_, Message, Renderer>, + mut layouts: impl Iterator<Item = Layout<'a>>, + renderer: &mut Renderer, + theme: &<Renderer as renderer::Renderer>::Theme, + style: &renderer::Style, + cursor: mouse::Cursor, + ) where + Renderer: renderer::Renderer, + { + let layout = layouts.next().unwrap(); + + element.draw(renderer, theme, style, layout, cursor); + + if let Some(mut overlay) = element.overlay(layout, renderer) { + recurse(&mut overlay, layouts, renderer, theme, style, cursor); + } + } + + self.overlay.with_element_mut(|element| { + let layouts = layout.children(); + + recurse(element, layouts, renderer, theme, style, cursor); + }) + } + + fn operate( + &mut self, + layout: Layout<'_>, + renderer: &Renderer, + operation: &mut dyn widget::Operation<Message>, + ) { + fn recurse<'a, Message, Renderer>( + element: &mut overlay::Element<'_, Message, Renderer>, + mut layouts: impl Iterator<Item = Layout<'a>>, + renderer: &Renderer, + operation: &mut dyn widget::Operation<Message>, + ) where + Renderer: renderer::Renderer, + { + let layout = layouts.next().unwrap(); + + element.operate(layout, renderer, operation); + + if let Some(mut overlay) = element.overlay(layout, renderer) { + recurse(&mut overlay, layouts, renderer, operation); + } + } + + let layouts = layout.children(); + + recurse(self.overlay.0.get_mut(), layouts, 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<'a, Message, Renderer>( + element: &mut overlay::Element<'_, Message, Renderer>, + mut layouts: impl Iterator<Item = Layout<'a>>, + event: Event, + cursor: mouse::Cursor, + renderer: &Renderer, + clipboard: &mut dyn Clipboard, + shell: &mut Shell<'_, Message>, + ) -> event::Status + where + Renderer: renderer::Renderer, + { + let layout = layouts.next().unwrap(); + + let status = + if let Some(mut overlay) = element.overlay(layout, renderer) { + recurse( + &mut overlay, + layouts, + 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 + } + } + + let layouts = layout.children(); + + recurse( + self.overlay.0.get_mut(), + layouts, + event, + cursor, + renderer, + clipboard, + shell, + ) + } + + fn mouse_interaction( + &self, + layout: Layout<'_>, + cursor: mouse::Cursor, + viewport: &Rectangle, + renderer: &Renderer, + ) -> mouse::Interaction { + fn recurse<'a, Message, Renderer>( + element: &mut overlay::Element<'_, Message, Renderer>, + mut layouts: impl Iterator<Item = Layout<'a>>, + cursor: mouse::Cursor, + viewport: &Rectangle, + renderer: &Renderer, + ) -> mouse::Interaction + where + Renderer: renderer::Renderer, + { + let layout = layouts.next().unwrap(); + + let interaction = + if let Some(mut overlay) = element.overlay(layout, renderer) { + recurse(&mut overlay, layouts, cursor, viewport, renderer) + } else { + mouse::Interaction::default() + }; + + element + .mouse_interaction(layout, cursor, viewport, renderer) + .max(interaction) + } + + self.overlay.with_element_mut(|element| { + let layouts = layout.children(); + + recurse(element, layouts, cursor, viewport, renderer) + }) + } + + fn is_over( + &self, + layout: Layout<'_>, + renderer: &Renderer, + cursor_position: Point, + ) -> bool { + fn recurse<'a, Message, Renderer>( + element: &mut overlay::Element<'_, Message, Renderer>, + mut layouts: impl Iterator<Item = Layout<'a>>, + renderer: &Renderer, + cursor_position: Point, + ) -> bool + where + Renderer: renderer::Renderer, + { + let layout = layouts.next().unwrap(); + + let is_over = element.is_over(layout, renderer, cursor_position); + + if is_over { + return true; + } + + if let Some(mut overlay) = element.overlay(layout, renderer) { + recurse(&mut overlay, layouts, renderer, cursor_position) + } else { + false + } + } + + self.overlay.with_element_mut(|element| { + let layouts = layout.children(); + + recurse(element, layouts, renderer, cursor_position) + }) + } + + fn overlay<'b>( + &'b mut self, + _layout: Layout<'_>, + _renderer: &Renderer, + ) -> Option<overlay::Element<'b, Message, Renderer>> { + None + } +} |