1mod align;
2mod canvas;
3mod constrained_box;
4mod container;
5mod empty;
6mod event_handler;
7mod expanded;
8mod flex;
9mod hook;
10mod image;
11mod label;
12mod list;
13mod mouse_event_handler;
14mod overlay;
15mod stack;
16mod svg;
17mod text;
18mod uniform_list;
19
20use self::expanded::Expanded;
21pub use self::{
22 align::*, canvas::*, constrained_box::*, container::*, empty::*, event_handler::*, flex::*,
23 hook::*, image::*, label::*, list::*, mouse_event_handler::*, overlay::*, stack::*, svg::*,
24 text::*, uniform_list::*,
25};
26pub use crate::presenter::ChildView;
27use crate::{
28 geometry::{
29 rect::RectF,
30 vector::{vec2f, Vector2F},
31 },
32 json, DebugContext, Event, EventContext, LayoutContext, PaintContext, SizeConstraint,
33};
34use core::panic;
35use json::ToJson;
36use std::{
37 any::Any,
38 borrow::Cow,
39 cell::RefCell,
40 mem,
41 ops::{Deref, DerefMut},
42 rc::Rc,
43};
44
45trait AnyElement {
46 fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F;
47 fn paint(&mut self, origin: Vector2F, visible_bounds: RectF, cx: &mut PaintContext);
48 fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool;
49 fn debug(&self, cx: &DebugContext) -> serde_json::Value;
50
51 fn size(&self) -> Vector2F;
52 fn metadata(&self) -> Option<&dyn Any>;
53}
54
55pub trait Element {
56 type LayoutState;
57 type PaintState;
58
59 fn layout(
60 &mut self,
61 constraint: SizeConstraint,
62 cx: &mut LayoutContext,
63 ) -> (Vector2F, Self::LayoutState);
64
65 fn paint(
66 &mut self,
67 bounds: RectF,
68 visible_bounds: RectF,
69 layout: &mut Self::LayoutState,
70 cx: &mut PaintContext,
71 ) -> Self::PaintState;
72
73 fn dispatch_event(
74 &mut self,
75 event: &Event,
76 bounds: RectF,
77 visible_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(ElementRc {
100 name: None,
101 element: Rc::new(RefCell::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(ElementRc {
110 name: Some(name.into()),
111 element: Rc::new(RefCell::new(Lifecycle::Init { element: self })),
112 })
113 }
114
115 fn constrained(self) -> ConstrainedBox
116 where
117 Self: 'static + Sized,
118 {
119 ConstrainedBox::new(self.boxed())
120 }
121
122 fn aligned(self) -> Align
123 where
124 Self: 'static + Sized,
125 {
126 Align::new(self.boxed())
127 }
128
129 fn contained(self) -> Container
130 where
131 Self: 'static + Sized,
132 {
133 Container::new(self.boxed())
134 }
135
136 fn expanded(self) -> Expanded
137 where
138 Self: 'static + Sized,
139 {
140 Expanded::new(self.boxed())
141 }
142
143 fn flex(self, flex: f32, expanded: bool) -> FlexItem
144 where
145 Self: 'static + Sized,
146 {
147 FlexItem::new(self.boxed()).flex(flex, expanded)
148 }
149
150 fn flex_float(self) -> FlexItem
151 where
152 Self: 'static + Sized,
153 {
154 FlexItem::new(self.boxed()).float()
155 }
156}
157
158pub enum Lifecycle<T: Element> {
159 Empty,
160 Init {
161 element: T,
162 },
163 PostLayout {
164 element: T,
165 constraint: SizeConstraint,
166 size: Vector2F,
167 layout: T::LayoutState,
168 },
169 PostPaint {
170 element: T,
171 constraint: SizeConstraint,
172 bounds: RectF,
173 visible_bounds: RectF,
174 layout: T::LayoutState,
175 paint: T::PaintState,
176 },
177}
178pub struct ElementBox(ElementRc);
179
180#[derive(Clone)]
181pub struct ElementRc {
182 name: Option<Cow<'static, str>>,
183 element: Rc<RefCell<dyn AnyElement>>,
184}
185
186impl<T: Element> AnyElement for Lifecycle<T> {
187 fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F {
188 let result;
189 *self = match mem::take(self) {
190 Lifecycle::Empty => unreachable!(),
191 Lifecycle::Init { mut element }
192 | Lifecycle::PostLayout { mut element, .. }
193 | Lifecycle::PostPaint { mut element, .. } => {
194 let (size, layout) = element.layout(constraint, cx);
195 debug_assert!(size.x().is_finite());
196 debug_assert!(size.y().is_finite());
197
198 result = size;
199 Lifecycle::PostLayout {
200 element,
201 constraint,
202 size,
203 layout,
204 }
205 }
206 };
207 result
208 }
209
210 fn paint(&mut self, origin: Vector2F, visible_bounds: RectF, cx: &mut PaintContext) {
211 *self = match mem::take(self) {
212 Lifecycle::PostLayout {
213 mut element,
214 constraint,
215 size,
216 mut layout,
217 } => {
218 let bounds = RectF::new(origin, size);
219 let visible_bounds = visible_bounds
220 .intersection(bounds)
221 .unwrap_or_else(|| RectF::new(bounds.origin(), Vector2F::default()));
222 let paint = element.paint(bounds, visible_bounds, &mut layout, cx);
223 Lifecycle::PostPaint {
224 element,
225 constraint,
226 bounds,
227 visible_bounds,
228 layout,
229 paint,
230 }
231 }
232 Lifecycle::PostPaint {
233 mut element,
234 constraint,
235 bounds,
236 mut layout,
237 ..
238 } => {
239 let bounds = RectF::new(origin, bounds.size());
240 let visible_bounds = visible_bounds
241 .intersection(bounds)
242 .unwrap_or_else(|| RectF::new(bounds.origin(), Vector2F::default()));
243 let paint = element.paint(bounds, visible_bounds, &mut layout, cx);
244 Lifecycle::PostPaint {
245 element,
246 constraint,
247 bounds,
248 visible_bounds,
249 layout,
250 paint,
251 }
252 }
253 _ => panic!("invalid element lifecycle state"),
254 }
255 }
256
257 fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool {
258 if let Lifecycle::PostPaint {
259 element,
260 bounds,
261 visible_bounds,
262 layout,
263 paint,
264 ..
265 } = self
266 {
267 element.dispatch_event(event, *bounds, *visible_bounds, layout, paint, cx)
268 } else {
269 panic!("invalid element lifecycle state");
270 }
271 }
272
273 fn size(&self) -> Vector2F {
274 match self {
275 Lifecycle::Empty | Lifecycle::Init { .. } => panic!("invalid element lifecycle state"),
276 Lifecycle::PostLayout { size, .. } => *size,
277 Lifecycle::PostPaint { bounds, .. } => bounds.size(),
278 }
279 }
280
281 fn metadata(&self) -> Option<&dyn Any> {
282 match self {
283 Lifecycle::Empty => unreachable!(),
284 Lifecycle::Init { element }
285 | Lifecycle::PostLayout { element, .. }
286 | Lifecycle::PostPaint { element, .. } => element.metadata(),
287 }
288 }
289
290 fn debug(&self, cx: &DebugContext) -> serde_json::Value {
291 match self {
292 Lifecycle::PostPaint {
293 element,
294 constraint,
295 bounds,
296 visible_bounds,
297 layout,
298 paint,
299 } => {
300 let mut value = element.debug(*bounds, layout, paint, cx);
301 if let json::Value::Object(map) = &mut value {
302 let mut new_map: crate::json::Map<String, serde_json::Value> =
303 Default::default();
304 if let Some(typ) = map.remove("type") {
305 new_map.insert("type".into(), typ);
306 }
307 new_map.insert("constraint".into(), constraint.to_json());
308 new_map.insert("bounds".into(), bounds.to_json());
309 new_map.insert("visible_bounds".into(), visible_bounds.to_json());
310 new_map.append(map);
311 json::Value::Object(new_map)
312 } else {
313 value
314 }
315 }
316 _ => panic!("invalid element lifecycle state"),
317 }
318 }
319}
320
321impl<T: Element> Default for Lifecycle<T> {
322 fn default() -> Self {
323 Self::Empty
324 }
325}
326
327impl ElementBox {
328 pub fn name(&self) -> Option<&str> {
329 self.0.name.as_deref()
330 }
331
332 pub fn metadata<T: 'static>(&self) -> Option<&T> {
333 let element = unsafe { &*self.0.element.as_ptr() };
334 element.metadata().and_then(|m| m.downcast_ref())
335 }
336}
337
338impl Into<ElementRc> for ElementBox {
339 fn into(self) -> ElementRc {
340 self.0
341 }
342}
343
344impl Deref for ElementBox {
345 type Target = ElementRc;
346
347 fn deref(&self) -> &Self::Target {
348 &self.0
349 }
350}
351
352impl DerefMut for ElementBox {
353 fn deref_mut(&mut self) -> &mut Self::Target {
354 &mut self.0
355 }
356}
357
358impl ElementRc {
359 pub fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F {
360 self.element.borrow_mut().layout(constraint, cx)
361 }
362
363 pub fn paint(&mut self, origin: Vector2F, visible_bounds: RectF, cx: &mut PaintContext) {
364 self.element.borrow_mut().paint(origin, visible_bounds, cx);
365 }
366
367 pub fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool {
368 self.element.borrow_mut().dispatch_event(event, cx)
369 }
370
371 pub fn size(&self) -> Vector2F {
372 self.element.borrow().size()
373 }
374
375 pub fn debug(&self, cx: &DebugContext) -> json::Value {
376 let mut value = self.element.borrow().debug(cx);
377
378 if let Some(name) = &self.name {
379 if let json::Value::Object(map) = &mut value {
380 let mut new_map: crate::json::Map<String, serde_json::Value> = Default::default();
381 new_map.insert("name".into(), json::Value::String(name.to_string()));
382 new_map.append(map);
383 return json::Value::Object(new_map);
384 }
385 }
386
387 value
388 }
389
390 pub fn with_metadata<T, F, R>(&self, f: F) -> R
391 where
392 T: 'static,
393 F: FnOnce(Option<&T>) -> R,
394 {
395 let element = self.element.borrow();
396 f(element.metadata().and_then(|m| m.downcast_ref()))
397 }
398}
399
400pub trait ParentElement<'a>: Extend<ElementBox> + Sized {
401 fn add_children(&mut self, children: impl IntoIterator<Item = ElementBox>) {
402 self.extend(children);
403 }
404
405 fn add_child(&mut self, child: ElementBox) {
406 self.add_children(Some(child));
407 }
408
409 fn with_children(mut self, children: impl IntoIterator<Item = ElementBox>) -> Self {
410 self.add_children(children);
411 self
412 }
413
414 fn with_child(self, child: ElementBox) -> Self {
415 self.with_children(Some(child))
416 }
417}
418
419impl<'a, T> ParentElement<'a> for T where T: Extend<ElementBox> {}
420
421fn constrain_size_preserving_aspect_ratio(max_size: Vector2F, size: Vector2F) -> Vector2F {
422 if max_size.x().is_infinite() && max_size.y().is_infinite() {
423 size
424 } else if max_size.x().is_infinite() || max_size.x() / max_size.y() > size.x() / size.y() {
425 vec2f(size.x() * max_size.y() / size.y(), max_size.y())
426 } else {
427 vec2f(max_size.x(), size.y() * max_size.x() / size.x())
428 }
429}