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