element.rs

  1use crate::{
  2    adapter::Adapter,
  3    color::Hsla,
  4    style::{Display, ElementStyle, Fill, Overflow, Position},
  5};
  6use anyhow::Result;
  7pub use gpui::LayoutContext;
  8use gpui::{
  9    geometry::{DefinedLength, Length},
 10    platform::{MouseButton, MouseButtonEvent},
 11    EngineLayout, EventContext, RenderContext, ViewContext,
 12};
 13use playground_macros::tailwind_lengths;
 14use std::{
 15    any::{Any, TypeId},
 16    cell::Cell,
 17    rc::Rc,
 18};
 19
 20pub use crate::paint_context::PaintContext;
 21pub use taffy::tree::NodeId;
 22
 23pub struct Layout<'a, E: ?Sized> {
 24    pub from_engine: EngineLayout,
 25    pub from_element: &'a mut E,
 26}
 27
 28pub struct ElementMetadata<V> {
 29    pub style: ElementStyle,
 30    pub handlers: Vec<EventHandler<V>>,
 31}
 32
 33pub struct EventHandler<V> {
 34    handler: Rc<dyn Fn(&mut V, &dyn Any, &mut EventContext<V>)>,
 35    event_type: TypeId,
 36    outside_bounds: bool,
 37}
 38
 39impl<V> Clone for EventHandler<V> {
 40    fn clone(&self) -> Self {
 41        Self {
 42            handler: self.handler.clone(),
 43            event_type: self.event_type,
 44            outside_bounds: self.outside_bounds,
 45        }
 46    }
 47}
 48
 49impl<V> Default for ElementMetadata<V> {
 50    fn default() -> Self {
 51        Self {
 52            style: ElementStyle::default(),
 53            handlers: Vec::new(),
 54        }
 55    }
 56}
 57
 58pub trait Element<V: 'static>: 'static {
 59    type Layout: 'static;
 60
 61    fn style_mut(&mut self) -> &mut ElementStyle;
 62    fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>>;
 63
 64    fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>)
 65        -> Result<(NodeId, Self::Layout)>;
 66    fn paint<'a>(
 67        &mut self,
 68        layout: Layout<Self::Layout>,
 69        view: &mut V,
 70        cx: &mut PaintContext<V>,
 71    ) -> Result<()>;
 72
 73    /// Convert to a dynamically-typed element suitable for layout and paint.
 74    fn into_any(self) -> AnyElement<V>
 75    where
 76        Self: 'static + Sized,
 77    {
 78        AnyElement {
 79            element: Box::new(self) as Box<dyn ElementObject<V>>,
 80            layout: None,
 81        }
 82    }
 83
 84    fn adapt(self) -> Adapter<V>
 85    where
 86        Self: Sized,
 87        Self: Element<V>,
 88    {
 89        Adapter(self.into_any())
 90    }
 91
 92    fn click(
 93        self,
 94        button: MouseButton,
 95        handler: impl Fn(&mut V, &MouseButtonEvent, &mut ViewContext<V>) + 'static,
 96    ) -> Self
 97    where
 98        Self: Sized,
 99    {
100        let pressed: Rc<Cell<bool>> = Default::default();
101        self.mouse_down(button, {
102            let pressed = pressed.clone();
103            move |_, _, _| {
104                pressed.set(true);
105            }
106        })
107        .mouse_up_outside(button, {
108            let pressed = pressed.clone();
109            move |_, _, _| {
110                pressed.set(false);
111            }
112        })
113        .mouse_up(button, move |view, event, event_cx| {
114            if pressed.get() {
115                pressed.set(false);
116                handler(view, event, event_cx);
117            }
118        })
119    }
120
121    fn mouse_down(
122        mut self,
123        button: MouseButton,
124        handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
125    ) -> Self
126    where
127        Self: Sized,
128    {
129        self.handlers_mut().push(EventHandler {
130            handler: Rc::new(move |view, event, event_cx| {
131                let event = event.downcast_ref::<MouseButtonEvent>().unwrap();
132                if event.button == button && event.is_down {
133                    handler(view, event, event_cx);
134                }
135            }),
136            event_type: TypeId::of::<MouseButtonEvent>(),
137            outside_bounds: false,
138        });
139        self
140    }
141
142    fn mouse_down_outside(
143        mut self,
144        button: MouseButton,
145        handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
146    ) -> Self
147    where
148        Self: Sized,
149    {
150        self.handlers_mut().push(EventHandler {
151            handler: Rc::new(move |view, event, event_cx| {
152                let event = event.downcast_ref::<MouseButtonEvent>().unwrap();
153                if event.button == button && event.is_down {
154                    handler(view, event, event_cx);
155                }
156            }),
157            event_type: TypeId::of::<MouseButtonEvent>(),
158            outside_bounds: true,
159        });
160        self
161    }
162
163    fn mouse_up(
164        mut self,
165        button: MouseButton,
166        handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
167    ) -> Self
168    where
169        Self: Sized,
170    {
171        self.handlers_mut().push(EventHandler {
172            handler: Rc::new(move |view, event, event_cx| {
173                let event = event.downcast_ref::<MouseButtonEvent>().unwrap();
174                if event.button == button && !event.is_down {
175                    handler(view, event, event_cx);
176                }
177            }),
178            event_type: TypeId::of::<MouseButtonEvent>(),
179            outside_bounds: false,
180        });
181        self
182    }
183
184    fn mouse_up_outside(
185        mut self,
186        button: MouseButton,
187        handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
188    ) -> Self
189    where
190        Self: Sized,
191    {
192        self.handlers_mut().push(EventHandler {
193            handler: Rc::new(move |view, event, event_cx| {
194                let event = event.downcast_ref::<MouseButtonEvent>().unwrap();
195                if event.button == button && !event.is_down {
196                    handler(view, event, event_cx);
197                }
198            }),
199            event_type: TypeId::of::<MouseButtonEvent>(),
200            outside_bounds: true,
201        });
202        self
203    }
204
205    // Display ////////////////////
206
207    fn block(mut self) -> Self
208    where
209        Self: Sized,
210    {
211        self.style_mut().display = Display::Block;
212        self
213    }
214
215    fn flex(mut self) -> Self
216    where
217        Self: Sized,
218    {
219        self.style_mut().display = Display::Flex;
220        self
221    }
222
223    fn grid(mut self) -> Self
224    where
225        Self: Sized,
226    {
227        self.style_mut().display = Display::Grid;
228        self
229    }
230
231    // style::Overflow ///////////////////
232
233    fn overflow_visible(mut self) -> Self
234    where
235        Self: Sized,
236    {
237        self.style_mut().overflow.x = Overflow::Visible;
238        self.style_mut().overflow.y = Overflow::Visible;
239        self
240    }
241
242    fn overflow_hidden(mut self) -> Self
243    where
244        Self: Sized,
245    {
246        self.style_mut().overflow.x = Overflow::Hidden;
247        self.style_mut().overflow.y = Overflow::Hidden;
248        self
249    }
250
251    fn overflow_scroll(mut self) -> Self
252    where
253        Self: Sized,
254    {
255        self.style_mut().overflow.x = Overflow::Scroll;
256        self.style_mut().overflow.y = Overflow::Scroll;
257        self
258    }
259
260    fn overflow_x_visible(mut self) -> Self
261    where
262        Self: Sized,
263    {
264        self.style_mut().overflow.x = Overflow::Visible;
265        self
266    }
267
268    fn overflow_x_hidden(mut self) -> Self
269    where
270        Self: Sized,
271    {
272        self.style_mut().overflow.x = Overflow::Hidden;
273        self
274    }
275
276    fn overflow_x_scroll(mut self) -> Self
277    where
278        Self: Sized,
279    {
280        self.style_mut().overflow.x = Overflow::Scroll;
281        self
282    }
283
284    fn overflow_y_visible(mut self) -> Self
285    where
286        Self: Sized,
287    {
288        self.style_mut().overflow.y = Overflow::Visible;
289        self
290    }
291
292    fn overflow_y_hidden(mut self) -> Self
293    where
294        Self: Sized,
295    {
296        self.style_mut().overflow.y = Overflow::Hidden;
297        self
298    }
299
300    fn overflow_y_scroll(mut self) -> Self
301    where
302        Self: Sized,
303    {
304        self.style_mut().overflow.y = Overflow::Scroll;
305        self
306    }
307
308    // Position ///////////////////
309
310    fn relative(mut self) -> Self
311    where
312        Self: Sized,
313    {
314        self.style_mut().position = Position::Relative;
315        self
316    }
317
318    fn absolute(mut self) -> Self
319    where
320        Self: Sized,
321    {
322        self.style_mut().position = Position::Absolute;
323
324        self
325    }
326
327    #[tailwind_lengths]
328    fn inset_(mut self, length: DefinedLength) -> Self
329    where
330        Self: Sized,
331    {
332        self.style_mut().inset.top = length;
333        self.style_mut().inset.right = length;
334        self.style_mut().inset.bottom = length;
335        self.style_mut().inset.left = length;
336        self
337    }
338
339    fn w(mut self, width: impl Into<Length>) -> Self
340    where
341        Self: Sized,
342    {
343        self.style_mut().size.width = width.into();
344        self
345    }
346
347    fn w_auto(mut self) -> Self
348    where
349        Self: Sized,
350    {
351        self.style_mut().size.width = Length::Auto;
352        self
353    }
354
355    #[tailwind_lengths]
356    fn w_(mut self, length: DefinedLength) -> Self
357    where
358        Self: Sized,
359    {
360        self.style_mut().size.width = length;
361        self
362    }
363
364    #[tailwind_lengths]
365    fn min_w_(mut self, length: DefinedLength) -> Self
366    where
367        Self: Sized,
368    {
369        self.style_mut().min_size.width = length;
370        self
371    }
372
373    fn h(mut self, height: impl Into<Length>) -> Self
374    where
375        Self: Sized,
376    {
377        self.style_mut().size.height = height.into();
378        self
379    }
380
381    fn h_auto(mut self) -> Self
382    where
383        Self: Sized,
384    {
385        self.style_mut().size.height = Length::Auto;
386        self
387    }
388
389    #[tailwind_lengths]
390    fn h_(mut self, height: DefinedLength) -> Self
391    where
392        Self: Sized,
393    {
394        self.style_mut().size.height = height;
395        self
396    }
397
398    #[tailwind_lengths]
399    fn min_h_(mut self, length: DefinedLength) -> Self
400    where
401        Self: Sized,
402    {
403        self.style_mut().min_size.height = length;
404        self
405    }
406
407    fn fill(mut self, fill: impl Into<Fill>) -> Self
408    where
409        Self: Sized,
410    {
411        self.style_mut().fill = fill.into();
412        self
413    }
414
415    fn text_color(mut self, color: impl Into<Hsla>) -> Self
416    where
417        Self: Sized,
418    {
419        self.style_mut().text_color = Some(color.into());
420        self
421    }
422}
423
424// Object-safe counterpart of Element used by AnyElement to store elements as trait objects.
425trait ElementObject<V> {
426    fn style_mut(&mut self) -> &mut ElementStyle;
427    fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>>;
428    fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>)
429        -> Result<(NodeId, Box<dyn Any>)>;
430    fn paint(
431        &mut self,
432        layout: Layout<dyn Any>,
433        view: &mut V,
434        cx: &mut PaintContext<V>,
435    ) -> Result<()>;
436}
437
438impl<V: 'static, E: Element<V>> ElementObject<V> for E {
439    fn style_mut(&mut self) -> &mut ElementStyle {
440        Element::style_mut(self)
441    }
442
443    fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>> {
444        Element::handlers_mut(self)
445    }
446
447    fn layout(
448        &mut self,
449        view: &mut V,
450        cx: &mut LayoutContext<V>,
451    ) -> Result<(NodeId, Box<dyn Any>)> {
452        let (node_id, layout) = self.layout(view, cx)?;
453        let layout = Box::new(layout) as Box<dyn Any>;
454        Ok((node_id, layout))
455    }
456
457    fn paint(
458        &mut self,
459        layout: Layout<dyn Any>,
460        view: &mut V,
461        cx: &mut PaintContext<V>,
462    ) -> Result<()> {
463        let layout = Layout {
464            from_engine: layout.from_engine,
465            from_element: layout.from_element.downcast_mut::<E::Layout>().unwrap(),
466        };
467
468        self.paint(layout, view, cx)
469    }
470}
471
472/// A dynamically typed element.
473pub struct AnyElement<V> {
474    element: Box<dyn ElementObject<V>>,
475    layout: Option<(NodeId, Box<dyn Any>)>,
476}
477
478impl<V: 'static> AnyElement<V> {
479    pub fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<NodeId> {
480        let pushed_text_style = self.push_text_style(cx);
481
482        let (node_id, layout) = self.element.layout(view, cx)?;
483        self.layout = Some((node_id, layout));
484
485        if pushed_text_style {
486            cx.pop_text_style();
487        }
488
489        Ok(node_id)
490    }
491
492    pub fn push_text_style(&mut self, cx: &mut impl RenderContext) -> bool {
493        let text_style = self.element.style_mut().text_style();
494        if let Some(text_style) = text_style {
495            let mut current_text_style = cx.text_style();
496            text_style.apply(&mut current_text_style);
497            cx.push_text_style(current_text_style);
498            true
499        } else {
500            false
501        }
502    }
503
504    pub fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>) -> Result<()> {
505        let pushed_text_style = self.push_text_style(cx);
506
507        let (layout_node_id, element_layout) =
508            self.layout.as_mut().expect("paint called before layout");
509
510        let layout = Layout {
511            from_engine: cx
512                .layout_engine()
513                .unwrap()
514                .computed_layout(*layout_node_id)
515                .expect("you can currently only use playground elements within an adapter"),
516            from_element: element_layout.as_mut(),
517        };
518
519        for event_handler in self.element.handlers_mut().iter().cloned() {
520            let EngineLayout { order, bounds } = layout.from_engine;
521
522            let view_id = cx.view_id();
523            let view_event_handler = event_handler.handler.clone();
524
525            // TODO: Tuck this into a method on PaintContext.
526            cx.scene
527                .interactive_regions
528                .push(gpui::scene::InteractiveRegion {
529                    order,
530                    bounds,
531                    outside_bounds: event_handler.outside_bounds,
532                    event_handler: Rc::new(move |view, event, window_cx, view_id| {
533                        let mut view_context = ViewContext::mutable(window_cx, view_id);
534                        let mut event_context = EventContext::new(&mut view_context);
535                        view_event_handler(view.downcast_mut().unwrap(), event, &mut event_context);
536                    }),
537                    event_type: event_handler.event_type,
538                    view_id,
539                });
540        }
541
542        self.element.paint(layout, view, cx)?;
543        if pushed_text_style {
544            cx.pop_text_style();
545        }
546
547        Ok(())
548    }
549}
550
551impl<V: 'static> Element<V> for AnyElement<V> {
552    type Layout = ();
553
554    fn style_mut(&mut self) -> &mut ElementStyle {
555        self.element.style_mut()
556    }
557
558    fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>> {
559        self.element.handlers_mut()
560    }
561
562    fn layout(
563        &mut self,
564        view: &mut V,
565        cx: &mut LayoutContext<V>,
566    ) -> Result<(NodeId, Self::Layout)> {
567        Ok((self.layout(view, cx)?, ()))
568    }
569
570    fn paint(&mut self, layout: Layout<()>, view: &mut V, cx: &mut PaintContext<V>) -> Result<()> {
571        self.paint(view, cx)
572    }
573}
574
575pub trait IntoElement<V: 'static> {
576    type Element: Element<V>;
577
578    fn into_element(self) -> Self::Element;
579
580    fn into_any_element(self) -> AnyElement<V>
581    where
582        Self: Sized,
583    {
584        self.into_element().into_any()
585    }
586}