summaryrefslogtreecommitdiffstats
path: root/widget/src/container.rs
diff options
context:
space:
mode:
Diffstat (limited to 'widget/src/container.rs')
-rw-r--r--widget/src/container.rs133
1 files changed, 116 insertions, 17 deletions
diff --git a/widget/src/container.rs b/widget/src/container.rs
index da9a31d6..ee7a4965 100644
--- a/widget/src/container.rs
+++ b/widget/src/container.rs
@@ -5,11 +5,13 @@ use crate::core::layout;
use crate::core::mouse;
use crate::core::overlay;
use crate::core::renderer;
-use crate::core::widget::{self, Operation, Tree};
+use crate::core::widget::tree::{self, Tree};
+use crate::core::widget::{self, Operation};
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};
@@ -134,12 +136,20 @@ where
Renderer: crate::core::Renderer,
Renderer::Theme: StyleSheet,
{
+ fn tag(&self) -> tree::Tag {
+ self.content.as_widget().tag()
+ }
+
+ fn state(&self) -> tree::State {
+ self.content.as_widget().state()
+ }
+
fn children(&self) -> Vec<Tree> {
- vec![Tree::new(&self.content)]
+ self.content.as_widget().children()
}
fn diff(&self, tree: &mut Tree) {
- tree.diff_children(std::slice::from_ref(&self.content))
+ self.content.as_widget().diff(tree);
}
fn width(&self) -> Length {
@@ -152,11 +162,11 @@ where
fn layout(
&self,
+ tree: &mut Tree,
renderer: &Renderer,
limits: &layout::Limits,
) -> layout::Node {
layout(
- renderer,
limits,
self.width,
self.height,
@@ -165,9 +175,7 @@ where
self.padding,
self.horizontal_alignment,
self.vertical_alignment,
- |renderer, limits| {
- self.content.as_widget().layout(renderer, limits)
- },
+ |limits| self.content.as_widget().layout(tree, renderer, limits),
)
}
@@ -180,9 +188,10 @@ where
) {
operation.container(
self.id.as_ref().map(|id| &id.0),
+ layout.bounds(),
&mut |operation| {
self.content.as_widget().operate(
- &mut tree.children[0],
+ tree,
layout.children().next().unwrap(),
renderer,
operation,
@@ -200,15 +209,17 @@ where
renderer: &Renderer,
clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>,
+ viewport: &Rectangle,
) -> event::Status {
self.content.as_widget_mut().on_event(
- &mut tree.children[0],
+ tree,
event,
layout.children().next().unwrap(),
cursor,
renderer,
clipboard,
shell,
+ viewport,
)
}
@@ -221,7 +232,7 @@ where
renderer: &Renderer,
) -> mouse::Interaction {
self.content.as_widget().mouse_interaction(
- &tree.children[0],
+ tree,
layout.children().next().unwrap(),
cursor,
viewport,
@@ -244,7 +255,7 @@ where
draw_background(renderer, &style, layout.bounds());
self.content.as_widget().draw(
- &tree.children[0],
+ tree,
renderer,
theme,
&renderer::Style {
@@ -265,7 +276,7 @@ where
renderer: &Renderer,
) -> Option<overlay::Element<'b, Message, Renderer>> {
self.content.as_widget_mut().overlay(
- &mut tree.children[0],
+ tree,
layout.children().next().unwrap(),
renderer,
)
@@ -287,8 +298,7 @@ where
}
/// Computes the layout of a [`Container`].
-pub fn layout<Renderer>(
- renderer: &Renderer,
+pub fn layout(
limits: &layout::Limits,
width: Length,
height: Length,
@@ -297,7 +307,7 @@ pub fn layout<Renderer>(
padding: Padding,
horizontal_alignment: alignment::Horizontal,
vertical_alignment: alignment::Vertical,
- layout_content: impl FnOnce(&Renderer, &layout::Limits) -> layout::Node,
+ layout_content: impl FnOnce(&layout::Limits) -> layout::Node,
) -> layout::Node {
let limits = limits
.loose()
@@ -306,7 +316,7 @@ pub fn layout<Renderer>(
.width(width)
.height(height);
- let mut content = layout_content(renderer, &limits.pad(padding).loose());
+ let mut content = layout_content(&limits.pad(padding).loose());
let padding = padding.fit(content.size(), limits.max());
let size = limits.pad(padding).resolve(content.size());
@@ -366,3 +376,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,
+ })
+}