Skip to main content

egui_reactor/
view.rs

1//! [`View`]: what a component body, an `rsx!` block and a child slot all are.
2
3use crate::cx::Cx;
4use crate::layout::ItemStyle;
5
6/// Something that can draw itself into a [`Cx`].
7///
8/// The canonical implementation is a closure, which is what `rsx!` expands to.
9/// The other impls exist so that plain values (`"text"`, `Option`, `Vec`) can
10/// be dropped into a child slot without ceremony.
11pub trait View {
12    /// Draw this view.
13    fn show(self, cx: &mut Cx<'_, '_>);
14}
15
16/// Draws nothing. This is what an empty child slot is.
17impl View for () {
18    fn show(self, _cx: &mut Cx<'_, '_>) {}
19}
20
21impl View for &str {
22    fn show(self, cx: &mut Cx<'_, '_>) {
23        cx.leaf(&ItemStyle::default(), |ui| ui.label(self));
24    }
25}
26
27impl View for String {
28    fn show(self, cx: &mut Cx<'_, '_>) {
29        cx.leaf(&ItemStyle::default(), |ui| ui.label(self));
30    }
31}
32
33impl<V: View> View for Option<V> {
34    fn show(self, cx: &mut Cx<'_, '_>) {
35        if let Some(view) = self {
36            view.show(cx);
37        }
38    }
39}
40
41impl<V: View> View for Vec<V> {
42    fn show(self, cx: &mut Cx<'_, '_>) {
43        for view in self {
44            view.show(cx);
45        }
46    }
47}
48
49impl<V: View, const N: usize> View for [V; N] {
50    fn show(self, cx: &mut Cx<'_, '_>) {
51        for view in self {
52            view.show(cx);
53        }
54    }
55}
56
57/// The escape hatch: any closure taking a `Cx` is a view.
58///
59/// A blanket impl over `IntoIterator` would be nicer than the `Vec` and array
60/// impls above, but it overlaps both this one and `Option`, so the concrete
61/// impls stay.
62impl<F: FnOnce(&mut Cx<'_, '_>)> View for F {
63    fn show(self, cx: &mut Cx<'_, '_>) {
64        self(cx);
65    }
66}
67
68/// Wrap a closure as a [`View`], fixing the closure's argument type.
69///
70/// `rsx!` always emits `::egui_reactor::view(|cx| { .. })`: passing a bare
71/// closure where `impl View` is expected leaves `cx` un-inferred, because the
72/// `FnOnce` bound is higher-ranked over the `Cx` lifetimes. Users writing the
73/// escape hatch by hand want this function for the same reason.
74pub fn view<F: FnOnce(&mut Cx<'_, '_>)>(f: F) -> impl View {
75    f
76}