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