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<Option<f32>>);
9
10    /// Scroll the widget to the given [`AbsoluteOffset`] along the horizontal & vertical axis.
11    fn scroll_to(&mut self, offset: AbsoluteOffset<Option<f32>>);
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>(
25    target: Id,
26    offset: RelativeOffset<Option<f32>>,
27) -> impl Operation<T> {
28    struct SnapTo {
29        target: Id,
30        offset: RelativeOffset<Option<f32>>,
31    }
32
33    impl<T> Operation<T> for SnapTo {
34        fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {
35            operate(self);
36        }
37
38        fn scrollable(
39            &mut self,
40            id: Option<&Id>,
41            _bounds: Rectangle,
42            _content_bounds: Rectangle,
43            _translation: Vector,
44            state: &mut dyn Scrollable,
45        ) {
46            if Some(&self.target) == id {
47                state.snap_to(self.offset);
48            }
49        }
50    }
51
52    SnapTo { target, offset }
53}
54
55/// Produces an [`Operation`] that scrolls the widget with the given [`Id`] to
56/// the provided [`AbsoluteOffset`].
57pub fn scroll_to<T>(
58    target: Id,
59    offset: AbsoluteOffset<Option<f32>>,
60) -> impl Operation<T> {
61    struct ScrollTo {
62        target: Id,
63        offset: AbsoluteOffset<Option<f32>>,
64    }
65
66    impl<T> Operation<T> for ScrollTo {
67        fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {
68            operate(self);
69        }
70
71        fn scrollable(
72            &mut self,
73            id: Option<&Id>,
74            _bounds: Rectangle,
75            _content_bounds: Rectangle,
76            _translation: Vector,
77            state: &mut dyn Scrollable,
78        ) {
79            if Some(&self.target) == id {
80                state.scroll_to(self.offset);
81            }
82        }
83    }
84
85    ScrollTo { target, offset }
86}
87
88/// Produces an [`Operation`] that scrolls the widget with the given [`Id`] by
89/// the provided [`AbsoluteOffset`].
90pub fn scroll_by<T>(target: Id, offset: AbsoluteOffset) -> impl Operation<T> {
91    struct ScrollBy {
92        target: Id,
93        offset: AbsoluteOffset,
94    }
95
96    impl<T> Operation<T> for ScrollBy {
97        fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {
98            operate(self);
99        }
100
101        fn scrollable(
102            &mut self,
103            id: Option<&Id>,
104            bounds: Rectangle,
105            content_bounds: Rectangle,
106            _translation: Vector,
107            state: &mut dyn Scrollable,
108        ) {
109            if Some(&self.target) == id {
110                state.scroll_by(self.offset, bounds, content_bounds);
111            }
112        }
113    }
114
115    ScrollBy { target, offset }
116}
117
118/// The amount of absolute offset in each direction of a [`Scrollable`].
119#[derive(Debug, Clone, Copy, PartialEq, Default)]
120pub struct AbsoluteOffset<T = f32> {
121    /// The amount of horizontal offset
122    pub x: T,
123    /// The amount of vertical offset
124    pub y: T,
125}
126
127impl From<AbsoluteOffset> for AbsoluteOffset<Option<f32>> {
128    fn from(offset: AbsoluteOffset) -> Self {
129        Self {
130            x: Some(offset.x),
131            y: Some(offset.y),
132        }
133    }
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<T = f32> {
141    /// The amount of horizontal offset
142    pub x: T,
143    /// The amount of vertical offset
144    pub y: T,
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}
154
155impl From<RelativeOffset> for RelativeOffset<Option<f32>> {
156    fn from(offset: RelativeOffset) -> Self {
157        Self {
158            x: Some(offset.x),
159            y: Some(offset.y),
160        }
161    }
162}