element.rs

  1//! Elements are the workhorses of GPUI. They are responsible for laying out and painting all of
  2//! the contents of a window. Elements form a tree and are laid out according to the web layout
  3//! standards as implemented by [taffy](https://github.com/DioxusLabs/taffy). Most of the time,
  4//! you won't need to interact with this module or these APIs directly. Elements provide their
  5//! own APIs and GPUI, or other element implementation, uses the APIs in this module to convert
  6//! that element tree into the pixels you see on the screen.
  7//!
  8//! # Element Basics
  9//!
 10//! Elements are constructed by calling [`Render::render()`] on the root view of the window, which
 11//! which recursively constructs the element tree from the current state of the application,.
 12//! These elements are then laid out by Taffy, and painted to the screen according to their own
 13//! implementation of [`Element::paint()`]. Before the start of the next frame, the entire element
 14//! tree and any callbacks they have registered with GPUI are dropped and the process repeats.
 15//!
 16//! But some state is too simple and voluminous to store in every view that needs it, e.g.
 17//! whether a hover has been started or not. For this, GPUI provides the [`Element::State`], associated type.
 18//! If an element returns an [`ElementId`] from [`IntoElement::element_id()`], and that element id
 19//! appears in the same place relative to other views and ElementIds in the frame, then the previous
 20//! frame's state will be passed to the element's layout and paint methods.
 21//!
 22//! # Implementing your own elements
 23//!
 24//! Elements are intended to be the low level, imperative API to GPUI. They are responsible for upholding,
 25//! or breaking, GPUI's features as they deem necessary. As an example, most GPUI elements are expected
 26//! to stay in the bounds that their parent element gives them. But with [`WindowContext::break_content_mask`],
 27//! you can ignore this restriction and paint anywhere inside of the window's bounds. This is useful for overlays
 28//! and popups and anything else that shows up 'on top' of other elements.
 29//! With great power, comes great responsibility.
 30//!
 31//! However, most of the time, you won't need to implement your own elements. GPUI provides a number of
 32//! elements that should cover most common use cases out of the box and it's recommended that you use those
 33//! to construct `components`, using the [`RenderOnce`] trait and the `#[derive(IntoElement)]` macro. Only implement
 34//! elements when you need to take manual control of the layout and painting process, such as when using
 35//! your own custom layout algorithm or rendering a code editor.
 36
 37use crate::{
 38    util::FluentBuilder, ArenaBox, AvailableSpace, Bounds, ElementContext, ElementId, LayoutId,
 39    Pixels, Point, Size, ViewContext, WindowContext, ELEMENT_ARENA,
 40};
 41use derive_more::{Deref, DerefMut};
 42pub(crate) use smallvec::SmallVec;
 43use std::{any::Any, fmt::Debug, ops::DerefMut};
 44
 45/// Implemented by types that participate in laying out and painting the contents of a window.
 46/// Elements form a tree and are laid out according to web-based layout rules, as implemented by Taffy.
 47/// You can create custom elements by implementing this trait, see the module-level documentation
 48/// for more details.
 49pub trait Element: 'static + IntoElement {
 50    /// The type of state to store for this element between frames. See the module-level documentation
 51    /// for details.
 52    type State: 'static;
 53
 54    /// Before an element can be painted, we need to know where it's going to be and how big it is.
 55    /// Use this method to request a layout from Taffy and initialize the element's state.
 56    fn request_layout(
 57        &mut self,
 58        state: Option<Self::State>,
 59        cx: &mut ElementContext,
 60    ) -> (LayoutId, Self::State);
 61
 62    /// Once layout has been completed, this method will be called to paint the element to the screen.
 63    /// The state argument is the same state that was returned from [`Element::request_layout()`].
 64    fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut ElementContext);
 65
 66    /// Convert this element into a dynamically-typed [`AnyElement`].
 67    fn into_any(self) -> AnyElement {
 68        AnyElement::new(self)
 69    }
 70}
 71
 72/// Implemented by any type that can be converted into an element.
 73pub trait IntoElement: Sized {
 74    /// The specific type of element into which the implementing type is converted.
 75    /// Useful for converting other types into elements automatically, like Strings
 76    type Element: Element;
 77
 78    /// The [`ElementId`] of self once converted into an [`Element`].
 79    /// If present, the resulting element's state will be carried across frames.
 80    fn element_id(&self) -> Option<ElementId>;
 81
 82    /// Convert self into a type that implements [`Element`].
 83    fn into_element(self) -> Self::Element;
 84
 85    /// Convert self into a dynamically-typed [`AnyElement`].
 86    fn into_any_element(self) -> AnyElement {
 87        self.into_element().into_any()
 88    }
 89
 90    /// Convert into an element, then draw in the current window at the given origin.
 91    /// The available space argument is provided to the layout engine to determine the size of the
 92    // root element.  Once the element is drawn, its associated element state is yielded to the
 93    // given callback.
 94    fn draw_and_update_state<T, R>(
 95        self,
 96        origin: Point<Pixels>,
 97        available_space: Size<T>,
 98        cx: &mut ElementContext,
 99        f: impl FnOnce(&mut <Self::Element as Element>::State, &mut ElementContext) -> R,
100    ) -> R
101    where
102        T: Clone + Default + Debug + Into<AvailableSpace>,
103    {
104        let element = self.into_element();
105        let element_id = element.element_id();
106        let element = DrawableElement {
107            element: Some(element),
108            phase: ElementDrawPhase::Start,
109        };
110
111        let frame_state =
112            DrawableElement::draw(element, origin, available_space.map(Into::into), cx);
113
114        if let Some(mut frame_state) = frame_state {
115            f(&mut frame_state, cx)
116        } else {
117            cx.with_element_state(element_id.unwrap(), |element_state, cx| {
118                let mut element_state = element_state.unwrap();
119                let result = f(&mut element_state, cx);
120                (result, element_state)
121            })
122        }
123    }
124}
125
126impl<T: IntoElement> FluentBuilder for T {}
127
128/// An object that can be drawn to the screen. This is the trait that distinguishes `Views` from
129/// models. Views are drawn to the screen and care about the current window's state, models are not and do not.
130pub trait Render: 'static + Sized {
131    /// Render this view into an element tree.
132    fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement;
133}
134
135impl Render for () {
136    fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
137        ()
138    }
139}
140
141/// You can derive [`IntoElement`] on any type that implements this trait.
142/// It is used to construct reusable `components` out of plain data. Think of
143/// components as a recipe for a certain pattern of elements. RenderOnce allows
144/// you to invoke this pattern, without breaking the fluent builder pattern of
145/// the element APIs.
146pub trait RenderOnce: 'static {
147    /// Render this component into an element tree. Note that this method
148    /// takes ownership of self, as compared to [`Render::render()`] method
149    /// which takes a mutable reference.
150    fn render(self, cx: &mut WindowContext) -> impl IntoElement;
151}
152
153/// This is a helper trait to provide a uniform interface for constructing elements that
154/// can accept any number of any kind of child elements
155pub trait ParentElement {
156    /// Extend this element's children with the given child elements.
157    fn extend(&mut self, elements: impl Iterator<Item = AnyElement>);
158
159    /// Add a single child element to this element.
160    fn child(mut self, child: impl IntoElement) -> Self
161    where
162        Self: Sized,
163    {
164        self.extend(std::iter::once(child.into_element().into_any()));
165        self
166    }
167
168    /// Add multiple child elements to this element.
169    fn children(mut self, children: impl IntoIterator<Item = impl IntoElement>) -> Self
170    where
171        Self: Sized,
172    {
173        self.extend(children.into_iter().map(|child| child.into_any_element()));
174        self
175    }
176}
177
178/// An element for rendering components. An implementation detail of the [`IntoElement`] derive macro
179/// for [`RenderOnce`]
180#[doc(hidden)]
181pub struct Component<C: RenderOnce>(Option<C>);
182
183impl<C: RenderOnce> Component<C> {
184    /// Create a new component from the given RenderOnce type.
185    pub fn new(component: C) -> Self {
186        Component(Some(component))
187    }
188}
189
190impl<C: RenderOnce> Element for Component<C> {
191    type State = AnyElement;
192
193    fn request_layout(
194        &mut self,
195        _: Option<Self::State>,
196        cx: &mut ElementContext,
197    ) -> (LayoutId, Self::State) {
198        let mut element = self
199            .0
200            .take()
201            .unwrap()
202            .render(cx.deref_mut())
203            .into_any_element();
204        let layout_id = element.request_layout(cx);
205        (layout_id, element)
206    }
207
208    fn paint(&mut self, _: Bounds<Pixels>, element: &mut Self::State, cx: &mut ElementContext) {
209        element.paint(cx)
210    }
211}
212
213impl<C: RenderOnce> IntoElement for Component<C> {
214    type Element = Self;
215
216    fn element_id(&self) -> Option<ElementId> {
217        None
218    }
219
220    fn into_element(self) -> Self::Element {
221        self
222    }
223}
224
225/// A globally unique identifier for an element, used to track state across frames.
226#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
227pub(crate) struct GlobalElementId(SmallVec<[ElementId; 32]>);
228
229trait ElementObject {
230    fn element_id(&self) -> Option<ElementId>;
231
232    fn request_layout(&mut self, cx: &mut ElementContext) -> LayoutId;
233
234    fn paint(&mut self, cx: &mut ElementContext);
235
236    fn measure(
237        &mut self,
238        available_space: Size<AvailableSpace>,
239        cx: &mut ElementContext,
240    ) -> Size<Pixels>;
241
242    fn draw(
243        &mut self,
244        origin: Point<Pixels>,
245        available_space: Size<AvailableSpace>,
246        cx: &mut ElementContext,
247    );
248}
249
250/// A wrapper around an implementer of [`Element`] that allows it to be drawn in a window.
251pub(crate) struct DrawableElement<E: Element> {
252    element: Option<E>,
253    phase: ElementDrawPhase<E::State>,
254}
255
256#[derive(Default)]
257enum ElementDrawPhase<S> {
258    #[default]
259    Start,
260    LayoutRequested {
261        layout_id: LayoutId,
262        frame_state: Option<S>,
263    },
264    LayoutComputed {
265        layout_id: LayoutId,
266        available_space: Size<AvailableSpace>,
267        frame_state: Option<S>,
268    },
269}
270
271/// A wrapper around an implementer of [`Element`] that allows it to be drawn in a window.
272impl<E: Element> DrawableElement<E> {
273    fn new(element: E) -> Self {
274        DrawableElement {
275            element: Some(element),
276            phase: ElementDrawPhase::Start,
277        }
278    }
279
280    fn element_id(&self) -> Option<ElementId> {
281        self.element.as_ref()?.element_id()
282    }
283
284    fn request_layout(&mut self, cx: &mut ElementContext) -> LayoutId {
285        let (layout_id, frame_state) = if let Some(id) = self.element.as_ref().unwrap().element_id()
286        {
287            let layout_id = cx.with_element_state(id, |element_state, cx| {
288                self.element
289                    .as_mut()
290                    .unwrap()
291                    .request_layout(element_state, cx)
292            });
293            (layout_id, None)
294        } else {
295            let (layout_id, frame_state) = self.element.as_mut().unwrap().request_layout(None, cx);
296            (layout_id, Some(frame_state))
297        };
298
299        self.phase = ElementDrawPhase::LayoutRequested {
300            layout_id,
301            frame_state,
302        };
303        layout_id
304    }
305
306    fn paint(mut self, cx: &mut ElementContext) -> Option<E::State> {
307        match self.phase {
308            ElementDrawPhase::LayoutRequested {
309                layout_id,
310                frame_state,
311            }
312            | ElementDrawPhase::LayoutComputed {
313                layout_id,
314                frame_state,
315                ..
316            } => {
317                let bounds = cx.layout_bounds(layout_id);
318
319                if let Some(mut frame_state) = frame_state {
320                    self.element
321                        .take()
322                        .unwrap()
323                        .paint(bounds, &mut frame_state, cx);
324                    Some(frame_state)
325                } else {
326                    let element_id = self
327                        .element
328                        .as_ref()
329                        .unwrap()
330                        .element_id()
331                        .expect("if we don't have frame state, we should have element state");
332                    cx.with_element_state(element_id, |element_state, cx| {
333                        let mut element_state = element_state.unwrap();
334                        self.element
335                            .take()
336                            .unwrap()
337                            .paint(bounds, &mut element_state, cx);
338                        ((), element_state)
339                    });
340                    None
341                }
342            }
343
344            _ => panic!("must call layout before paint"),
345        }
346    }
347
348    fn measure(
349        &mut self,
350        available_space: Size<AvailableSpace>,
351        cx: &mut ElementContext,
352    ) -> Size<Pixels> {
353        if matches!(&self.phase, ElementDrawPhase::Start) {
354            self.request_layout(cx);
355        }
356
357        let layout_id = match &mut self.phase {
358            ElementDrawPhase::LayoutRequested {
359                layout_id,
360                frame_state,
361            } => {
362                cx.compute_layout(*layout_id, available_space);
363                let layout_id = *layout_id;
364                self.phase = ElementDrawPhase::LayoutComputed {
365                    layout_id,
366                    available_space,
367                    frame_state: frame_state.take(),
368                };
369                layout_id
370            }
371            ElementDrawPhase::LayoutComputed {
372                layout_id,
373                available_space: prev_available_space,
374                ..
375            } => {
376                if available_space != *prev_available_space {
377                    cx.compute_layout(*layout_id, available_space);
378                    *prev_available_space = available_space;
379                }
380                *layout_id
381            }
382            _ => panic!("cannot measure after painting"),
383        };
384
385        cx.layout_bounds(layout_id).size
386    }
387
388    fn draw(
389        mut self,
390        origin: Point<Pixels>,
391        available_space: Size<AvailableSpace>,
392        cx: &mut ElementContext,
393    ) -> Option<E::State> {
394        self.measure(available_space, cx);
395        cx.with_absolute_element_offset(origin, |cx| self.paint(cx))
396    }
397}
398
399impl<E> ElementObject for Option<DrawableElement<E>>
400where
401    E: Element,
402    E::State: 'static,
403{
404    fn element_id(&self) -> Option<ElementId> {
405        self.as_ref().unwrap().element_id()
406    }
407
408    fn request_layout(&mut self, cx: &mut ElementContext) -> LayoutId {
409        DrawableElement::request_layout(self.as_mut().unwrap(), cx)
410    }
411
412    fn paint(&mut self, cx: &mut ElementContext) {
413        DrawableElement::paint(self.take().unwrap(), cx);
414    }
415
416    fn measure(
417        &mut self,
418        available_space: Size<AvailableSpace>,
419        cx: &mut ElementContext,
420    ) -> Size<Pixels> {
421        DrawableElement::measure(self.as_mut().unwrap(), available_space, cx)
422    }
423
424    fn draw(
425        &mut self,
426        origin: Point<Pixels>,
427        available_space: Size<AvailableSpace>,
428        cx: &mut ElementContext,
429    ) {
430        DrawableElement::draw(self.take().unwrap(), origin, available_space, cx);
431    }
432}
433
434/// A dynamically typed element that can be used to store any element type.
435pub struct AnyElement(ArenaBox<dyn ElementObject>);
436
437impl AnyElement {
438    pub(crate) fn new<E>(element: E) -> Self
439    where
440        E: 'static + Element,
441        E::State: Any,
442    {
443        let element = ELEMENT_ARENA
444            .with_borrow_mut(|arena| arena.alloc(|| Some(DrawableElement::new(element))))
445            .map(|element| element as &mut dyn ElementObject);
446        AnyElement(element)
447    }
448
449    /// Request the layout ID of the element stored in this `AnyElement`.
450    /// Used for laying out child elements in a parent element.
451    pub fn request_layout(&mut self, cx: &mut ElementContext) -> LayoutId {
452        self.0.request_layout(cx)
453    }
454
455    /// Paints the element stored in this `AnyElement`.
456    pub fn paint(&mut self, cx: &mut ElementContext) {
457        self.0.paint(cx)
458    }
459
460    /// Initializes this element and performs layout within the given available space to determine its size.
461    pub fn measure(
462        &mut self,
463        available_space: Size<AvailableSpace>,
464        cx: &mut ElementContext,
465    ) -> Size<Pixels> {
466        self.0.measure(available_space, cx)
467    }
468
469    /// Initializes this element and performs layout in the available space, then paints it at the given origin.
470    pub fn draw(
471        &mut self,
472        origin: Point<Pixels>,
473        available_space: Size<AvailableSpace>,
474        cx: &mut ElementContext,
475    ) {
476        self.0.draw(origin, available_space, cx)
477    }
478
479    /// Returns the element ID of the element stored in this `AnyElement`, if any.
480    pub fn inner_id(&self) -> Option<ElementId> {
481        self.0.element_id()
482    }
483}
484
485impl Element for AnyElement {
486    type State = ();
487
488    fn request_layout(
489        &mut self,
490        _: Option<Self::State>,
491        cx: &mut ElementContext,
492    ) -> (LayoutId, Self::State) {
493        let layout_id = self.request_layout(cx);
494        (layout_id, ())
495    }
496
497    fn paint(&mut self, _: Bounds<Pixels>, _: &mut Self::State, cx: &mut ElementContext) {
498        self.paint(cx)
499    }
500}
501
502impl IntoElement for AnyElement {
503    type Element = Self;
504
505    fn element_id(&self) -> Option<ElementId> {
506        None
507    }
508
509    fn into_element(self) -> Self::Element {
510        self
511    }
512
513    fn into_any_element(self) -> AnyElement {
514        self
515    }
516}
517
518/// The empty element, which renders nothing.
519pub type Empty = ();
520
521impl IntoElement for () {
522    type Element = Self;
523
524    fn element_id(&self) -> Option<ElementId> {
525        None
526    }
527
528    fn into_element(self) -> Self::Element {
529        self
530    }
531}
532
533impl Element for () {
534    type State = ();
535
536    fn request_layout(
537        &mut self,
538        _state: Option<Self::State>,
539        cx: &mut ElementContext,
540    ) -> (LayoutId, Self::State) {
541        (cx.request_layout(&crate::Style::default(), None), ())
542    }
543
544    fn paint(
545        &mut self,
546        _bounds: Bounds<Pixels>,
547        _state: &mut Self::State,
548        _cx: &mut ElementContext,
549    ) {
550    }
551}