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}