1pub mod focusable;
3pub mod scrollable;
4pub mod text;
5pub mod text_input;
6
7pub use focusable::Focusable;
8pub use scrollable::Scrollable;
9pub use text::Text;
10pub use text_input::TextInput;
11
12use crate::widget::Id;
13use crate::{Rectangle, Size, Vector};
14
15use std::any::Any;
16use std::fmt;
17use std::sync::Arc;
18
19pub trait Operation<T = ()>: Send {
22 fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>));
29
30 fn container(&mut self, _id: Option<&Id>, _bounds: Rectangle, _viewport: &Rectangle) {}
32
33 fn scrollable(
35 &mut self,
36 _id: Option<&Id>,
37 _bounds: Rectangle,
38 _content: Size,
39 _translation: Vector,
40 _state: &mut dyn Scrollable,
41 ) {
42 }
43
44 fn focusable(&mut self, _id: Option<&Id>, _bounds: Rectangle, _state: &mut dyn Focusable) {}
46
47 fn text_input(&mut self, _id: Option<&Id>, _bounds: Rectangle, _state: &mut dyn TextInput) {}
49
50 fn text(&mut self, _id: Option<&Id>, _bounds: Rectangle, _state: &mut dyn Text) {}
52
53 fn custom(&mut self, _id: Option<&Id>, _bounds: Rectangle, _state: &mut dyn Any) {}
55
56 fn finish(&self) -> Outcome<T> {
58 Outcome::None
59 }
60}
61
62impl<T, O> Operation<O> for Box<T>
63where
64 T: Operation<O> + ?Sized,
65{
66 fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<O>)) {
67 self.as_mut().traverse(operate);
68 }
69
70 fn container(&mut self, id: Option<&Id>, bounds: Rectangle, viewport: &Rectangle) {
71 self.as_mut().container(id, bounds, viewport);
72 }
73
74 fn focusable(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Focusable) {
75 self.as_mut().focusable(id, bounds, state);
76 }
77
78 fn scrollable(
79 &mut self,
80 id: Option<&Id>,
81 bounds: Rectangle,
82 content: Size,
83 translation: Vector,
84 state: &mut dyn Scrollable,
85 ) {
86 self.as_mut()
87 .scrollable(id, bounds, content, translation, state);
88 }
89
90 fn text_input(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn TextInput) {
91 self.as_mut().text_input(id, bounds, state);
92 }
93
94 fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &mut dyn Text) {
95 self.as_mut().text(id, bounds, text);
96 }
97
98 fn custom(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Any) {
99 self.as_mut().custom(id, bounds, state);
100 }
101
102 fn finish(&self) -> Outcome<O> {
103 self.as_ref().finish()
104 }
105}
106
107pub enum Outcome<T> {
109 None,
111
112 Some(T),
114
115 Chain(Box<dyn Operation<T>>),
117}
118
119impl<T> fmt::Debug for Outcome<T>
120where
121 T: fmt::Debug,
122{
123 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124 match self {
125 Self::None => write!(f, "Outcome::None"),
126 Self::Some(output) => write!(f, "Outcome::Some({output:?})"),
127 Self::Chain(_) => write!(f, "Outcome::Chain(...)"),
128 }
129 }
130}
131
132#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
139pub enum Animation {
140 #[default]
142 Auto,
143
144 Instant,
146
147 Smooth,
149}
150
151pub fn black_box<'a, T, O>(operation: &'a mut dyn Operation<T>) -> impl Operation<O> + 'a
153where
154 T: 'a,
155{
156 struct BlackBox<'a, T> {
157 operation: &'a mut dyn Operation<T>,
158 }
159
160 impl<T, O> Operation<O> for BlackBox<'_, T> {
161 fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<O>))
162 where
163 Self: Sized,
164 {
165 self.operation.traverse(&mut |operation| {
166 operate(&mut BlackBox { operation });
167 });
168 }
169
170 fn container(&mut self, id: Option<&Id>, bounds: Rectangle, viewport: &Rectangle) {
171 self.operation.container(id, bounds, viewport);
172 }
173
174 fn focusable(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Focusable) {
175 self.operation.focusable(id, bounds, state);
176 }
177
178 fn scrollable(
179 &mut self,
180 id: Option<&Id>,
181 bounds: Rectangle,
182 content: Size,
183 translation: Vector,
184 state: &mut dyn Scrollable,
185 ) {
186 self.operation
187 .scrollable(id, bounds, content, translation, state);
188 }
189
190 fn text_input(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn TextInput) {
191 self.operation.text_input(id, bounds, state);
192 }
193
194 fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &mut dyn Text) {
195 self.operation.text(id, bounds, text);
196 }
197
198 fn custom(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Any) {
199 self.operation.custom(id, bounds, state);
200 }
201
202 fn finish(&self) -> Outcome<O> {
203 Outcome::None
204 }
205 }
206
207 BlackBox { operation }
208}
209
210pub fn map<A, B>(
212 operation: impl Operation<A>,
213 f: impl Fn(A) -> B + Send + Sync + 'static,
214) -> impl Operation<B>
215where
216 A: 'static,
217 B: 'static,
218{
219 struct Map<O, A, B> {
220 operation: O,
221 f: Arc<dyn Fn(A) -> B + Send + Sync>,
222 }
223
224 impl<O, A, B> Operation<B> for Map<O, A, B>
225 where
226 O: Operation<A>,
227 A: 'static,
228 B: 'static,
229 {
230 fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<B>)) {
231 struct MapRef<'a, A> {
232 operation: &'a mut dyn Operation<A>,
233 }
234
235 impl<A, B> Operation<B> for MapRef<'_, A> {
236 fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<B>)) {
237 self.operation.traverse(&mut |operation| {
238 operate(&mut MapRef { operation });
239 });
240 }
241
242 fn container(&mut self, id: Option<&Id>, bounds: Rectangle, viewport: &Rectangle) {
243 let Self { operation, .. } = self;
244
245 operation.container(id, bounds, viewport);
246 }
247
248 fn scrollable(
249 &mut self,
250 id: Option<&Id>,
251 bounds: Rectangle,
252 content: Size,
253 translation: Vector,
254 state: &mut dyn Scrollable,
255 ) {
256 self.operation
257 .scrollable(id, bounds, content, translation, state);
258 }
259
260 fn focusable(
261 &mut self,
262 id: Option<&Id>,
263 bounds: Rectangle,
264 state: &mut dyn Focusable,
265 ) {
266 self.operation.focusable(id, bounds, state);
267 }
268
269 fn text_input(
270 &mut self,
271 id: Option<&Id>,
272 bounds: Rectangle,
273 state: &mut dyn TextInput,
274 ) {
275 self.operation.text_input(id, bounds, state);
276 }
277
278 fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &mut dyn Text) {
279 self.operation.text(id, bounds, text);
280 }
281
282 fn custom(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Any) {
283 self.operation.custom(id, bounds, state);
284 }
285 }
286
287 self.operation.traverse(&mut |operation| {
288 operate(&mut MapRef { operation });
289 });
290 }
291
292 fn container(&mut self, id: Option<&Id>, bounds: Rectangle, viewport: &Rectangle) {
293 self.operation.container(id, bounds, viewport);
294 }
295
296 fn focusable(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Focusable) {
297 self.operation.focusable(id, bounds, state);
298 }
299
300 fn scrollable(
301 &mut self,
302 id: Option<&Id>,
303 bounds: Rectangle,
304 content: Size,
305 translation: Vector,
306 state: &mut dyn Scrollable,
307 ) {
308 self.operation
309 .scrollable(id, bounds, content, translation, state);
310 }
311
312 fn text_input(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn TextInput) {
313 self.operation.text_input(id, bounds, state);
314 }
315
316 fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &mut dyn Text) {
317 self.operation.text(id, bounds, text);
318 }
319
320 fn custom(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Any) {
321 self.operation.custom(id, bounds, state);
322 }
323
324 fn finish(&self) -> Outcome<B> {
325 match self.operation.finish() {
326 Outcome::None => Outcome::None,
327 Outcome::Some(output) => Outcome::Some((self.f)(output)),
328 Outcome::Chain(next) => Outcome::Chain(Box::new(Map {
329 operation: next,
330 f: self.f.clone(),
331 })),
332 }
333 }
334 }
335
336 Map {
337 operation,
338 f: Arc::new(f),
339 }
340}
341
342pub fn then<A, B, O>(
345 operation: impl Operation<A> + 'static,
346 next: impl Fn(A) -> O + Send + Sync + 'static,
347) -> impl Operation<B>
348where
349 A: 'static,
350 B: 'static,
351 O: Operation<B> + 'static,
352{
353 struct Chain<T, O, A> {
354 operation: T,
355 next: Arc<dyn Fn(A) -> O + Send + Sync>,
356 }
357
358 impl<T, O, A, B> Operation<B> for Chain<T, O, A>
359 where
360 T: Operation<A> + 'static,
361 O: Operation<B> + 'static,
362 A: 'static,
363 B: 'static,
364 {
365 fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<B>)) {
366 self.operation.traverse(&mut |operation| {
367 operate(&mut black_box(operation));
368 });
369 }
370
371 fn container(&mut self, id: Option<&Id>, bounds: Rectangle, viewport: &Rectangle) {
372 self.operation.container(id, bounds, viewport);
373 }
374
375 fn focusable(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Focusable) {
376 self.operation.focusable(id, bounds, state);
377 }
378
379 fn scrollable(
380 &mut self,
381 id: Option<&Id>,
382 bounds: Rectangle,
383 content: Size,
384 translation: crate::Vector,
385 state: &mut dyn Scrollable,
386 ) {
387 self.operation
388 .scrollable(id, bounds, content, translation, state);
389 }
390
391 fn text_input(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn TextInput) {
392 self.operation.text_input(id, bounds, state);
393 }
394
395 fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &mut dyn Text) {
396 self.operation.text(id, bounds, text);
397 }
398
399 fn custom(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Any) {
400 self.operation.custom(id, bounds, state);
401 }
402
403 fn finish(&self) -> Outcome<B> {
404 match self.operation.finish() {
405 Outcome::None => Outcome::None,
406 Outcome::Some(value) => Outcome::Chain(Box::new((self.next)(value))),
407 Outcome::Chain(next) => Outcome::Chain(Box::new(Chain {
408 operation: next,
409 next: self.next.clone(),
410 })),
411 }
412 }
413 }
414
415 Chain {
416 operation,
417 next: Arc::new(next),
418 }
419}
420
421pub fn scope<T: 'static>(target: Id, operation: impl Operation<T> + 'static) -> impl Operation<T> {
424 struct ScopedOperation<Message> {
425 target: Id,
426 current: Option<Id>,
427 operation: Box<dyn Operation<Message>>,
428 }
429
430 impl<Message: 'static> Operation<Message> for ScopedOperation<Message> {
431 fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<Message>)) {
432 if self.current.as_ref() == Some(&self.target) {
433 self.operation.as_mut().traverse(operate);
434 } else {
435 operate(self);
436 }
437
438 self.current = None;
439 }
440
441 fn container(&mut self, id: Option<&Id>, _bounds: Rectangle, _viewport: &Rectangle) {
442 self.current = id.cloned();
443 }
444
445 fn finish(&self) -> Outcome<Message> {
446 match self.operation.finish() {
447 Outcome::Chain(next) => Outcome::Chain(Box::new(ScopedOperation {
448 target: self.target.clone(),
449 current: None,
450 operation: next,
451 })),
452 outcome => outcome,
453 }
454 }
455 }
456
457 ScopedOperation {
458 target,
459 current: None,
460 operation: Box::new(operation),
461 }
462}