1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
mod button;
mod ext;
mod for_each;
mod h_stack;
mod handler;
mod r#if;
mod list;
mod modified;
mod picker;
mod text_field;
mod text;
mod v_stack;
mod z_stack;

pub use button::*;
pub use ext::*;
pub use for_each::*;
pub use h_stack::*;
pub use handler::*;
pub use r#if::*;
pub use list::*;
pub use modified::*;
pub use picker::*;
pub use text_field::*;
pub use text::*;
pub use v_stack::*;
pub use z_stack::*;

use crate::{Node, Bind, Context, Event, IdPath, Id, IdentifyExt};

/// The primary view trait. Represents a lightweight UI component.
pub trait View: Bind {
    type Body: View = !;

    fn body(&self) -> Self::Body {
        panic!("View does not have a body!")
    }

    // TODO: Return an error type from fire to avoid panicking on wrong paths?

    fn fire(&self, event: &Event, id_path: &IdPath) {
        self.body().fire(event, id_path);
    }

    fn render(&mut self, context: &Context) -> Node {
        self.bind(context);
        self.body().render(context)
    }
}

macro_rules! impl_tuple_view {
    ($($tvs:ident),*) => {
        impl<$($tvs),*> View for ($($tvs,)*) where $($tvs: View),* {
            fn fire(&self, event: &Event, id_path: &IdPath) {
                if let Some(head) = id_path.head() {
                    match head {
                        $(${ignore($tvs)} Id::Index(${index()}) => self.${index()}.fire(event, &id_path.tail()),)*
                        i => panic!("Cannot fire event for child id {} on a {}-tuple", i, ${count($tvs, 0)})
                    }
                }
            }

            fn render(&mut self, context: &Context) -> Node {
                Node::Group {
                    children: vec![
                        $(${ignore($tvs)} self.${index()}.render(&context.child(${index()})).identify(${index()}),)*
                    ]
                }
            }
        }
    };
}

impl View for ! {}

// Note: We explicitly implement the 0 (unit) and 1 tuples to avoid e.g. the
// overhead of using a Group requiring a Vec.

impl View for () {
    fn fire(&self, _event: &Event, _id_path: &IdPath) {}

    fn render(&mut self, _context: &Context) -> Node {
        Node::Empty {}
    }
}

impl<T> View for (T,) where T: View {
    type Body = T::Body;

    fn body(&self) -> Self::Body {
        self.0.body()
    }

    fn fire(&self, event: &Event, id_path: &IdPath) {
        if let Some(head) = id_path.head() {
            match head {
                Id::Index(0) => self.0.fire(event, &id_path.tail()),
                i => panic!("Cannot fire event for child id {} on 1-tuple", i)
            }
        }
    }

    fn render(&mut self, context: &Context) -> Node {
        Node::Child { wrapped: Box::new(self.0.render(&context.child(0)).identify(0)) }
    }
}

// TODO: Generate with variadic generics once available

impl_tuple_view!(T1, T2);
impl_tuple_view!(T1, T2, T3);
impl_tuple_view!(T1, T2, T3, T4);
impl_tuple_view!(T1, T2, T3, T4, T5);
impl_tuple_view!(T1, T2, T3, T4, T5, T6);
impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7);
impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8);
impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8, T9);
impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13);
impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14);
impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15);
impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16);
impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17);
impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18);
impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19);
impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20);
impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21);
impl_tuple_view!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22);
impl_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);
impl_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);