diff --git a/crates/gpui3/src/element.rs b/crates/gpui3/src/element.rs index 888010dc065efd91cb03c860c27b48c3794086fb..2d81e406913351bbfd968ed9a1516fa11885cec6 100644 --- a/crates/gpui3/src/element.rs +++ b/crates/gpui3/src/element.rs @@ -1,6 +1,7 @@ use crate::{BorrowWindow, Bounds, ElementId, FocusHandle, LayoutId, Pixels, Point, ViewContext}; use derive_more::{Deref, DerefMut}; pub(crate) use smallvec::SmallVec; +use std::mem; pub trait Element: 'static + Send + Sync + IntoAnyElement { type ViewState: 'static + Send + Sync; @@ -8,17 +9,24 @@ pub trait Element: 'static + Send + Sync + IntoAnyElement { fn id(&self) -> Option; - fn layout( + fn initialize( &mut self, - state: &mut Self::ViewState, + view_state: &mut Self::ViewState, element_state: Option, cx: &mut ViewContext, - ) -> (LayoutId, Self::ElementState); + ) -> Self::ElementState; + + fn layout( + &mut self, + view_state: &mut Self::ViewState, + element_state: &mut Self::ElementState, + cx: &mut ViewContext, + ) -> LayoutId; fn paint( &mut self, bounds: Bounds, - state: &mut Self::ViewState, + view_state: &mut Self::ViewState, element_state: &mut Self::ElementState, cx: &mut ViewContext, ); @@ -97,9 +105,10 @@ pub trait ParentElement: Element { } } -trait ElementObject: 'static + Send + Sync { - fn layout(&mut self, state: &mut S, cx: &mut ViewContext) -> LayoutId; - fn paint(&mut self, state: &mut S, offset: Option>, cx: &mut ViewContext); +trait ElementObject: 'static + Send + Sync { + fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext); + fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext) -> LayoutId; + fn paint(&mut self, view_state: &mut V, offset: Option>, cx: &mut ViewContext); } struct RenderedElement { @@ -108,17 +117,17 @@ struct RenderedElement { } #[derive(Default)] -enum ElementRenderPhase { +enum ElementRenderPhase { #[default] - Rendered, + Start, + Initialized { + frame_state: Option, + }, LayoutRequested { layout_id: LayoutId, - frame_state: Option, - }, - Painted { - bounds: Bounds, - frame_state: Option, + frame_state: Option, }, + Painted, } /// Internal struct that wraps an element to store Layout and ElementState after the element is rendered. @@ -128,52 +137,57 @@ impl RenderedElement { fn new(element: E) -> Self { RenderedElement { element, - phase: ElementRenderPhase::Rendered, + phase: ElementRenderPhase::Start, } } +} - fn paint_with_element_state( - &mut self, - bounds: Bounds, - view_state: &mut E::ViewState, - frame_state: &mut Option, - cx: &mut ViewContext, - ) { - if let Some(id) = self.element.id() { +impl ElementObject for RenderedElement +where + E: Element, +{ + fn initialize(&mut self, view_state: &mut E::ViewState, cx: &mut ViewContext) { + let frame_state = if let Some(id) = self.element.id() { cx.with_element_state(id, |element_state, cx| { - let mut element_state = element_state.unwrap(); - self.element - .paint(bounds, view_state, &mut element_state, cx); + let element_state = self.element.initialize(view_state, element_state, cx); ((), element_state) }); + None } else { - self.element - .paint(bounds, view_state, frame_state.as_mut().unwrap(), cx); - } + let frame_state = self.element.initialize(view_state, None, cx); + Some(frame_state) + }; + + self.phase = ElementRenderPhase::Initialized { frame_state }; } -} -impl ElementObject for RenderedElement -where - E: Element, - S: 'static + Send + Sync, -{ fn layout(&mut self, state: &mut E::ViewState, cx: &mut ViewContext) -> LayoutId { - let (layout_id, frame_state) = if let Some(id) = self.element.id() { - let layout_id = cx.with_element_state(id, |element_state, cx| { - self.element.layout(state, element_state, cx) - }); - (layout_id, None) - } else { - let (layout_id, frame_state) = self.element.layout(state, None, cx); - (layout_id, Some(frame_state)) + let layout_id; + let mut frame_state; + match mem::take(&mut self.phase) { + ElementRenderPhase::Initialized { + frame_state: initial_frame_state, + } => { + frame_state = initial_frame_state; + if let Some(id) = self.element.id() { + layout_id = cx.with_element_state(id, |element_state, cx| { + let mut element_state = element_state.unwrap(); + let layout_id = self.element.layout(state, &mut element_state, cx); + (layout_id, element_state) + }); + } else { + layout_id = self + .element + .layout(state, frame_state.as_mut().unwrap(), cx); + } + } + _ => panic!("must call initialize before layout"), }; self.phase = ElementRenderPhase::LayoutRequested { layout_id, frame_state, }; - layout_id } @@ -183,60 +197,63 @@ where offset: Option>, cx: &mut ViewContext, ) { - self.phase = match std::mem::take(&mut self.phase) { - ElementRenderPhase::Rendered => panic!("must call layout before paint"), - + self.phase = match mem::take(&mut self.phase) { ElementRenderPhase::LayoutRequested { layout_id, mut frame_state, } => { let mut bounds = cx.layout_bounds(layout_id); offset.map(|offset| bounds.origin += offset); - self.paint_with_element_state(bounds, view_state, &mut frame_state, cx); - ElementRenderPhase::Painted { - bounds, - frame_state, + if let Some(id) = self.element.id() { + cx.with_element_state(id, |element_state, cx| { + let mut element_state = element_state.unwrap(); + self.element + .paint(bounds, view_state, &mut element_state, cx); + ((), element_state) + }); + } else { + self.element + .paint(bounds, view_state, frame_state.as_mut().unwrap(), cx); } + ElementRenderPhase::Painted } - ElementRenderPhase::Painted { - bounds, - mut frame_state, - } => { - self.paint_with_element_state(bounds, view_state, &mut frame_state, cx); - ElementRenderPhase::Painted { - bounds, - frame_state, - } - } + _ => panic!("must call layout before paint"), }; } } -pub struct AnyElement(Box>); +pub struct AnyElement(Box>); -impl AnyElement { - pub fn new>(element: E) -> Self { +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) + pub fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext) { + self.0.initialize(view_state, cx); } - pub fn paint(&mut self, state: &mut S, offset: Option>, cx: &mut ViewContext) { - self.0.paint(state, offset, cx) + pub fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext) -> LayoutId { + self.0.layout(view_state, cx) + } + + pub fn paint( + &mut self, + view_state: &mut V, + offset: Option>, + cx: &mut ViewContext, + ) { + self.0.paint(view_state, offset, cx) } } -pub trait IntoAnyElement { - fn into_any(self) -> AnyElement; +pub trait IntoAnyElement { + fn into_any(self) -> AnyElement; } -impl IntoAnyElement for AnyElement { - fn into_any(self) -> AnyElement { +impl IntoAnyElement for AnyElement { + fn into_any(self) -> AnyElement { self } } diff --git a/crates/gpui3/src/elements/div.rs b/crates/gpui3/src/elements/div.rs index 78743f70891578444db82baff8c223bd07087bb0..552c27686ed3e15488f04439c226080a7db17050 100644 --- a/crates/gpui3/src/elements/div.rs +++ b/crates/gpui3/src/elements/div.rs @@ -369,14 +369,25 @@ where self.identity.id() } - fn layout( + fn initialize( &mut self, view_state: &mut Self::ViewState, element_state: Option, cx: &mut ViewContext, - ) -> (LayoutId, Self::ElementState) { - let element_state = element_state.unwrap_or_default(); - let style = self.compute_style(Bounds::default(), &element_state, cx); + ) -> Self::ElementState { + for child in &mut self.children { + child.initialize(view_state, cx); + } + element_state.unwrap_or_default() + } + + fn layout( + &mut self, + view_state: &mut Self::ViewState, + element_state: &mut Self::ElementState, + cx: &mut ViewContext, + ) -> LayoutId { + let style = self.compute_style(Bounds::default(), element_state, cx); style.apply_text_style(cx, |cx| { self.with_element_id(cx, |this, cx| { let layout_ids = this @@ -384,9 +395,7 @@ where .iter_mut() .map(|child| child.layout(view_state, cx)) .collect::>(); - - let layout_id = cx.request_layout(&style, layout_ids); - (layout_id, element_state) + cx.request_layout(&style, layout_ids) }) }) } diff --git a/crates/gpui3/src/elements/img.rs b/crates/gpui3/src/elements/img.rs index e1e93fdd947a16deaafa7da82a748333d2579259..261062a5b942035c0ae3b0694791c00f2de6ab71 100644 --- a/crates/gpui3/src/elements/img.rs +++ b/crates/gpui3/src/elements/img.rs @@ -71,24 +71,30 @@ where self.base.id() } - fn layout( + fn initialize( &mut self, - view_state: &mut Self::ViewState, + view_state: &mut V, element_state: Option, + cx: &mut ViewContext, + ) -> Self::ElementState { + self.base.initialize(view_state, element_state, cx) + } + + fn layout( + &mut self, + view_state: &mut V, + element_state: &mut Self::ElementState, cx: &mut ViewContext, - ) -> (LayoutId, Self::ElementState) - where - Self: Sized, - { + ) -> LayoutId { self.base.layout(view_state, element_state, cx) } fn paint( &mut self, bounds: Bounds, - view: &mut Self::ViewState, + view: &mut V, element_state: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut ViewContext, ) { cx.stack(0, |cx| { self.base.paint(bounds, view, element_state, cx); diff --git a/crates/gpui3/src/elements/svg.rs b/crates/gpui3/src/elements/svg.rs index aec1164295c83f8dfbe9398282e83aec83d76b69..f0d6956503aee723f4c6c9c51c675c61d41f313e 100644 --- a/crates/gpui3/src/elements/svg.rs +++ b/crates/gpui3/src/elements/svg.rs @@ -1,7 +1,7 @@ use crate::{ div, Active, Anonymous, AnyElement, Bounds, Click, Div, DivState, Element, ElementId, ElementIdentity, EventListeners, Hover, Identified, Interactive, IntoAnyElement, LayoutId, - NonFocusable, Pixels, SharedString, StyleRefinement, Styled, + NonFocusable, Pixels, SharedString, StyleRefinement, Styled, ViewContext, }; use util::ResultExt; @@ -62,16 +62,22 @@ where self.base.id() } - fn layout( + fn initialize( &mut self, - view: &mut V, + view_state: &mut V, element_state: Option, - cx: &mut crate::ViewContext, - ) -> (LayoutId, Self::ElementState) - where - Self: Sized, - { - self.base.layout(view, element_state, cx) + cx: &mut ViewContext, + ) -> Self::ElementState { + self.base.initialize(view_state, element_state, cx) + } + + fn layout( + &mut self, + view_state: &mut V, + element_state: &mut Self::ElementState, + cx: &mut ViewContext, + ) -> LayoutId { + self.base.layout(view_state, element_state, cx) } fn paint( @@ -79,7 +85,7 @@ where bounds: Bounds, view: &mut Self::ViewState, element_state: &mut Self::ElementState, - cx: &mut crate::ViewContext, + cx: &mut ViewContext, ) where Self: Sized, { diff --git a/crates/gpui3/src/elements/text.rs b/crates/gpui3/src/elements/text.rs index 47203aaa6052f8037e05e5ab57d5d3c18a719ce1..70d642baebc13126c9951f0c76f521a07de61e0f 100644 --- a/crates/gpui3/src/elements/text.rs +++ b/crates/gpui3/src/elements/text.rs @@ -39,31 +39,40 @@ impl IntoAnyElement for String { } } -pub struct Text { +pub struct Text { text: SharedString, - state_type: PhantomData, + state_type: PhantomData, } -impl IntoAnyElement for Text { - fn into_any(self) -> AnyElement { +impl IntoAnyElement for Text { + fn into_any(self) -> AnyElement { AnyElement::new(self) } } -impl Element for Text { - type ViewState = S; +impl Element for Text { + type ViewState = V; type ElementState = Arc>>; fn id(&self) -> Option { None } + fn initialize( + &mut self, + _view_state: &mut V, + element_state: Option, + _cx: &mut ViewContext, + ) -> Self::ElementState { + element_state.unwrap_or_default() + } + fn layout( &mut self, - _view: &mut S, - _element_state: Option, - cx: &mut ViewContext, - ) -> (LayoutId, Self::ElementState) { + _view: &mut V, + element_state: &mut Self::ElementState, + cx: &mut ViewContext, + ) -> LayoutId { let text_system = cx.text_system().clone(); let text_style = cx.text_style(); let font_size = text_style.font_size * cx.rem_size(); @@ -71,7 +80,6 @@ impl Element for Text { .line_height .to_pixels(font_size.into(), cx.rem_size()); let text = self.text.clone(); - let element_state = Arc::new(Mutex::new(None)); let rem_size = cx.rem_size(); let layout_id = cx.request_measured_layout(Default::default(), rem_size, { @@ -102,15 +110,15 @@ impl Element for Text { } }); - (layout_id, element_state) + layout_id } - fn paint<'a>( + fn paint( &mut self, bounds: Bounds, - _: &mut Self::ViewState, + _: &mut V, element_state: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut ViewContext, ) { let element_state = element_state.lock(); let element_state = element_state diff --git a/crates/gpui3/src/view.rs b/crates/gpui3/src/view.rs index 99e8c58b645ba08e34529b57b672d2bfc50ef8f7..8d4b72aa438c6270dc6223e1b2476c1efb37bd49 100644 --- a/crates/gpui3/src/view.rs +++ b/crates/gpui3/src/view.rs @@ -6,12 +6,12 @@ use crate::{ }; use std::{marker::PhantomData, sync::Arc}; -pub struct View { - state: Handle, - render: Arc) -> AnyElement + Send + Sync + 'static>, +pub struct View { + state: Handle, + render: Arc) -> AnyElement + Send + Sync + 'static>, } -impl View { +impl View { pub fn into_any(self) -> AnyView { AnyView { view: Arc::new(Mutex::new(self)), @@ -19,7 +19,7 @@ impl View { } } -impl Clone for View { +impl Clone for View { fn clone(&self) -> Self { Self { state: self.state.clone(), @@ -28,13 +28,13 @@ impl Clone for View { } } -pub fn view( - state: Handle, - render: impl Fn(&mut S, &mut ViewContext) -> E + Send + Sync + 'static, -) -> View +pub fn view( + state: Handle, + render: impl Fn(&mut V, &mut ViewContext) -> E + Send + Sync + 'static, +) -> View where - E: IntoAnyElement, - S: 'static + Send + Sync, + E: IntoAnyElement, + V: 'static + Send + Sync, { View { state, @@ -42,8 +42,8 @@ where } } -impl - IntoAnyElement for View +impl + IntoAnyElement for View { fn into_any(self) -> AnyElement { AnyElement::new(EraseViewState { @@ -53,74 +53,87 @@ impl } } -impl Element for View { +impl Element for View { type ViewState = (); - type ElementState = AnyElement; + type ElementState = AnyElement; fn id(&self) -> Option { Some(ElementId::View(self.state.id)) } - fn layout( + fn initialize( &mut self, - _: &mut Self::ViewState, + _: &mut (), _: Option, - cx: &mut ViewContext, - ) -> (LayoutId, Self::ElementState) { - self.state.update(cx, |state, cx| { - let mut element = (self.render)(state, cx); - let layout_id = element.layout(state, cx); - (layout_id, element) - }) + cx: &mut ViewContext<()>, + ) -> Self::ElementState { + self.state.update(cx, |state, cx| (self.render)(state, cx)) + } + + fn layout( + &mut self, + _: &mut (), + element: &mut Self::ElementState, + cx: &mut ViewContext<()>, + ) -> LayoutId { + self.state.update(cx, |state, cx| element.layout(state, cx)) } fn paint( &mut self, _: Bounds, - _: &mut Self::ViewState, + _: &mut (), element: &mut Self::ElementState, - cx: &mut ViewContext, + cx: &mut ViewContext<()>, ) { self.state .update(cx, |state, cx| element.paint(state, None, cx)) } } -struct EraseViewState { - view: View, - parent_view_state_type: PhantomData, +struct EraseViewState { + view: View, + parent_view_state_type: PhantomData, } -impl IntoAnyElement - for EraseViewState +impl IntoAnyElement for EraseViewState where - ViewState: 'static + Send + Sync, - ParentViewState: 'static + Send + Sync, + V: 'static + Send + Sync, + ParentV: 'static + Send + Sync, { - fn into_any(self) -> AnyElement { + fn into_any(self) -> AnyElement { AnyElement::new(self) } } -impl Element for EraseViewState +impl Element for EraseViewState where - ViewState: 'static + Send + Sync, - ParentViewState: 'static + Send + Sync, + V: 'static + Send + Sync, + ParentV: 'static + Send + Sync, { - type ViewState = ParentViewState; + type ViewState = ParentV; type ElementState = AnyBox; fn id(&self) -> Option { Element::id(&self.view) } - fn layout( + fn initialize( &mut self, _: &mut Self::ViewState, _: Option, cx: &mut ViewContext, - ) -> (LayoutId, Self::ElementState) { - ViewObject::layout(&mut self.view, cx) + ) -> Self::ElementState { + ViewObject::initialize(&mut self.view, cx) + } + + fn layout( + &mut self, + _: &mut Self::ViewState, + element: &mut Self::ElementState, + cx: &mut ViewContext, + ) -> LayoutId { + ViewObject::layout(&mut self.view, element, cx) } fn paint( @@ -136,22 +149,28 @@ where trait ViewObject: 'static + Send + Sync { fn entity_id(&self) -> EntityId; - fn layout(&mut self, cx: &mut WindowContext) -> (LayoutId, AnyBox); + fn initialize(&mut self, cx: &mut WindowContext) -> AnyBox; + fn layout(&mut self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId; fn paint(&mut self, bounds: Bounds, element: &mut AnyBox, cx: &mut WindowContext); } -impl ViewObject for View { +impl ViewObject for View { fn entity_id(&self) -> EntityId { self.state.id } - fn layout(&mut self, cx: &mut WindowContext) -> (LayoutId, AnyBox) { + fn initialize(&mut self, cx: &mut WindowContext) -> AnyBox { + cx.with_element_id(self.entity_id(), |cx| { + self.state + .update(cx, |state, cx| Box::new((self.render)(state, cx)) as AnyBox) + }) + } + + fn layout(&mut self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId { cx.with_element_id(self.entity_id(), |cx| { self.state.update(cx, |state, cx| { - let mut element = (self.render)(state, cx); - let layout_id = element.layout(state, cx); - let element = Box::new(element) as AnyBox; - (layout_id, element) + let element = element.downcast_mut::>().unwrap(); + element.layout(state, cx) }) }) } @@ -159,7 +178,7 @@ impl ViewObject for View { fn paint(&mut self, _: Bounds, element: &mut AnyBox, cx: &mut WindowContext) { cx.with_element_id(self.entity_id(), |cx| { self.state.update(cx, |state, cx| { - let element = element.downcast_mut::>().unwrap(); + let element = element.downcast_mut::>().unwrap(); element.paint(state, None, cx); }); }); @@ -170,11 +189,11 @@ pub struct AnyView { view: Arc>, } -impl IntoAnyElement for AnyView +impl IntoAnyElement for AnyView where - ParentViewState: 'static + Send + Sync, + ParentV: 'static + Send + Sync, { - fn into_any(self) -> AnyElement { + fn into_any(self) -> AnyElement { AnyElement::new(EraseAnyViewState { view: self, parent_view_state_type: PhantomData, @@ -190,13 +209,22 @@ impl Element for AnyView { Some(ElementId::View(self.view.lock().entity_id())) } - fn layout( + fn initialize( &mut self, _: &mut Self::ViewState, _: Option, cx: &mut ViewContext, - ) -> (LayoutId, Self::ElementState) { - self.view.lock().layout(cx) + ) -> Self::ElementState { + self.view.lock().initialize(cx) + } + + fn layout( + &mut self, + _: &mut Self::ViewState, + element: &mut Self::ElementState, + cx: &mut ViewContext, + ) -> LayoutId { + self.view.lock().layout(element, cx) } fn paint( @@ -215,33 +243,42 @@ struct EraseAnyViewState { parent_view_state_type: PhantomData, } -impl IntoAnyElement for EraseAnyViewState +impl IntoAnyElement for EraseAnyViewState where - ParentViewState: 'static + Send + Sync, + ParentV: 'static + Send + Sync, { - fn into_any(self) -> AnyElement { + fn into_any(self) -> AnyElement { AnyElement::new(self) } } -impl Element for EraseAnyViewState +impl Element for EraseAnyViewState where - ParentViewState: 'static + Send + Sync, + ParentV: 'static + Send + Sync, { - type ViewState = ParentViewState; + type ViewState = ParentV; type ElementState = AnyBox; fn id(&self) -> Option { Element::id(&self.view) } - fn layout( + fn initialize( &mut self, _: &mut Self::ViewState, _: Option, cx: &mut ViewContext, - ) -> (LayoutId, Self::ElementState) { - self.view.view.lock().layout(cx) + ) -> Self::ElementState { + self.view.view.lock().initialize(cx) + } + + fn layout( + &mut self, + _: &mut Self::ViewState, + element: &mut Self::ElementState, + cx: &mut ViewContext, + ) -> LayoutId { + self.view.view.lock().layout(element, cx) } fn paint( diff --git a/crates/gpui3/src/window.rs b/crates/gpui3/src/window.rs index 17687f3597eb24fdb1fe0e0ab62571b51355247e..e491913b29bba06a631ec5b353ade39223aa5568 100644 --- a/crates/gpui3/src/window.rs +++ b/crates/gpui3/src/window.rs @@ -653,7 +653,8 @@ impl<'a, 'w> WindowContext<'a, 'w> { element_state: Option, cx: &mut ViewContext<()>, ) -> AnyBox { - let (layout_id, mut element_state) = root_view.layout(&mut (), element_state, cx); + let mut element_state = root_view.initialize(&mut (), element_state, cx); + let layout_id = root_view.layout(&mut (), &mut element_state, cx); let available_space = cx.window.content_size.map(Into::into); cx.window .layout_engine