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 Empty {
136 fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
137 Empty
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 struct Empty;
520
521impl IntoElement for Empty {
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 Empty {
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}