Introduce Layer
trait
This commit is contained in:
parent
c901f40fd6
commit
f064f0482b
@ -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>
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
34
native/src/layer.rs
Normal file
34
native/src/layer.rs
Normal file
@ -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>,
|
||||
) {
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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<'_>,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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 = 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 layout_is_cached = hash == cache.hash && bounds == cache.bounds;
|
||||
let overlay = overlay.map(|root| {
|
||||
let hash = {
|
||||
let hasher = &mut crate::Hasher::default();
|
||||
root.hash_layout(hasher);
|
||||
|
||||
let layout = if layout_is_cached {
|
||||
cache.layout
|
||||
} else {
|
||||
renderer.layout(&root, &layout::Limits::new(Size::ZERO, bounds))
|
||||
};
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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`].
|
||||
|
@ -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`].
|
||||
|
Loading…
Reference in New Issue
Block a user