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