Introduce Layer trait

This commit is contained in:
Héctor Ramón Jiménez 2020-04-16 13:22:00 +02:00
parent c901f40fd6
commit f064f0482b
12 changed files with 252 additions and 54 deletions

View file

@ -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,
}
}