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 traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {
32            operate(self);
33        }
34
35        fn scrollable(
36            &mut self,
37            id: Option<&Id>,
38            _bounds: Rectangle,
39            _content_bounds: Rectangle,
40            _translation: Vector,
41            state: &mut dyn Scrollable,
42        ) {
43            if Some(&self.target) == id {
44                state.snap_to(self.offset);
45            }
46        }
47    }
48
49    SnapTo { target, offset }
50}
51
52/// Produces an [`Operation`] that scrolls the widget with the given [`Id`] to
53/// the provided [`AbsoluteOffset`].
54pub fn scroll_to<T>(target: Id, offset: AbsoluteOffset) -> impl Operation<T> {
55    struct ScrollTo {
56        target: Id,
57        offset: AbsoluteOffset,
58    }
59
60    impl<T> Operation<T> for ScrollTo {
61        fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {
62            operate(self);
63        }
64
65        fn scrollable(
66            &mut self,
67            id: Option<&Id>,
68            _bounds: Rectangle,
69            _content_bounds: Rectangle,
70            _translation: Vector,
71            state: &mut dyn Scrollable,
72        ) {
73            if Some(&self.target) == id {
74                state.scroll_to(self.offset);
75            }
76        }
77    }
78
79    ScrollTo { target, offset }
80}
81
82/// Produces an [`Operation`] that scrolls the widget with the given [`Id`] by
83/// the provided [`AbsoluteOffset`].
84pub fn scroll_by<T>(target: Id, offset: AbsoluteOffset) -> impl Operation<T> {
85    struct ScrollBy {
86        target: Id,
87        offset: AbsoluteOffset,
88    }
89
90    impl<T> Operation<T> for ScrollBy {
91        fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {
92            operate(self);
93        }
94
95        fn scrollable(
96            &mut self,
97            id: Option<&Id>,
98            bounds: Rectangle,
99            content_bounds: Rectangle,
100            _translation: Vector,
101            state: &mut dyn Scrollable,
102        ) {
103            if Some(&self.target) == id {
104                state.scroll_by(self.offset, bounds, content_bounds);
105            }
106        }
107    }
108
109    ScrollBy { target, offset }
110}
111
112/// The amount of absolute offset in each direction of a [`Scrollable`].
113#[derive(Debug, Clone, Copy, PartialEq, Default)]
114pub struct AbsoluteOffset {
115    /// The amount of horizontal offset
116    pub x: f32,
117    /// The amount of vertical offset
118    pub y: f32,
119}
120
121/// The amount of relative offset in each direction of a [`Scrollable`].
122///
123/// A value of `0.0` means start, while `1.0` means end.
124#[derive(Debug, Clone, Copy, PartialEq, Default)]
125pub struct RelativeOffset {
126    /// The amount of horizontal offset
127    pub x: f32,
128    /// The amount of vertical offset
129    pub y: f32,
130}
131
132impl RelativeOffset {
133    /// A relative offset that points to the top-left of a [`Scrollable`].
134    pub const START: Self = Self { x: 0.0, y: 0.0 };
135
136    /// A relative offset that points to the bottom-right of a [`Scrollable`].
137    pub const END: Self = Self { x: 1.0, y: 1.0 };
138}