element.rs

  1use std::sync::Arc;
  2
  3use crate::{
  4    BorrowWindow, Bounds, Clickable, ElementId, Group, LayoutId, MouseDownEvent, MouseUpEvent,
  5    Pixels, Point, SharedString, ViewContext,
  6};
  7use derive_more::{Deref, DerefMut};
  8pub(crate) use smallvec::SmallVec;
  9
 10pub trait Element: 'static + Send + Sync {
 11    type ViewState: 'static + Send + Sync;
 12    type ElementState: 'static + Send + Sync;
 13
 14    fn element_id(&self) -> Option<ElementId>;
 15
 16    fn layout(
 17        &mut self,
 18        state: &mut Self::ViewState,
 19        element_state: Option<Self::ElementState>,
 20        cx: &mut ViewContext<Self::ViewState>,
 21    ) -> (LayoutId, Self::ElementState);
 22
 23    fn paint(
 24        &mut self,
 25        bounds: Bounds<Pixels>,
 26        state: &mut Self::ViewState,
 27        element_state: &mut Self::ElementState,
 28        cx: &mut ViewContext<Self::ViewState>,
 29    );
 30
 31    fn group(self, name: impl Into<SharedString>) -> Group<Self>
 32    where
 33        Self: Sized,
 34    {
 35        Group::new(name.into(), self)
 36    }
 37}
 38
 39pub trait IdentifiedElement: Element {
 40    fn element_id(&self) -> ElementId {
 41        Element::element_id(self).unwrap()
 42    }
 43
 44    fn on_click(
 45        self,
 46        listener: impl Fn(
 47                &mut Self::ViewState,
 48                (&MouseDownEvent, &MouseUpEvent),
 49                &mut ViewContext<Self::ViewState>,
 50            ) + Send
 51            + Sync
 52            + 'static,
 53    ) -> Clickable<Self>
 54    where
 55        Self: Sized,
 56    {
 57        Clickable::new(self, Arc::from(listener))
 58    }
 59}
 60
 61#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
 62pub(crate) struct GlobalElementId(SmallVec<[ElementId; 8]>);
 63
 64pub trait ParentElement {
 65    type State;
 66
 67    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::State>; 2]>;
 68
 69    fn child(mut self, child: impl IntoAnyElement<Self::State>) -> Self
 70    where
 71        Self: Sized,
 72    {
 73        self.children_mut().push(child.into_any());
 74        self
 75    }
 76
 77    fn children(mut self, iter: impl IntoIterator<Item = impl IntoAnyElement<Self::State>>) -> Self
 78    where
 79        Self: Sized,
 80    {
 81        self.children_mut()
 82            .extend(iter.into_iter().map(|item| item.into_any()));
 83        self
 84    }
 85
 86    // HACK: This is a temporary hack to get children working for the purposes
 87    // of building UI on top of the current version of gpui2.
 88    //
 89    // We'll (hopefully) be moving away from this in the future.
 90    fn children_any<I>(mut self, children: I) -> Self
 91    where
 92        I: IntoIterator<Item = AnyElement<Self::State>>,
 93        Self: Sized,
 94    {
 95        self.children_mut().extend(children.into_iter());
 96        self
 97    }
 98
 99    // HACK: This is a temporary hack to get children working for the purposes
