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 layout: &mut Self::LayoutState,
78 paint: &mut Self::PaintState,
79 cx: &mut EventContext,
80 ) -> bool;
81
82 fn metadata(&self) -> Option<&dyn Any> {
83 None
84 }
85
86 fn debug(
87 &self,
88 bounds: RectF,
89 layout: &Self::LayoutState,
90 paint: &Self::PaintState,
91 cx: &DebugContext,
92 ) -> serde_json::Value;
93
94 fn boxed(self) -> ElementBox
95 where
96 Self: 'static + Sized,
97 {
98 ElementBox(ElementRc {
99 name: None,
100 element: Rc::new(RefCell::new(Lifecycle::Init { element: self })),
101 })
102 }
103
104 fn named(self, name: impl Into<Cow<'static, str>>) -> ElementBox
105 where
106 Self: 'static + Sized,
107 {
108 ElementBox(ElementRc {
109 name: Some(name.into()),
110 element: Rc::new(RefCell::new(Lifecycle::Init { element: self })),
111 })
112 }
113
114 fn constrained(self) -> ConstrainedBox
115 where
116 Self: 'static + Sized,
117 {
118 ConstrainedBox::new(self.boxed())
119 }
120
121 fn aligned(self) -> Align
122 where
123 Self: 'static + Sized,
124 {
125 Align::new(self.boxed())
126 }
127
128 fn contained(self) -> Container
129 where
130 Self: 'static + Sized,
131 {
132 Container::new(self.boxed())
133 }
134
135 fn expanded(self) -> Expanded
136 where
137 Self: 'static + Sized,
138 {
139 Expanded::new(self.boxed())
140 }
141
142 fn flexible(self, flex: f32, expanded: bool) -> Flexible
143 where
144 Self: 'static + Sized,
145 {
146 Flexible::new(flex, expanded, self.boxed())
147 }
148}
149
150pub enum Lifecycle<T: Element> {
151 Empty,
152 Init {
153 element: T,
154 },
155 PostLayout {
156 element: T,
157 constraint: SizeConstraint,
158 size: Vector2F,
159 layout: T::LayoutState,
160 },
161 PostPaint {
162 element: T,
163 constraint: SizeConstraint,
164 bounds: RectF,
165 layout: T::LayoutState,
166 paint: T::PaintState,
167 },
168}
169pub struct ElementBox(ElementRc);
170
171#[derive(Clone)]
172pub struct ElementRc {
173 name: Option<Cow<'static, str>>,
174 element: Rc<RefCell<dyn AnyElement>>,
175}
176
177impl<T: Element> AnyElement for Lifecycle<T> {
178 fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F {
179 let result;
180 *self = match mem::take(self) {
181 Lifecycle::Empty => unreachable!(),
182 Lifecycle::Init { mut element }
183 | Lifecycle::PostLayout { mut element, .. }
184 | Lifecycle::PostPaint { mut element, .. } => {
185 let (size, layout) = element.layout(constraint, cx);
186 debug_assert!(size.x().is_finite());
187 debug_assert!(size.y().is_finite());
188
189 result = size;
190 Lifecycle::PostLayout {
191 element,
192 constraint,
193 size,
194 layout,
195 }
196 }
197 };
198 result
199 }
200
201 fn paint(&mut self, origin: Vector2F, visible_bounds: RectF, cx: &mut PaintContext) {
202 *self = match mem::take(self) {
203 Lifecycle::PostLayout {
204 mut element,
205 constraint,
206 size,
207 mut layout,
208 } => {
209 let bounds = RectF::new(origin, size);
210 let visible_bounds = visible_bounds
211 .intersection(bounds)
212 .unwrap_or_else(|| RectF::new(bounds.origin(), Vector2F::default()));
213 let paint = element.paint(bounds, visible_bounds, &mut layout, cx);
214 Lifecycle::PostPaint {
215 element,
216 constraint,
217 bounds,
218 layout,
219 paint,
220 }
221 }
222 Lifecycle::PostPaint {
223 mut element,
224 constraint,
225 bounds,
226 mut layout,
227 ..
228 } => {
229 let bounds = RectF::new(origin, bounds.size());
230 let visible_bounds = visible_bounds
231 .intersection(bounds)
232 .unwrap_or_else(|| RectF::new(bounds.origin(), Vector2F::default()));
233 let paint = element.paint(bounds, visible_bounds, &mut layout, cx);
234 Lifecycle::PostPaint {
235 element,
236 constraint,
237 bounds,
238 layout,
239 paint,
240 }
241 }
242 _ => panic!("invalid element lifecycle state"),
243 }
244 }
245
246 fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool {
247 if let Lifecycle::PostPaint {
248 element,
249 bounds,
250 layout,
251 paint,
252 ..
253 } = self
254 {
255 element.dispatch_event(event, *bounds, layout, paint, cx)
256 } else {
257 panic!("invalid element lifecycle state");
258 }
259 }
260
261 fn size(&self) -> Vector2F {
262 match self {
263 Lifecycle::Empty | Lifecycle::Init { .. } => panic!("invalid element lifecycle state"),
264 Lifecycle::PostLayout { size, .. } => *size,
265 Lifecycle::PostPaint { bounds, .. } => bounds.size(),
266 }
267 }
268
269 fn metadata(&self) -> Option<&dyn Any> {
270 match self {
271 Lifecycle::Empty => unreachable!(),
272 Lifecycle::Init { element }
273 | Lifecycle::PostLayout { element, .. }
274 | Lifecycle::PostPaint { element, .. } => element.metadata(),
275 }
276 }
277
278 fn debug(&self, cx: &DebugContext) -> serde_json::Value {
279 match self {
280 Lifecycle::PostPaint {
281 element,
282 constraint,
283 bounds,
284 layout,
285 paint,
286 } => {
287 let mut value = element.debug(*bounds, layout, paint, cx);
288 if let json::Value::Object(map) = &mut value {
289 let mut new_map: crate::json::Map<String, serde_json::Value> =
290 Default::default();
291 if let Some(typ) = map.remove("type") {
292 new_map.insert("type".into(), typ);
293 }
294 new_map.insert("constraint".into(), constraint.to_json());
295 new_map.append(map);
296 json::Value::Object(new_map)
297 } else {
298 value
299 }
300 }
301 _ => panic!("invalid element lifecycle state"),
302 }
303 }
304}
305
306impl<T: Element> Default for Lifecycle<T> {
307 fn default() -> Self {
308 Self::Empty
309 }
310}
311
312impl ElementBox {
313 pub fn name(&self) -> Option<&str> {
314 self.0.name.as_deref()
315 }
316
317 pub fn metadata<T: 'static>(&self) -> Option<&T> {
318 let element = unsafe { &*self.0.element.as_ptr() };
319 element.metadata().and_then(|m| m.downcast_ref())
320 }
321}
322
323impl Into<ElementRc> for ElementBox {
324 fn into(self) -> ElementRc {
325 self.0
326 }
327}
328
329impl Deref for ElementBox {
330 type Target = ElementRc;
331
332 fn deref(&self) -> &Self::Target {
333 &self.0
334 }
335}
336
337impl DerefMut for ElementBox {
338 fn deref_mut(&mut self) -> &mut Self::Target {
339 &mut self.0
340 }
341}
342
343impl ElementRc {
344 pub fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F {
345 self.element.borrow_mut().layout(constraint, cx)
346 }
347
348 pub fn paint(&mut self, origin: Vector2F, visible_bounds: RectF, cx: &mut PaintContext) {
349 self.element.borrow_mut().paint(origin, visible_bounds, cx);
350 }
351
352 pub fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool {
353 self.element.borrow_mut().dispatch_event(event, cx)
354 }
355
356 pub fn size(&self) -> Vector2F {
357 self.element.borrow().size()
358 }
359
360 pub fn debug(&self, cx: &DebugContext) -> json::Value {
361 let mut value = self.element.borrow().debug(cx);
362
363 if let Some(name) = &self.name {
364 if let json::Value::Object(map) = &mut value {
365 let mut new_map: crate::json::Map<String, serde_json::Value> = Default::default();
366 new_map.insert("name".into(), json::Value::String(name.to_string()));
367 new_map.append(map);
368 return json::Value::Object(new_map);
369 }
370 }
371
372 value
373 }
374
375 pub fn with_metadata<T, F, R>(&self, f: F) -> R
376 where
377 T: 'static,
378 F: FnOnce(Option<&T>) -> R,
379 {
380 let element = self.element.borrow();
381 f(element.metadata().and_then(|m| m.downcast_ref()))
382 }
383}
384
385pub trait ParentElement<'a>: Extend<ElementBox> + Sized {
386 fn add_children(&mut self, children: impl IntoIterator<Item = ElementBox>) {
387 self.extend(children);
388 }
389
390 fn add_child(&mut self, child: ElementBox) {
391 self.add_children(Some(child));
392 }
393
394 fn with_children(mut self, children: impl IntoIterator<Item = ElementBox>) -> Self {
395 self.add_children(children);
396 self
397 }
398
399 fn with_child(self, child: ElementBox) -> Self {
400 self.with_children(Some(child))
401 }
402}
403
404impl<'a, T> ParentElement<'a> for T where T: Extend<ElementBox> {}
405
406fn constrain_size_preserving_aspect_ratio(max_size: Vector2F, size: Vector2F) -> Vector2F {
407 if max_size.x().is_infinite() && max_size.y().is_infinite() {
408 size
409 } else if max_size.x().is_infinite() || max_size.x() / max_size.y() > size.x() / size.y() {
410 vec2f(size.x() * max_size.y() / size.y(), max_size.y())
411 } else {
412 vec2f(max_size.x(), size.y() * max_size.x() / size.x())
413 }
414}