elements.rs

  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}