diff --git a/crates/gpui3/src/app.rs b/crates/gpui3/src/app.rs index 526ed6d2b3b652d7a8dbf9e1b3e9855528cd0c85..fdb96902e64bb9c8542ea3b1ae51afe460316dad 100644 --- a/crates/gpui3/src/app.rs +++ b/crates/gpui3/src/app.rs @@ -9,8 +9,8 @@ use refineable::Refineable; use crate::{ current_platform, image_cache::ImageCache, AssetSource, Context, DisplayId, Executor, LayoutId, - MainThread, MainThreadOnly, Platform, RootView, SubscriberSet, SvgRenderer, Task, TextStyle, - TextStyleRefinement, TextSystem, Window, WindowContext, WindowHandle, WindowId, + MainThread, MainThreadOnly, Platform, SubscriberSet, SvgRenderer, Task, TextStyle, + TextStyleRefinement, TextSystem, View, Window, WindowContext, WindowHandle, WindowId, }; use anyhow::{anyhow, Result}; use collections::{HashMap, HashSet, VecDeque}; @@ -404,7 +404,7 @@ impl MainThread { pub fn open_window( &mut self, options: crate::WindowOptions, - build_root_view: impl FnOnce(&mut WindowContext) -> RootView + Send + 'static, + build_root_view: impl FnOnce(&mut WindowContext) -> View + Send + 'static, ) -> WindowHandle { self.update(|cx| { let id = cx.windows.insert(None); diff --git a/crates/gpui3/src/element.rs b/crates/gpui3/src/element.rs index 65ce28ed1ae07aad21eef6a7e61916934eb45517..534be128dd1a2e5755fa5d73a325bee60fc65e98 100644 --- a/crates/gpui3/src/element.rs +++ b/crates/gpui3/src/element.rs @@ -7,7 +7,7 @@ use crate::{ use derive_more::{Deref, DerefMut}; pub(crate) use smallvec::SmallVec; -pub trait Element: 'static + Send + Sync { +pub trait Element: 'static + Send + Sync + IntoAnyElement { type ViewState: 'static + Send + Sync; type ElementState: 'static + Send + Sync; @@ -227,6 +227,12 @@ where pub struct AnyElement(Box>); +impl AnyElement { + pub fn new>(element: E) -> Self { + AnyElement(Box::new(RenderedElement::new(element))) + } +} + impl AnyElement { pub fn layout(&mut self, state: &mut S, cx: &mut ViewContext) -> LayoutId { self.0.layout(state, cx) @@ -241,12 +247,6 @@ pub trait IntoAnyElement { fn into_any(self) -> AnyElement; } -impl IntoAnyElement for E { - fn into_any(self) -> AnyElement { - AnyElement(Box::new(RenderedElement::new(self))) - } -} - impl IntoAnyElement for AnyElement { fn into_any(self) -> AnyElement { self diff --git a/crates/gpui3/src/elements/clickable.rs b/crates/gpui3/src/elements/clickable.rs index 6a2347babd1bdd76efcd8b6c3e3ab42c19395d8d..861108a79ac3c08d88d077edc839596d26bfbe25 100644 --- a/crates/gpui3/src/elements/clickable.rs +++ b/crates/gpui3/src/elements/clickable.rs @@ -1,6 +1,6 @@ use crate::{ - AnyElement, Bounds, DispatchPhase, Element, IdentifiedElement, Interactive, MouseDownEvent, - MouseEventListeners, MouseUpEvent, ParentElement, Pixels, Styled, ViewContext, + AnyElement, Bounds, DispatchPhase, Element, IdentifiedElement, Interactive, IntoAnyElement, + MouseDownEvent, MouseEventListeners, MouseUpEvent, ParentElement, Pixels, Styled, ViewContext, }; use parking_lot::Mutex; use refineable::Cascade; @@ -51,6 +51,12 @@ where } } +impl IntoAnyElement for Clickable { + fn into_any(self) -> AnyElement { + AnyElement::new(self) + } +} + impl Element for Clickable where E: IdentifiedElement, diff --git a/crates/gpui3/src/elements/div.rs b/crates/gpui3/src/elements/div.rs index f8867b1238e06c1cd140098028e75bcc11e0a1cf..444e0956847a5c2252a07151afdff623b0816e1f 100644 --- a/crates/gpui3/src/elements/div.rs +++ b/crates/gpui3/src/elements/div.rs @@ -1,7 +1,7 @@ use crate::{ AnyElement, BorrowWindow, Bounds, Cascade, Element, ElementId, IdentifiedElement, Interactive, - LayoutId, MouseEventListeners, Overflow, ParentElement, Pixels, Point, Refineable, Style, - Styled, ViewContext, + IntoAnyElement, LayoutId, MouseEventListeners, Overflow, ParentElement, Pixels, Point, + Refineable, Style, Styled, ViewContext, }; use parking_lot::Mutex; use smallvec::SmallVec; @@ -29,7 +29,21 @@ pub fn div() -> Div { } } -impl Element for Div { +impl IntoAnyElement for Div +where + S: 'static + Send + Sync, + Marker: 'static + Send + Sync, +{ + fn into_any(self) -> AnyElement { + AnyElement::new(self) + } +} + +impl Element for Div +where + S: 'static + Send + Sync, + Marker: 'static + Send + Sync, +{ type ViewState = S; type ElementState = (); diff --git a/crates/gpui3/src/elements/group.rs b/crates/gpui3/src/elements/group.rs index 27a0e2886ebb0ec45af2d4b29cf037acf0d7c4f3..398ac65e1b2449e64f55860fedb5f80bdc482047 100644 --- a/crates/gpui3/src/elements/group.rs +++ b/crates/gpui3/src/elements/group.rs @@ -1,6 +1,6 @@ use crate::{ AnyElement, AppContext, Bounds, Element, ElementId, IdentifiedElement, Interactive, - MouseEventListeners, ParentElement, Pixels, SharedString, Styled, ViewContext, + IntoAnyElement, MouseEventListeners, ParentElement, Pixels, SharedString, Styled, ViewContext, }; use collections::HashMap; use refineable::Cascade; @@ -27,6 +27,12 @@ impl Group { } } +impl IntoAnyElement for Group { + fn into_any(self) -> AnyElement { + AnyElement::new(self) + } +} + impl Element for Group { type ViewState = E::ViewState; type ElementState = E::ElementState; diff --git a/crates/gpui3/src/elements/hoverable.rs b/crates/gpui3/src/elements/hoverable.rs index e2cae04bf5ec7a5d6e81208d9896676ed716e78e..e34a7ad7b5fbdb4b4cbe549334590bdc912435dd 100644 --- a/crates/gpui3/src/elements/hoverable.rs +++ b/crates/gpui3/src/elements/hoverable.rs @@ -1,7 +1,7 @@ use crate::{ group_bounds, AnyElement, Bounds, DispatchPhase, Element, ElementId, IdentifiedElement, - Interactive, MouseEventListeners, MouseMoveEvent, ParentElement, Pixels, SharedString, Styled, - ViewContext, + Interactive, IntoAnyElement, MouseEventListeners, MouseMoveEvent, ParentElement, Pixels, + SharedString, Styled, ViewContext, }; use refineable::{Cascade, CascadeSlot, Refineable}; use smallvec::SmallVec; @@ -51,6 +51,17 @@ impl + Styled> Interactive for Ho } } +impl IntoAnyElement for Hoverable +where + E: Element + Styled, + ::Style: 'static + Refineable + Send + Sync + Default, + <::Style as Refineable>::Refinement: 'static + Refineable + Send + Sync + Default, +{ + fn into_any(self) -> AnyElement { + AnyElement::new(self) + } +} + impl Element for Hoverable where E: Element + Styled, diff --git a/crates/gpui3/src/elements/identified.rs b/crates/gpui3/src/elements/identified.rs index f49e533dd9718a844a5958d0997a1150ce9109d3..3e6207912a33acb28fe0365b7ce0416836bce635 100644 --- a/crates/gpui3/src/elements/identified.rs +++ b/crates/gpui3/src/elements/identified.rs @@ -2,8 +2,8 @@ use refineable::{Cascade, Refineable}; use smallvec::SmallVec; use crate::{ - AnyElement, BorrowWindow, Bounds, Element, ElementId, IdentifiedElement, LayoutId, - ParentElement, Styled, ViewContext, + AnyElement, BorrowWindow, Bounds, Element, ElementId, IdentifiedElement, IntoAnyElement, + LayoutId, ParentElement, Styled, ViewContext, }; pub struct Identified { @@ -11,6 +11,12 @@ pub struct Identified { pub(crate) id: ElementId, } +impl IntoAnyElement for Identified { + fn into_any(self) -> AnyElement { + AnyElement::new(self) + } +} + impl Element for Identified { type ViewState = E::ViewState; type ElementState = E::ElementState; diff --git a/crates/gpui3/src/elements/img.rs b/crates/gpui3/src/elements/img.rs index 4f2417eb0c72e927634878e09ad97dee6eac9017..6b8c9b714c527f262c889cb05aafb68f386dea0b 100644 --- a/crates/gpui3/src/elements/img.rs +++ b/crates/gpui3/src/elements/img.rs @@ -1,5 +1,6 @@ use crate::{ - BorrowWindow, Bounds, Element, LayoutId, Pixels, SharedString, Style, Styled, ViewContext, + AnyElement, BorrowWindow, Bounds, Element, IntoAnyElement, LayoutId, Pixels, SharedString, + Style, Styled, ViewContext, }; use futures::FutureExt; use refineable::Cascade; @@ -34,6 +35,15 @@ impl Img { } } +impl IntoAnyElement for Img +where + S: 'static + Send + Sync, +{ + fn into_any(self) -> AnyElement { + AnyElement::new(self) + } +} + impl Element for Img { type ViewState = S; type ElementState = (); diff --git a/crates/gpui3/src/elements/pressable.rs b/crates/gpui3/src/elements/pressable.rs index 26db6b622965537d5f96d6fa1be1fa4afa3333dc..68929008543d637ea39b27e0cc9238984701ba3a 100644 --- a/crates/gpui3/src/elements/pressable.rs +++ b/crates/gpui3/src/elements/pressable.rs @@ -1,7 +1,7 @@ use crate::{ group_bounds, AnyElement, Bounds, DispatchPhase, Element, IdentifiedElement, Interactive, - MouseDownEvent, MouseEventListeners, MouseUpEvent, ParentElement, Pixels, SharedString, Styled, - ViewContext, + IntoAnyElement, MouseDownEvent, MouseEventListeners, MouseUpEvent, ParentElement, Pixels, + SharedString, Styled, ViewContext, }; use refineable::{Cascade, CascadeSlot, Refineable}; use smallvec::SmallVec; @@ -54,6 +54,17 @@ impl + Styled> Interactive for Pr } } +impl IntoAnyElement for Pressable +where + E: Styled + IdentifiedElement, + ::Style: 'static + Refineable + Send + Sync + Default, + <::Style as Refineable>::Refinement: 'static + Refineable + Send + Sync + Default, +{ + fn into_any(self) -> AnyElement { + AnyElement::new(self) + } +} + impl Element for Pressable where E: Styled + IdentifiedElement, diff --git a/crates/gpui3/src/elements/svg.rs b/crates/gpui3/src/elements/svg.rs index c1a4f417c96f2e5eff3a539f4dc9a20fd61586b7..afcd1810d5677b8b9e46a2e2d8a6e3fefe264a21 100644 --- a/crates/gpui3/src/elements/svg.rs +++ b/crates/gpui3/src/elements/svg.rs @@ -1,4 +1,6 @@ -use crate::{Bounds, Element, LayoutId, Pixels, SharedString, Style, Styled}; +use crate::{ + AnyElement, Bounds, Element, IntoAnyElement, LayoutId, Pixels, SharedString, Style, Styled, +}; use refineable::Cascade; use std::marker::PhantomData; use util::ResultExt; @@ -24,6 +26,15 @@ impl Svg { } } +impl IntoAnyElement for Svg +where + S: 'static + Send + Sync, +{ + fn into_any(self) -> AnyElement { + AnyElement::new(self) + } +} + impl Element for Svg { type ViewState = S; type ElementState = (); diff --git a/crates/gpui3/src/elements/text.rs b/crates/gpui3/src/elements/text.rs index 57525b1de4e7c485a6f1de83cf9e4285833044c6..6423e44ae08dd83e0e27f2f523a968380a5bf0d5 100644 --- a/crates/gpui3/src/elements/text.rs +++ b/crates/gpui3/src/elements/text.rs @@ -42,6 +42,12 @@ pub struct Text { state_type: PhantomData, } +impl IntoAnyElement for Text { + fn into_any(self) -> AnyElement { + AnyElement::new(self) + } +} + impl Element for Text { type ViewState = S; type ElementState = Arc>>; diff --git a/crates/gpui3/src/view.rs b/crates/gpui3/src/view.rs index a7db926fc3ed2ecbf9733978636e56cc98f5ae38..6af7a09df21de73267b2069aaf6e54dbb7d47930 100644 --- a/crates/gpui3/src/view.rs +++ b/crates/gpui3/src/view.rs @@ -1,56 +1,60 @@ use parking_lot::Mutex; use crate::{ - AnyBox, AnyElement, BorrowWindow, Bounds, Element, ElementId, Handle, IdentifiedElement, - IntoAnyElement, LayoutId, Pixels, ViewContext, WindowContext, + AnyBox, AnyElement, BorrowWindow, Bounds, Element, ElementId, EntityId, Handle, + IdentifiedElement, IntoAnyElement, LayoutId, Pixels, ViewContext, WindowContext, }; use std::{any::Any, marker::PhantomData, sync::Arc}; -pub struct View { +pub struct View { state: Handle, render: Arc) -> AnyElement + Send + Sync + 'static>, - parent_state_type: PhantomData

, } -impl View { - pub fn into_any(self) -> AnyView

{ +impl View { + pub fn into_any(self) -> AnyView { AnyView { view: Arc::new(Mutex::new(self)), - parent_state_type: PhantomData, } } } -impl Clone for View { +impl Clone for View { fn clone(&self) -> Self { Self { state: self.state.clone(), render: self.render.clone(), - parent_state_type: PhantomData, } } } -pub type RootView = View; - -pub fn view( +pub fn view( state: Handle, render: impl Fn(&mut S, &mut ViewContext) -> E + Send + Sync + 'static, -) -> View +) -> View where S: 'static + Send + Sync, - P: 'static, E: Element, { View { state, render: Arc::new(move |state, cx| render(state, cx).into_any()), - parent_state_type: PhantomData, } } -impl Element for View { - type ViewState = P; +impl + IntoAnyElement for View +{ + fn into_any(self) -> AnyElement { + AnyElement::new(EraseViewState { + view: self, + parent_view_state_type: PhantomData, + }) + } +} + +impl Element for View { + type ViewState = (); type ElementState = AnyElement; fn element_id(&self) -> Option { @@ -82,14 +86,67 @@ impl Element for View } } -trait ViewObject: Send + 'static { +struct EraseViewState { + view: View, + parent_view_state_type: PhantomData, +} + +impl IntoAnyElement + for EraseViewState +where + ViewState: 'static + Send + Sync, + ParentViewState: 'static + Send + Sync, +{ + fn into_any(self) -> AnyElement { + AnyElement::new(self) + } +} + +impl Element for EraseViewState +where + ViewState: 'static + Send + Sync, + ParentViewState: 'static + Send + Sync, +{ + type ViewState = ParentViewState; + type ElementState = AnyBox; + + fn element_id(&self) -> Option { + Element::element_id(&self.view) + } + + fn layout( + &mut self, + _: &mut Self::ViewState, + _: Option, + cx: &mut ViewContext, + ) -> (LayoutId, Self::ElementState) { + ViewObject::layout(&mut self.view, cx) + } + + fn paint( + &mut self, + bounds: Bounds, + _: &mut Self::ViewState, + element: &mut Self::ElementState, + cx: &mut ViewContext, + ) { + ViewObject::paint(&mut self.view, bounds, element, cx) + } +} + +trait ViewObject: 'static + Send + Sync { + fn entity_id(&self) -> EntityId; fn layout(&mut self, cx: &mut WindowContext) -> (LayoutId, AnyBox); fn paint(&mut self, bounds: Bounds, element: &mut dyn Any, cx: &mut WindowContext); } -impl IdentifiedElement for View {} +impl IdentifiedElement for View {} + +impl ViewObject for View { + fn entity_id(&self) -> EntityId { + self.state.id + } -impl ViewObject for View { fn layout(&mut self, cx: &mut WindowContext) -> (LayoutId, AnyBox) { cx.with_element_id(IdentifiedElement::element_id(self), |cx| { self.state.update(cx, |state, cx| { @@ -111,17 +168,28 @@ impl ViewObject for View { +pub struct AnyView { view: Arc>, - parent_state_type: PhantomData, } -impl Element for AnyView { +impl IntoAnyElement for AnyView +where + ParentViewState: 'static + Send + Sync, +{ + fn into_any(self) -> AnyElement { + AnyElement::new(EraseAnyViewState { + view: self, + parent_view_state_type: PhantomData, + }) + } +} + +impl Element for AnyView { type ViewState = (); type ElementState = AnyBox; fn element_id(&self) -> Option { - None + Some(ElementId::View(self.view.lock().entity_id())) } fn layout( @@ -144,11 +212,55 @@ impl Element for AnyView { } } -impl Clone for AnyView { +struct EraseAnyViewState { + view: AnyView, + parent_view_state_type: PhantomData, +} + +impl IntoAnyElement for EraseAnyViewState +where + ParentViewState: 'static + Send + Sync, +{ + fn into_any(self) -> AnyElement { + AnyElement::new(self) + } +} + +impl Element for EraseAnyViewState +where + ParentViewState: 'static + Send + Sync, +{ + type ViewState = ParentViewState; + type ElementState = AnyBox; + + fn element_id(&self) -> Option { + Element::element_id(&self.view) + } + + fn layout( + &mut self, + _: &mut Self::ViewState, + _: Option, + cx: &mut ViewContext, + ) -> (LayoutId, Self::ElementState) { + self.view.view.lock().layout(cx) + } + + fn paint( + &mut self, + bounds: Bounds, + _: &mut Self::ViewState, + element: &mut Self::ElementState, + cx: &mut ViewContext, + ) { + self.view.view.lock().paint(bounds, element, cx) + } +} + +impl Clone for AnyView { fn clone(&self) -> Self { Self { view: self.view.clone(), - parent_state_type: PhantomData, } } } diff --git a/crates/gpui3/src/window.rs b/crates/gpui3/src/window.rs index c05d4fd6f194d710d4eef6e09f19b0c663525a4b..0af65f476c902eb02554c7a1c40b5082d2fa0947 100644 --- a/crates/gpui3/src/window.rs +++ b/crates/gpui3/src/window.rs @@ -50,7 +50,7 @@ pub struct Window { rem_size: Pixels, content_size: Size, layout_engine: TaffyLayoutEngine, - pub(crate) root_view: Option>, + pub(crate) root_view: Option, pub(crate) element_id_stack: GlobalElementId, prev_element_states: HashMap, element_states: HashMap, @@ -624,7 +624,7 @@ impl<'a, 'w> WindowContext<'a, 'w> { }); fn draw_with_element_state( - root_view: &mut AnyView<()>, + root_view: &mut AnyView, element_state: Option, cx: &mut ViewContext<()>, ) -> AnyBox { diff --git a/crates/storybook2/src/collab_panel.rs b/crates/storybook2/src/collab_panel.rs index a1efce7c0d235e29864552784a36ab4aaad994d8..ab1bd6a1575572b1eb4b1a78522849b9d4353863 100644 --- a/crates/storybook2/src/collab_panel.rs +++ b/crates/storybook2/src/collab_panel.rs @@ -8,7 +8,7 @@ pub struct CollabPanel { scroll_state: ScrollState, } -pub fn collab_panel(cx: &mut WindowContext) -> View { +pub fn collab_panel(cx: &mut WindowContext) -> View { view(cx.entity(|cx| CollabPanel::new(cx)), CollabPanel::render) } diff --git a/crates/storybook2/src/workspace.rs b/crates/storybook2/src/workspace.rs index 2fb680cfc336907c81753901e2767659b3fce9c4..29c098297ce9fe916c456d753a9207dfc6b7c18c 100644 --- a/crates/storybook2/src/workspace.rs +++ b/crates/storybook2/src/workspace.rs @@ -3,17 +3,17 @@ use crate::{ themes::rose_pine, }; use gpui3::{ - div, img, svg, view, Context, Element, ParentElement, RootView, StyleHelpers, Styled, View, - ViewContext, WindowContext, + div, img, svg, view, Context, Element, ParentElement, StyleHelpers, Styled, View, ViewContext, + WindowContext, }; use ui::{theme, themed}; pub struct Workspace { - left_panel: View, - right_panel: View, + left_panel: View, + right_panel: View, } -pub fn workspace(cx: &mut WindowContext) -> RootView { +pub fn workspace(cx: &mut WindowContext) -> View { view(cx.entity(|cx| Workspace::new(cx)), Workspace::render) } diff --git a/crates/ui2/src/components/workspace.rs b/crates/ui2/src/components/workspace.rs index 4ffdacd00e4cad86d56927ecb5175c8c8d98ba29..89a4d6783b86fd79557edb8c801c20e713ce08e2 100644 --- a/crates/ui2/src/components/workspace.rs +++ b/crates/ui2/src/components/workspace.rs @@ -116,7 +116,7 @@ pub struct Workspace { bottom_panel_scroll_state: ScrollState, } -fn workspace(cx: &mut WindowContext) -> View { +fn workspace(cx: &mut WindowContext) -> View { view(cx.entity(|cx| Workspace::new()), Workspace::render) } @@ -377,11 +377,11 @@ mod stories { // state_type: PhantomData, // } - pub struct WorkspaceStory

{ - workspace: View, + pub struct WorkspaceStory { + workspace: View, } - pub fn workspace_story(cx: &mut WindowContext) -> View, P> { + pub fn workspace_story(cx: &mut WindowContext) -> View { todo!() // let workspace = workspace::

(cx); // view(