diff options
author | 2023-07-27 01:02:28 +0200 | |
---|---|---|
committer | 2023-07-27 01:04:18 +0200 | |
commit | e2ba7ece83f141c149659747977147392df008f4 (patch) | |
tree | 5fa04524d0ca95c6289c4d5962af7a97098ec811 /widget/src/container.rs | |
parent | e29754f32d03efc4b075e9b63cc554d128bc2ccf (diff) | |
download | iced-e2ba7ece83f141c149659747977147392df008f4.tar.gz iced-e2ba7ece83f141c149659747977147392df008f4.tar.bz2 iced-e2ba7ece83f141c149659747977147392df008f4.zip |
Introduce `visible_bounds` operation for `Container`
Diffstat (limited to 'widget/src/container.rs')
-rw-r--r-- | widget/src/container.rs | 93 |
1 files changed, 92 insertions, 1 deletions
diff --git a/widget/src/container.rs b/widget/src/container.rs index 64cf5cd5..1f1df861 100644 --- a/widget/src/container.rs +++ b/widget/src/container.rs @@ -8,8 +8,9 @@ use crate::core::renderer; use crate::core::widget::{self, Operation, Tree}; use crate::core::{ Background, Clipboard, Color, Element, Layout, Length, Padding, Pixels, - Point, Rectangle, Shell, Widget, + Point, Rectangle, Shell, Size, Vector, Widget, }; +use crate::runtime::Command; pub use iced_style::container::{Appearance, StyleSheet}; @@ -180,6 +181,7 @@ where ) { operation.container( self.id.as_ref().map(|id| &id.0), + layout.bounds(), &mut |operation| { self.content.as_widget().operate( &mut tree.children[0], @@ -368,3 +370,92 @@ impl From<Id> for widget::Id { id.0 } } + +/// Produces a [`Command`] that queries the visible screen bounds of the +/// [`Container`] with the given [`Id`]. +pub fn visible_bounds(id: Id) -> Command<Option<Rectangle>> { + struct VisibleBounds { + target: widget::Id, + depth: usize, + scrollables: Vec<(Vector, Rectangle, usize)>, + bounds: Option<Rectangle>, + } + + impl Operation<Option<Rectangle>> for VisibleBounds { + fn scrollable( + &mut self, + _state: &mut dyn widget::operation::Scrollable, + _id: Option<&widget::Id>, + bounds: Rectangle, + translation: Vector, + ) { + match self.scrollables.last() { + Some((last_translation, last_viewport, _depth)) => { + let viewport = last_viewport + .intersection(&(bounds - *last_translation)) + .unwrap_or(Rectangle::new(Point::ORIGIN, Size::ZERO)); + + self.scrollables.push(( + translation + *last_translation, + viewport, + self.depth, + )); + } + None => { + self.scrollables.push((translation, bounds, self.depth)); + } + } + } + + fn container( + &mut self, + id: Option<&widget::Id>, + bounds: Rectangle, + operate_on_children: &mut dyn FnMut( + &mut dyn Operation<Option<Rectangle>>, + ), + ) { + if self.bounds.is_some() { + return; + } + + if id == Some(&self.target) { + match self.scrollables.last() { + Some((translation, viewport, _)) => { + self.bounds = + viewport.intersection(&(bounds - *translation)); + } + None => { + self.bounds = Some(bounds); + } + } + + return; + } + + self.depth += 1; + + operate_on_children(self); + + self.depth -= 1; + + match self.scrollables.last() { + Some((_, _, depth)) if self.depth == *depth => { + let _ = self.scrollables.pop(); + } + _ => {} + } + } + + fn finish(&self) -> widget::operation::Outcome<Option<Rectangle>> { + widget::operation::Outcome::Some(self.bounds) + } + } + + Command::widget(VisibleBounds { + target: id.into(), + depth: 0, + scrollables: Vec::new(), + bounds: None, + }) +} |