iced_core/widget/operation/
scrollable.rs

1//! Operate on widgets that can be scrolled.
2use crate::widget::{Id, Operation};
3use crate::{Rectangle, Vector};
4
5/// The internal state of a widget that can be scrolled.
6pub trait Scrollable {
7    /// Snaps the scroll of the widget to the given `percentage` along the horizontal & vertical axis.
8    fn snap_to(&mut self, offset: RelativeOffset);
9
10    /// Scroll the widget to the given [`AbsoluteOffset`] along the horizontal & vertical axis.
11    fn scroll_to(&mut self, offset: AbsoluteOffset);
12
13    /// Scroll the widget by the given [`AbsoluteOffset`] along the horizontal & vertical axis.
14    fn scroll_by(
15        &mut self,
16        offset: AbsoluteOffset,
17        bounds: Rectangle,
18        content_bounds: Rectangle,
19    );
20}
21
22/// Produces an [`Operation`] that snaps the widget with the given [`Id`] to
23/// the provided `percentage`.
24pub fn snap_to<T>(target: Id, offset: RelativeOffset) -> impl Operation<T> {
25    struct SnapTo {
26        target: Id,
27        offset: RelativeOffset,
28    }
29
30    impl<T> Operation<T> for SnapTo {
31        fn container(
32            &mut self,
33            _id: Option<&Id>,
34            _bounds: Rectangle,
35            operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>),
36        ) {
37            operate_on_children(self);
38        }
39
40        fn scrollable(
41            &mut self,
42            id: Option<&Id>,
43            _bounds: Rectangle,
44            _content_bounds: Rectangle,
45            _translation: Vector,
46            state: &mut dyn Scrollable,
47        ) {
48            if Some(&self.target) == id {
49                state.snap_to(self.offset);
50            }
51        }
52    }
53
54    SnapTo { target, offset }
55}
56
57/// Produces an [`Operation`] that scrolls the widget with the given [`Id`] to
58/// the provided [`AbsoluteOffset`].
59pub fn scroll_to<T>(target: Id, offset: AbsoluteOffset) -> impl Operation<T> {
60    struct ScrollTo {
61        target: Id,
62        offset: AbsoluteOffset,
63    }
64
65    impl<T> Operation<T> for ScrollTo {
66        fn container(
67            &mut self,
68            _id: Option<&Id>,
69            _bounds: Rectangle,
70            operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>),
71        ) {
72            operate_on_children(self);
73        }
74
75        fn scrollable(
76            &mut self,
77            id: Option<&Id>,
78            _bounds: Rectangle,
79            _content_bounds: Rectangle,
80            _translation: Vector,
81            state: &mut dyn Scrollable,
82        ) {
83            if Some(&self.target) == id {
84                state.scroll_to(self.offset);
85            }
86        }
87    }
88
89    ScrollTo { target, offset }
90}
91
92/// Produces an [`Operation`] that scrolls the widget with the given [`Id`] by
93/// the provided [`AbsoluteOffset`].
94pub fn scroll_by<T>(target: Id, offset: AbsoluteOffset) -> impl Operation<T> {
95    struct ScrollBy {
96        target: Id,
97        offset: AbsoluteOffset,
98    }
99
100    impl<T> Operation<T> for ScrollBy {
101        fn container(
102            &mut self,
103            _id: Option<&Id>,
104            _bounds: Rectangle,
105            operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>),
106        ) {
107            operate_on_children(self);
108        }
109
110        fn scrollable(
111            &mut self,
112            id: Option<&Id>,
113            bounds: Rectangle,
114            content_bounds: Rectangle,
115            _translation: Vector,
116            state: &mut dyn Scrollable,
117        ) {
118            if Some(&self.target) == id {
119                state.scroll_by(self.offset, bounds, content_bounds);
120            }
121        }
122    }
123
124    ScrollBy { target, offset }
125}
126
127/// The amount of absolute offset in each direction of a [`Scrollable`].
128#[derive(Debug, Clone, Copy, PartialEq, Default)]
129pub struct AbsoluteOffset {
130    /// The amount of horizontal offset
131    pub x: f32,
132    /// The amount of vertical offset
133    pub y: f32,
134}
135
136/// The amount of relative offset in each direction of a [`Scrollable`].
137///
138/// A value of `0.0` means start, while `1.0` means end.
139#[derive(Debug, Clone, Copy, PartialEq, Default)]
140pub struct RelativeOffset {
141    /// The amount of horizontal offset
142    pub x: f32,
143    /// The amount of vertical offset
144    pub y: f32,
145}
146
147impl RelativeOffset {
148    /// A relative offset that points to the top-left of a [`Scrollable`].
149    pub const START: Self = Self { x: 0.0, y: 0.0 };
150
151    /// A relative offset that points to the bottom-right of a [`Scrollable`].
152    pub const END: Self = Self { x: 1.0, y: 1.0 };
153}