ori_core/views/
mod.rs

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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
//! The builtin views in Ori.

mod aligned;
mod animate;
mod aspect;
mod build_handler;
mod builder;
mod button;
mod checkbox;
mod clickable;
mod collapsing;
mod color_picker;
mod constrain;
mod container;
mod cursor;
mod decorate;
mod draw_handler;
mod event_handler;
mod flex;
mod focus;
mod image;
mod layout;
mod memo;
mod opaque;
mod pad;
mod painter;
mod popup;
mod rebuild_handler;
mod scroll;
mod slider;
mod stack;
mod suspense;
mod text;
mod text_input;
mod tooltip;
mod transform;
mod trigger;
mod with_state;
mod with_style;
mod wrap;
mod zstack;

pub use aligned::*;
pub use animate::*;
pub use aspect::*;
pub use build_handler::*;
pub use builder::*;
pub use button::*;
pub use checkbox::*;
pub use clickable::*;
pub use collapsing::*;
pub use color_picker::*;
pub use constrain::*;
pub use container::*;
pub use cursor::*;
pub use decorate::*;
pub use draw_handler::*;
pub use event_handler::*;
pub use flex::*;
pub use focus::*;
pub use layout::*;
pub use memo::*;
pub use opaque::*;
pub use pad::*;
pub use painter::*;
pub use popup::*;
pub use rebuild_handler::*;
pub use scroll::*;
pub use slider::*;
pub use stack::*;
pub use suspense::*;
pub use text::*;
pub use text_input::*;
pub use tooltip::*;
pub use transform::*;
pub use trigger::*;
pub use with_state::*;
pub use wrap::*;
pub use zstack::*;

#[cfg(test)]
#[allow(dead_code)]
mod testing {
    use std::collections::HashMap;

    use crate::{
        command::{CommandProxy, CommandReceiver, CommandWaker},
        context::{BaseCx, BuildCx, Contexts, DrawCx, EventCx, LayoutCx, RebuildCx},
        event::Event,
        layout::{Rect, Size, Space},
        style::Styles,
        view::{View, ViewState},
        window::Window,
    };

    pub struct ViewTester<T, V: View<T>> {
        pub state: V::State,
        pub view_state: ViewState,
        pub contexts: Contexts,
        pub command_rx: CommandReceiver,
        pub command_proxy: CommandProxy,
    }

    impl<T, V: View<T>> ViewTester<T, V> {
        pub fn new(view: &mut V, data: &mut T) -> Self {
            let waker = CommandWaker::new(|| {});

            let window = Window::new();

            let mut contexts = Contexts::new();
            contexts.insert(window);
            contexts.insert(Styles::new());

            let (mut proxy, rx) = CommandProxy::new(waker);

            let mut view_state = ViewState::default();

            let mut base_cx = BaseCx::new(&mut contexts, &mut proxy);
            let mut build_cx = BuildCx::new(&mut base_cx, &mut view_state);

            let state = view.build(&mut build_cx, data);

            Self {
                state,
                view_state,
                contexts,
                command_rx: rx,
                command_proxy: proxy,
            }
        }

        pub fn rebuild(&mut self, view: &mut V, data: &mut T, old: &V) {
            let mut base_cx = BaseCx::new(&mut self.contexts, &mut self.command_proxy);
            let mut rebuild_cx = RebuildCx::new(&mut base_cx, &mut self.view_state);

            view.rebuild(&mut self.state, &mut rebuild_cx, data, old);
        }

        pub fn event(&mut self, view: &mut V, data: &mut T, event: &Event) -> bool {
            let mut needs_rebuild = false;

            let mut base_cx = BaseCx::new(&mut self.contexts, &mut self.command_proxy);
            let mut event_cx = EventCx::new(&mut base_cx, &mut self.view_state, &mut needs_rebuild);
            let _ = view.event(&mut self.state, &mut event_cx, data, event);

            needs_rebuild
        }

        pub fn layout(&mut self, view: &mut V, data: &mut T, space: Space) -> Size {
            let mut base_cx = BaseCx::new(&mut self.contexts, &mut self.command_proxy);
            let mut layout_cx = LayoutCx::new(&mut base_cx, &mut self.view_state);

            let size = view.layout(&mut self.state, &mut layout_cx, data, space);
            self.view_state.set_size(size);

            size
        }
    }

    pub fn test_layout<T>(view: &mut impl View<T>, data: &mut T, space: Space) -> SavedLayouts {
        let mut tester = ViewTester::new(view, data);
        tester.layout(view, data, space);
        tester.event(view, data, &Event::Notify);
        tester.contexts.get_or_default::<SavedLayouts>().clone()
    }

    pub type SavedLayouts = HashMap<String, Rect>;

    pub fn save_layout<V>(name: impl Into<String>, view: V) -> LayoutSaver<V> {
        LayoutSaver::new(name, view)
    }

    pub struct LayoutSaver<V> {
        pub content: V,
        pub name: String,
    }

    impl<V> LayoutSaver<V> {
        pub fn new(name: impl Into<String>, content: V) -> Self {
            Self {
                content,
                name: name.into(),
            }
        }
    }

    impl<T, V: View<T>> View<T> for LayoutSaver<V> {
        type State = V::State;

        fn build(&mut self, cx: &mut BuildCx, data: &mut T) -> Self::State {
            self.content.build(cx, data)
        }

        fn rebuild(
            &mut self,
            state: &mut Self::State,
            cx: &mut RebuildCx,
            data: &mut T,
            old: &Self,
        ) {
            self.content.rebuild(state, cx, data, &old.content);
        }

        fn event(
            &mut self,
            state: &mut Self::State,
            cx: &mut EventCx,
            data: &mut T,
            event: &Event,
        ) -> bool {
            let handled = self.content.event(state, cx, data, event);

            let layout_rect = cx.rect().transform(cx.transform());
            cx.context_or_default::<SavedLayouts>()
                .insert(self.name.clone(), layout_rect);

            handled
        }

        fn layout(
            &mut self,
            state: &mut Self::State,
            cx: &mut LayoutCx,
            data: &mut T,
            space: Space,
        ) -> Size {
            self.content.layout(state, cx, data, space)
        }

        fn draw(&mut self, state: &mut Self::State, cx: &mut DrawCx, data: &mut T) {
            self.content.draw(state, cx, data);
        }
    }
}