From 90c20ac46b72b6d8f735f7efd283b9d1dfecfb9d Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 11 Jan 2022 10:47:56 +0700 Subject: Draft `Responsive` widget --- native/src/widget/responsive.rs | 188 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 native/src/widget/responsive.rs (limited to 'native/src/widget') diff --git a/native/src/widget/responsive.rs b/native/src/widget/responsive.rs new file mode 100644 index 00000000..0cb85d45 --- /dev/null +++ b/native/src/widget/responsive.rs @@ -0,0 +1,188 @@ +use crate::event::{self, Event}; +use crate::layout::{self, Layout}; +use crate::renderer; +use crate::{ + Clipboard, Element, Hasher, Length, Point, Rectangle, Shell, Size, Widget, +}; + +use std::cell::RefCell; +use std::hash::Hasher as _; + +#[derive(Debug, Clone, Default)] +pub struct State { + last_size: Option, + last_layout: layout::Node, + last_layout_hash: u64, +} + +impl State { + pub fn new() -> State { + State::default() + } +} + +#[allow(missing_debug_implementations)] +pub struct Responsive<'a, Message, Renderer>( + RefCell>, +); + +impl<'a, Message, Renderer> Responsive<'a, Message, Renderer> { + pub fn new( + state: &'a mut State, + view: impl FnOnce(Size) -> Element<'a, Message, Renderer> + 'a, + ) -> Self { + Self(RefCell::new(Internal { + state, + content: Content::Pending(Some(Box::new(view))), + })) + } +} + +impl<'a, Message, Renderer> Widget + for Responsive<'a, Message, Renderer> +where + Renderer: crate::Renderer, +{ + fn width(&self) -> Length { + Length::Fill + } + + fn height(&self) -> Length { + Length::Fill + } + + fn hash_layout(&self, _hasher: &mut Hasher) {} + + fn layout( + &self, + _renderer: &Renderer, + limits: &layout::Limits, + ) -> layout::Node { + let size = limits.max(); + + self.0.borrow_mut().state.last_size = Some(size); + + layout::Node::new(size) + } + + fn on_event( + &mut self, + event: Event, + layout: Layout<'_>, + cursor_position: Point, + renderer: &Renderer, + clipboard: &mut dyn Clipboard, + shell: &mut Shell<'_, Message>, + ) -> event::Status { + use std::ops::DerefMut; + + let mut internal = self.0.borrow_mut(); + + let Internal { content, state } = internal.deref_mut(); + + let content = content.resolve(state, renderer); + + let content_layout = Layout::with_offset( + layout.position() - Point::ORIGIN, + &state.last_layout, + ); + + content.on_event( + event, + content_layout, + cursor_position, + renderer, + clipboard, + shell, + ) + } + + fn draw( + &self, + renderer: &mut Renderer, + style: &renderer::Style, + layout: Layout<'_>, + cursor_position: Point, + viewport: &Rectangle, + ) { + use std::ops::DerefMut; + + let mut internal = self.0.borrow_mut(); + + let Internal { content, state } = internal.deref_mut(); + + let content = content.resolve(state, renderer); + + let content_layout = Layout::with_offset( + layout.position() - Point::ORIGIN, + &state.last_layout, + ); + + content.draw(renderer, style, content_layout, cursor_position, viewport) + } +} + +struct Internal<'a, Message, Renderer> { + state: &'a mut State, + content: Content<'a, Message, Renderer>, +} + +enum Content<'a, Message, Renderer> { + Pending( + Option Element<'a, Message, Renderer> + 'a>>, + ), + Ready(Element<'a, Message, Renderer>), +} + +impl<'a, Message, Renderer> Content<'a, Message, Renderer> +where + Renderer: crate::Renderer, +{ + fn resolve( + &mut self, + state: &mut State, + renderer: &Renderer, + ) -> &mut Element<'a, Message, Renderer> { + match self { + Content::Ready(element) => element, + Content::Pending(view) => { + let element = + view.take().unwrap()(state.last_size.unwrap_or(Size::ZERO)); + + let new_layout_hash = { + let mut hasher = Hasher::default(); + element.hash_layout(&mut hasher); + + hasher.finish() + }; + + if new_layout_hash != state.last_layout_hash { + state.last_layout = element.layout( + renderer, + &layout::Limits::new( + Size::ZERO, + state.last_size.unwrap_or(Size::ZERO), + ), + ); + + state.last_layout_hash = new_layout_hash; + } + + *self = Content::Ready(element); + + self.resolve(state, renderer) + } + } + } +} + +impl<'a, Message, Renderer> From> + for Element<'a, Message, Renderer> +where + Renderer: crate::Renderer + 'a, + Message: 'a, +{ + fn from(responsive: Responsive<'a, Message, Renderer>) -> Self { + Self::new(responsive) + } +} -- cgit From 6ab4611a6eec9c4bb4ca1ff1bb580bb7edf49add Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 11 Jan 2022 13:47:43 +0700 Subject: Invalidate widget tree from `Responsive` widget ... by introducing a new `invalidate_widgets` method to `Shell` --- native/src/widget/responsive.rs | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'native/src/widget') diff --git a/native/src/widget/responsive.rs b/native/src/widget/responsive.rs index 0cb85d45..becaa980 100644 --- a/native/src/widget/responsive.rs +++ b/native/src/widget/responsive.rs @@ -80,6 +80,10 @@ where let Internal { content, state } = internal.deref_mut(); + if state.last_size != Some(state.last_layout.size()) { + shell.invalidate_widgets(); + } + let content = content.resolve(state, renderer); let content_layout = Layout::with_offset( -- cgit From 810e086728e938d1d12758c7b486c1e371127349 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 11 Jan 2022 14:12:28 +0700 Subject: Introduce `Renderer` argument to `mouse_interaction` and `on_event` --- native/src/widget/button.rs | 5 ++++- native/src/widget/checkbox.rs | 1 + native/src/widget/column.rs | 7 ++++++- native/src/widget/container.rs | 6 +++++- native/src/widget/image/viewer.rs | 1 + native/src/widget/pane_grid.rs | 11 +++++++++-- native/src/widget/pane_grid/content.rs | 11 +++++++---- native/src/widget/pane_grid/title_bar.rs | 14 +++++++++++--- native/src/widget/pick_list.rs | 2 ++ native/src/widget/radio.rs | 1 + native/src/widget/row.rs | 7 ++++++- native/src/widget/scrollable.rs | 5 ++++- native/src/widget/slider.rs | 1 + native/src/widget/text_input.rs | 1 + native/src/widget/toggler.rs | 1 + native/src/widget/tooltip.rs | 9 +++++++-- 16 files changed, 67 insertions(+), 16 deletions(-) (limited to 'native/src/widget') diff --git a/native/src/widget/button.rs b/native/src/widget/button.rs index 686289e4..b4a3adc3 100644 --- a/native/src/widget/button.rs +++ b/native/src/widget/button.rs @@ -253,6 +253,7 @@ where layout: Layout<'_>, cursor_position: Point, _viewport: &Rectangle, + _renderer: &Renderer, ) -> mouse::Interaction { let is_mouse_over = layout.bounds().contains(cursor_position); let is_disabled = self.on_press.is_none(); @@ -343,8 +344,10 @@ where fn overlay( &mut self, layout: Layout<'_>, + renderer: &Renderer, ) -> Option> { - self.content.overlay(layout.children().next().unwrap()) + self.content + .overlay(layout.children().next().unwrap(), renderer) } } diff --git a/native/src/widget/checkbox.rs b/native/src/widget/checkbox.rs index 95856928..a314140c 100644 --- a/native/src/widget/checkbox.rs +++ b/native/src/widget/checkbox.rs @@ -195,6 +195,7 @@ where layout: Layout<'_>, cursor_position: Point, _viewport: &Rectangle, + _renderer: &Renderer, ) -> mouse::Interaction { if layout.bounds().contains(cursor_position) { mouse::Interaction::Pointer diff --git a/native/src/widget/column.rs b/native/src/widget/column.rs index 4c43c8c8..66ed5e23 100644 --- a/native/src/widget/column.rs +++ b/native/src/widget/column.rs @@ -169,6 +169,7 @@ where layout: Layout<'_>, cursor_position: Point, viewport: &Rectangle, + renderer: &Renderer, ) -> mouse::Interaction { self.children .iter() @@ -178,6 +179,7 @@ where layout, cursor_position, viewport, + renderer, ) }) .max() @@ -217,11 +219,14 @@ where fn overlay( &mut self, layout: Layout<'_>, + renderer: &Renderer, ) -> Option> { self.children .iter_mut() .zip(layout.children()) - .filter_map(|(child, layout)| child.widget.overlay(layout)) + .filter_map(|(child, layout)| { + child.widget.overlay(layout, renderer) + }) .next() } } diff --git a/native/src/widget/container.rs b/native/src/widget/container.rs index 0c291788..4444732a 100644 --- a/native/src/widget/container.rs +++ b/native/src/widget/container.rs @@ -184,11 +184,13 @@ where layout: Layout<'_>, cursor_position: Point, viewport: &Rectangle, + renderer: &Renderer, ) -> mouse::Interaction { self.content.widget.mouse_interaction( layout.children().next().unwrap(), cursor_position, viewport, + renderer, ) } @@ -235,8 +237,10 @@ where fn overlay( &mut self, layout: Layout<'_>, + renderer: &Renderer, ) -> Option> { - self.content.overlay(layout.children().next().unwrap()) + self.content + .overlay(layout.children().next().unwrap(), renderer) } } diff --git a/native/src/widget/image/viewer.rs b/native/src/widget/image/viewer.rs index 645ce852..486d5fa5 100644 --- a/native/src/widget/image/viewer.rs +++ b/native/src/widget/image/viewer.rs @@ -286,6 +286,7 @@ where layout: Layout<'_>, cursor_position: Point, _viewport: &Rectangle, + _renderer: &Renderer, ) -> mouse::Interaction { let bounds = layout.bounds(); let is_mouse_over = bounds.contains(cursor_position); diff --git a/native/src/widget/pane_grid.rs b/native/src/widget/pane_grid.rs index b3d8b819..5f293fa6 100644 --- a/native/src/widget/pane_grid.rs +++ b/native/src/widget/pane_grid.rs @@ -472,6 +472,7 @@ where layout: Layout<'_>, cursor_position: Point, viewport: &Rectangle, + renderer: &Renderer, ) -> mouse::Interaction { if self.state.picked_pane().is_some() { return mouse::Interaction::Grab; @@ -511,7 +512,12 @@ where .iter() .zip(layout.children()) .map(|((_pane, content), layout)| { - content.mouse_interaction(layout, cursor_position, viewport) + content.mouse_interaction( + layout, + cursor_position, + viewport, + renderer, + ) }) .max() .unwrap_or_default() @@ -678,11 +684,12 @@ where fn overlay( &mut self, layout: Layout<'_>, + renderer: &Renderer, ) -> Option> { self.elements .iter_mut() .zip(layout.children()) - .filter_map(|((_, pane), layout)| pane.overlay(layout)) + .filter_map(|((_, pane), layout)| pane.overlay(layout, renderer)) .next() } } diff --git a/native/src/widget/pane_grid/content.rs b/native/src/widget/pane_grid/content.rs index 533827b7..6d12aa2d 100644 --- a/native/src/widget/pane_grid/content.rs +++ b/native/src/widget/pane_grid/content.rs @@ -205,6 +205,7 @@ where layout: Layout<'_>, cursor_position: Point, viewport: &Rectangle, + renderer: &Renderer, ) -> mouse::Interaction { let (body_layout, title_bar_interaction) = if let Some(title_bar) = &self.title_bar { @@ -222,6 +223,7 @@ where title_bar_layout, cursor_position, viewport, + renderer, ); (children.next().unwrap(), mouse_interaction) @@ -230,7 +232,7 @@ where }; self.body - .mouse_interaction(body_layout, cursor_position, viewport) + .mouse_interaction(body_layout, cursor_position, viewport, renderer) .max(title_bar_interaction) } @@ -245,17 +247,18 @@ where pub(crate) fn overlay( &mut self, layout: Layout<'_>, + renderer: &Renderer, ) -> Option> { if let Some(title_bar) = self.title_bar.as_mut() { let mut children = layout.children(); let title_bar_layout = children.next()?; - match title_bar.overlay(title_bar_layout) { + match title_bar.overlay(title_bar_layout, renderer) { Some(overlay) => Some(overlay), - None => self.body.overlay(children.next()?), + None => self.body.overlay(children.next()?, renderer), } } else { - self.body.overlay(layout) + self.body.overlay(layout, renderer) } } } diff --git a/native/src/widget/pane_grid/title_bar.rs b/native/src/widget/pane_grid/title_bar.rs index 353e1ce9..ea9ebfc4 100644 --- a/native/src/widget/pane_grid/title_bar.rs +++ b/native/src/widget/pane_grid/title_bar.rs @@ -258,6 +258,7 @@ where layout: Layout<'_>, cursor_position: Point, viewport: &Rectangle, + renderer: &Renderer, ) -> mouse::Interaction { let mut children = layout.children(); let padded = children.next().unwrap(); @@ -269,13 +270,19 @@ where title_layout, cursor_position, viewport, + renderer, ); if let Some(controls) = &self.controls { let controls_layout = children.next().unwrap(); controls - .mouse_interaction(controls_layout, cursor_position, viewport) + .mouse_interaction( + controls_layout, + cursor_position, + viewport, + renderer, + ) .max(title_interaction) } else { title_interaction @@ -285,6 +292,7 @@ where pub(crate) fn overlay( &mut self, layout: Layout<'_>, + renderer: &Renderer, ) -> Option> { let mut children = layout.children(); let padded = children.next()?; @@ -296,11 +304,11 @@ where content, controls, .. } = self; - content.overlay(title_layout).or_else(move || { + content.overlay(title_layout, renderer).or_else(move || { controls.as_mut().and_then(|controls| { let controls_layout = children.next()?; - controls.overlay(controls_layout) + controls.overlay(controls_layout, renderer) }) }) } diff --git a/native/src/widget/pick_list.rs b/native/src/widget/pick_list.rs index 1f79e07a..a200fb13 100644 --- a/native/src/widget/pick_list.rs +++ b/native/src/widget/pick_list.rs @@ -331,6 +331,7 @@ where layout: Layout<'_>, cursor_position: Point, _viewport: &Rectangle, + _renderer: &Renderer, ) -> mouse::Interaction { let bounds = layout.bounds(); let is_mouse_over = bounds.contains(cursor_position); @@ -415,6 +416,7 @@ where fn overlay( &mut self, layout: Layout<'_>, + _renderer: &Renderer, ) -> Option> { if *self.is_open { let bounds = layout.bounds(); diff --git a/native/src/widget/radio.rs b/native/src/widget/radio.rs index 1dbe7cf5..c6cc46ed 100644 --- a/native/src/widget/radio.rs +++ b/native/src/widget/radio.rs @@ -209,6 +209,7 @@ where layout: Layout<'_>, cursor_position: Point, _viewport: &Rectangle, + _renderer: &Renderer, ) -> mouse::Interaction { if layout.bounds().contains(cursor_position) { mouse::Interaction::Pointer diff --git a/native/src/widget/row.rs b/native/src/widget/row.rs index a0174f79..c423d31f 100644 --- a/native/src/widget/row.rs +++ b/native/src/widget/row.rs @@ -168,6 +168,7 @@ where layout: Layout<'_>, cursor_position: Point, viewport: &Rectangle, + renderer: &Renderer, ) -> mouse::Interaction { self.children .iter() @@ -177,6 +178,7 @@ where layout, cursor_position, viewport, + renderer, ) }) .max() @@ -216,11 +218,14 @@ where fn overlay( &mut self, layout: Layout<'_>, + renderer: &Renderer, ) -> Option> { self.children .iter_mut() .zip(layout.children()) - .filter_map(|(child, layout)| child.widget.overlay(layout)) + .filter_map(|(child, layout)| { + child.widget.overlay(layout, renderer) + }) .next() } } diff --git a/native/src/widget/scrollable.rs b/native/src/widget/scrollable.rs index 3ef737c0..4b005c6b 100644 --- a/native/src/widget/scrollable.rs +++ b/native/src/widget/scrollable.rs @@ -427,6 +427,7 @@ where layout: Layout<'_>, cursor_position: Point, _viewport: &Rectangle, + renderer: &Renderer, ) -> mouse::Interaction { let bounds = layout.bounds(); let content_layout = layout.children().next().unwrap(); @@ -457,6 +458,7 @@ where y: bounds.y + offset as f32, ..bounds }, + renderer, ) } } @@ -581,11 +583,12 @@ where fn overlay( &mut self, layout: Layout<'_>, + renderer: &Renderer, ) -> Option> { let Self { content, state, .. } = self; content - .overlay(layout.children().next().unwrap()) + .overlay(layout.children().next().unwrap(), renderer) .map(|overlay| { let bounds = layout.bounds(); let content_layout = layout.children().next().unwrap(); diff --git a/native/src/widget/slider.rs b/native/src/widget/slider.rs index 65632a5c..917bfc14 100644 --- a/native/src/widget/slider.rs +++ b/native/src/widget/slider.rs @@ -361,6 +361,7 @@ where layout: Layout<'_>, cursor_position: Point, _viewport: &Rectangle, + _renderer: &Renderer, ) -> mouse::Interaction { let bounds = layout.bounds(); let is_mouse_over = bounds.contains(cursor_position); diff --git a/native/src/widget/text_input.rs b/native/src/widget/text_input.rs index f06b6aa6..03adeb12 100644 --- a/native/src/widget/text_input.rs +++ b/native/src/widget/text_input.rs @@ -764,6 +764,7 @@ where layout: Layout<'_>, cursor_position: Point, _viewport: &Rectangle, + _renderer: &Renderer, ) -> mouse::Interaction { if layout.bounds().contains(cursor_position) { mouse::Interaction::Text diff --git a/native/src/widget/toggler.rs b/native/src/widget/toggler.rs index 7eca58d2..002e0a4f 100644 --- a/native/src/widget/toggler.rs +++ b/native/src/widget/toggler.rs @@ -196,6 +196,7 @@ where layout: Layout<'_>, cursor_position: Point, _viewport: &Rectangle, + _renderer: &Renderer, ) -> mouse::Interaction { if layout.bounds().contains(cursor_position) { mouse::Interaction::Pointer diff --git a/native/src/widget/tooltip.rs b/native/src/widget/tooltip.rs index 79a57824..f6630864 100644 --- a/native/src/widget/tooltip.rs +++ b/native/src/widget/tooltip.rs @@ -147,9 +147,14 @@ where layout: Layout<'_>, cursor_position: Point, viewport: &Rectangle, + renderer: &Renderer, ) -> mouse::Interaction { - self.content - .mouse_interaction(layout, cursor_position, viewport) + self.content.mouse_interaction( + layout, + cursor_position, + viewport, + renderer, + ) } fn draw( -- cgit From 2e255b7b91264cf1e53e89dfdefd95270957b2e2 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 11 Jan 2022 14:21:38 +0700 Subject: Implement `Widget::mouse_interaction` for `Responsive` --- native/src/widget/responsive.rs | 62 +++++++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 21 deletions(-) (limited to 'native/src/widget') diff --git a/native/src/widget/responsive.rs b/native/src/widget/responsive.rs index becaa980..fd9e490a 100644 --- a/native/src/widget/responsive.rs +++ b/native/src/widget/responsive.rs @@ -1,5 +1,6 @@ use crate::event::{self, Event}; use crate::layout::{self, Layout}; +use crate::mouse; use crate::renderer; use crate::{ Clipboard, Element, Hasher, Length, Point, Rectangle, Shell, Size, Widget, @@ -74,22 +75,13 @@ where clipboard: &mut dyn Clipboard, shell: &mut Shell<'_, Message>, ) -> event::Status { - use std::ops::DerefMut; - let mut internal = self.0.borrow_mut(); - let Internal { content, state } = internal.deref_mut(); - - if state.last_size != Some(state.last_layout.size()) { + if internal.state.last_size != Some(internal.state.last_layout.size()) { shell.invalidate_widgets(); } - let content = content.resolve(state, renderer); - - let content_layout = Layout::with_offset( - layout.position() - Point::ORIGIN, - &state.last_layout, - ); + let (content, content_layout) = internal.content(layout, renderer); content.on_event( event, @@ -109,20 +101,28 @@ where cursor_position: Point, viewport: &Rectangle, ) { - use std::ops::DerefMut; - let mut internal = self.0.borrow_mut(); + let (content, content_layout) = internal.content(layout, renderer); - let Internal { content, state } = internal.deref_mut(); - - let content = content.resolve(state, renderer); + content.draw(renderer, style, content_layout, cursor_position, viewport) + } - let content_layout = Layout::with_offset( - layout.position() - Point::ORIGIN, - &state.last_layout, - ); + fn mouse_interaction( + &self, + layout: Layout<'_>, + cursor_position: Point, + viewport: &Rectangle, + renderer: &Renderer, + ) -> mouse::Interaction { + let mut internal = self.0.borrow_mut(); + let (content, content_layout) = internal.content(layout, renderer); - content.draw(renderer, style, content_layout, cursor_position, viewport) + content.mouse_interaction( + content_layout, + cursor_position, + viewport, + renderer, + ) } } @@ -131,6 +131,26 @@ struct Internal<'a, Message, Renderer> { content: Content<'a, Message, Renderer>, } +impl<'a, Message, Renderer> Internal<'a, Message, Renderer> +where + Renderer: crate::Renderer, +{ + fn content( + &mut self, + layout: Layout<'_>, + renderer: &Renderer, + ) -> (&mut Element<'a, Message, Renderer>, Layout<'_>) { + let content = self.content.resolve(&mut self.state, renderer); + + let content_layout = Layout::with_offset( + layout.position() - Point::ORIGIN, + &self.state.last_layout, + ); + + (content, content_layout) + } +} + enum Content<'a, Message, Renderer> { Pending( Option Element<'a, Message, Renderer> + 'a>>, -- cgit From 870d651f35c4dad12c805951fca70213816983de Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 12 Jan 2022 11:15:05 +0700 Subject: Implement `Widget::overlay` for `Responsive` widget --- native/src/widget/responsive.rs | 212 ---------------------------------------- 1 file changed, 212 deletions(-) delete mode 100644 native/src/widget/responsive.rs (limited to 'native/src/widget') diff --git a/native/src/widget/responsive.rs b/native/src/widget/responsive.rs deleted file mode 100644 index fd9e490a..00000000 --- a/native/src/widget/responsive.rs +++ /dev/null @@ -1,212 +0,0 @@ -use crate::event::{self, Event}; -use crate::layout::{self, Layout}; -use crate::mouse; -use crate::renderer; -use crate::{ - Clipboard, Element, Hasher, Length, Point, Rectangle, Shell, Size, Widget, -}; - -use std::cell::RefCell; -use std::hash::Hasher as _; - -#[derive(Debug, Clone, Default)] -pub struct State { - last_size: Option, - last_layout: layout::Node, - last_layout_hash: u64, -} - -impl State { - pub fn new() -> State { - State::default() - } -} - -#[allow(missing_debug_implementations)] -pub struct Responsive<'a, Message, Renderer>( - RefCell>, -); - -impl<'a, Message, Renderer> Responsive<'a, Message, Renderer> { - pub fn new( - state: &'a mut State, - view: impl FnOnce(Size) -> Element<'a, Message, Renderer> + 'a, - ) -> Self { - Self(RefCell::new(Internal { - state, - content: Content::Pending(Some(Box::new(view))), - })) - } -} - -impl<'a, Message, Renderer> Widget - for Responsive<'a, Message, Renderer> -where - Renderer: crate::Renderer, -{ - fn width(&self) -> Length { - Length::Fill - } - - fn height(&self) -> Length { - Length::Fill - } - - fn hash_layout(&self, _hasher: &mut Hasher) {} - - fn layout( - &self, - _renderer: &Renderer, - limits: &layout::Limits, - ) -> layout::Node { - let size = limits.max(); - - self.0.borrow_mut().state.last_size = Some(size); - - layout::Node::new(size) - } - - fn on_event( - &mut self, - event: Event, - layout: Layout<'_>, - cursor_position: Point, - renderer: &Renderer, - clipboard: &mut dyn Clipboard, - shell: &mut Shell<'_, Message>, - ) -> event::Status { - let mut internal = self.0.borrow_mut(); - - if internal.state.last_size != Some(internal.state.last_layout.size()) { - shell.invalidate_widgets(); - } - - let (content, content_layout) = internal.content(layout, renderer); - - content.on_event( - event, - content_layout, - cursor_position, - renderer, - clipboard, - shell, - ) - } - - fn draw( - &self, - renderer: &mut Renderer, - style: &renderer::Style, - layout: Layout<'_>, - cursor_position: Point, - viewport: &Rectangle, - ) { - let mut internal = self.0.borrow_mut(); - let (content, content_layout) = internal.content(layout, renderer); - - content.draw(renderer, style, content_layout, cursor_position, viewport) - } - - fn mouse_interaction( - &self, - layout: Layout<'_>, - cursor_position: Point, - viewport: &Rectangle, - renderer: &Renderer, - ) -> mouse::Interaction { - let mut internal = self.0.borrow_mut(); - let (content, content_layout) = internal.content(layout, renderer); - - content.mouse_interaction( - content_layout, - cursor_position, - viewport, - renderer, - ) - } -} - -struct Internal<'a, Message, Renderer> { - state: &'a mut State, - content: Content<'a, Message, Renderer>, -} - -impl<'a, Message, Renderer> Internal<'a, Message, Renderer> -where - Renderer: crate::Renderer, -{ - fn content( - &mut self, - layout: Layout<'_>, - renderer: &Renderer, - ) -> (&mut Element<'a, Message, Renderer>, Layout<'_>) { - let content = self.content.resolve(&mut self.state, renderer); - - let content_layout = Layout::with_offset( - layout.position() - Point::ORIGIN, - &self.state.last_layout, - ); - - (content, content_layout) - } -} - -enum Content<'a, Message, Renderer> { - Pending( - Option Element<'a, Message, Renderer> + 'a>>, - ), - Ready(Element<'a, Message, Renderer>), -} - -impl<'a, Message, Renderer> Content<'a, Message, Renderer> -where - Renderer: crate::Renderer, -{ - fn resolve( - &mut self, - state: &mut State, - renderer: &Renderer, - ) -> &mut Element<'a, Message, Renderer> { - match self { - Content::Ready(element) => element, - Content::Pending(view) => { - let element = - view.take().unwrap()(state.last_size.unwrap_or(Size::ZERO)); - - let new_layout_hash = { - let mut hasher = Hasher::default(); - element.hash_layout(&mut hasher); - - hasher.finish() - }; - - if new_layout_hash != state.last_layout_hash { - state.last_layout = element.layout( - renderer, - &layout::Limits::new( - Size::ZERO, - state.last_size.unwrap_or(Size::ZERO), - ), - ); - - state.last_layout_hash = new_layout_hash; - } - - *self = Content::Ready(element); - - self.resolve(state, renderer) - } - } - } -} - -impl<'a, Message, Renderer> From> - for Element<'a, Message, Renderer> -where - Renderer: crate::Renderer + 'a, - Message: 'a, -{ - fn from(responsive: Responsive<'a, Message, Renderer>) -> Self { - Self::new(responsive) - } -} -- cgit