diff options
author | 2020-07-05 05:44:10 +0200 | |
---|---|---|
committer | 2020-07-08 11:29:19 +0200 | |
commit | 625979b6652a8a14a0eaf6bd62f1e9a8da0ae421 (patch) | |
tree | 0ed6994fc2ff0a8671bb6ec26bdae21af2b6fb23 /native/src | |
parent | 61f22b1db23f3495145a9a4f7255311fe8381998 (diff) | |
download | iced-625979b6652a8a14a0eaf6bd62f1e9a8da0ae421.tar.gz iced-625979b6652a8a14a0eaf6bd62f1e9a8da0ae421.tar.bz2 iced-625979b6652a8a14a0eaf6bd62f1e9a8da0ae421.zip |
Draft `Widget::overlay` idempotency
Diffstat (limited to 'native/src')
-rw-r--r-- | native/src/element.rs | 14 | ||||
-rw-r--r-- | native/src/overlay/menu.rs | 31 | ||||
-rw-r--r-- | native/src/program/state.rs | 4 | ||||
-rw-r--r-- | native/src/user_interface.rs | 128 | ||||
-rw-r--r-- | native/src/widget.rs | 6 | ||||
-rw-r--r-- | native/src/widget/column.rs | 2 | ||||
-rw-r--r-- | native/src/widget/combo_box.rs | 68 | ||||
-rw-r--r-- | native/src/widget/container.rs | 2 | ||||
-rw-r--r-- | native/src/widget/row.rs | 2 | ||||
-rw-r--r-- | native/src/widget/scrollable.rs | 8 |
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))) }) |