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