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::{
41 any::Any,
42 borrow::Cow,
43 cell::RefCell,
44 mem,
45 ops::{Deref, DerefMut},
46 rc::Rc,
47};
48
49trait AnyElement {
50 fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F;
51 fn paint(&mut self, origin: Vector2F, cx: &mut PaintContext);
52 fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool;
53 fn debug(&self, cx: &DebugContext) -> serde_json::Value;
54
55 fn size(&self) -> Vector2F;
56 fn metadata(&self) -> Option<&dyn Any>;
57}
58
59pub trait Element {
60 type LayoutState;
61 type PaintState;
62
63 fn layout(
64 &mut self,
65 constraint: SizeConstraint,
66 cx: &mut LayoutContext,
67 ) -> (Vector2F, Self::LayoutState);
68
69 fn paint(
70 &mut self,
71 bounds: RectF,
72 layout: &mut Self::LayoutState,
73 cx: &mut PaintContext,
74 ) -> Self::PaintState;
75
76 fn dispatch_event(
77 &mut self,
78 event: &Event,
79 bounds: RectF,
80 layout: &mut Self::LayoutState,
81 paint: &mut Self::PaintState,
82 cx: &mut EventContext,
83 ) -> bool;
84
85 fn metadata(&self) -> Option<&dyn Any> {
86 None
87 }
88
89 fn debug(
90 &self,
91 bounds: RectF,
92 layout: &Self::LayoutState,
93 paint: &Self::PaintState,
94 cx: &DebugContext,
95 ) -> serde_json::Value;
96
97 fn boxed(self) -> ElementBox
98 where
99 Self: 'static + Sized,
100 {
101 ElementBox(ElementRc {
102 name: None,
103 element: Rc::new(RefCell::new(Lifecycle::Init { element: self })),
104 })
105 }
106
107 fn named(self, name: impl Into<Cow<'static, str>>) -> ElementBox
108 where
109 Self: 'static + Sized,
110 {
111 ElementBox(ElementRc {
112 name: Some(name.into()),
113 element: Rc::new(RefCell::new(Lifecycle::Init { element: self })),
114 })
115 }
116}
117
118pub enum Lifecycle<T: Element> {
119 Empty,
120 Init {
121 element: T,
122 },
123 PostLayout {
124 element: T,
125 constraint: SizeConstraint,
126 size: Vector2F,
127 layout: T::LayoutState,
128 },
129 PostPaint {
130 element: T,
131 constraint: SizeConstraint,
132 bounds: RectF,
133 layout: T::LayoutState,
134 paint: T::PaintState,
135 },
136}
137pub struct ElementBox(ElementRc);
138
139#[derive(Clone)]
140pub struct ElementRc {
141 name: Option<Cow<'static, str>>,
142 element: Rc<RefCell<dyn AnyElement>>,
143}
144
145impl<T: Element> AnyElement for Lifecycle<T> {
146 fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F {
147 let result;
148 *self = match mem::take(self) {
149 Lifecycle::Empty => unreachable!(),
150 Lifecycle::Init { mut element }
151 | Lifecycle::PostLayout { mut element, .. }
152 | Lifecycle::PostPaint { mut element, .. } => {
153 let (size, layout) = element.layout(constraint, cx);
154 debug_assert!(size.x().is_finite());
155 debug_assert!(size.y().is_finite());
156
157 result = size;
158 Lifecycle::PostLayout {
159 element,
160 constraint,
161 size,
162 layout,
163 }
164 }
165 };
166 result
167 }
168
169 fn paint(&mut self, origin: Vector2F, cx: &mut PaintContext) {
170 *self = match mem::take(self) {
171 Lifecycle::PostLayout {
172 mut element,
173 constraint,
174 size,
175 mut layout,
176 } => {
177 let bounds = RectF::new(origin, size);
178 let paint = element.paint(bounds, &mut layout, cx);
179 Lifecycle::PostPaint {
180 element,
181 constraint,
182 bounds,
183 layout,
184 paint,
185 }
186 }
187 Lifecycle::PostPaint {
188 mut element,
189 constraint,
190 bounds,
191 mut layout,
192 ..
193 } => {
194 let bounds = RectF::new(origin, bounds.size());
195 let paint = element.paint(bounds, &mut layout, cx);
196 Lifecycle::PostPaint {
197 element,
198 constraint,
199 bounds,
200 layout,
201 paint,
202 }
203 }
204 _ => panic!("invalid element lifecycle state"),
205 }
206 }
207
208 fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool {
209 if let Lifecycle::PostPaint {
210 element,
211 bounds,
212 layout,
213 paint,
214 ..
215 } = self
216 {
217 element.dispatch_event(event, *bounds, layout, paint, cx)
218 } else {
219 panic!("invalid element lifecycle state");
220 }
221 }
222
223 fn size(&self) -> Vector2F {
224 match self {
225 Lifecycle::Empty | Lifecycle::Init { .. } => panic!("invalid element lifecycle state"),
226 Lifecycle::PostLayout { size, .. } => *size,
227 Lifecycle::PostPaint { bounds, .. } => bounds.size(),
228 }
229 }
230
231 fn metadata(&self) -> Option<&dyn Any> {
232 match self {
233 Lifecycle::Empty => unreachable!(),
234 Lifecycle::Init { element }
235 | Lifecycle::PostLayout { element, .. }
236 | Lifecycle::PostPaint { element, .. } => element.metadata(),
237 }
238 }
239
240 fn debug(&self, cx: &DebugContext) -> serde_json::Value {
241 match self {
242 Lifecycle::PostPaint {
243 element,
244 constraint,
245 bounds,
246 layout,
247 paint,
248 } => {
249 let mut value = element.debug(*bounds, layout, paint, cx);
250 if let json::Value::Object(map) = &mut value {
251 let mut new_map: crate::json::Map<String, serde_json::Value> =
252 Default::default();
253 if let Some(typ) = map.remove("type") {
254 new_map.insert("type".into(), typ);
255 }
256 new_map.insert("constraint".into(), constraint.to_json());
257 new_map.append(map);
258 json::Value::Object(new_map)
259 } else {
260 value
261 }
262 }
263 _ => panic!("invalid element lifecycle state"),
264 }
265 }
266}
267
268impl<T: Element> Default for Lifecycle<T> {
269 fn default() -> Self {
270 Self::Empty
271 }
272}
273
274impl ElementBox {
275 pub fn metadata(&self) -> Option<&dyn Any> {
276 let element = unsafe { &*self.0.element.as_ptr() };
277 element.metadata()
278 }
279}
280
281impl Into<ElementRc> for ElementBox {
282 fn into(self) -> ElementRc {
283 self.0
284 }
285}
286
287impl Deref for ElementBox {
288 type Target = ElementRc;
289
290 fn deref(&self) -> &Self::Target {
291 &self.0
292 }
293}
294
295impl DerefMut for ElementBox {
296 fn deref_mut(&mut self) -> &mut Self::Target {
297 &mut self.0
298 }
299}
300
301impl ElementRc {
302 pub fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F {
303 self.element.borrow_mut().layout(constraint, cx)
304 }
305
306 pub fn paint(&mut self, origin: Vector2F, cx: &mut PaintContext) {
307 self.element.borrow_mut().paint(origin, cx);
308 }
309
310 pub fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool {
311 self.element.borrow_mut().dispatch_event(event, cx)
312 }
313
314 pub fn size(&self) -> Vector2F {
315 self.element.borrow().size()
316 }
317
318 pub fn debug(&self, cx: &DebugContext) -> json::Value {
319 let mut value = self.element.borrow().debug(cx);
320
321 if let Some(name) = &self.name {
322 if let json::Value::Object(map) = &mut value {
323 let mut new_map: crate::json::Map<String, serde_json::Value> = Default::default();
324 new_map.insert("name".into(), json::Value::String(name.to_string()));
325 new_map.append(map);
326 return json::Value::Object(new_map);
327 }
328 }
329
330 value
331 }
332}
333
334pub trait ParentElement<'a>: Extend<ElementBox> + Sized {
335 fn add_children(&mut self, children: impl IntoIterator<Item = ElementBox>) {
336 self.extend(children);
337 }
338
339 fn add_child(&mut self, child: ElementBox) {
340 self.add_children(Some(child));
341 }
342
343 fn with_children(mut self, children: impl IntoIterator<Item = ElementBox>) -> Self {
344 self.add_children(children);
345 self
346 }
347
348 fn with_child(self, child: ElementBox) -> Self {
349 self.with_children(Some(child))
350 }
351}
352
353impl<'a, T> ParentElement<'a> for T where T: Extend<ElementBox> {}