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/// A quick way to create a [`Render`]able view without having to define a new type.
140#[cfg(any(test, feature = "test-support"))]
141pub struct TestView(Box<dyn FnMut(&mut ViewContext<TestView>) -> AnyElement>);
142
143#[cfg(any(test, feature = "test-support"))]
144impl TestView {
145 /// Construct a TestView from a render closure.
146 pub fn new<F: FnMut(&mut ViewContext<TestView>) -> AnyElement + 'static>(f: F) -> Self {
147 Self(Box::new(f))
148 }
149}
150
151#[cfg(any(test, feature = "test-support"))]
152impl Render for TestView {
153 fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
154 (self.0)(cx)
155 }
156}
157
158/// You can derive [`IntoElement`] on any type that implements this trait.
159/// It is used to construct reusable `components` out of plain data. Think of
160/// components as a recipe for a certain pattern of elements. RenderOnce allows
161/// you to invoke this pattern, without breaking the fluent builder pattern of
162/// the element APIs.
163pub trait RenderOnce: 'static {
164 /// Render this component into an element tree. Note that this method
165 /// takes ownership of self, as compared to [`Render::render()`] method
166 /// which takes a mutable reference.
167 fn render(self, cx: &mut WindowContext) -> impl IntoElement;
168}
169
170/// This is a helper trait to provide a uniform interface for constructing elements that
171/// can accept any number of any kind of child elements
172pub trait ParentElement {
173 /// Extend this element's children with the given child elements.
174 fn extend(&mut self, elements: impl Iterator<Item = AnyElement>);
175
176 /// Add a single child element to this element.
177 fn child(mut self, child: impl IntoElement) -> Self
178 where
179 Self: Sized,
180 {
181 self.extend(std::iter::once(child.into_element().into_any()));
182 self
183 }
184
185 /// Add multiple child elements to this element.
186 fn children(mut self, children: impl IntoIterator<Item = impl IntoElement>) -> Self
187 where
188 Self: Sized,
189 {
190 self.extend(children.into_iter().map(|child| child.into_any_element()));
191 self
192 }
193}
194
195/// An element for rendering components. An implementation detail of the [`IntoElement`] derive macro
196/// for [`RenderOnce`]
197#[doc(hidden)]
198pub struct Component<C: RenderOnce>(Option<C>);
199
200impl<C: RenderOnce> Component<C> {
201 /// Create a new component from the given RenderOnce type.
202 pub fn new(component: C) -> Self {
203 Component(Some(component))
204 }
205}
206
207impl<C: RenderOnce> Element for Component<C> {
208 type State = AnyElement;
209
210 fn request_layout(
211 &mut self,
212 _: Option<Self::State>,
213 cx: &mut ElementContext,
214 ) -> (LayoutId, Self::State) {
215 let mut element = self
216 .0
217 .take()
218 .unwrap()
219 .render(cx.deref_mut())
220 .into_any_element();
221 let layout_id = element.request_layout(cx);
222 (layout_id, element)
223 }
224
225 fn paint(&mut self, _: Bounds<Pixels>, element: &mut Self::State, cx: &mut ElementContext) {
226 element.paint(cx)
227 }
228}
229
230impl<C: RenderOnce> IntoElement for Component<C> {
231 type Element = Self;
232
233 fn element_id(&self) -> Option<ElementId> {
234 None
235 }
236
237 fn into_element(self) -> Self::Element {
238 self
239 }
240}
241
242/// A globally unique identifier for an element, used to track state across frames.
243#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
244pub(crate) struct GlobalElementId(SmallVec<[ElementId; 32]>);
245
246trait ElementObject {
247 fn element_id(&self) -> Option<ElementId>;
248
249 fn request_layout(&mut self, cx: &mut ElementContext) -> LayoutId;
250
251 fn paint(&mut self, cx: &mut ElementContext);
252
253 fn measure(
254 &mut self,
255 available_space: Size<AvailableSpace>,
256 cx: &mut ElementContext,
257 ) -> Size<Pixels>;
258
259 fn draw(
260 &mut self,
261 origin: Point<Pixels>,
262 available_space: Size<AvailableSpace>,
263 cx: &mut ElementContext,
264 );
265}
266
267/// A wrapper around an implementer of [`Element`] that allows it to be drawn in a window.
268pub(crate) struct DrawableElement<E: Element> {
269 element: Option<E>,
270 phase: ElementDrawPhase<E::State>,
271}
272
273#[derive(Default)]
274enum ElementDrawPhase<S> {
275 #[default]
276 Start,
277 LayoutRequested {
278 layout_id: LayoutId,
279 frame_state: Option<S>,
280 },
281 LayoutComputed {
282 layout_id: LayoutId,
283 available_space: Size<AvailableSpace>,
284 frame_state: Option<S>,
285 },
286}
287
288/// A wrapper around an implementer of [`Element`] that allows it to be drawn in a window.
289impl<E: Element> DrawableElement<E> {
290 fn new(element: E) -> Self {
291 DrawableElement {
292 element: Some(element),
293 phase: ElementDrawPhase::Start,
294 }
295 }
296
297 fn element_id(&self) -> Option<ElementId> {
298 self.element.as_ref()?.element_id()
299 }
300
301 fn request_layout(&mut self, cx: &mut ElementContext) -> LayoutId {
302 let (layout_id, frame_state) = if let Some(id) = self.element.as_ref().unwrap().element_id()
303 {
304 let layout_id = cx.with_element_state(id, |element_state, cx| {
305 self.element
306 .as_mut()
307 .unwrap()
308 .request_layout(element_state, cx)
309 });
310 (layout_id, None)
311 } else {
312 let (layout_id, frame_state) = self.element.as_mut().unwrap().request_layout(None, cx);
313 (layout_id, Some(frame_state))
314 };
315
316 self.phase = ElementDrawPhase::LayoutRequested {
317 layout_id,
318 frame_state,
319 };
320 layout_id
321 }
322
323 fn paint(mut self, cx: &mut ElementContext) -> Option<E::State> {
324 match self.phase {
325 ElementDrawPhase::LayoutRequested {
326 layout_id,
327 frame_state,
328 }
329 | ElementDrawPhase::LayoutComputed {
330 layout_id,
331 frame_state,
332 ..
333 } => {
334 let bounds = cx.layout_bounds(layout_id);
335
336 if let Some(mut frame_state) = frame_state {
337 self.element
338 .take()
339 .unwrap()
340 .paint(bounds, &mut frame_state, cx);
341 Some(frame_state)
342 } else {
343 let element_id = self
344 .element
345 .as_ref()
346 .unwrap()
347 .element_id()
348 .expect("if we don't have frame state, we should have element state");
349 cx.with_element_state(element_id, |element_state, cx| {
350 let mut element_state = element_state.unwrap();
351 self.element
352 .take()
353 .unwrap()
354 .paint(bounds, &mut element_state, cx);
355 ((), element_state)
356 });
357 None
358 }
359 }
360
361 _ => panic!("must call layout before paint"),
362 }
363 }
364
365 fn measure(
366 &mut self,
367 available_space: Size<AvailableSpace>,
368 cx: &mut ElementContext,
369 ) -> Size<Pixels> {
370 if matches!(&self.phase, ElementDrawPhase::Start) {
371 self.request_layout(cx);
372 }
373
374 let layout_id = match &mut self.phase {
375 ElementDrawPhase::LayoutRequested {
376 layout_id,
377 frame_state,
378 } => {
379 cx.compute_layout(*layout_id, available_space);
380 let layout_id = *layout_id;
381 self.phase = ElementDrawPhase::LayoutComputed {
382 layout_id,
383 available_space,
384 frame_state: frame_state.take(),
385 };
386 layout_id
387 }
388 ElementDrawPhase::LayoutComputed {
389 layout_id,
390 available_space: prev_available_space,
391 ..
392 } => {
393 if available_space != *prev_available_space {
394 cx.compute_layout(*layout_id, available_space);
395 *prev_available_space = available_space;
396 }
397 *layout_id
398 }
399 _ => panic!("cannot measure after painting"),
400 };
401
402 cx.layout_bounds(layout_id).size
403 }
404
405 fn draw(
406 mut self,
407 origin: Point<Pixels>,
408 available_space: Size<AvailableSpace>,
409 cx: &mut ElementContext,
410 ) -> Option<E::State> {
411 self.measure(available_space, cx);
412 cx.with_absolute_element_offset(origin, |cx| self.paint(cx))
413 }
414}
415
416impl<E> ElementObject for Option<DrawableElement<E>>
417where
418 E: Element,
419 E::State: 'static,
420{
421 fn element_id(&self) -> Option<ElementId> {
422 self.as_ref().unwrap().element_id()
423 }
424
425 fn request_layout(&mut self, cx: &mut ElementContext) -> LayoutId {
426 DrawableElement::request_layout(self.as_mut().unwrap(), cx)
427 }
428
429 fn paint(&mut self, cx: &mut ElementContext) {
430 DrawableElement::paint(self.take().unwrap(), cx);
431 }
432
433 fn measure(
434 &mut self,
435 available_space: Size<AvailableSpace>,
436 cx: &mut ElementContext,
437 ) -> Size<Pixels> {
438 DrawableElement::measure(self.as_mut().unwrap(), available_space, cx)
439 }
440
441 fn draw(
442 &mut self,
443 origin: Point<Pixels>,
444 available_space: Size<AvailableSpace>,
445 cx: &mut ElementContext,
446 ) {
447 DrawableElement::draw(self.take().unwrap(), origin, available_space, cx);
448 }
449}
450
451/// A dynamically typed element that can be used to store any element type.
452pub struct AnyElement(ArenaBox<dyn ElementObject>);
453
454impl AnyElement {
455 pub(crate) fn new<E>(element: E) -> Self
456 where
457 E: 'static + Element,
458 E::State: Any,
459 {
460 let element = ELEMENT_ARENA
461 .with_borrow_mut(|arena| arena.alloc(|| Some(DrawableElement::new(element))))
462 .map(|element| element as &mut dyn ElementObject);
463 AnyElement(element)
464 }
465
466 /// Request the layout ID of the element stored in this `AnyElement`.
467 /// Used for laying out child elements in a parent element.
468 pub fn request_layout(&mut self, cx: &mut ElementContext) -> LayoutId {
469 self.0.request_layout(cx)
470 }
471
472 /// Paints the element stored in this `AnyElement`.
473 pub fn paint(&mut self, cx: &mut ElementContext) {
474 self.0.paint(cx)
475 }
476
477 /// Initializes this element and performs layout within the given available space to determine its size.
478 pub fn measure(
479 &mut self,
480 available_space: Size<AvailableSpace>,
481 cx: &mut ElementContext,
482 ) -> Size<Pixels> {
483 self.0.measure(available_space, cx)
484 }
485
486 /// Initializes this element and performs layout in the available space, then paints it at the given origin.
487 pub fn draw(
488 &mut self,
489 origin: Point<Pixels>,
490 available_space: Size<AvailableSpace>,
491 cx: &mut ElementContext,
492 ) {
493 self.0.draw(origin, available_space, cx)
494 }
495
496 /// Returns the element ID of the element stored in this `AnyElement`, if any.
497 pub fn inner_id(&self) -> Option<ElementId> {
498 self.0.element_id()
499 }
500}
501
502impl Element for AnyElement {
503 type State = ();
504
505 fn request_layout(
506 &mut self,
507 _: Option<Self::State>,
508 cx: &mut ElementContext,
509 ) -> (LayoutId, Self::State) {
510 let layout_id = self.request_layout(cx);
511 (layout_id, ())
512 }
513
514 fn paint(&mut self, _: Bounds<Pixels>, _: &mut Self::State, cx: &mut ElementContext) {
515 self.paint(cx)
516 }
517}
518
519impl IntoElement for AnyElement {
520 type Element = Self;
521
522 fn element_id(&self) -> Option<ElementId> {
523 None
524 }
525
526 fn into_element(self) -> Self::Element {
527 self
528 }
529
530 fn into_any_element(self) -> AnyElement {
531 self
532 }
533}
534
535/// The empty element, which renders nothing.
536pub type Empty = ();
537
538impl IntoElement for () {
539 type Element = Self;
540
541 fn element_id(&self) -> Option<ElementId> {
542 None
543 }
544
545 fn into_element(self) -> Self::Element {
546 self
547 }
548}
549
550impl Element for () {
551 type State = ();
552
553 fn request_layout(
554 &mut self,
555 _state: Option<Self::State>,
556 cx: &mut ElementContext,
557 ) -> (LayoutId, Self::State) {
558 (cx.request_layout(&crate::Style::default(), None), ())
559 }
560
561 fn paint(
562 &mut self,
563 _bounds: Bounds<Pixels>,
564 _state: &mut Self::State,
565 _cx: &mut ElementContext,
566 ) {
567 }
568}