1mod align;
2mod canvas;
3mod constrained_box;
4mod container;
5mod empty;
6mod event_handler;
7mod flex;
8mod label;
9mod line_box;
10mod list;
11mod mouse_event_handler;
12mod stack;
13mod svg;
14mod text;
15mod uniform_list;
16
17pub use crate::presenter::ChildView;
18pub use align::*;
19pub use canvas::*;
20pub use constrained_box::*;
21pub use container::*;
22pub use empty::*;
23pub use event_handler::*;
24pub use flex::*;
25pub use label::*;
26pub use line_box::*;
27pub use list::*;
28pub use mouse_event_handler::*;
29pub use stack::*;
30pub use svg::*;
31pub use text::*;
32pub use uniform_list::*;
33
34use crate::{
35 geometry::{rect::RectF, vector::Vector2F},
36 json, DebugContext, Event, EventContext, LayoutContext, PaintContext, SizeConstraint,
37};
38use core::panic;
39use json::ToJson;
40use std::{any::Any, borrow::Cow, mem};
41
42trait AnyElement {
43 fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F;
44 fn paint(&mut self, origin: Vector2F, cx: &mut PaintContext);
45 fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool;
46 fn debug(&self, cx: &DebugContext) -> serde_json::Value;
47
48 fn size(&self) -> Vector2F;
49 fn metadata(&self) -> Option<&dyn Any>;
50}
51
52pub trait Element {
53 type LayoutState;
54 type PaintState;
55
56 fn layout(
57 &mut self,
58 constraint: SizeConstraint,
59 cx: &mut LayoutContext,
60 ) -> (Vector2F, Self::LayoutState);
61
62 fn paint(
63 &mut self,
64 bounds: RectF,
65 layout: &mut Self::LayoutState,
66 cx: &mut PaintContext,
67 ) -> Self::PaintState;
68
69 fn dispatch_event(
70 &mut self,
71 event: &Event,
72 bounds: RectF,
73 layout: &mut Self::LayoutState,
74 paint: &mut Self::PaintState,
75 cx: &mut EventContext,
76 ) -> bool;
77
78 fn metadata(&self) -> Option<&dyn Any> {
79 None
80 }
81
82 fn debug(
83 &self,
84 bounds: RectF,
85 layout: &Self::LayoutState,
86 paint: &Self::PaintState,
87 cx: &DebugContext,
88 ) -> serde_json::Value;
89
90 fn boxed(self) -> ElementBox
91 where
92 Self: 'static + Sized,
93 {
94 ElementBox {
95 name: None,
96 element: Box::new(Lifecycle::Init { element: self }),
97 }
98 }
99
100 fn named(self, name: impl Into<Cow<'static, str>>) -> ElementBox
101 where
102 Self: 'static + Sized,
103 {
104 ElementBox {
105 name: Some(name.into()),
106 element: Box::new(Lifecycle::Init { element: self }),
107 }
108 }
109}
110
111pub enum Lifecycle<T: Element> {
112 Empty,
113 Init {
114 element: T,
115 },
116 PostLayout {
117 element: T,
118 constraint: SizeConstraint,
119 size: Vector2F,
120 layout: T::LayoutState,
121 },
122 PostPaint {
123 element: T,
124 constraint: SizeConstraint,
125 bounds: RectF,
126 layout: T::LayoutState,
127 paint: T::PaintState,
128 },
129}
130pub struct ElementBox {
131 name: Option<Cow<'static, str>>,
132 element: Box<dyn AnyElement>,
133}
134
135impl<T: Element> AnyElement for Lifecycle<T> {
136 fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F {
137 let result;
138 *self = match mem::take(self) {
139 Lifecycle::Empty => unreachable!(),
140 Lifecycle::Init { mut element }
141 | Lifecycle::PostLayout { mut element, .. }
142 | Lifecycle::PostPaint { mut element, .. } => {
143 let (size, layout) = element.layout(constraint, cx);
144 debug_assert!(size.x().is_finite());
145 debug_assert!(size.y().is_finite());
146
147 result = size;
148 Lifecycle::PostLayout {
149 element,
150 constraint,
151 size,
152 layout,
153 }
154 }
155 };
156 result
157 }
158
159 fn paint(&mut self, origin: Vector2F, cx: &mut PaintContext) {
160 *self = match mem::take(self) {
161 Lifecycle::PostLayout {
162 mut element,
163 constraint,
164 size,
165 mut layout,
166 } => {
167 let bounds = RectF::new(origin, size);
168 let paint = element.paint(bounds, &mut layout, cx);
169 Lifecycle::PostPaint {
170 element,
171 constraint,
172 bounds,
173 layout,
174 paint,
175 }
176 }
177 Lifecycle::PostPaint {
178 mut element,
179 constraint,
180 bounds,
181 mut layout,
182 ..
183 } => {
184 let bounds = RectF::new(origin, bounds.size());
185 let paint = element.paint(bounds, &mut layout, cx);
186 Lifecycle::PostPaint {
187 element,
188 constraint,
189 bounds,
190 layout,
191 paint,
192 }
193 }
194 _ => panic!("invalid element lifecycle state"),
195 }
196 }
197
198 fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool {
199 if let Lifecycle::PostPaint {
200 element,
201 bounds,
202 layout,
203 paint,
204 ..
205 } = self
206 {
207 element.dispatch_event(event, *bounds, layout, paint, cx)
208 } else {
209 panic!("invalid element lifecycle state");
210 }
211 }
212
213 fn size(&self) -> Vector2F {
214 match self {
215 Lifecycle::Empty | Lifecycle::Init { .. } => panic!("invalid element lifecycle state"),
216 Lifecycle::PostLayout { size, .. } => *size,
217 Lifecycle::PostPaint { bounds, .. } => bounds.size(),
218 }
219 }
220
221 fn metadata(&self) -> Option<&dyn Any> {
222 match self {
223 Lifecycle::Empty => unreachable!(),
224 Lifecycle::Init { element }
225 | Lifecycle::PostLayout { element, .. }
226 | Lifecycle::PostPaint { element, .. } => element.metadata(),
227 }
228 }
229
230 fn debug(&self, cx: &DebugContext) -> serde_json::Value {
231 match self {
232 Lifecycle::PostPaint {
233 element,
234 constraint,
235 bounds,
236 layout,
237 paint,
238 } => {
239 let mut value = element.debug(*bounds, layout, paint, cx);
240 if let json::Value::Object(map) = &mut value {
241 let mut new_map: crate::json::Map<String, serde_json::Value> =
242 Default::default();
243 if let Some(typ) = map.remove("type") {
244 new_map.insert("type".into(), typ);
245 }
246 new_map.insert("constraint".into(), constraint.to_json());
247 new_map.append(map);
248 json::Value::Object(new_map)
249 } else {
250 value
251 }
252 }
253 _ => panic!("invalid element lifecycle state"),
254 }
255 }
256}
257
258impl<T: Element> Default for Lifecycle<T> {
259 fn default() -> Self {
260 Self::Empty
261 }
262}
263
264impl ElementBox {
265 pub fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F {
266 self.element.layout(constraint, cx)
267 }
268
269 pub fn paint(&mut self, origin: Vector2F, cx: &mut PaintContext) {
270 self.element.paint(origin, cx);
271 }
272
273 pub fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool {
274 self.element.dispatch_event(event, cx)
275 }
276
277 pub fn size(&self) -> Vector2F {
278 self.element.size()
279 }
280
281 pub fn metadata(&self) -> Option<&dyn Any> {
282 self.element.metadata()
283 }
284
285 pub fn debug(&self, cx: &DebugContext) -> json::Value {
286 let mut value = self.element.debug(cx);
287
288 if let Some(name) = &self.name {
289 if let json::Value::Object(map) = &mut value {
290 let mut new_map: crate::json::Map<String, serde_json::Value> = Default::default();
291 new_map.insert("name".into(), json::Value::String(name.to_string()));
292 new_map.append(map);
293 return json::Value::Object(new_map);
294 }
295 }
296
297 value
298 }
299}
300
301pub trait ParentElement<'a>: Extend<ElementBox> + Sized {
302 fn add_children(&mut self, children: impl IntoIterator<Item = ElementBox>) {
303 self.extend(children);
304 }
305
306 fn add_child(&mut self, child: ElementBox) {
307 self.add_children(Some(child));
308 }
309
310 fn with_children(mut self, children: impl IntoIterator<Item = ElementBox>) -> Self {
311 self.add_children(children);
312 self
313 }
314
315 fn with_child(self, child: ElementBox) -> Self {
316 self.with_children(Some(child))
317 }
318}
319
320impl<'a, T> ParentElement<'a> for T where T: Extend<ElementBox> {}