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