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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
use super::*;

#[derive(Default)]
pub struct Sense {
    pub clicked: bool,
    pub click_time: Option<f64>,
    pub hovered_time: Option<f64>,
    pub captured_time: Option<f64>,
}

impl Sense {
    pub fn is_hovered(&self) -> bool {
        self.hovered_time.is_some()
    }
    pub fn is_captured(&self) -> bool {
        self.captured_time.is_some()
    }
    pub fn set_hovered(&mut self, hovered: bool) {
        if hovered {
            if self.hovered_time.is_none() {
                self.hovered_time = Some(0.0);
            }
        } else {
            self.hovered_time = None;
        }
    }
    pub fn set_captured(&mut self, captured: bool) {
        if captured {
            if self.captured_time.is_none() {
                self.captured_time = Some(0.0);
            }
        } else {
            self.captured_time = None;
        }
    }
    pub fn click(&mut self) {
        self.click_time = Some(0.0);
        self.clicked = true;
    }
    pub fn take_clicked(&mut self) -> bool {
        std::mem::replace(&mut self.clicked, false)
    }
    pub fn update(&mut self, delta_time: f64) {
        if let Some(time) = &mut self.click_time {
            *time += delta_time;
        }
        if let Some(time) = &mut self.hovered_time {
            *time += delta_time;
        }
        if let Some(time) = &mut self.captured_time {
            *time += delta_time;
        }
    }
    pub fn handle_event(&mut self, _event: &Event) {
        // if let Event::Click { .. } = event {
        //     self.clicked = true;
        //     self.click_time = Some(0.0);
        // }
        todo!()
    }
}

#[derive(Debug, Copy, Clone)]
pub struct Constraints {
    pub min_size: vec2<f64>,
    pub flex: vec2<f64>,
}

impl Constraints {
    pub fn zero() -> Self {
        Self {
            min_size: vec2::ZERO,
            flex: vec2::ZERO,
        }
    }
}

impl Default for Constraints {
    fn default() -> Self {
        Self {
            min_size: vec2(0.0, 0.0),
            flex: vec2(1.0, 1.0),
        }
    }
}

pub struct DrawContext<'a, 'b> {
    pub draw2d: &'a draw2d::Helper,
    pub theme: &'a Theme,
    pub position: Aabb2<f64>,
    pub framebuffer: &'a mut ugli::Framebuffer<'b>,
}

pub trait Widget {
    fn sense(&mut self) -> Option<&mut Sense> {
        None
    }
    fn update(&mut self, delta_time: f64) {
        #![allow(unused_variables)]
    }
    fn draw(&mut self, cx: &mut DrawContext) {
        #![allow(unused_variables)]
    }
    fn handle_event(&mut self, event: &Event) {
        #![allow(unused_variables)]
    }
    fn walk_children_mut(&mut self, f: &mut dyn FnMut(&mut dyn Widget)) {
        #![allow(unused_variables)]
    }
    fn calc_constraints(&mut self, children: &ConstraintsContext) -> Constraints;
    fn layout_children(&mut self, cx: &mut LayoutContext) {
        self.walk_children_mut(&mut |child| cx.set_position(child, cx.position));
    }
}

impl<T: Widget> Widget for Box<T> {
    fn calc_constraints(&mut self, children: &ConstraintsContext) -> Constraints {
        children.get_constraints(&**self)
    }
    fn walk_children_mut(&mut self, f: &mut dyn FnMut(&mut dyn Widget)) {
        f(&mut **self);
    }
}

impl Widget for Box<dyn Widget + '_> {
    fn calc_constraints(&mut self, cx: &ConstraintsContext) -> Constraints {
        cx.get_constraints(&**self)
    }
    fn walk_children_mut(&mut self, f: &mut dyn FnMut(&mut dyn Widget)) {
        f(&mut **self);
    }
}

mod ext {
    use super::*;

    pub trait WidgetExt<'a>: Widget + Sized + 'a {
        fn boxed(self) -> Box<dyn Widget + 'a> {
            Box::new(self)
        }
    }

    impl<'a, T: Widget + 'a> WidgetExt<'a> for T {}
}

pub use ext::WidgetExt as _;