summaryrefslogtreecommitdiffstats
path: root/native
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2020-07-05 05:44:10 +0200
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2020-07-08 11:29:19 +0200
commit625979b6652a8a14a0eaf6bd62f1e9a8da0ae421 (patch)
tree0ed6994fc2ff0a8671bb6ec26bdae21af2b6fb23 /native
parent61f22b1db23f3495145a9a4f7255311fe8381998 (diff)
downloadiced-625979b6652a8a14a0eaf6bd62f1e9a8da0ae421.tar.gz
iced-625979b6652a8a14a0eaf6bd62f1e9a8da0ae421.tar.bz2
iced-625979b6652a8a14a0eaf6bd62f1e9a8da0ae421.zip
Draft `Widget::overlay` idempotency
Diffstat (limited to 'native')
-rw-r--r--native/src/element.rs14
-rw-r--r--native/src/overlay/menu.rs31
-rw-r--r--native/src/program/state.rs4
-rw-r--r--native/src/user_interface.rs128
-rw-r--r--native/src/widget.rs6
-rw-r--r--native/src/widget/column.rs2
-rw-r--r--native/src/widget/combo_box.rs68
-rw-r--r--native/src/widget/container.rs2
-rw-r--r--native/src/widget/row.rs2
-rw-r--r--native/src/widget/scrollable.rs8
10 files changed, 134 insertions, 131 deletions
diff --git a/native/src/element.rs b/native/src/element.rs
index c881871a..b00f9e55 100644
--- a/native/src/element.rs
+++ b/native/src/element.rs
@@ -273,10 +273,10 @@ where
self.widget.hash_layout(state);
}
- pub fn overlay(
- &mut self,
+ pub fn overlay<'b>(
+ &'b mut self,
layout: Layout<'_>,
- ) -> Option<Overlay<'a, Message, Renderer>> {
+ ) -> Option<Overlay<'b, Message, Renderer>> {
self.widget.overlay(layout)
}
}
@@ -366,10 +366,12 @@ where
fn overlay(
&mut self,
layout: Layout<'_>,
- ) -> Option<Overlay<'a, B, Renderer>> {
+ ) -> Option<Overlay<'_, B, Renderer>> {
+ let mapper = self.mapper.clone();
+
self.widget
.overlay(layout)
- .map(|overlay| overlay.map(self.mapper.clone()))
+ .map(move |overlay| overlay.map(mapper))
}
}
@@ -450,7 +452,7 @@ where
fn overlay(
&mut self,
layout: Layout<'_>,
- ) -> Option<Overlay<'a, Message, Renderer>> {
+ ) -> Option<Overlay<'_, Message, Renderer>> {
self.element.overlay(layout)
}
}
diff --git a/native/src/overlay/menu.rs b/native/src/overlay/menu.rs
index 9c180671..2a19e286 100644
--- a/native/src/overlay/menu.rs
+++ b/native/src/overlay/menu.rs
@@ -1,5 +1,5 @@
use crate::{
- container, layout, mouse, overlay, scrollable, Clipboard, Container,
+ container, layout, mouse, overlay, scrollable, text, Clipboard, Container,
Element, Event, Hasher, Layout, Length, Point, Rectangle, Scrollable, Size,
Vector, Widget,
};
@@ -39,10 +39,10 @@ where
pub fn new<T: 'a>(
state: &'a mut State,
options: impl Into<Cow<'a, [T]>>,
- on_selected: Box<dyn Fn(T) -> Message>,
+ on_selected: &'a dyn Fn(T) -> Message,
width: u16,
target_height: f32,
- text_size: u16,
+ text_size: Option<u16>,
padding: u16,
style: <Renderer as self::Renderer>::Style,
) -> Self
@@ -175,8 +175,8 @@ where
{
hovered_option: &'a mut Option<usize>,
options: Cow<'a, [T]>,
- on_selected: Box<dyn Fn(T) -> Message>,
- text_size: u16,
+ on_selected: &'a dyn Fn(T) -> Message,
+ text_size: Option<u16>,
padding: u16,
style: <Renderer as self::Renderer>::Style,
}
@@ -188,8 +188,8 @@ where
pub fn new(
hovered_option: &'a mut Option<usize>,
options: impl Into<Cow<'a, [T]>>,
- on_selected: Box<dyn Fn(T) -> Message>,
- text_size: u16,
+ on_selected: &'a dyn Fn(T) -> Message,
+ text_size: Option<u16>,
padding: u16,
style: <Renderer as self::Renderer>::Style,
) -> Self {
@@ -221,17 +221,18 @@ where
fn layout(
&self,
- _renderer: &Renderer,
+ renderer: &Renderer,
limits: &layout::Limits,
) -> layout::Node {
use std::f32;
let limits = limits.width(Length::Fill).height(Length::Shrink);
+ let text_size = self.text_size.unwrap_or(renderer.default_size());
let size = {
let intrinsic = Size::new(
0.0,
- f32::from(self.text_size + self.padding * 2)
+ f32::from(text_size + self.padding * 2)
* self.options.len() as f32,
);
@@ -253,7 +254,7 @@ where
layout: Layout<'_>,
cursor_position: Point,
messages: &mut Vec<Message>,
- _renderer: &Renderer,
+ renderer: &Renderer,
_clipboard: Option<&dyn Clipboard>,
) {
match event {
@@ -270,11 +271,13 @@ where
}
Event::Mouse(mouse::Event::CursorMoved { .. }) => {
let bounds = layout.bounds();
+ let text_size =
+ self.text_size.unwrap_or(renderer.default_size());
if bounds.contains(cursor_position) {
*self.hovered_option = Some(
((cursor_position.y - bounds.y)
- / f32::from(self.text_size + self.padding * 2))
+ / f32::from(text_size + self.padding * 2))
as usize,
);
}
@@ -296,14 +299,16 @@ where
cursor_position,
&self.options,
*self.hovered_option,
- self.text_size,
+ self.text_size.unwrap_or(renderer.default_size()),
self.padding,
&self.style,
)
}
}
-pub trait Renderer: scrollable::Renderer + container::Renderer {
+pub trait Renderer:
+ scrollable::Renderer + container::Renderer + text::Renderer
+{
type Style: Default + Clone;
fn decorate(
diff --git a/native/src/program/state.rs b/native/src/program/state.rs
index fdc42e8b..ddbbbb59 100644
--- a/native/src/program/state.rs
+++ b/native/src/program/state.rs
@@ -35,7 +35,7 @@ where
renderer: &mut P::Renderer,
debug: &mut Debug,
) -> Self {
- let user_interface = build_user_interface(
+ let mut user_interface = build_user_interface(
&mut program,
Cache::default(),
renderer,
@@ -153,7 +153,7 @@ where
command
}));
- let user_interface = build_user_interface(
+ let mut user_interface = build_user_interface(
&mut self.program,
temp_cache,
renderer,
diff --git a/native/src/user_interface.rs b/native/src/user_interface.rs
index 12cea684..9ec6bb96 100644
--- a/native/src/user_interface.rs
+++ b/native/src/user_interface.rs
@@ -1,4 +1,4 @@
-use crate::{layout, Clipboard, Element, Event, Layout, Overlay, Point, Size};
+use crate::{layout, Clipboard, Element, Event, Layout, Point, Size};
use std::hash::Hasher;
@@ -19,13 +19,13 @@ use std::hash::Hasher;
/// [`UserInterface`]: struct.UserInterface.html
#[allow(missing_debug_implementations)]
pub struct UserInterface<'a, Message, Renderer> {
- base: Layer<Element<'a, Message, Renderer>>,
- overlay: Option<Layer<Overlay<'a, Message, Renderer>>>,
+ root: Element<'a, Message, Renderer>,
+ base: Layer,
+ overlay: Option<Layer>,
bounds: Size,
}
-struct Layer<T> {
- root: T,
+struct Layer {
layout: layout::Node,
hash: u64,
}
@@ -97,9 +97,9 @@ where
cache: Cache,
renderer: &mut Renderer,
) -> Self {
- let mut root = root.into();
+ let root = root.into();
- let (base, overlay) = {
+ let base = {
let hash = {
let hasher = &mut crate::Hasher::default();
root.hash_layout(hasher);
@@ -115,27 +115,13 @@ where
renderer.layout(&root, &layout::Limits::new(Size::ZERO, bounds))
};
- let overlay = root.overlay(Layout::new(&layout));
-
- (Layer { root, layout, hash }, overlay)
+ Layer { layout, hash }
};
- 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 {
+ root,
base,
- overlay,
+ overlay: None,
bounds,
}
}
@@ -215,35 +201,49 @@ where
) -> Vec<Message> {
let mut messages = Vec::new();
- for event in events {
- if let Some(overlay) = &mut self.overlay {
- let base_cursor =
- if overlay.layout.bounds().contains(cursor_position) {
- // TODO: Encode cursor availability
- Point::new(-1.0, -1.0)
- } else {
- cursor_position
- };
+ let base_events = if let Some(mut overlay) =
+ self.root.overlay(Layout::new(&self.base.layout))
+ {
+ let layer = {
+ let new_hash = {
+ let hasher = &mut crate::Hasher::default();
+ overlay.hash_layout(hasher);
- overlay.root.on_event(
+ hasher.finish()
+ };
+
+ let layout = match self.overlay.take() {
+ Some(Layer { hash, layout }) if new_hash == hash => layout,
+ _ => overlay.layout(&renderer, self.bounds),
+ };
+
+ Layer {
+ layout,
+ hash: new_hash,
+ }
+ };
+
+ for event in events {
+ overlay.on_event(
event.clone(),
- Layout::new(&overlay.layout),
+ Layout::new(&layer.layout),
cursor_position,
&mut messages,
renderer,
clipboard,
);
+ }
- 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(
+ self.overlay = Some(layer);
+
+ None
+ } else {
+ Some(events)
+ };
+
+ if let Some(events) = base_events {
+ for event in events {
+ self.root.widget.on_event(
event,
Layout::new(&self.base.layout),
cursor_position,
@@ -327,12 +327,12 @@ where
/// }
/// ```
pub fn draw(
- &self,
+ &mut self,
renderer: &mut Renderer,
cursor_position: Point,
) -> Renderer::Output {
- if let Some(overlay) = &self.overlay {
- let overlay_bounds = overlay.layout.bounds();
+ if let Some(layer) = &self.overlay {
+ let overlay_bounds = layer.layout.bounds();
let base_cursor = if overlay_bounds.contains(cursor_position) {
Point::new(-1.0, -1.0)
@@ -340,27 +340,33 @@ where
cursor_position
};
- let base_primitives = self.base.root.widget.draw(
+ let base_primitives = self.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,
- );
+ if let Some(overlay) =
+ self.root.overlay(Layout::new(&self.base.layout))
+ {
+ let overlay_primitives = overlay.draw(
+ renderer,
+ &Renderer::Defaults::default(),
+ Layout::new(&layer.layout),
+ cursor_position,
+ );
- renderer.overlay(
- base_primitives,
- overlay_primitives,
- overlay_bounds,
- )
+ renderer.overlay(
+ base_primitives,
+ overlay_primitives,
+ overlay_bounds,
+ )
+ } else {
+ base_primitives
+ }
} else {
- self.base.root.widget.draw(
+ self.root.widget.draw(
renderer,
&Renderer::Defaults::default(),
Layout::new(&self.base.layout),
diff --git a/native/src/widget.rs b/native/src/widget.rs
index 664a0cfd..4bca7722 100644
--- a/native/src/widget.rs
+++ b/native/src/widget.rs
@@ -179,10 +179,10 @@ where
) {
}
- fn overlay(
- &mut self,
+ fn overlay<'b>(
+ &'b mut self,
_layout: Layout<'_>,
- ) -> Option<Overlay<'a, Message, Renderer>> {
+ ) -> Option<Overlay<'b, Message, Renderer>> {
None
}
}
diff --git a/native/src/widget/column.rs b/native/src/widget/column.rs
index 9a6dbdb3..e83ef93d 100644
--- a/native/src/widget/column.rs
+++ b/native/src/widget/column.rs
@@ -208,7 +208,7 @@ where
fn overlay(
&mut self,
layout: Layout<'_>,
- ) -> Option<Overlay<'a, Message, Renderer>> {
+ ) -> Option<Overlay<'_, Message, Renderer>> {
self.children
.iter_mut()
.zip(layout.children())
diff --git a/native/src/widget/combo_box.rs b/native/src/widget/combo_box.rs
index df2a530a..4a509354 100644
--- a/native/src/widget/combo_box.rs
+++ b/native/src/widget/combo_box.rs
@@ -10,7 +10,7 @@ pub struct ComboBox<'a, T, Message, Renderer: self::Renderer>
where
[T]: ToOwned<Owned = Vec<T>>,
{
- internal: Option<Internal<'a, T, Message>>,
+ internal: Internal<'a, T, Message>,
options: Cow<'a, [T]>,
selected: Option<T>,
width: Length,
@@ -42,10 +42,10 @@ where
on_selected: impl Fn(T) -> Message + 'static,
) -> Self {
Self {
- internal: Some(Internal {
+ internal: Internal {
menu: &mut state.menu,
on_selected: Box::new(on_selected),
- }),
+ },
options: options.into(),
selected,
width: Length::Shrink,
@@ -180,16 +180,14 @@ where
) {
match event {
Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => {
- if let Some(internal) = &mut self.internal {
- if layout.bounds().contains(cursor_position) {
- let selected = self.selected.as_ref();
-
- internal.menu.open(
- self.options
- .iter()
- .position(|option| Some(option) == selected),
- );
- }
+ if layout.bounds().contains(cursor_position) {
+ let selected = self.selected.as_ref();
+
+ self.internal.menu.open(
+ self.options
+ .iter()
+ .position(|option| Some(option) == selected),
+ );
}
}
_ => {}
@@ -217,33 +215,23 @@ where
fn overlay(
&mut self,
layout: Layout<'_>,
- ) -> Option<Overlay<'a, Message, Renderer>> {
- let is_open = self
- .internal
- .as_ref()
- .map(|internal| internal.menu.is_open())
- .unwrap_or(false);
-
- if is_open {
- if let Some(Internal { menu, on_selected }) = self.internal.take() {
- let bounds = layout.bounds();
-
- Some(Overlay::new(
- layout.position(),
- Box::new(Menu::new(
- menu,
- self.options.clone(),
- on_selected,
- bounds.width.round() as u16,
- bounds.height,
- self.text_size.unwrap_or(20),
- self.padding,
- Renderer::menu_style(&self.style),
- )),
- ))
- } else {
- None
- }
+ ) -> Option<Overlay<'_, Message, Renderer>> {
+ if self.internal.menu.is_open() {
+ let bounds = layout.bounds();
+
+ Some(Overlay::new(
+ layout.position(),
+ Box::new(Menu::new(
+ self.internal.menu,
+ self.options.clone(),
+ &self.internal.on_selected,
+ bounds.width.round() as u16,
+ bounds.height,
+ self.text_size,
+ self.padding,
+ Renderer::menu_style(&self.style),
+ )),
+ ))
} else {
None
}
diff --git a/native/src/widget/container.rs b/native/src/widget/container.rs
index 3bdb1a27..4ab10837 100644
--- a/native/src/widget/container.rs
+++ b/native/src/widget/container.rs
@@ -218,7 +218,7 @@ where
fn overlay(
&mut self,
layout: Layout<'_>,
- ) -> Option<Overlay<'a, Message, Renderer>> {
+ ) -> Option<Overlay<'_, Message, Renderer>> {
self.content.overlay(layout.children().next().unwrap())
}
}
diff --git a/native/src/widget/row.rs b/native/src/widget/row.rs
index 25bd641f..1cfe2d66 100644
--- a/native/src/widget/row.rs
+++ b/native/src/widget/row.rs
@@ -210,7 +210,7 @@ where
fn overlay(
&mut self,
layout: Layout<'_>,
- ) -> Option<Overlay<'a, Message, Renderer>> {
+ ) -> Option<Overlay<'_, Message, Renderer>> {
self.children
.iter_mut()
.zip(layout.children())
diff --git a/native/src/widget/scrollable.rs b/native/src/widget/scrollable.rs
index 92e5265a..87871e28 100644
--- a/native/src/widget/scrollable.rs
+++ b/native/src/widget/scrollable.rs
@@ -319,14 +319,16 @@ where
fn overlay(
&mut self,
layout: Layout<'_>,
- ) -> Option<Overlay<'a, Message, Renderer>> {
- self.content
+ ) -> Option<Overlay<'_, Message, Renderer>> {
+ let Self { content, state, .. } = self;
+
+ content
.overlay(layout.children().next().unwrap())
.map(|overlay| {
let bounds = layout.bounds();
let content_layout = layout.children().next().unwrap();
let content_bounds = content_layout.bounds();
- let offset = self.state.offset(bounds, content_bounds);
+ let offset = state.offset(bounds, content_bounds);
overlay.translate(Vector::new(0.0, -(offset as f32)))
})