chargrid_common/control_flow/boxed.rs
1pub use crate::control_flow::LoopControl;
2use crate::{
3 align::Alignment,
4 border::BorderStyle,
5 control_flow::{
6 Lens, OrClickOut, OrClose, OrEscape, OrEscapeOrClickOut, OrEscapeOrStart, unboxed,
7 },
8 pad_by::Padding,
9};
10pub use chargrid_core::app;
11use chargrid_core::{
12 BoxedComponent, Component, Ctx, Event, FrameBuffer, ICoord, Rgba32, Style, Tint, UCoord, input,
13};
14use std::time::Duration;
15
16/// A component which exposes additional methods for sequencing control flow operations. For
17/// components which notionally yield a single value of type `T` (e.g. a menu from which a single
18/// selection may be made), the convention is to have their `CF` yield a result of `Option<T>`.
19/// In such a case, a value of `None` will be yielded in response to all input until the component
20/// "completes" (e.g. in the menu example, until the selection is made), at which point `Some(...)`
21/// will be yielded containing a value representing the result of the component. In these cases,
22/// unless specified otherwise, it's considered unspecified behaviour to present a completed
23/// component with input events.
24pub struct CF<O, S>(unboxed::CF<BoxedComponent<O, S>>);
25
26/// Build a new `CF` from an existing component
27pub fn cf<C: 'static + Component>(component: C) -> CF<C::Output, C::State>
28where
29 C::State: Sized,
30{
31 CF(unboxed::cf(BoxedComponent(Box::new(component))))
32}
33
34impl<O, S> From<BoxedComponent<O, S>> for CF<O, S> {
35 fn from(boxed_component: BoxedComponent<O, S>) -> Self {
36 CF(unboxed::cf(boxed_component))
37 }
38}
39
40impl<O, S> Component for CF<O, S> {
41 type Output = O;
42 type State = S;
43 fn render(&self, state: &Self::State, ctx: Ctx, fb: &mut FrameBuffer) {
44 self.0.render(state, ctx, fb);
45 }
46 fn update(&mut self, state: &mut Self::State, ctx: Ctx, event: Event) -> Self::Output {
47 self.0.update(state, ctx, event)
48 }
49 fn size(&self, state: &Self::State, ctx: Ctx) -> UCoord {
50 self.0.size(state, ctx)
51 }
52}
53
54impl<O: 'static, S: 'static> CF<O, S> {
55 /// Change the expected `State` of `self` by applying a `Lens`.
56 pub fn lens_state<S_, L>(self, lens: L) -> CF<O, S_>
57 where
58 S_: 'static,
59 L: 'static + Lens<Input = S_, Output = S>,
60 {
61 self.0.lens_state(lens).boxed()
62 }
63
64 /// Convenience method to change the result type to an option whose
65 /// value is `Some(<existing value>)`
66 pub fn some(self) -> CF<Option<O>, S> {
67 self.0.some().boxed()
68 }
69
70 /// Convenience method to change the result type to an option whose
71 /// value is `None`
72 pub fn none(self) -> CF<Option<O>, S> {
73 self.0.none().boxed()
74 }
75
76 /// Returns a new `CF` with identical behaviour to `self`, but which
77 /// is rendered over a passive component `background` with a given
78 /// `Tint` applied when rendered (`self` is rendered as normal)
79 pub fn overlay_tint<D: 'static + Component<State = S>, T: 'static + Tint>(
80 self,
81 background: D,
82 tint: T,
83 depth_delta: i8,
84 ) -> Self {
85 self.0.overlay_tint(background, tint, depth_delta).boxed()
86 }
87
88 /// Returns a new `CF` with identical behaviour to `self`, but which
89 /// is rendered over a passive component `background`
90 pub fn overlay<D: 'static + Component<State = S>>(
91 self,
92 background: D,
93 depth_delta: i8,
94 ) -> Self {
95 self.0.overlay(background, depth_delta).boxed()
96 }
97
98 /// Returns a new `CF` with identical behaviour to `self` but the
99 /// frame is cleared before rendering. Useful as the outer-most layer
100 /// of an application
101 pub fn clear_each_frame(self) -> Self {
102 self.0.clear_each_frame().boxed()
103 }
104
105 /// Returns a new `CF` with identical behaviour to `self` but whose
106 /// background has been filled in with a given colour
107 pub fn fill(self, background: Rgba32) -> Self {
108 self.0.fill(background).boxed()
109 }
110
111 /// Returns a new `CF` with identical behaviour to `self` but with
112 /// a border of specified style
113 pub fn border(self, style: BorderStyle) -> Self {
114 self.0.border(style).boxed()
115 }
116
117 /// Returns a new `CF` with identical behaviour to `self` but
118 /// padded to a given size
119 pub fn pad_to(self, size: UCoord) -> Self {
120 self.0.pad_to(size).boxed()
121 }
122
123 /// Returns a new `CF` with identical behaviour to `self` but
124 /// padded by a given size
125 pub fn pad_by(self, padding: Padding) -> Self {
126 self.0.pad_by(padding).boxed()
127 }
128
129 /// Returns a new `CF` with identical behaviour to `self` but
130 /// with a specified alignment
131 pub fn align(self, alignment: Alignment) -> Self {
132 self.0.align(alignment).boxed()
133 }
134
135 /// Returns a new `CF` with identical behaviour to `self` but
136 /// centered within its parent component
137 pub fn centre(self) -> Self {
138 self.0.centre().boxed()
139 }
140
141 /// Returns a new `CF` with identical behaviour to `self` but
142 /// with a specified offset applied when rendsering
143 pub fn add_offset(self, offset: ICoord) -> Self {
144 self.0.add_offset(offset).boxed()
145 }
146
147 /// Returns a new `CF` with identical behaviour to `self` but
148 /// with a specified horizontal offset
149 pub fn add_x(self, x: i32) -> Self {
150 self.0.add_x(x).boxed()
151 }
152
153 /// Returns a new `CF` with identical behaviour to `self` but
154 /// with a specified vertical offset
155 pub fn add_y(self, y: i32) -> Self {
156 self.0.add_y(y).boxed()
157 }
158
159 /// Returns a new `CF` with identical behaviour to `self` but
160 /// whose size has been overridden to a specific value
161 pub fn set_size(self, size: UCoord) -> Self {
162 self.0.set_size(size).boxed()
163 }
164
165 /// Returns a new `CF` with identical behaviour to `self` but
166 /// whose width has been overridden to a specific value
167 pub fn set_width(self, width: u32) -> Self {
168 self.0.set_width(width).boxed()
169 }
170
171 /// Returns a new `CF` with identical behaviour to `self` but
172 /// whose height has been overridden to a specific value
173 pub fn set_height(self, height: u32) -> Self {
174 self.0.set_height(height).boxed()
175 }
176
177 /// Returns a new `CF` with identical behaviour to `self` but
178 /// whose size is bounded by some minimum size
179 pub fn bound_size(self, size: UCoord) -> Self {
180 self.0.bound_size(size).boxed()
181 }
182
183 /// Returns a new `CF` with identical behaviour to `self` but
184 /// whose width is bounded by some minimum width
185 pub fn bound_width(self, width: u32) -> Self {
186 self.0.bound_width(width).boxed()
187 }
188
189 /// Returns a new `CF` with identical behaviour to `self` but
190 /// whose height is bounded by some minimum height
191 pub fn bound_height(self, height: u32) -> Self {
192 self.0.bound_height(height).boxed()
193 }
194
195 /// Returns a new `CF` with identical behaviour to `self` but
196 /// with an additional component rendered on top with a specified
197 /// padding. Useful for adding title text to components
198 pub fn with_title_vertical<T: 'static + Component<State = S>>(
199 self,
200 title: T,
201 padding: i32,
202 ) -> Self {
203 self.0.with_title_vertical(title, padding).boxed()
204 }
205
206 /// Returns a new `CF` with identical behaviour to `self` but
207 /// with an additional component rendered to the left with a specified
208 /// padding. Useful for adding labels to fields.
209 pub fn with_title_horizontal<T: 'static + Component<State = S>>(
210 self,
211 title: T,
212 padding: i32,
213 ) -> Self {
214 self.0.with_title_horizontal(title, padding).boxed()
215 }
216}
217
218impl<O: 'static, S: 'static> CF<O, S> {
219 /// Internalizes the expected `State` of a `CF` to a given value, and
220 /// produces a new `CF` expecting no external state (ie. it expects `()`
221 /// as its external state). The specified value will be presented as the
222 /// `State` to the callee.
223 pub fn with_state(self, state: S) -> CF<O, ()> {
224 self.0.with_state(state).boxed()
225 }
226}
227
228impl<S: 'static> CF<(), S> {
229 /// Takes a `CF` which yields no value, and creates a new `CF` which renders the same,
230 /// but which yields `None` until a specified `Duration` has passed, at which point it
231 /// yields `Some(())`
232 pub fn delay(self, duration: Duration) -> CF<Option<()>, S> {
233 self.0.delay(duration).boxed()
234 }
235
236 /// Takes a `CF` which yields no value, and creates a new `CF` which renders the same,
237 /// but which yields `None` until a key is pressed, at which point it yields `Some(())`
238 pub fn press_any_key(self) -> CF<Option<()>, S> {
239 self.0.press_any_key().boxed()
240 }
241}
242
243impl<T: 'static, S: 'static> CF<Option<T>, S> {
244 /// Creates a `CF` which behaves the same as `self` until `self` completes, at which point a
245 /// given function is invoked on `self` and the result of `self` completing. An example of when
246 /// this is necessary is a menu from which a single selection can be made, but which preserves
247 /// the most-recently highlighted entry the next time it is opened. One could store the state
248 /// representing the currently-highlighted entry in the menu component itself, and have the
249 /// menu yield the selection when the component completes. Since `f` is invoked on the
250 /// component as well as its result, it's free to leak the component through its return value
251 /// so the menu can be re-invoked with its internal state preserved. This is only valid for
252 /// components which may complete multiple times, of which `chargrid_common::menu::MenuCF` is
253 /// an example.
254 pub fn and_then_persistent<U, D, F>(self, f: F) -> CF<Option<U>, S>
255 where
256 D: 'static + Component<Output = Option<U>, State = S>,
257 F: 'static + FnOnce(Self, T) -> D,
258 {
259 self.0.and_then_persistent(|a, b| f(a.into(), b)).boxed()
260 }
261
262 /// Invoke a function `f` on the result of `self` when it completes. The given function returns
263 /// a new component which replaces `self`. Use to sequence multiple components one after the
264 /// other.
265 pub fn and_then<U, D, F>(self, f: F) -> CF<Option<U>, S>
266 where
267 D: 'static + Component<Output = Option<U>, State = S>,
268 F: 'static + FnOnce(T) -> D,
269 {
270 self.0.and_then(f).boxed()
271 }
272
273 /// Invoke a function `f` on the result of `self` when it completes. The given function returns
274 /// a new component which replaces `self`. Use to sequence multiple components one after the
275 /// other. Unlike with `and_then`, the given function is also passed a mutable reference to the
276 /// state.
277 pub fn and_then_side_effect<U, D, F>(self, f: F) -> CF<Option<U>, S>
278 where
279 D: 'static + Component<Output = Option<U>, State = S>,
280 F: 'static + FnOnce(T, &mut S) -> D,
281 {
282 self.0.and_then_side_effect(f).boxed()
283 }
284
285 /// Invoke a function `f` after `self` completes, ignoring the result. The given function
286 /// returns a new component which replaces `self`.
287 pub fn then<U, D, F>(self, f: F) -> CF<Option<U>, S>
288 where
289 D: 'static + Component<Output = Option<U>, State = S>,
290 F: 'static + FnOnce() -> D,
291 {
292 self.0.then(f).boxed()
293 }
294
295 /// Invoke a function `f` after `self` completes, ignoring the result. The given function
296 /// returns a new component which replaces `self`. Unlike with `then`, the given function is
297 /// also passed a mutable reference to the state.
298 pub fn then_side_effect<U, D, F>(self, f: F) -> CF<Option<U>, S>
299 where
300 D: 'static + Component<Output = Option<U>, State = S>,
301 F: 'static + FnOnce(&mut S) -> D,
302 {
303 self.0.then_side_effect(f).boxed()
304 }
305
306 /// Invoke a function `f` on a mutable reference to the external state, after `self` completes.
307 /// The behaviour of `self` is otherwise unchanged.
308 pub fn side_effect<F>(self, f: F) -> CF<Option<T>, S>
309 where
310 F: 'static + FnOnce(&mut S),
311 {
312 self.0.side_effect(f).boxed()
313 }
314
315 /// Creates a new `CF` which invokes a given function `f` on the result of `self`, yielding the
316 /// result
317 pub fn map<U, F>(self, f: F) -> CF<Option<U>, S>
318 where
319 F: 'static + FnOnce(T) -> U,
320 {
321 self.0.map(f).boxed()
322 }
323
324 /// Creates a new `CF` which invokes a given function `f` after `self` completes (ignoring ites
325 /// result), yielding the result of `f`
326 pub fn map_val<U, F>(self, f: F) -> CF<Option<U>, S>
327 where
328 F: 'static + FnOnce() -> U,
329 {
330 self.0.map_val(f).boxed()
331 }
332
333 /// Creates a new `CF` which invokes a given function `f` on the result of `self`, yielding the
334 /// result. Unlike with `map`, the given function is also passed a mutable reference to the
335 /// external state.
336 pub fn map_side_effect<U, F>(self, f: F) -> CF<Option<U>, S>
337 where
338 F: 'static + FnOnce(T, &mut S) -> U,
339 {
340 self.0.map_side_effect(f).boxed()
341 }
342
343 /// Creates a new `CF` which may be interrupted by the user pressing the escape key
344 pub fn catch_escape(self) -> CF<Option<OrEscape<T>>, S> {
345 self.0.catch_escape().boxed()
346 }
347
348 /// Creates a new `CF` which may be interrupted by the user pressing the escape key or the
349 /// start button on a gamepad
350 pub fn catch_escape_or_start(self) -> CF<Option<OrEscapeOrStart<T>>, S> {
351 self.0.catch_escape_or_start().boxed()
352 }
353
354 /// Creates a new `CF` which may be interrupted by the user clicking outside the component
355 pub fn catch_click_out(self) -> CF<Option<OrClickOut<T>>, S> {
356 self.0.catch_click_out().boxed()
357 }
358
359 /// Creates a new `CF` which may be interrupted by the user clicking outside the component or
360 /// pressing escape
361 pub fn catch_escape_or_click_out(self) -> CF<Option<OrEscapeOrClickOut<T>>, S> {
362 self.0.catch_escape_or_click_out().boxed()
363 }
364
365 /// Applies a common policy for interracting with menus. Intercepts the escape and "east"
366 /// gamepad button (the right-most symbol button on most gamepads) and yields
367 /// `Some(Err(Close))` in response, and intercepts the "start" gamepad button and injects a
368 /// "return" keypress in its place.
369 pub fn menu_harness(self) -> CF<Option<OrClose<T>>, S> {
370 self.0.menu_harness().boxed()
371 }
372
373 /// Prevents `Event::Peek` events from propagating to `self`
374 pub fn no_peek(self) -> CF<Option<T>, S> {
375 self.0.no_peek().boxed()
376 }
377
378 /// Creates a new `CF` with the same behaviour as `self` but whose yielded result is replaced
379 /// with a given result
380 pub fn replace<U: 'static>(self, value: U) -> CF<Option<U>, S> {
381 self.0.replace(value).boxed()
382 }
383
384 /// Convenience combinator for use in a loop context (e.g. in the argument to `repeat`).
385 /// Creates a new `CF` which behaves the same as `self` but whose result is wrapped in
386 /// `LoopControl::Continue`
387 pub fn continue_<Br: 'static>(self) -> CF<Option<LoopControl<T, Br>>, S> {
388 self.0.continue_().boxed()
389 }
390
391 /// Convenience combinator for use in a loop context (e.g. in the argument to `repeat`).
392 /// Creates a new `CF` which behaves the same as `self` but whose result is wrapped in
393 /// `LoopControl::Break`
394 pub fn break_<Co: 'static>(self) -> CF<Option<LoopControl<Co, T>>, S> {
395 self.0.break_().boxed()
396 }
397
398 /// Convenience combinator for use in a loop context (e.g. in the argument to `repeat`).
399 /// Creates a new `CF` which behaves the same as `self` but whose result is replaced by
400 /// `LoopControl::Continue(value)`
401 pub fn continue_with<Br: 'static, U: 'static>(
402 self,
403 value: U,
404 ) -> CF<Option<LoopControl<U, Br>>, S> {
405 self.0.continue_with(value).boxed()
406 }
407
408 /// Convenience combinator for use in a loop context (e.g. in the argument to `repeat`).
409 /// Creates a new `CF` which behaves the same as `self` but whose result is replaced by
410 /// `LoopControl::Break(value)`
411 pub fn break_with<Co: 'static, U: 'static>(
412 self,
413 value: U,
414 ) -> CF<Option<LoopControl<Co, U>>, S> {
415 self.0.break_with(value).boxed()
416 }
417
418 /// For components which may complete multiple times (e.g. menus) this combinator repeatedly
419 /// invokes the component, and calls the provided function `f` on some accumulator value, and
420 /// the result of the component. The provided function returns a `LoopControl` which determines
421 /// whether to continue repeating.
422 pub fn repeat<A, O, F>(self, init: A, f: F) -> CF<Option<O>, S>
423 where
424 A: 'static,
425 O: 'static,
426 F: 'static + FnMut(A, T) -> CF<Option<LoopControl<A, O>>, S>,
427 {
428 loop_((self, f, init), |(self_, mut f, acc)| {
429 self_.and_then_persistent(|self_, entry| {
430 f(acc, entry).map(|loop_control| loop_control.map_continue(|c| (self_, f, c)))
431 })
432 })
433 }
434
435 /// For components which may complete multiple times (e.g. menus) this combinator repeatedly
436 /// invokes the component, and calls the provided function `f` on the result of the component.
437 /// The provided function returns a `LoopControl` which determines whether to continue
438 /// repeating.
439 pub fn repeat_unit<O, F>(self, mut f: F) -> CF<Option<O>, S>
440 where
441 O: 'static,
442 F: 'static + FnMut(T) -> CF<Option<LoopControl<(), O>>, S>,
443 {
444 self.repeat((), move |(), entry| f(entry))
445 }
446
447 /// Prevent a component from receiving any events.
448 pub fn pause(self) -> CF<Option<T>, S> {
449 self.0.pause().boxed()
450 }
451
452 /// Call a given function on each tick of the component.
453 pub fn on_each_tick<F: FnMut() + 'static>(self, f: F) -> Self {
454 self.0.on_each_tick(f).boxed()
455 }
456
457 /// Call a given function on the state on each tick of the component.
458 pub fn on_each_tick_with_state<F: FnMut(&mut S) + 'static>(self, f: F) -> Self {
459 self.0.on_each_tick_with_state(f).boxed()
460 }
461
462 /// Call a function on the state when the window is closed.
463 pub fn on_exit_with_state<F: FnMut(&mut S) + 'static>(self, f: F) -> Self {
464 self.0.on_exit_with_state(f).boxed()
465 }
466}
467
468impl<O: 'static> CF<O, ()> {
469 /// For components that don't depend on external state, this combinator creates a new `CF` that
470 /// accepts any state.
471 pub fn ignore_state<S: 'static>(self) -> CF<O, S> {
472 self.0.ignore_state().boxed()
473 }
474}
475
476impl<S: 'static> CF<(), S> {
477 /// For components that yield `()`, creates a new `CF` that claims to yield `Option<T>` for any
478 /// `T`, but which always yields `None`.
479 pub fn ignore_output<O: 'static>(self) -> CF<Option<O>, S> {
480 self.0.ignore_output().boxed()
481 }
482}
483
484impl<S: 'static> CF<app::Output, S> {
485 /// Yields `Some(app::Exit)` when a window closed event is received. This typically annotates
486 /// the outside of an application so that application doesn't need to deal with window close
487 /// events.
488 pub fn exit_on_close(self) -> Self {
489 self.0.exit_on_close().boxed()
490 }
491}
492
493/// Convenience type alias for most applications. There is no external state, and the yielded
494/// result is an app control flow signal (typically whether the application wishes to exit).
495pub type App = CF<app::Output, ()>;
496
497/// Creates a `CF` which always yields clones of a given value
498pub fn val<S: 'static, T: 'static + Clone>(t: T) -> CF<Option<T>, S> {
499 unboxed::val(t).boxed()
500}
501
502/// Creates a `CF` which yields a given value once. Should not be ticked multiple times
503pub fn val_once<S: 'static, T: 'static>(t: T) -> CF<Option<T>, S> {
504 unboxed::val_once(t).boxed()
505}
506
507/// Creates a `CF` which yields a given value once, wrapped in `LoopControl::Break`. Should not be
508/// ticked multiple times
509pub fn break_<S: 'static, T: 'static, Co: 'static>(t: T) -> CF<Option<LoopControl<Co, T>>, S> {
510 val_once(t).break_()
511}
512
513/// Creates a `CF` which yields a given value once, wrapped in `LoopControl::Continue`. Should not
514/// be ticked multiple times
515pub fn continue_<S: 'static, T: 'static, Br: 'static>(t: T) -> CF<Option<LoopControl<T, Br>>, S> {
516 val_once(t).continue_()
517}
518
519/// Creates a new `CF` which never completes
520pub fn never<S: 'static, T: 'static>() -> CF<Option<T>, S> {
521 unboxed::never().boxed()
522}
523
524/// Repeatedly invoke the component-producing function `f` on the result of the component produced
525/// by `f`'s its previous invocation. The external state of the components produced by `f` is
526/// passed in as the `state` argument, and the component returned by `loop_state` expects no
527/// external state.
528pub fn loop_state<S, Co, Br, C, F>(state: S, init: Co, f: F) -> CF<Option<Br>, ()>
529where
530 S: 'static,
531 C::State: Sized,
532 C: 'static + Component<Output = Option<LoopControl<Co, Br>>, State = S>,
533 F: 'static + FnMut(Co) -> C,
534{
535 unboxed::loop_state(state, init, f).boxed()
536}
537
538/// Repeatedly invoke the component-producing function `f` on the result of the component produced
539/// by `f`'s its previous invocation.
540pub fn loop_<Co, Br, C, F>(init: Co, f: F) -> CF<Option<Br>, C::State>
541where
542 C::State: Sized,
543 C: 'static + Component<Output = Option<LoopControl<Co, Br>>>,
544 F: 'static + FnMut(Co) -> C,
545{
546 unboxed::loop_(init, f).boxed()
547}
548
549/// Repeatedly invoke the component-producing function `f` until its produced component yields
550/// `LoopControl::Break`.
551pub fn loop_unit<Br, C, F>(f: F) -> CF<Option<Br>, C::State>
552where
553 C::State: Sized,
554 C: 'static + Component<Output = Option<LoopControl<(), Br>>>,
555 F: 'static + FnMut() -> C,
556{
557 unboxed::loop_unit(f).boxed()
558}
559
560/// Repeatedly invoke the component-producing function `f` until its produced component yields
561/// `LoopControl::Break`. The provided function is also passed a mutable reference to a state.
562pub fn loop_mut<Co, Br, T, C, F>(init: Co, value: T, f: F) -> CF<Option<Br>, C::State>
563where
564 T: 'static,
565 C::State: Sized,
566 C: 'static + Component<Output = Option<LoopControl<Co, Br>>>,
567 F: 'static + FnMut(Co, &mut T) -> C,
568{
569 unboxed::loop_mut(init, value, f).boxed()
570}
571
572pub fn on_state<S, T, F>(f: F) -> CF<Option<T>, S>
573where
574 S: 'static,
575 T: 'static,
576 F: 'static + FnOnce(&mut S) -> T,
577{
578 unboxed::on_state(f).boxed()
579}
580
581pub fn on_state_then<C, F>(f: F) -> CF<C::Output, C::State>
582where
583 C: 'static + Component,
584 C::State: Sized,
585 F: 'static + FnOnce(&mut C::State) -> C,
586{
587 unboxed::on_state_then(f).boxed()
588}
589
590pub fn render<F: 'static + Fn(Ctx, &mut FrameBuffer)>(f: F) -> CF<(), ()> {
591 unboxed::render(f).boxed()
592}
593
594pub fn render_state<S: 'static, F: 'static + Fn(&S, Ctx, &mut FrameBuffer)>(f: F) -> CF<(), S> {
595 unboxed::render_state(f).boxed()
596}
597
598pub fn unit<S: 'static>() -> CF<(), S> {
599 unboxed::unit().boxed()
600}
601
602pub fn many<I, S, C>(iterable: I) -> CF<(), S>
603where
604 I: 'static,
605 S: 'static,
606 C: 'static + Component<State = S>,
607 for<'a> &'a I: IntoIterator<Item = &'a C>,
608 for<'a> &'a mut I: IntoIterator<Item = &'a mut C>,
609{
610 unboxed::many(iterable).boxed()
611}
612
613pub fn styled_string<S: 'static>(string: String, style: Style) -> CF<(), S> {
614 unboxed::styled_string(string, style).boxed()
615}
616
617pub fn on_input<F, T, S>(f: F) -> CF<Option<T>, S>
618where
619 F: 'static + FnMut(input::Input) -> Option<T>,
620 S: 'static,
621{
622 unboxed::on_input(f).boxed()
623}
624
625pub fn on_input_state<F, T, S>(f: F) -> CF<Option<T>, S>
626where
627 F: 'static + FnMut(input::Input, &mut S) -> Option<T>,
628 S: 'static,
629{
630 unboxed::on_input_state(f).boxed()
631}