nuit_core/compose/view/
view.rs

1use crate::{Node, Bind, Context, Event, IdPath, Id, IdentifyExt};
2
3/// The primary view trait. Represents a lightweight UI component.
4pub trait View: Bind {
5    type Body: View = NeverView;
6
7    fn body(&self) -> Self::Body {
8        panic!("View does not have a body!")
9    }
10
11    // TODO: Return an error type from fire to avoid panicking on wrong paths?
12
13    fn fire(&self, event: &Event, event_path: &IdPath, context: &Context) {
14        self.bind(context);
15        self.body().fire(event, event_path, context);
16    }
17
18    fn render(&self, context: &Context) -> Node {
19        self.bind(context);
20        self.body().render(context)
21    }
22}
23
24macro_rules! impl_tuple_view {
25    ($($tvs:ident),*) => {
26        impl<$($tvs),*> View for ($($tvs,)*) where $($tvs: View),* {
27            fn fire(&self, event: &Event, event_path: &IdPath, context: &Context) {
28                if let Some(head) = event_path.head() {
29                    match head {
30                        $(${ignore($tvs)} Id::Index(${index()}) => self.${index()}.fire(event, &event_path.tail(), &context.child(${index()})),)*
31                        i => panic!("Cannot fire event for child id {} on a {}-tuple", i, ${count($tvs, 0)})
32                    }
33                }
34            }
35
36            fn render(&self, context: &Context) -> Node {
37                Node::Group {
38                    children: vec![
39                        $(${ignore($tvs)} self.${index()}.render(&context.child(${index()})).identify(${index()}),)*
40                    ]
41                }
42            }
43        }
44    };
45}
46
47/// A view type that can never be constructed.
48pub enum NeverView {}
49
50impl Bind for NeverView {}
51impl View for NeverView {}
52
53// Note: We explicitly implement the 0 (unit) and 1 tuples to avoid e.g. the
54// overhead of using a Group requiring a Vec.
55
56impl View for () {
57    fn fire(&self, _event: &Event, _id_path: &IdPath, _context: &Context) {}
58
59    fn render(&self, _context: &Context) -> Node {
60        Node::Empty {}
61    }
62}
63
64impl<T> View for (T,) where T: View {
65    type Body = T::Body;
66
67    fn body(&self) -> Self::Body {
68        self.0.body()
69    }
70
71    fn fire(&self, event: &Event, event_path: &IdPath, context: &Context) {
72        if let Some(head) = event_path.head() {
73            match head {
74                Id::Index(0) => self.0.fire(event, &event_path.tail(), &context.child(0)),
75                i => panic!("Cannot fire event for child id {} on 1-tuple", i)
76            }
77        }
78    }
79
80    fn render(&self, context: &Context) -> Node {
81        Node::Child { wrapped: Box::new(self.0.render(&context.child(0)).identify(0)) }
82    }
83}
84
85// TODO: Generate with variadic generics once available
86
87impl_tuple_view!(T1, T2);
88impl_tuple_view!(T1, T2, T3);
89impl_tuple_view!(T1, T2, T3, T4);
90impl_tuple_view!(T1, T2, T3, T4, T5);
91impl_tuple_view!(T1, T2, T3, T4, T5, T6);
92impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7);
93impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8);
94impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8, T9);
95impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
96impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
97impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
98impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13);
99impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14);
100impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15);
101impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16);
102impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17);
103impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18);
104impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19);
105impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20);
106impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21);
107impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22);
108impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23);
109impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24);