summaryrefslogtreecommitdiffstats
path: root/widget
diff options
context:
space:
mode:
Diffstat (limited to 'widget')
-rw-r--r--widget/src/button.rs2
-rw-r--r--widget/src/column.rs2
-rw-r--r--widget/src/container.rs93
-rw-r--r--widget/src/lazy/component.rs10
-rw-r--r--widget/src/pane_grid.rs2
-rw-r--r--widget/src/row.rs2
-rw-r--r--widget/src/scrollable.rs14
7 files changed, 116 insertions, 9 deletions
diff --git a/widget/src/button.rs b/widget/src/button.rs
index 1312095f..5727c631 100644
--- a/widget/src/button.rs
+++ b/widget/src/button.rs
@@ -181,7 +181,7 @@ where
renderer: &Renderer,
operation: &mut dyn Operation<Message>,
) {
- operation.container(None, &mut |operation| {
+ operation.container(None, layout.bounds(), &mut |operation| {
self.content.as_widget().operate(
&mut tree.children[0],
layout.children().next().unwrap(),
diff --git a/widget/src/column.rs b/widget/src/column.rs
index 9271d5ef..c16477f3 100644
--- a/widget/src/column.rs
+++ b/widget/src/column.rs
@@ -148,7 +148,7 @@ where
renderer: &Renderer,
operation: &mut dyn Operation<Message>,
) {
- operation.container(None, &mut |operation| {
+ operation.container(None, layout.bounds(), &mut |operation| {
self.children
.iter()
.zip(&mut tree.children)
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,
+ })
+}
diff --git a/widget/src/lazy/component.rs b/widget/src/lazy/component.rs
index bc0e23df..19df2792 100644
--- a/widget/src/lazy/component.rs
+++ b/widget/src/lazy/component.rs
@@ -7,7 +7,8 @@ use crate::core::renderer;
use crate::core::widget;
use crate::core::widget::tree::{self, Tree};
use crate::core::{
- self, Clipboard, Element, Length, Point, Rectangle, Shell, Size, Widget,
+ self, Clipboard, Element, Length, Point, Rectangle, Shell, Size, Vector,
+ Widget,
};
use crate::runtime::overlay::Nested;
@@ -340,11 +341,12 @@ where
fn container(
&mut self,
id: Option<&widget::Id>,
+ bounds: Rectangle,
operate_on_children: &mut dyn FnMut(
&mut dyn widget::Operation<T>,
),
) {
- self.operation.container(id, &mut |operation| {
+ self.operation.container(id, bounds, &mut |operation| {
operate_on_children(&mut MapOperation { operation });
});
}
@@ -369,8 +371,10 @@ where
&mut self,
state: &mut dyn widget::operation::Scrollable,
id: Option<&widget::Id>,
+ bounds: Rectangle,
+ translation: Vector,
) {
- self.operation.scrollable(state, id);
+ self.operation.scrollable(state, id, bounds, translation);
}
fn custom(
diff --git a/widget/src/pane_grid.rs b/widget/src/pane_grid.rs
index 4f6dfbe8..0f4ab9eb 100644
--- a/widget/src/pane_grid.rs
+++ b/widget/src/pane_grid.rs
@@ -297,7 +297,7 @@ where
renderer: &Renderer,
operation: &mut dyn widget::Operation<Message>,
) {
- operation.container(None, &mut |operation| {
+ operation.container(None, layout.bounds(), &mut |operation| {
self.contents
.iter()
.zip(&mut tree.children)
diff --git a/widget/src/row.rs b/widget/src/row.rs
index 7baaaae3..99b2a0bf 100644
--- a/widget/src/row.rs
+++ b/widget/src/row.rs
@@ -137,7 +137,7 @@ where
renderer: &Renderer,
operation: &mut dyn Operation<Message>,
) {
- operation.container(None, &mut |operation| {
+ operation.container(None, layout.bounds(), &mut |operation| {
self.children
.iter()
.zip(&mut tree.children)
diff --git a/widget/src/scrollable.rs b/widget/src/scrollable.rs
index f621fb26..103e3944 100644
--- a/widget/src/scrollable.rs
+++ b/widget/src/scrollable.rs
@@ -254,10 +254,22 @@ where
) {
let state = tree.state.downcast_mut::<State>();
- operation.scrollable(state, self.id.as_ref().map(|id| &id.0));
+ let bounds = layout.bounds();
+ let content_layout = layout.children().next().unwrap();
+ let content_bounds = content_layout.bounds();
+ let translation =
+ state.translation(self.direction, bounds, content_bounds);
+
+ operation.scrollable(
+ state,
+ self.id.as_ref().map(|id| &id.0),
+ bounds,
+ translation,
+ );
operation.container(
self.id.as_ref().map(|id| &id.0),
+ bounds,
&mut |operation| {
self.content.as_widget().operate(
&mut tree.children[0],