diff --git a/crates/gpui/src/elements.rs b/crates/gpui/src/elements.rs index e5aa225fe3..de2f7e5a6b 100644 --- a/crates/gpui/src/elements.rs +++ b/crates/gpui/src/elements.rs @@ -38,40 +38,15 @@ use crate::{ use anyhow::{anyhow, Result}; use core::panic; use json::ToJson; -use std::{any::Any, borrow::Cow, marker::PhantomData, mem, ops::Range}; +use std::{ + any::Any, + borrow::Cow, + marker::PhantomData, + mem, + ops::{Deref, DerefMut, Range}, +}; use util::ResultExt; -trait AnyDrawable { - fn layout( - &mut self, - constraint: SizeConstraint, - view: &mut V, - cx: &mut ViewContext, - ) -> Vector2F; - - fn paint( - &mut self, - scene: &mut SceneBuilder, - origin: Vector2F, - visible_bounds: RectF, - view: &mut V, - cx: &mut ViewContext, - ); - - fn rect_for_text_range( - &self, - range_utf16: Range, - view: &V, - cx: &ViewContext, - ) -> Option; - - fn debug(&self, view: &V, cx: &ViewContext) -> serde_json::Value; - - fn size(&self) -> Vector2F; - - fn metadata(&self) -> Option<&dyn Any>; -} - pub trait Drawable { type LayoutState; type PaintState; @@ -122,7 +97,7 @@ pub trait Drawable { Self: 'static + Sized, { Element { - element: Box::new(Lifecycle::Init { element: self }), + drawable: Box::new(Lifecycle::Init { element: self }), view_type: PhantomData, name: None, } @@ -143,7 +118,7 @@ pub trait Drawable { Self: 'static + Sized, { Element { - element: Box::new(Lifecycle::Init { element: self }), + drawable: Box::new(Lifecycle::Init { element: self }), view_type: PhantomData, name: Some(name.into()), } @@ -234,7 +209,38 @@ pub trait Drawable { } } -pub enum Lifecycle> { +trait AnyDrawable { + fn layout( + &mut self, + constraint: SizeConstraint, + view: &mut V, + cx: &mut ViewContext, + ) -> Vector2F; + + fn paint( + &mut self, + scene: &mut SceneBuilder, + origin: Vector2F, + visible_bounds: RectF, + view: &mut V, + cx: &mut ViewContext, + ); + + fn rect_for_text_range( + &self, + range_utf16: Range, + view: &V, + cx: &ViewContext, + ) -> Option; + + fn debug(&self, view: &V, cx: &ViewContext) -> serde_json::Value; + + fn size(&self) -> Vector2F; + + fn metadata(&self) -> Option<&dyn Any>; +} + +enum Lifecycle> { Empty, Init { element: E, @@ -420,7 +426,7 @@ impl> Default for Lifecycle { } pub struct Element { - element: Box>, + drawable: Box>, view_type: PhantomData, name: Option>, } @@ -431,7 +437,7 @@ impl Element { } pub fn metadata(&self) -> Option<&T> { - self.element + self.drawable .metadata() .and_then(|data| data.downcast_ref::()) } @@ -442,7 +448,7 @@ impl Element { view: &mut V, cx: &mut ViewContext, ) -> Vector2F { - self.element.layout(constraint, view, cx) + self.drawable.layout(constraint, view, cx) } pub fn paint( @@ -453,7 +459,7 @@ impl Element { view: &mut V, cx: &mut ViewContext, ) { - self.element.paint(scene, origin, visible_bounds, view, cx); + self.drawable.paint(scene, origin, visible_bounds, view, cx); } pub fn rect_for_text_range( @@ -462,15 +468,15 @@ impl Element { view: &V, cx: &ViewContext, ) -> Option { - self.element.rect_for_text_range(range_utf16, view, cx) + self.drawable.rect_for_text_range(range_utf16, view, cx) } pub fn size(&self) -> Vector2F { - self.element.size() + self.drawable.size() } pub fn debug(&self, view: &V, cx: &ViewContext) -> json::Value { - let mut value = self.element.debug(view, cx); + let mut value = self.drawable.debug(view, cx); if let Some(name) = &self.name { if let json::Value::Object(map) = &mut value { @@ -489,7 +495,7 @@ impl Element { T: 'static, F: FnOnce(Option<&T>) -> R, { - f(self.element.metadata().and_then(|m| m.downcast_ref())) + f(self.drawable.metadata().and_then(|m| m.downcast_ref())) } } @@ -504,6 +510,81 @@ impl RootElement { } } +pub trait Component { + fn render(&self, view: &mut V, cx: &mut ViewContext) -> Element; +} + +pub struct ComponentHost> { + component: C, + view_type: PhantomData, +} + +impl> Deref for ComponentHost { + type Target = C; + + fn deref(&self) -> &Self::Target { + &self.component + } +} + +impl> DerefMut for ComponentHost { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.component + } +} + +impl> Drawable for ComponentHost { + type LayoutState = Element; + type PaintState = (); + + fn layout( + &mut self, + constraint: SizeConstraint, + view: &mut V, + cx: &mut ViewContext, + ) -> (Vector2F, Element) { + let mut element = self.component.render(view, cx); + let size = element.layout(constraint, view, cx); + (size, element) + } + + fn paint( + &mut self, + scene: &mut SceneBuilder, + bounds: RectF, + visible_bounds: RectF, + element: &mut Element, + view: &mut V, + cx: &mut ViewContext, + ) { + element.paint(scene, bounds.origin(), visible_bounds, view, cx); + } + + fn rect_for_text_range( + &self, + range_utf16: Range, + _: RectF, + _: RectF, + element: &Element, + _: &(), + view: &V, + cx: &ViewContext, + ) -> Option { + element.rect_for_text_range(range_utf16, view, cx) + } + + fn debug( + &self, + _: RectF, + element: &Element, + _: &(), + view: &V, + cx: &ViewContext, + ) -> serde_json::Value { + element.debug(view, cx) + } +} + pub trait AnyRootElement { fn layout(&mut self, constraint: SizeConstraint, cx: &mut WindowContext) -> Result; fn paint(