1use std::rc::Rc;
2
3use crate::Vec2;
4
5#[derive(Clone, Copy, Debug, PartialEq, Eq)]
7pub enum NestedScrollSource {
8 UserInput,
9 SideEffect,
10}
11
12pub type PreScrollFn = Rc<dyn Fn(Vec2, NestedScrollSource) -> Vec2>;
13pub type PostScrollFn = Rc<dyn Fn(Vec2, Vec2, NestedScrollSource) -> Vec2>;
14
15#[derive(Clone, Default)]
16pub struct NestedScrollConnection {
17 pub on_pre_scroll: Option<PreScrollFn>,
18 pub on_post_scroll: Option<PostScrollFn>,
19 pub on_pre_fling: Option<PreScrollFn>,
20 pub on_post_fling: Option<PostScrollFn>,
21}
22
23impl std::fmt::Debug for NestedScrollConnection {
24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25 f.debug_struct("NestedScrollConnection")
26 .field("has_pre_scroll", &self.on_pre_scroll.is_some())
27 .field("has_post_scroll", &self.on_post_scroll.is_some())
28 .field("has_pre_fling", &self.on_pre_fling.is_some())
29 .field("has_post_fling", &self.on_post_fling.is_some())
30 .finish()
31 }
32}
33
34impl NestedScrollConnection {
35 pub fn new() -> Self {
36 Self::default()
37 }
38
39 pub fn on_pre_scroll(mut self, f: impl Fn(Vec2, NestedScrollSource) -> Vec2 + 'static) -> Self {
40 self.on_pre_scroll = Some(Rc::new(f));
41 self
42 }
43
44 pub fn on_post_scroll(
45 mut self,
46 f: impl Fn(Vec2, Vec2, NestedScrollSource) -> Vec2 + 'static,
47 ) -> Self {
48 self.on_post_scroll = Some(Rc::new(f));
49 self
50 }
51
52 pub fn on_pre_fling(mut self, f: impl Fn(Vec2, NestedScrollSource) -> Vec2 + 'static) -> Self {
53 self.on_pre_fling = Some(Rc::new(f));
54 self
55 }
56
57 pub fn on_post_fling(
58 mut self,
59 f: impl Fn(Vec2, Vec2, NestedScrollSource) -> Vec2 + 'static,
60 ) -> Self {
61 self.on_post_fling = Some(Rc::new(f));
62 self
63 }
64
65 pub fn dispatch_pre_scroll(&self, available: Vec2, source: NestedScrollSource) -> Vec2 {
66 self.on_pre_scroll
67 .as_ref()
68 .map(|f| f(available, source))
69 .unwrap_or(Vec2::ZERO)
70 }
71
72 pub fn dispatch_post_scroll(
73 &self,
74 consumed: Vec2,
75 available: Vec2,
76 source: NestedScrollSource,
77 ) -> Vec2 {
78 self.on_post_scroll
79 .as_ref()
80 .map(|f| f(consumed, available, source))
81 .unwrap_or(Vec2::ZERO)
82 }
83
84 pub fn dispatch_pre_fling(&self, available: Vec2, source: NestedScrollSource) -> Vec2 {
85 self.on_pre_fling
86 .as_ref()
87 .map(|f| f(available, source))
88 .unwrap_or(Vec2::ZERO)
89 }
90
91 pub fn dispatch_post_fling(
92 &self,
93 consumed: Vec2,
94 available: Vec2,
95 source: NestedScrollSource,
96 ) -> Vec2 {
97 self.on_post_fling
98 .as_ref()
99 .map(|f| f(consumed, available, source))
100 .unwrap_or(Vec2::ZERO)
101 }
102
103 pub fn then(&self, further: &Self) -> Self {
104 let on_pre_scroll: Option<PreScrollFn> = match (&self.on_pre_scroll, &further.on_pre_scroll)
105 {
106 (Some(close), Some(far)) => {
107 let close = close.clone();
108 let far = far.clone();
109 Some(Rc::new(move |v, s| {
110 let fc = far(v, s);
111 let cc = close(v - fc, s);
112 fc + cc
113 }))
114 }
115 (Some(close), None) => Some(close.clone()),
116 (None, Some(far)) => Some(far.clone()),
117 (None, None) => None,
118 };
119 let on_post_scroll: Option<PostScrollFn> =
120 match (&self.on_post_scroll, &further.on_post_scroll) {
121 (Some(close), Some(far)) => {
122 let close = close.clone();
123 let far = far.clone();
124 Some(Rc::new(move |consumed, available, s| {
125 let cc = close(consumed, available, s);
126 let fc = far(consumed + cc, available - cc, s);
127 cc + fc
128 }))
129 }
130 (Some(close), None) => Some(close.clone()),
131 (None, Some(far)) => Some(far.clone()),
132 (None, None) => None,
133 };
134 let on_pre_fling: Option<PreScrollFn> = match (&self.on_pre_fling, &further.on_pre_fling) {
135 (Some(close), Some(far)) => {
136 let close = close.clone();
137 let far = far.clone();
138 Some(Rc::new(move |v, s| {
139 let fc = far(v, s);
140 let cc = close(v - fc, s);
141 fc + cc
142 }))
143 }
144 (Some(close), None) => Some(close.clone()),
145 (None, Some(far)) => Some(far.clone()),
146 (None, None) => None,
147 };
148 let on_post_fling: Option<PostScrollFn> = match (&self.on_post_fling, &further.on_post_fling)
149 {
150 (Some(close), Some(far)) => {
151 let close = close.clone();
152 let far = far.clone();
153 Some(Rc::new(move |consumed, available, s| {
154 let cc = close(consumed, available, s);
155 let fc = far(consumed + cc, available - cc, s);
156 cc + fc
157 }))
158 }
159 (Some(close), None) => Some(close.clone()),
160 (None, Some(far)) => Some(far.clone()),
161 (None, None) => None,
162 };
163 Self {
164 on_pre_scroll,
165 on_post_scroll,
166 on_pre_fling,
167 on_post_fling,
168 }
169 }
170}