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, AppContext, DebugContext, Event, EventContext, LayoutContext,
33 PaintContext, SizeConstraint,
34};
35use core::panic;
36use json::ToJson;
37use replace_with::replace_with_or_abort;
38use std::{any::Any, borrow::Cow};
39
40trait AnyElement {
41 fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F;
42 fn after_layout(&mut self, _: &mut AfterLayoutContext) {}
43 fn paint(&mut self, origin: Vector2F, cx: &mut PaintContext);
44 fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool;
45 fn debug(&self, cx: &DebugContext) -> serde_json::Value;
46
47 fn size(&self) -> Vector2F;
48 fn metadata(&self) -> Option<&dyn Any>;
49}
50
51pub trait Element {
52 type LayoutState;
53 type PaintState;
54
55 fn layout(
56 &mut self,
57 constraint: SizeConstraint,
58 cx: &mut LayoutContext,
59 ) -> (Vector2F, Self::LayoutState);
60
61 fn after_layout(
62 &mut self,
63 size: Vector2F,
64 layout: &mut Self::LayoutState,
65 cx: &mut AfterLayoutContext,
66 );
67
68 fn paint(
69 &mut self,
70 bounds: RectF,
71 layout: &mut Self::LayoutState,
72 cx: &mut PaintContext,
73 ) -> Self::PaintState;
74
75 fn dispatch_event(
76 &mut self,
77 event: &Event,
78 bounds: RectF,
79 layout: &mut Self::LayoutState,
80 paint: &mut Self::PaintState,
81 cx: &mut EventContext,
82 ) -> bool;
83
84 fn metadata(&self) -> Option<&dyn Any> {
85 None
86 }
87
88 fn debug(
89 &self,
90 bounds: RectF,
91 layout: &Self::LayoutState,
92 paint: &Self::PaintState,
93 cx: &DebugContext,
94 ) -> serde_json::Value;
95
96 fn boxed(self) -> ElementBox
97 where
98 Self: 'static + Sized,
99 {
100 ElementBox {
101 name: None,
102 element: Box::new(Lifecycle::Init { element: self }),
103 }
104 }
105
106 fn named(self, name: impl Into<Cow<'static, str>>) -> ElementBox
107 where
108 Self: 'static + Sized,
109 {
110 ElementBox {
111 name: Some(name.into()),
112 element: Box::new(Lifecycle::Init { element: self }),
113 }
114 }
115}
116
117pub enum Lifecycle<T: Element> {
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 mut result = None;
143 replace_with_or_abort(self, |me| match me {
144 Lifecycle::Init { mut element }
145 | Lifecycle::PostLayout { mut element, .. }
146 | Lifecycle::PostPaint { mut element, .. } => {
147 let (size, layout) = element.layout(constraint, cx);
148 debug_assert!(size.x().is_finite());
149 debug_assert!(size.y().is_finite());
150
151 result = Some(size);
152 Lifecycle::PostLayout {
153 element,
154 constraint,
155 size,
156 layout,
157 }
158 }
159 });
160 result.unwrap()
161 }
162
163 fn after_layout(&mut self, cx: &mut AfterLayoutContext) {
164 if let Lifecycle::PostLayout {
165 element,
166 size,
167 layout,
168 ..
169 } = self
170 {
171 element.after_layout(*size, layout, cx);
172 } else {
173 panic!("invalid element lifecycle state");
174 }
175 }
176
177 fn paint(&mut self, origin: Vector2F, cx: &mut PaintContext) {
178 replace_with_or_abort(self, |me| {
179 if let Lifecycle::PostLayout {
180 mut element,
181 constraint,
182 size,
183 mut layout,
184 } = me
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
201 fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool {
202 if let Lifecycle::PostPaint {
203 element,
204 bounds,
205 layout,
206 paint,
207 ..
208 } = self
209 {
210 element.dispatch_event(event, *bounds, layout, paint, cx)
211 } else {
212 panic!("invalid element lifecycle state");
213 }
214 }
215
216 fn size(&self) -> Vector2F {
217 match self {
218 Lifecycle::Init { .. } => panic!("invalid element lifecycle state"),
219 Lifecycle::PostLayout { size, .. } => *size,
220 Lifecycle::PostPaint { bounds, .. } => bounds.size(),
221 }
222 }
223
224 fn metadata(&self) -> Option<&dyn Any> {
225 match self {
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 ElementBox {
261 pub fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F {
262 self.element.layout(constraint, cx)
263 }
264
265 pub fn after_layout(&mut self, cx: &mut AfterLayoutContext) {
266 self.element.after_layout(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> {}