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