summaryrefslogtreecommitdiffstats
path: root/widget/src/container.rs
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2023-07-27 01:02:28 +0200
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2023-07-27 01:04:18 +0200
commite2ba7ece83f141c149659747977147392df008f4 (patch)
tree5fa04524d0ca95c6289c4d5962af7a97098ec811 /widget/src/container.rs
parente29754f32d03efc4b075e9b63cc554d128bc2ccf (diff)
downloadiced-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.rs93
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,
+ })
+}