freya_components/scrollviews/
use_scroll_controller.rs1use freya_core::prelude::*;
2use torin::prelude::Direction;
3
4#[derive(Default, PartialEq, Eq)]
5pub enum ScrollPosition {
6 #[default]
7 Start,
8 End,
9}
10
11#[derive(Default)]
12pub struct ScrollConfig {
13 pub default_vertical_position: ScrollPosition,
14 pub default_horizontal_position: ScrollPosition,
15}
16
17pub struct ScrollRequest {
18 pub(crate) position: ScrollPosition,
19 pub(crate) direction: Direction,
20 pub(crate) init: bool,
21}
22
23impl ScrollRequest {
24 pub fn new(position: ScrollPosition, direction: Direction) -> ScrollRequest {
25 ScrollRequest {
26 position,
27 direction,
28 init: false,
29 }
30 }
31}
32
33pub enum ScrollEvent {
34 X(i32),
35 Y(i32),
36}
37
38#[derive(PartialEq, Clone, Copy)]
39pub struct ScrollController {
40 notifier: State<()>,
41 requests: State<Vec<ScrollRequest>>,
42 on_scroll: State<Callback<ScrollEvent, bool>>,
43 get_scroll: State<Callback<(), (i32, i32)>>,
44}
45
46impl From<ScrollController> for (i32, i32) {
47 fn from(val: ScrollController) -> Self {
48 val.get_scroll.read().call(())
49 }
50}
51
52impl ScrollController {
53 pub fn new(x: i32, y: i32, initial_requests: Vec<ScrollRequest>) -> Self {
54 let mut scroll = State::create((x, y));
55 Self {
56 notifier: State::create(()),
57 requests: State::create(initial_requests),
58 on_scroll: State::create(Callback::new(move |ev| {
59 let current = *scroll.read();
60 match ev {
61 ScrollEvent::X(x) => {
62 scroll.write().0 = x;
63 }
64 ScrollEvent::Y(y) => {
65 scroll.write().1 = y;
66 }
67 }
68 current != *scroll.read()
69 })),
70 get_scroll: State::create(Callback::new(move |_| *scroll.read())),
71 }
72 }
73 pub fn managed(
74 notifier: State<()>,
75 requests: State<Vec<ScrollRequest>>,
76 on_scroll: State<Callback<ScrollEvent, bool>>,
77 get_scroll: State<Callback<(), (i32, i32)>>,
78 ) -> Self {
79 Self {
80 notifier,
81 requests,
82 on_scroll,
83 get_scroll,
84 }
85 }
86
87 pub fn use_apply(&mut self, width: f32, height: f32) {
88 let _ = self.notifier.read();
89 for request in self.requests.write().drain(..) {
90 match request {
91 ScrollRequest {
92 position: ScrollPosition::Start,
93 direction: Direction::Vertical,
94 ..
95 } => {
96 self.on_scroll.write().call(ScrollEvent::Y(0));
97 }
98 ScrollRequest {
99 position: ScrollPosition::Start,
100 direction: Direction::Horizontal,
101 ..
102 } => {
103 self.on_scroll.write().call(ScrollEvent::X(0));
104 }
105 ScrollRequest {
106 position: ScrollPosition::End,
107 direction: Direction::Vertical,
108 init,
109 ..
110 } => {
111 if init && height == 0. {
112 continue;
113 }
114 let (_x, y) = self.get_scroll.read().call(());
115 self.on_scroll
116 .write()
117 .call(ScrollEvent::Y(y - height as i32));
118 }
119 ScrollRequest {
120 position: ScrollPosition::End,
121 direction: Direction::Horizontal,
122 init,
123 ..
124 } => {
125 if init && width == 0. {
126 continue;
127 }
128
129 let (x, _y) = self.get_scroll.read().call(());
130 self.on_scroll
131 .write()
132 .call(ScrollEvent::X(x - width as i32));
133 }
134 }
135 }
136 }
137
138 pub fn scroll_to_x(&mut self, to: i32) -> bool {
139 self.on_scroll.write().call(ScrollEvent::X(to))
140 }
141
142 pub fn scroll_to_y(&mut self, to: i32) -> bool {
143 self.on_scroll.write().call(ScrollEvent::Y(to))
144 }
145
146 pub fn scroll_to(&mut self, scroll_position: ScrollPosition, scroll_direction: Direction) {
147 self.requests
148 .write()
149 .push(ScrollRequest::new(scroll_position, scroll_direction));
150 self.notifier.write();
151 }
152}
153
154pub fn use_scroll_controller(init: impl FnOnce() -> ScrollConfig) -> ScrollController {
155 use_hook(|| {
156 let config = init();
157
158 ScrollController::new(
159 0,
160 0,
161 vec![
162 ScrollRequest {
163 position: config.default_vertical_position,
164 direction: Direction::Vertical,
165 init: true,
166 },
167 ScrollRequest {
168 position: config.default_horizontal_position,
169 direction: Direction::Horizontal,
170 init: true,
171 },
172 ],
173 )
174 })
175}