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