100    // of building UI on top of the current version of gpui2.
101    //
102    // We'll (hopefully) be moving away from this in the future.
103    fn child_any(mut self, children: AnyElement<Self::State>) -> Self
104    where
105        Self: Sized,
106    {
107        self.children_mut().push(children);
108        self
109    }
110}
111
112trait ElementObject<S>: 'static + Send + Sync {
113    fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> LayoutId;
114    fn paint(&mut self, state: &mut S, offset: Option<Point<Pixels>>, cx: &mut ViewContext<S>);
115}
116
117struct RenderedElement<E: Element> {
118    element: E,
119    phase: ElementRenderPhase<E::ElementState>,
120}
121
122#[derive(Default)]
123enum ElementRenderPhase<S> {
124    #[default]
125    Rendered,
126    LayoutRequested {
127        layout_id: LayoutId,
128        frame_state: Option<S>,
129    },
130    Painted {
131        bounds: Bounds<Pixels>,
132        frame_state: Option<S>,
133    },
134}
135
136/// Internal struct that wraps an element to store Layout and ElementState after the element is rendered.
137/// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
138/// improved usability.
139impl<E: Element> RenderedElement<E> {
140    fn new(element: E) -> Self {
141        RenderedElement {
142            element,
143            phase: ElementRenderPhase::Rendered,
144        }
145    }
146
147    fn paint_with_element_state(
148        &mut self,
149        bounds: Bounds<Pixels>,
150        view_state: &mut E::ViewState,
151        frame_state: &mut Option<E::ElementState>,
152        cx: &mut ViewContext<E::ViewState>,
153    ) {
154        if let Some(id) = self.element.element_id() {
155            cx.with_element_state(id, |element_state, cx| {
156                let mut element_state = element_state.unwrap();
157                self.element
158                    .paint(bounds, view_state, &mut element_state, cx);
159                ((), element_state)
160            });
161        } else {
162            self.element
163                .paint(bounds, view_state, frame_state.as_mut().unwrap(), cx);
164        }
165    }
166}
167
168impl<E, S> ElementObject<E::ViewState> for RenderedElement<E>
169where
170    E: Element<ElementState = S>,
171    S: 'static + Send + Sync,
172{
173    fn layout(&mut self, state: &mut E::ViewState, cx: &mut ViewContext<E::ViewState>) -> LayoutId {
174        let (layout_id, frame_state) = if let Some(id) = self.element.element_id() {
175            let layout_id = cx.with_element_state(id, |element_state, cx| {
176                self.element.layout(state, element_state, cx)
177            });
178            (layout_id, None)
179        } else {
180            let (layout_id, frame_state) = self.element.layout(state, None, cx);
181            (layout_id, Some(frame_state))
182        };
183
184        self.phase = ElementRenderPhase::LayoutRequested {
185            layout_id,
186            frame_state,
187        };
188
189        layout_id
190    }
191
192    fn paint(
193        &mut self,
194        view_state: &mut E::ViewState,
195        offset: Option<Point<Pixels>>,
196        cx: &mut ViewContext<E::ViewState>,
197    ) {
198        self.phase = match std::mem::take(&mut self.phase) {
199            ElementRenderPhase::Rendered => panic!("must call layout before paint"),
200
201            ElementRenderPhase::LayoutRequested {
202                layout_id,
203                mut frame_state,
204            } => {
205                let mut bounds = cx.layout_bounds(layout_id);
206                offset.map(|offset| bounds.origin += offset);
207                self.paint_with_element_state(bounds, view_state, &mut frame_state, cx);
208                ElementRenderPhase::Painted {
209                    bounds,
210                    frame_state,
211                }
212            }
213
214            ElementRenderPhase::Painted {
215                bounds,
216                mut frame_state,
217            } => {
218                self.paint_with_element_state(bounds, view_state, &mut frame_state, cx);
219                ElementRenderPhase::Painted {
220                    bounds,
221                    frame_state,
222                }
223            }
224        };
225    }
226}
227
228pub struct AnyElement<S>(Box<dyn ElementObject<S>>);
229
230impl<S: 'static + Send + Sync> AnyElement<S> {
231    pub fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> LayoutId {
232        self.0.layout(state, cx)
233    }
234
235    pub fn paint(&mut self, state: &mut S, offset: Option<Point<Pixels>>, cx: &mut ViewContext<S>) {
236        self.0.paint(state, offset, cx)
237    }
238}
239
240pub trait IntoAnyElement<S> {
241    fn into_any(self) -> AnyElement<S>;
242}
243
244impl<E: Element> IntoAnyElement<E::ViewState> for E {
245    fn into_any(self) -> AnyElement<E::ViewState> {
246        AnyElement(Box::new(RenderedElement::new(self)))
247    }
248}
249
250impl<S> IntoAnyElement<S> for AnyElement<S> {
251    fn into_any(self) -> AnyElement<S> {
252        self
253    }
254}