diff options
author | 2020-04-16 13:22:00 +0200 | |
---|---|---|
committer | 2020-07-08 10:41:16 +0200 | |
commit | f064f0482b653a1fbee4afbddcecf91e3a399004 (patch) | |
tree | 2a468e4dc80be13cbf0ae7dd703607010e16697c | |
parent | c901f40fd6c5aa39f4dc056b2b59bc7133b287e6 (diff) | |
download | iced-f064f0482b653a1fbee4afbddcecf91e3a399004.tar.gz iced-f064f0482b653a1fbee4afbddcecf91e3a399004.tar.bz2 iced-f064f0482b653a1fbee4afbddcecf91e3a399004.zip |
Introduce `Layer` trait
-rw-r--r-- | graphics/src/renderer.rs | 29 | ||||
-rw-r--r-- | native/src/element.rs | 5 | ||||
-rw-r--r-- | native/src/layer.rs | 34 | ||||
-rw-r--r-- | native/src/layout.rs | 7 | ||||
-rw-r--r-- | native/src/lib.rs | 2 | ||||
-rw-r--r-- | native/src/overlay.rs | 37 | ||||
-rw-r--r-- | native/src/renderer.rs | 9 | ||||
-rw-r--r-- | native/src/renderer/null.rs | 3 | ||||
-rw-r--r-- | native/src/user_interface.rs | 149 | ||||
-rw-r--r-- | native/src/widget.rs | 5 | ||||
-rw-r--r-- | native/src/widget/column.rs | 15 | ||||
-rw-r--r-- | native/src/widget/container.rs | 11 |
12 files changed, 252 insertions, 54 deletions
diff --git a/graphics/src/renderer.rs b/graphics/src/renderer.rs index 44bacd4e..771f436c 100644 --- a/graphics/src/renderer.rs +++ b/graphics/src/renderer.rs @@ -1,7 +1,9 @@ use crate::{Backend, Defaults, Primitive}; use iced_native::layout::{self, Layout}; use iced_native::mouse; -use iced_native::{Background, Color, Element, Point, Widget}; +use iced_native::{ + Background, Color, Element, Point, Rectangle, Vector, Widget, +}; /// A backend-agnostic renderer that supports all the built-in widgets. #[derive(Debug)] @@ -53,6 +55,31 @@ where layout } + + fn overlay( + &mut self, + (base_primitive, base_cursor): (Primitive, mouse::Interaction), + (overlay_primitives, overlay_cursor): (Primitive, mouse::Interaction), + overlay_bounds: Rectangle, + ) -> (Primitive, mouse::Interaction) { + ( + Primitive::Group { + primitives: vec![ + base_primitive, + Primitive::Clip { + bounds: overlay_bounds, + offset: Vector::new(0, 0), + content: Box::new(overlay_primitives), + }, + ], + }, + if base_cursor > overlay_cursor { + base_cursor + } else { + overlay_cursor + }, + ) + } } impl<B> layout::Debugger for Renderer<B> diff --git a/native/src/element.rs b/native/src/element.rs index c6d65550..01379d2d 100644 --- a/native/src/element.rs +++ b/native/src/element.rs @@ -274,8 +274,9 @@ where pub fn overlay( &mut self, - ) -> Option<Box<dyn Overlay<Message, Renderer> + 'a>> { - self.widget.overlay() + layout: Layout<'_>, + ) -> Option<Overlay<'a, Message, Renderer>> { + self.widget.overlay(layout) } } diff --git a/native/src/layer.rs b/native/src/layer.rs new file mode 100644 index 00000000..d89fb4e5 --- /dev/null +++ b/native/src/layer.rs @@ -0,0 +1,34 @@ +use crate::{layout, Clipboard, Event, Hasher, Layout, Point, Size}; + +pub trait Layer<Message, Renderer> +where + Renderer: crate::Renderer, +{ + fn layout( + &self, + renderer: &Renderer, + bounds: Size, + position: Point, + ) -> layout::Node; + + fn draw( + &self, + renderer: &mut Renderer, + defaults: &Renderer::Defaults, + layout: Layout<'_>, + cursor_position: Point, + ) -> Renderer::Output; + + fn hash_layout(&self, state: &mut Hasher, position: Point); + + fn on_event( + &mut self, + _event: Event, + _layout: Layout<'_>, + _cursor_position: Point, + _messages: &mut Vec<Message>, + _renderer: &Renderer, + _clipboard: Option<&dyn Clipboard>, + ) { + } +} diff --git a/native/src/layout.rs b/native/src/layout.rs index 4a3ab94a..178f0f24 100644 --- a/native/src/layout.rs +++ b/native/src/layout.rs @@ -34,6 +34,13 @@ impl<'a> Layout<'a> { } } + /// Gets the position of the [`Layout`]. + /// + /// [`Layout`]: struct.Layout.html + pub fn position(&self) -> Point { + self.position + } + /// Gets the bounds of the [`Layout`]. /// /// The returned [`Rectangle`] describes the position and size of a diff --git a/native/src/lib.rs b/native/src/lib.rs index dbec068d..6974c2bd 100644 --- a/native/src/lib.rs +++ b/native/src/lib.rs @@ -48,6 +48,7 @@ mod clipboard; mod element; mod event; mod hasher; +mod layer; mod overlay; mod runtime; mod user_interface; @@ -75,6 +76,7 @@ pub use debug::Debug; pub use element::Element; pub use event::Event; pub use hasher::Hasher; +pub use layer::Layer; pub use layout::Layout; pub use overlay::Overlay; pub use program::Program; diff --git a/native/src/overlay.rs b/native/src/overlay.rs index d34432a4..a4bd5ea3 100644 --- a/native/src/overlay.rs +++ b/native/src/overlay.rs @@ -1,26 +1,41 @@ -use crate::{layout, Clipboard, Event, Hasher, Layout, Point}; +use crate::{layout, Clipboard, Event, Hasher, Layer, Layout, Point, Size}; -pub trait Overlay<Message, Renderer> +#[allow(missing_debug_implementations)] +pub struct Overlay<'a, Message, Renderer> { + position: Point, + layer: Box<dyn Layer<Message, Renderer> + 'a>, +} + +impl<'a, Message, Renderer> Overlay<'a, Message, Renderer> where Renderer: crate::Renderer, { - fn layout( - &self, - renderer: &Renderer, - limits: &layout::Limits, - ) -> layout::Node; + pub fn new( + position: Point, + layer: Box<dyn Layer<Message, Renderer> + 'a>, + ) -> Self { + Self { position, layer } + } - fn draw( + pub fn layout(&self, renderer: &Renderer, bounds: Size) -> layout::Node { + self.layer.layout(renderer, bounds, self.position) + } + + pub fn draw( &self, renderer: &mut Renderer, defaults: &Renderer::Defaults, layout: Layout<'_>, cursor_position: Point, - ) -> Renderer::Output; + ) -> Renderer::Output { + self.layer.draw(renderer, defaults, layout, cursor_position) + } - fn hash_layout(&self, state: &mut Hasher); + pub fn hash_layout(&self, state: &mut Hasher) { + self.layer.hash_layout(state, self.position); + } - fn on_event( + pub fn on_event( &mut self, _event: Event, _layout: Layout<'_>, diff --git a/native/src/renderer.rs b/native/src/renderer.rs index a16df72b..29a091a4 100644 --- a/native/src/renderer.rs +++ b/native/src/renderer.rs @@ -25,7 +25,7 @@ mod null; #[cfg(debug_assertions)] pub use null::Null; -use crate::{layout, Element}; +use crate::{layout, Element, Rectangle}; /// A component that can take the state of a user interface and produce an /// output for its users. @@ -56,4 +56,11 @@ pub trait Renderer: Sized { ) -> layout::Node { element.layout(self, limits) } + + fn overlay( + &mut self, + base: Self::Output, + overlay: Self::Output, + overlay_bounds: Rectangle, + ) -> Self::Output; } diff --git a/native/src/renderer/null.rs b/native/src/renderer/null.rs index 5fd3627b..bd6aca29 100644 --- a/native/src/renderer/null.rs +++ b/native/src/renderer/null.rs @@ -22,6 +22,9 @@ impl Null { impl Renderer for Null { type Output = (); type Defaults = (); + + fn overlay(&mut self, _base: (), _overlay: (), _overlay_bounds: Rectangle) { + } } impl column::Renderer for Null { diff --git a/native/src/user_interface.rs b/native/src/user_interface.rs index b9646043..6758bce3 100644 --- a/native/src/user_interface.rs +++ b/native/src/user_interface.rs @@ -1,4 +1,4 @@ -use crate::{layout, Clipboard, Element, Event, Layout, Point, Size}; +use crate::{layout, Clipboard, Element, Event, Layout, Overlay, Point, Size}; use std::hash::Hasher; @@ -19,12 +19,17 @@ use std::hash::Hasher; /// [`UserInterface`]: struct.UserInterface.html #[allow(missing_debug_implementations)] pub struct UserInterface<'a, Message, Renderer> { - hash: u64, - root: Element<'a, Message, Renderer>, - layout: layout::Node, + base: Layer<Element<'a, Message, Renderer>>, + overlay: Option<Layer<Overlay<'a, Message, Renderer>>>, bounds: Size, } +struct Layer<T> { + root: T, + layout: layout::Node, + hash: u64, +} + impl<'a, Message, Renderer> UserInterface<'a, Message, Renderer> where Renderer: crate::Renderer, @@ -92,27 +97,45 @@ where cache: Cache, renderer: &mut Renderer, ) -> Self { - let root = root.into(); + let mut root = root.into(); - let hash = { - let hasher = &mut crate::Hasher::default(); - root.hash_layout(hasher); + let (base, overlay) = { + let hash = { + let hasher = &mut crate::Hasher::default(); + root.hash_layout(hasher); - hasher.finish() - }; + hasher.finish() + }; - let layout_is_cached = hash == cache.hash && bounds == cache.bounds; + let layout_is_cached = hash == cache.hash && bounds == cache.bounds; - let layout = if layout_is_cached { - cache.layout - } else { - renderer.layout(&root, &layout::Limits::new(Size::ZERO, bounds)) + let layout = if layout_is_cached { + cache.layout + } else { + renderer.layout(&root, &layout::Limits::new(Size::ZERO, bounds)) + }; + + let overlay = root.overlay(Layout::new(&layout)); + + (Layer { root, layout, hash }, overlay) }; + let overlay = overlay.map(|root| { + let hash = { + let hasher = &mut crate::Hasher::default(); + root.hash_layout(hasher); + + hasher.finish() + }; + + let layout = root.layout(&renderer, bounds); + + Layer { root, layout, hash } + }); + UserInterface { - hash, - root, - layout, + base, + overlay, bounds, } } @@ -193,14 +216,42 @@ where let mut messages = Vec::new(); for event in events { - self.root.widget.on_event( - event, - Layout::new(&self.layout), - cursor_position, - &mut messages, - renderer, - clipboard, - ); + if let Some(overlay) = &mut self.overlay { + overlay.root.on_event( + event.clone(), + Layout::new(&overlay.layout), + cursor_position, + &mut messages, + renderer, + clipboard, + ); + + let base_cursor = + if overlay.layout.bounds().contains(cursor_position) { + // TODO: Encode cursor availability + Point::new(-1.0, -1.0) + } else { + cursor_position + }; + + self.base.root.widget.on_event( + event, + Layout::new(&self.base.layout), + base_cursor, + &mut messages, + renderer, + clipboard, + ); + } else { + self.base.root.widget.on_event( + event, + Layout::new(&self.base.layout), + cursor_position, + &mut messages, + renderer, + clipboard, + ); + } } messages @@ -280,12 +331,42 @@ where renderer: &mut Renderer, cursor_position: Point, ) -> Renderer::Output { - self.root.widget.draw( - renderer, - &Renderer::Defaults::default(), - Layout::new(&self.layout), - cursor_position, - ) + if let Some(overlay) = &self.overlay { + let overlay_bounds = overlay.layout.bounds(); + + let base_cursor = if overlay_bounds.contains(cursor_position) { + Point::new(-1.0, -1.0) + } else { + cursor_position + }; + + let base_primitives = self.base.root.widget.draw( + renderer, + &Renderer::Defaults::default(), + Layout::new(&self.base.layout), + base_cursor, + ); + + let overlay_primitives = overlay.root.draw( + renderer, + &Renderer::Defaults::default(), + Layout::new(&overlay.layout), + cursor_position, + ); + + renderer.overlay( + base_primitives, + overlay_primitives, + overlay_bounds, + ) + } else { + self.base.root.widget.draw( + renderer, + &Renderer::Defaults::default(), + Layout::new(&self.base.layout), + cursor_position, + ) + } } /// Extract the [`Cache`] of the [`UserInterface`], consuming it in the @@ -295,8 +376,8 @@ where /// [`UserInterface`]: struct.UserInterface.html pub fn into_cache(self) -> Cache { Cache { - hash: self.hash, - layout: self.layout, + hash: self.base.hash, + layout: self.base.layout, bounds: self.bounds, } } diff --git a/native/src/widget.rs b/native/src/widget.rs index dd1a97d2..0494636f 100644 --- a/native/src/widget.rs +++ b/native/src/widget.rs @@ -176,7 +176,10 @@ where ) { } - fn overlay(&mut self) -> Option<Box<dyn Overlay<Message, Renderer> + 'a>> { + fn overlay( + &mut self, + _layout: Layout<'_>, + ) -> Option<Overlay<'a, Message, Renderer>> { None } } diff --git a/native/src/widget/column.rs b/native/src/widget/column.rs index 6afc94d6..9a6dbdb3 100644 --- a/native/src/widget/column.rs +++ b/native/src/widget/column.rs @@ -2,8 +2,8 @@ use std::hash::Hash; use crate::{ - layout, Align, Clipboard, Element, Event, Hasher, Layout, Length, Point, - Widget, + layout, Align, Clipboard, Element, Event, Hasher, Layout, Length, Overlay, + Point, Widget, }; use std::u32; @@ -204,6 +204,17 @@ where child.widget.hash_layout(state); } } + + fn overlay( + &mut self, + layout: Layout<'_>, + ) -> Option<Overlay<'a, Message, Renderer>> { + self.children + .iter_mut() + .zip(layout.children()) + .filter_map(|(child, layout)| child.widget.overlay(layout)) + .next() + } } /// The renderer of a [`Column`]. diff --git a/native/src/widget/container.rs b/native/src/widget/container.rs index 3ad12eeb..3bdb1a27 100644 --- a/native/src/widget/container.rs +++ b/native/src/widget/container.rs @@ -2,8 +2,8 @@ use std::hash::Hash; use crate::{ - layout, Align, Clipboard, Element, Event, Hasher, Layout, Length, Point, - Rectangle, Widget, + layout, Align, Clipboard, Element, Event, Hasher, Layout, Length, Overlay, + Point, Rectangle, Widget, }; use std::u32; @@ -214,6 +214,13 @@ where self.content.hash_layout(state); } + + fn overlay( + &mut self, + layout: Layout<'_>, + ) -> Option<Overlay<'a, Message, Renderer>> { + self.content.overlay(layout.children().next().unwrap()) + } } /// The renderer of a [`Container`]. |