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