1use crate::{
2 geometry::{rect::RectF, vector::Vector2F},
3 json, AfterLayoutContext, DebugContext, Event, EventContext, LayoutContext, PaintContext,
4 SizeConstraint,
5};
6use core::panic;
7use replace_with::replace_with_or_abort;
8use std::{any::Any, borrow::Cow};
9
10trait AnyElement {
11 fn layout(&mut self, constraint: SizeConstraint, ctx: &mut LayoutContext) -> Vector2F;
12 fn after_layout(&mut self, _: &mut AfterLayoutContext) {}
13 fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext);
14 fn dispatch_event(&mut self, event: &Event, ctx: &mut EventContext) -> bool;
15 fn debug(&self, ctx: &DebugContext) -> serde_json::Value;
16
17 fn size(&self) -> Vector2F;
18 fn metadata(&self) -> Option<&dyn Any>;
19}
20
21pub trait Element {
22 type LayoutState;
23 type PaintState;
24
25 fn layout(
26 &mut self,
27 constraint: SizeConstraint,
28 ctx: &mut LayoutContext,
29 ) -> (Vector2F, Self::LayoutState);
30
31 fn after_layout(
32 &mut self,
33 size: Vector2F,
34 layout: &mut Self::LayoutState,
35 ctx: &mut AfterLayoutContext,
36 );
37
38 fn paint(
39 &mut self,
40 bounds: RectF,
41 layout: &mut Self::LayoutState,
42 ctx: &mut PaintContext,
43 ) -> Self::PaintState;
44
45 fn dispatch_event(
46 &mut self,
47 event: &Event,
48 bounds: RectF,
49 layout: &mut Self::LayoutState,
50 paint: &mut Self::PaintState,
51 ctx: &mut EventContext,
52 ) -> bool;
53
54 fn metadata(&self) -> Option<&dyn Any> {
55 None
56 }
57
58 fn debug(
59 &self,
60 bounds: RectF,
61 layout: &Self::LayoutState,
62 paint: &Self::PaintState,
63 ctx: &DebugContext,
64 ) -> serde_json::Value;
65
66 fn boxed(self) -> ElementBox
67 where
68 Self: 'static + Sized,
69 {
70 ElementBox {
71 name: None,
72 element: Box::new(Lifecycle::Init { element: self }),
73 }
74 }
75
76 fn named(self, name: impl Into<Cow<'static, str>>) -> ElementBox
77 where
78 Self: 'static + Sized,
79 {
80 ElementBox {
81 name: Some(name.into()),
82 element: Box::new(Lifecycle::Init { element: self }),
83 }
84 }
85}
86
87pub enum Lifecycle<T: Element> {
88 Init {
89 element: T,
90 },
91 PostLayout {
92 element: T,
93 size: Vector2F,
94 layout: T::LayoutState,
95 },
96 PostPaint {
97 element: T,
98 bounds: RectF,
99 layout: T::LayoutState,
100 paint: T::PaintState,
101 },
102}
103pub struct ElementBox {
104 name: Option<Cow<'static, str>>,
105 element: Box<dyn AnyElement>,
106}
107
108impl<T: Element> AnyElement for Lifecycle<T> {
109 fn layout(&mut self, constraint: SizeConstraint, ctx: &mut LayoutContext) -> Vector2F {
110 let mut result = None;
111 replace_with_or_abort(self, |me| match me {
112 Lifecycle::Init { mut element }
113 | Lifecycle::PostLayout { mut element, .. }
114 | Lifecycle::PostPaint { mut element, .. } => {
115 let (size, layout) = element.layout(constraint, ctx);
116 debug_assert!(size.x().is_finite());
117 debug_assert!(size.y().is_finite());
118
119 result = Some(size);
120 Lifecycle::PostLayout {
121 element,
122 size,
123 layout,
124 }
125 }
126 });
127 result.unwrap()
128 }
129
130 fn after_layout(&mut self, ctx: &mut AfterLayoutContext) {
131 if let Lifecycle::PostLayout {
132 element,
133 size,
134 layout,
135 } = self
136 {
137 element.after_layout(*size, layout, ctx);
138 } else {
139 panic!("invalid element lifecycle state");
140 }
141 }
142
143 fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext) {
144 replace_with_or_abort(self, |me| {
145 if let Lifecycle::PostLayout {
146 mut element,
147 size,
148 mut layout,
149 } = me
150 {
151 let bounds = RectF::new(origin, size);
152 let paint = element.paint(bounds, &mut layout, ctx);
153 Lifecycle::PostPaint {
154 element,
155 bounds,
156 layout,
157 paint,
158 }
159 } else {
160 panic!("invalid element lifecycle state");
161 }
162 });
163 }
164
165 fn dispatch_event(&mut self, event: &Event, ctx: &mut EventContext) -> bool {
166 if let Lifecycle::PostPaint {
167 element,
168 bounds,
169 layout,
170 paint,
171 } = self
172 {
173 element.dispatch_event(event, *bounds, layout, paint, ctx)
174 } else {
175 panic!("invalid element lifecycle state");
176 }
177 }
178
179 fn size(&self) -> Vector2F {
180 match self {
181 Lifecycle::Init { .. } => panic!("invalid element lifecycle state"),
182 Lifecycle::PostLayout { size, .. } => *size,
183 Lifecycle::PostPaint { bounds, .. } => bounds.size(),
184 }
185 }
186
187 fn metadata(&self) -> Option<&dyn Any> {
188 match self {
189 Lifecycle::Init { element }
190 | Lifecycle::PostLayout { element, .. }
191 | Lifecycle::PostPaint { element, .. } => element.metadata(),
192 }
193 }
194
195 fn debug(&self, ctx: &DebugContext) -> serde_json::Value {
196 match self {
197 Lifecycle::PostPaint {
198 element,
199 bounds,
200 layout,
201 paint,
202 } => element.debug(*bounds, layout, paint, ctx),
203 _ => panic!("invalid element lifecycle state"),
204 }
205 }
206}
207
208impl ElementBox {
209 pub fn layout(&mut self, constraint: SizeConstraint, ctx: &mut LayoutContext) -> Vector2F {
210 self.element.layout(constraint, ctx)
211 }
212
213 pub fn after_layout(&mut self, ctx: &mut AfterLayoutContext) {
214 self.element.after_layout(ctx);
215 }
216
217 pub fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext) {
218 self.element.paint(origin, ctx);
219 }
220
221 pub fn dispatch_event(&mut self, event: &Event, ctx: &mut EventContext) -> bool {
222 self.element.dispatch_event(event, ctx)
223 }
224
225 pub fn size(&self) -> Vector2F {
226 self.element.size()
227 }
228
229 pub fn metadata(&self) -> Option<&dyn Any> {
230 self.element.metadata()
231 }
232
233 pub fn debug(&self, ctx: &DebugContext) -> json::Value {
234 let mut value = self.element.debug(ctx);
235
236 if let Some(name) = &self.name {
237 if let json::Value::Object(map) = &mut value {
238 let mut new_map: crate::json::Map<String, serde_json::Value> = Default::default();
239 new_map.insert("name".into(), json::Value::String(name.to_string()));
240 new_map.append(map);
241 return json::Value::Object(new_map);
242 }
243 }
244
245 value
246 }
247}