1mod align;
2mod canvas;
3mod clipped;
4mod constrained_box;
5mod container;
6mod empty;
7mod expanded;
8mod flex;
9mod hook;
10mod image;
11mod keystroke_label;
12mod label;
13mod list;
14mod mouse_event_handler;
15pub mod node;
16mod overlay;
17mod resizable;
18mod stack;
19mod svg;
20mod text;
21mod tooltip;
22mod uniform_list;
23
24pub use self::{
25 align::*, canvas::*, constrained_box::*, container::*, empty::*, flex::*, hook::*, image::*,
26 keystroke_label::*, label::*, list::*, mouse_event_handler::*, overlay::*, resizable::*,
27 stack::*, svg::*, text::*, tooltip::*, uniform_list::*,
28};
29pub use crate::window::ChildView;
30
31use self::{
32 clipped::Clipped,
33 expanded::Expanded,
34 node::{length::Length, node, Node},
35};
36use crate::{
37 geometry::{
38 rect::RectF,
39 vector::{vec2f, Vector2F},
40 },
41 json, Action, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, View, ViewContext,
42 WeakViewHandle, WindowContext,
43};
44use anyhow::{anyhow, Result};
45use collections::HashMap;
46use core::panic;
47use json::ToJson;
48use smallvec::SmallVec;
49use std::{any::Any, borrow::Cow, mem, ops::Range};
50
51pub trait Element<V: View>: 'static {
52 type LayoutState;
53 type PaintState;
54
55 fn layout(
56 &mut self,
57 constraint: SizeConstraint,
58 view: &mut V,
59 cx: &mut LayoutContext<V>,
60 ) -> (Vector2F, Self::LayoutState);
61
62 fn paint(
63 &mut self,
64 scene: &mut SceneBuilder,
65 bounds: RectF,
66 visible_bounds: RectF,
67 layout: &mut Self::LayoutState,
68 view: &mut V,
69 cx: &mut PaintContext<V>,
70 ) -> Self::PaintState;
71
72 fn rect_for_text_range(
73 &self,
74 range_utf16: Range<usize>,
75 bounds: RectF,
76 visible_bounds: RectF,
77 layout: &Self::LayoutState,
78 paint: &Self::PaintState,
79 view: &V,
80 cx: &ViewContext<V>,
81 ) -> Option<RectF>;
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 view: &V,
93 cx: &ViewContext<V>,
94 ) -> serde_json::Value;
95
96 fn into_any(self) -> AnyElement<V>
97 where
98 Self: 'static + Sized,
99 {
100 AnyElement {
101 state: Box::new(ElementState::Init { element: self }),
102 name: None,
103 }
104 }
105
106 fn into_any_named(self, name: impl Into<Cow<'static, str>>) -> AnyElement<V>
107 where
108 Self: 'static + Sized,
109 {
110 AnyElement {
111 state: Box::new(ElementState::Init { element: self }),
112 name: Some(name.into()),
113 }
114 }
115
116 fn into_root_element(self, cx: &ViewContext<V>) -> RootElement<V>
117 where
118 Self: 'static + Sized,
119 {
120 RootElement {
121 element: self.into_any(),
122 view: cx.handle().downgrade(),
123 }
124 }
125
126 fn constrained(self) -> ConstrainedBox<V>
127 where
128 Self: 'static + Sized,
129 {
130 ConstrainedBox::new(self.into_any())
131 }
132
133 fn aligned(self) -> Align<V>
134 where
135 Self: 'static + Sized,
136 {
137 Align::new(self.into_any())
138 }
139
140 fn clipped(self) -> Clipped<V>
141 where
142 Self: 'static + Sized,
143 {
144 Clipped::new(self.into_any())
145 }
146
147 fn contained(self) -> Container<V>
148 where
149 Self: 'static + Sized,
150 {
151 Container::new(self.into_any())
152 }
153
154 fn expanded(self) -> Expanded<V>
155 where
156 Self: 'static + Sized,
157 {
158 Expanded::new(self.into_any())
159 }
160
161 fn flex(self, flex: f32, expanded: bool) -> FlexItem<V>
162 where
163 Self: 'static + Sized,
164 {
165 FlexItem::new(self.into_any()).flex(flex, expanded)
166 }
167
168 fn flex_float(self) -> FlexItem<V>
169 where
170 Self: 'static + Sized,
171 {
172 FlexItem::new(self.into_any()).float()
173 }
174
175 fn with_tooltip<Tag: 'static>(
176 self,
177 id: usize,
178 text: String,
179 action: Option<Box<dyn Action>>,
180 style: TooltipStyle,
181 cx: &mut ViewContext<V>,
182 ) -> Tooltip<V>
183 where
184 Self: 'static + Sized,
185 {
186 Tooltip::new::<Tag, V>(id, text, action, style, self.into_any(), cx)
187 }
188
189 fn resizable(
190 self,
191 side: HandleSide,
192 size: f32,
193 on_resize: impl 'static + FnMut(&mut V, f32, &mut ViewContext<V>),
194 ) -> Resizable<V>
195 where
196 Self: 'static + Sized,
197 {
198 Resizable::new(self.into_any(), side, size, on_resize)
199 }
200
201 fn mouse<Tag>(self, region_id: usize) -> MouseEventHandler<Tag, V>
202 where
203 Self: Sized,
204 {
205 MouseEventHandler::for_child(self.into_any(), region_id)
206 }
207
208 fn margin_left(self, margin_left: impl Into<Length>) -> Node<V>
209 where
210 Self: Sized,
211 {
212 node(self).margin_left(margin_left)
213 }
214}
215
216trait AnyElementState<V: View> {
217 fn layout(
218 &mut self,
219 constraint: SizeConstraint,
220 view: &mut V,
221 cx: &mut LayoutContext<V>,
222 ) -> Vector2F;
223
224 fn paint(
225 &mut self,
226 scene: &mut SceneBuilder,
227 origin: Vector2F,
228 visible_bounds: RectF,
229 view: &mut V,
230 cx: &mut ViewContext<V>,
231 );
232
233 fn rect_for_text_range(
234 &self,
235 range_utf16: Range<usize>,
236 view: &V,
237 cx: &ViewContext<V>,
238 ) -> Option<RectF>;
239
240 fn debug(&self, view: &V, cx: &ViewContext<V>) -> serde_json::Value;
241
242 fn size(&self) -> Vector2F;
243
244 fn metadata(&self) -> Option<&dyn Any>;
245}
246
247enum ElementState<V: View, E: Element<V>> {
248 Empty,
249 Init {
250 element: E,
251 },
252 PostLayout {
253 element: E,
254 constraint: SizeConstraint,
255 size: Vector2F,
256 layout: E::LayoutState,
257 },
258 PostPaint {
259 element: E,
260 constraint: SizeConstraint,
261 bounds: RectF,
262 visible_bounds: RectF,
263 layout: E::LayoutState,
264 paint: E::PaintState,
265 },
266}
267
268impl<V: View, E: Element<V>> AnyElementState<V> for ElementState<V, E> {
269 fn layout(
270 &mut self,
271 constraint: SizeConstraint,
272 view: &mut V,
273 cx: &mut LayoutContext<V>,
274 ) -> Vector2F {
275 let result;
276 *self = match mem::take(self) {
277 ElementState::Empty => unreachable!(),
278 ElementState::Init { mut element }
279 | ElementState::PostLayout { mut element, .. }
280 | ElementState::PostPaint { mut element, .. } => {
281 let (size, layout) = element.layout(constraint, view, cx);
282 debug_assert!(size.x().is_finite());
283 debug_assert!(size.y().is_finite());
284
285 result = size;
286 ElementState::PostLayout {
287 element,
288 constraint,
289 size,
290 layout,
291 }
292 }
293 };
294 result
295 }
296
297 fn paint(
298 &mut self,
299 scene: &mut SceneBuilder,
300 origin: Vector2F,
301 visible_bounds: RectF,
302 view: &mut V,
303 cx: &mut ViewContext<V>,
304 ) {
305 *self = match mem::take(self) {
306 ElementState::PostLayout {
307 mut element,
308 constraint,
309 size,
310 mut layout,
311 } => {
312 let bounds = RectF::new(origin, size);
313 let paint = element.paint(
314 scene,
315 bounds,
316 visible_bounds,
317 &mut layout,
318 view,
319 &mut PaintContext::new(cx),
320 );
321 ElementState::PostPaint {
322 element,
323 constraint,
324 bounds,
325 visible_bounds,
326 layout,
327 paint,
328 }
329 }
330 ElementState::PostPaint {
331 mut element,
332 constraint,
333 bounds,
334 mut layout,
335 ..
336 } => {
337 let bounds = RectF::new(origin, bounds.size());
338 let paint = element.paint(
339 scene,
340 bounds,
341 visible_bounds,
342 &mut layout,
343 view,
344 &mut PaintContext::new(cx),
345 );
346 ElementState::PostPaint {
347 element,
348 constraint,
349 bounds,
350 visible_bounds,
351 layout,
352 paint,
353 }
354 }
355 ElementState::Empty => panic!("invalid element lifecycle state"),
356 ElementState::Init { .. } => {
357 panic!("invalid element lifecycle state, paint called before layout")
358 }
359 }
360 }
361
362 fn rect_for_text_range(
363 &self,
364 range_utf16: Range<usize>,
365 view: &V,
366 cx: &ViewContext<V>,
367 ) -> Option<RectF> {
368 if let ElementState::PostPaint {
369 element,
370 bounds,
371 visible_bounds,
372 layout,
373 paint,
374 ..
375 } = self
376 {
377 element.rect_for_text_range(
378 range_utf16,
379 *bounds,
380 *visible_bounds,
381 layout,
382 paint,
383 view,
384 cx,
385 )
386 } else {
387 None
388 }
389 }
390
391 fn size(&self) -> Vector2F {
392 match self {
393 ElementState::Empty | ElementState::Init { .. } => {
394 panic!("invalid element lifecycle state")
395 }
396 ElementState::PostLayout { size, .. } => *size,
397 ElementState::PostPaint { bounds, .. } => bounds.size(),
398 }
399 }
400
401 fn metadata(&self) -> Option<&dyn Any> {
402 match self {
403 ElementState::Empty => unreachable!(),
404 ElementState::Init { element }
405 | ElementState::PostLayout { element, .. }
406 | ElementState::PostPaint { element, .. } => element.metadata(),
407 }
408 }
409
410 fn debug(&self, view: &V, cx: &ViewContext<V>) -> serde_json::Value {
411 match self {
412 ElementState::PostPaint {
413 element,
414 constraint,
415 bounds,
416 visible_bounds,
417 layout,
418 paint,
419 } => {
420 let mut value = element.debug(*bounds, layout, paint, view, cx);
421 if let json::Value::Object(map) = &mut value {
422 let mut new_map: crate::json::Map<String, serde_json::Value> =
423 Default::default();
424 if let Some(typ) = map.remove("type") {
425 new_map.insert("type".into(), typ);
426 }
427 new_map.insert("constraint".into(), constraint.to_json());
428 new_map.insert("bounds".into(), bounds.to_json());
429 new_map.insert("visible_bounds".into(), visible_bounds.to_json());
430 new_map.append(map);
431 json::Value::Object(new_map)
432 } else {
433 value
434 }
435 }
436
437 _ => panic!("invalid element lifecycle state"),
438 }
439 }
440}
441
442impl<V: View, E: Element<V>> Default for ElementState<V, E> {
443 fn default() -> Self {
444 Self::Empty
445 }
446}
447
448pub struct AnyElement<V: View> {
449 state: Box<dyn AnyElementState<V>>,
450 name: Option<Cow<'static, str>>,
451}
452
453impl<V: View> AnyElement<V> {
454 pub fn name(&self) -> Option<&str> {
455 self.name.as_deref()
456 }
457
458 pub fn metadata<T: 'static>(&self) -> Option<&T> {
459 self.state
460 .metadata()
461 .and_then(|data| data.downcast_ref::<T>())
462 }
463
464 pub fn layout(
465 &mut self,
466 constraint: SizeConstraint,
467 view: &mut V,
468 cx: &mut LayoutContext<V>,
469 ) -> Vector2F {
470 self.state.layout(constraint, view, cx)
471 }
472
473 pub fn paint(
474 &mut self,
475 scene: &mut SceneBuilder,
476 origin: Vector2F,
477 visible_bounds: RectF,
478 view: &mut V,
479 cx: &mut ViewContext<V>,
480 ) {
481 self.state.paint(scene, origin, visible_bounds, view, cx);
482 }
483
484 pub fn rect_for_text_range(
485 &self,
486 range_utf16: Range<usize>,
487 view: &V,
488 cx: &ViewContext<V>,
489 ) -> Option<RectF> {
490 self.state.rect_for_text_range(range_utf16, view, cx)
491 }
492
493 pub fn size(&self) -> Vector2F {
494 self.state.size()
495 }
496
497 pub fn debug(&self, view: &V, cx: &ViewContext<V>) -> json::Value {
498 let mut value = self.state.debug(view, cx);
499
500 if let Some(name) = &self.name {
501 if let json::Value::Object(map) = &mut value {
502 let mut new_map: crate::json::Map<String, serde_json::Value> = Default::default();
503 new_map.insert("name".into(), json::Value::String(name.to_string()));
504 new_map.append(map);
505 return json::Value::Object(new_map);
506 }
507 }
508
509 value
510 }
511
512 pub fn with_metadata<T, F, R>(&self, f: F) -> R
513 where
514 T: 'static,
515 F: FnOnce(Option<&T>) -> R,
516 {
517 f(self.state.metadata().and_then(|m| m.downcast_ref()))
518 }
519}
520
521impl<V: View> Element<V> for AnyElement<V> {
522 type LayoutState = ();
523 type PaintState = ();
524
525 fn layout(
526 &mut self,
527 constraint: SizeConstraint,
528 view: &mut V,
529 cx: &mut LayoutContext<V>,
530 ) -> (Vector2F, Self::LayoutState) {
531 let size = self.layout(constraint, view, cx);
532 (size, ())
533 }
534
535 fn paint(
536 &mut self,
537 scene: &mut SceneBuilder,
538 bounds: RectF,
539 visible_bounds: RectF,
540 _: &mut Self::LayoutState,
541 view: &mut V,
542 cx: &mut PaintContext<V>,
543 ) -> Self::PaintState {
544 self.paint(scene, bounds.origin(), visible_bounds, view, cx);
545 }
546
547 fn rect_for_text_range(
548 &self,
549 range_utf16: Range<usize>,
550 _: RectF,
551 _: RectF,
552 _: &Self::LayoutState,
553 _: &Self::PaintState,
554 view: &V,
555 cx: &ViewContext<V>,
556 ) -> Option<RectF> {
557 self.rect_for_text_range(range_utf16, view, cx)
558 }
559
560 fn debug(
561 &self,
562 _: RectF,
563 _: &Self::LayoutState,
564 _: &Self::PaintState,
565 view: &V,
566 cx: &ViewContext<V>,
567 ) -> serde_json::Value {
568 self.debug(view, cx)
569 }
570
571 fn into_any(self) -> AnyElement<V>
572 where
573 Self: Sized,
574 {
575 self
576 }
577}
578
579pub struct RootElement<V: View> {
580 element: AnyElement<V>,
581 view: WeakViewHandle<V>,
582}
583
584impl<V: View> RootElement<V> {
585 pub fn new(element: AnyElement<V>, view: WeakViewHandle<V>) -> Self {
586 Self { element, view }
587 }
588}
589
590pub trait AnyRootElement {
591 fn layout(
592 &mut self,
593 constraint: SizeConstraint,
594 new_parents: &mut HashMap<usize, usize>,
595 views_to_notify_if_ancestors_change: &mut HashMap<usize, SmallVec<[usize; 2]>>,
596 refreshing: bool,
597 cx: &mut WindowContext,
598 ) -> Result<Vector2F>;
599 fn paint(
600 &mut self,
601 scene: &mut SceneBuilder,
602 origin: Vector2F,
603 visible_bounds: RectF,
604 cx: &mut WindowContext,
605 ) -> Result<()>;
606 fn rect_for_text_range(
607 &self,
608 range_utf16: Range<usize>,
609 cx: &WindowContext,
610 ) -> Result<Option<RectF>>;
611 fn debug(&self, cx: &WindowContext) -> Result<serde_json::Value>;
612 fn name(&self) -> Option<&str>;
613}
614
615impl<V: View> AnyRootElement for RootElement<V> {
616 fn layout(
617 &mut self,
618 constraint: SizeConstraint,
619 new_parents: &mut HashMap<usize, usize>,
620 views_to_notify_if_ancestors_change: &mut HashMap<usize, SmallVec<[usize; 2]>>,
621 refreshing: bool,
622 cx: &mut WindowContext,
623 ) -> Result<Vector2F> {
624 let view = self
625 .view
626 .upgrade(cx)
627 .ok_or_else(|| anyhow!("layout called on a root element for a dropped view"))?;
628 view.update(cx, |view, cx| {
629 let mut cx = LayoutContext::new(
630 cx,
631 new_parents,
632 views_to_notify_if_ancestors_change,
633 refreshing,
634 );
635 Ok(self.element.layout(constraint, view, &mut cx))
636 })
637 }
638
639 fn paint(
640 &mut self,
641 scene: &mut SceneBuilder,
642 origin: Vector2F,
643 visible_bounds: RectF,
644 cx: &mut WindowContext,
645 ) -> Result<()> {
646 let view = self
647 .view
648 .upgrade(cx)
649 .ok_or_else(|| anyhow!("paint called on a root element for a dropped view"))?;
650
651 view.update(cx, |view, cx| {
652 self.element.paint(scene, origin, visible_bounds, view, cx);
653 Ok(())
654 })
655 }
656
657 fn rect_for_text_range(
658 &self,
659 range_utf16: Range<usize>,
660 cx: &WindowContext,
661 ) -> Result<Option<RectF>> {
662 let view = self.view.upgrade(cx).ok_or_else(|| {
663 anyhow!("rect_for_text_range called on a root element for a dropped view")
664 })?;
665 let view = view.read(cx);
666 let view_context = ViewContext::immutable(cx, self.view.id());
667 Ok(self
668 .element
669 .rect_for_text_range(range_utf16, view, &view_context))
670 }
671
672 fn debug(&self, cx: &WindowContext) -> Result<serde_json::Value> {
673 let view = self
674 .view
675 .upgrade(cx)
676 .ok_or_else(|| anyhow!("debug called on a root element for a dropped view"))?;
677 let view = view.read(cx);
678 let view_context = ViewContext::immutable(cx, self.view.id());
679 Ok(serde_json::json!({
680 "view_id": self.view.id(),
681 "view_name": V::ui_name(),
682 "view": view.debug_json(cx),
683 "element": self.element.debug(view, &view_context)
684 }))
685 }
686
687 fn name(&self) -> Option<&str> {
688 self.element.name()
689 }
690}
691
692pub trait ParentElement<'a, V: View>: Extend<AnyElement<V>> + Sized {
693 fn add_children<E: Element<V>>(&mut self, children: impl IntoIterator<Item = E>) {
694 self.extend(children.into_iter().map(|child| child.into_any()));
695 }
696
697 fn add_child<D: Element<V>>(&mut self, child: D) {
698 self.extend(Some(child.into_any()));
699 }
700
701 fn with_children<D: Element<V>>(mut self, children: impl IntoIterator<Item = D>) -> Self {
702 self.extend(children.into_iter().map(|child| child.into_any()));
703 self
704 }
705
706 fn with_child<D: Element<V>>(mut self, child: D) -> Self {
707 self.extend(Some(child.into_any()));
708 self
709 }
710}
711
712impl<'a, V: View, T> ParentElement<'a, V> for T where T: Extend<AnyElement<V>> {}
713
714pub fn constrain_size_preserving_aspect_ratio(max_size: Vector2F, size: Vector2F) -> Vector2F {
715 if max_size.x().is_infinite() && max_size.y().is_infinite() {
716 size
717 } else if max_size.x().is_infinite() || max_size.x() / max_size.y() > size.x() / size.y() {
718 vec2f(size.x() * max_size.y() / size.y(), max_size.y())
719 } else {
720 vec2f(max_size.x(), size.y() * max_size.x() / size.x())
721 }
722}