From 33a808a49b61f2efe6e221b305b3f6028ab420c2 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 15 Nov 2023 20:41:09 +0100 Subject: [PATCH] WIP --- crates/gpui2/src/element.rs | 86 ++++----------------- crates/gpui2/src/elements/div.rs | 91 +++++++---------------- crates/gpui2/src/elements/img.rs | 13 +--- crates/gpui2/src/elements/svg.rs | 13 +--- crates/gpui2/src/elements/text.rs | 16 +--- crates/gpui2/src/elements/uniform_list.rs | 4 +- crates/gpui2/src/view.rs | 87 ++++++++-------------- crates/gpui2/src/window.rs | 16 +++- 8 files changed, 95 insertions(+), 231 deletions(-) diff --git a/crates/gpui2/src/element.rs b/crates/gpui2/src/element.rs index 9db256a5722faef0bd3f47aa4ef569aa666a509f..3ee829df523aee8c84c78cd470d1e158fd3ee42a 100644 --- a/crates/gpui2/src/element.rs +++ b/crates/gpui2/src/element.rs @@ -10,21 +10,12 @@ pub trait Element { fn element_id(&self) -> Option; - /// Called to initialize this element for the current frame. If this - /// element had state in a previous frame, it will be passed in for the 3rd argument. - fn initialize( - &mut self, - view_state: &mut V, - element_state: Option, - cx: &mut ViewContext, - ) -> Self::ElementState; - fn layout( &mut self, view_state: &mut V, - element_state: &mut Self::ElementState, + previous_element_state: Option, cx: &mut ViewContext, - ) -> LayoutId; + ) -> (LayoutId, Self::ElementState); fn paint( &mut self, @@ -96,7 +87,6 @@ pub trait ParentComponent { } trait ElementObject { - 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, cx: &mut ViewContext); fn measure( @@ -123,9 +113,6 @@ struct RenderedElement> { enum ElementRenderPhase { #[default] Start, - Initialized { - frame_state: Option, - }, LayoutRequested { layout_id: LayoutId, frame_state: Option, @@ -157,42 +144,19 @@ where E: Element, E::ElementState: 'static, { - fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext) { - let frame_state = if let Some(id) = self.element.element_id() { - cx.with_element_state(id, |element_state, cx| { - let element_state = self.element.initialize(view_state, element_state, cx); - ((), element_state) - }); - None - } else { - let frame_state = self.element.initialize(view_state, None, cx); - Some(frame_state) - }; - - self.phase = ElementRenderPhase::Initialized { frame_state }; - } - fn layout(&mut self, state: &mut V, cx: &mut ViewContext) -> LayoutId { - 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; + let (layout_id, frame_state) = match mem::take(&mut self.phase) { + ElementRenderPhase::Start => { if let Some(id) = self.element.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) + let layout_id = cx.with_element_state(id, |element_state, cx| { + self.element.layout(state, element_state, cx) }); + (layout_id, None) } else { - layout_id = self - .element - .layout(state, frame_state.as_mut().unwrap(), cx); + let (layout_id, frame_state) = self.element.layout(state, None, cx); + (layout_id, Some(frame_state)) } } - ElementRenderPhase::Start => panic!("must call initialize before layout"), ElementRenderPhase::LayoutRequested { .. } | ElementRenderPhase::LayoutComputed { .. } | ElementRenderPhase::Painted { .. } => { @@ -244,10 +208,6 @@ where cx: &mut ViewContext, ) -> Size { if matches!(&self.phase, ElementRenderPhase::Start) { - self.initialize(view_state, cx); - } - - if matches!(&self.phase, ElementRenderPhase::Initialized { .. }) { self.layout(view_state, cx); } @@ -290,10 +250,7 @@ where cx: &mut ViewContext, ) { self.measure(available_space, view_state, cx); - // Ignore the element offset when drawing this element, as the origin is already specified - // in absolute terms. - origin -= cx.element_offset(); - cx.with_element_offset(origin, |cx| self.paint(view_state, cx)) + cx.with_absolute_element_offset(origin, |cx| self.paint(view_state, cx)) } } @@ -309,10 +266,6 @@ impl AnyElement { AnyElement(Box::new(RenderedElement::new(element))) } - pub fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext) { - self.0.initialize(view_state, cx); - } - pub fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext) -> LayoutId { self.0.layout(view_state, cx) } @@ -393,25 +346,16 @@ where None } - fn initialize( + fn layout( &mut self, view_state: &mut V, - _rendered_element: Option, + _: Option, cx: &mut ViewContext, - ) -> Self::ElementState { + ) -> (LayoutId, Self::ElementState) { let render = self.take().unwrap(); let mut rendered_element = (render)(view_state, cx).render(); - rendered_element.initialize(view_state, cx); - rendered_element - } - - fn layout( - &mut self, - view_state: &mut V, - rendered_element: &mut Self::ElementState, - cx: &mut ViewContext, - ) -> LayoutId { - rendered_element.layout(view_state, cx) + let layout_id = rendered_element.layout(view_state, cx); + (layout_id, rendered_element) } fn paint( diff --git a/crates/gpui2/src/elements/div.rs b/crates/gpui2/src/elements/div.rs index 1f9b2b020abafd626b45453190dedbab7c406874..3a3ad5936ebba2ca0567f0e1eb926a708617717a 100644 --- a/crates/gpui2/src/elements/div.rs +++ b/crates/gpui2/src/elements/div.rs @@ -617,46 +617,36 @@ impl Element for Div { self.interactivity.element_id.clone() } - fn initialize( - &mut self, - view_state: &mut V, - element_state: Option, - cx: &mut ViewContext, - ) -> Self::ElementState { - let interactive_state = self - .interactivity - .initialize(element_state.map(|s| s.interactive_state), cx); - - for child in &mut self.children { - child.initialize(view_state, cx); - } - - DivState { - interactive_state, - child_layout_ids: SmallVec::new(), - } - } - fn layout( &mut self, view_state: &mut V, - element_state: &mut Self::ElementState, + element_state: Option, cx: &mut ViewContext, - ) -> crate::LayoutId { + ) -> (LayoutId, Self::ElementState) { + let mut child_layout_ids = SmallVec::new(); let mut interactivity = mem::take(&mut self.interactivity); - let layout_id = - interactivity.layout(&mut element_state.interactive_state, cx, |style, cx| { + let (layout_id, interactive_state) = interactivity.layout( + element_state.map(|s| s.interactive_state), + cx, + |style, cx| { cx.with_text_style(style.text_style().cloned(), |cx| { - element_state.child_layout_ids = self + child_layout_ids = self .children .iter_mut() .map(|child| child.layout(view_state, cx)) .collect::>(); - cx.request_layout(&style, element_state.child_layout_ids.iter().copied()) + cx.request_layout(&style, child_layout_ids.iter().copied()) }) - }); + }, + ); self.interactivity = interactivity; - layout_id + ( + layout_id, + DivState { + interactive_state, + child_layout_ids, + }, + ) } fn paint( @@ -766,11 +756,12 @@ impl Interactivity where V: 'static, { - pub fn initialize( + pub fn layout( &mut self, element_state: Option, cx: &mut ViewContext, - ) -> InteractiveElementState { + f: impl FnOnce(Style, &mut ViewContext) -> LayoutId, + ) -> (LayoutId, InteractiveElementState) { let mut element_state = element_state.unwrap_or_default(); // Ensure we store a focus handle in our element state if we're focusable. @@ -785,17 +776,9 @@ where }); } - element_state - } - - pub fn layout( - &mut self, - element_state: &mut InteractiveElementState, - cx: &mut ViewContext, - f: impl FnOnce(Style, &mut ViewContext) -> LayoutId, - ) -> LayoutId { - let style = self.compute_style(None, element_state, cx); - f(style, cx) + let style = self.compute_style(None, &mut element_state, cx); + let layout_id = f(style, cx); + (layout_id, element_state) } pub fn paint( @@ -1327,21 +1310,12 @@ where self.element.element_id() } - fn initialize( - &mut self, - view_state: &mut V, - element_state: Option, - cx: &mut ViewContext, - ) -> Self::ElementState { - self.element.initialize(view_state, element_state, cx) - } - fn layout( &mut self, view_state: &mut V, - element_state: &mut Self::ElementState, + element_state: Option, cx: &mut ViewContext, - ) -> LayoutId { + ) -> (LayoutId, Self::ElementState) { self.element.layout(view_state, element_state, cx) } @@ -1422,21 +1396,12 @@ where self.element.element_id() } - fn initialize( - &mut self, - view_state: &mut V, - element_state: Option, - cx: &mut ViewContext, - ) -> Self::ElementState { - self.element.initialize(view_state, element_state, cx) - } - fn layout( &mut self, view_state: &mut V, - element_state: &mut Self::ElementState, + element_state: Option, cx: &mut ViewContext, - ) -> LayoutId { + ) -> (LayoutId, Self::ElementState) { self.element.layout(view_state, element_state, cx) } diff --git a/crates/gpui2/src/elements/img.rs b/crates/gpui2/src/elements/img.rs index c5c5fb628e31989f6a575a9b26f11f4336d7857d..1080135fe16edcabdf6c2176e264bd551be5011d 100644 --- a/crates/gpui2/src/elements/img.rs +++ b/crates/gpui2/src/elements/img.rs @@ -48,21 +48,12 @@ impl Element for Img { self.interactivity.element_id.clone() } - fn initialize( - &mut self, - _view_state: &mut V, - element_state: Option, - cx: &mut ViewContext, - ) -> Self::ElementState { - self.interactivity.initialize(element_state, cx) - } - fn layout( &mut self, _view_state: &mut V, - element_state: &mut Self::ElementState, + element_state: Option, cx: &mut ViewContext, - ) -> LayoutId { + ) -> (LayoutId, Self::ElementState) { self.interactivity.layout(element_state, cx, |style, cx| { cx.request_layout(&style, None) }) diff --git a/crates/gpui2/src/elements/svg.rs b/crates/gpui2/src/elements/svg.rs index 4b441ad425ee1bc4fe9b860635d8214ace1c21c3..c1c7691fbf41371cca9cba173485523df2dd7fb3 100644 --- a/crates/gpui2/src/elements/svg.rs +++ b/crates/gpui2/src/elements/svg.rs @@ -37,21 +37,12 @@ impl Element for Svg { self.interactivity.element_id.clone() } - fn initialize( - &mut self, - _view_state: &mut V, - element_state: Option, - cx: &mut ViewContext, - ) -> Self::ElementState { - self.interactivity.initialize(element_state, cx) - } - fn layout( &mut self, _view_state: &mut V, - element_state: &mut Self::ElementState, + element_state: Option, cx: &mut ViewContext, - ) -> LayoutId { + ) -> (LayoutId, Self::ElementState) { self.interactivity.layout(element_state, cx, |style, cx| { cx.request_layout(&style, None) }) diff --git a/crates/gpui2/src/elements/text.rs b/crates/gpui2/src/elements/text.rs index 93d087833a563b37b557fc1c09c65ce67136e8ad..1081154e7dfd90a08955ad63487b6e045791b57f 100644 --- a/crates/gpui2/src/elements/text.rs +++ b/crates/gpui2/src/elements/text.rs @@ -76,21 +76,13 @@ impl Element for Text { 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 V, - element_state: &mut Self::ElementState, + element_state: Option, cx: &mut ViewContext, - ) -> LayoutId { + ) -> (LayoutId, Self::ElementState) { + let element_state = element_state.unwrap_or_default(); let text_system = cx.text_system().clone(); let text_style = cx.text_style(); let font_size = text_style.font_size.to_pixels(cx.rem_size()); @@ -148,7 +140,7 @@ impl Element for Text { } }); - layout_id + (layout_id, element_state) } fn paint( diff --git a/crates/gpui2/src/elements/uniform_list.rs b/crates/gpui2/src/elements/uniform_list.rs index 340a2cbf87c79c93f54b8610cd44b26da9e41e4d..97361396199f69c1875800e4bb2f6a201b502ee4 100644 --- a/crates/gpui2/src/elements/uniform_list.rs +++ b/crates/gpui2/src/elements/uniform_list.rs @@ -131,9 +131,9 @@ impl Element for UniformList { fn layout( &mut self, _view_state: &mut V, - element_state: &mut Self::ElementState, + element_state: Option, cx: &mut ViewContext, - ) -> LayoutId { + ) -> (LayoutId, Self::ElementState) { let max_items = self.item_count; let item_size = element_state.item_size; let rem_size = cx.rem_size(); diff --git a/crates/gpui2/src/view.rs b/crates/gpui2/src/view.rs index 3edaa900b0435233f669ff553e01c1cdb9cb1adc..1ce1c4d34916b41202e8ff407c3f6993b25b67c7 100644 --- a/crates/gpui2/src/view.rs +++ b/crates/gpui2/src/view.rs @@ -1,7 +1,7 @@ use crate::{ private::Sealed, AnyBox, AnyElement, AnyModel, AnyWeakModel, AppContext, AvailableSpace, - Bounds, Component, Element, ElementId, Entity, EntityId, Flatten, LayoutId, Model, Pixels, - Size, ViewContext, VisualContext, WeakModel, WindowContext, + BorrowWindow, Bounds, Component, Element, ElementId, Entity, EntityId, Flatten, LayoutId, + Model, Pixels, Point, Size, ViewContext, VisualContext, WeakModel, WindowContext, }; use anyhow::{Context, Result}; use std::{ @@ -155,8 +155,7 @@ impl Eq for WeakView {} #[derive(Clone, Debug)] pub struct AnyView { model: AnyModel, - initialize: fn(&AnyView, &mut WindowContext) -> AnyBox, - layout: fn(&AnyView, &mut AnyBox, &mut WindowContext) -> LayoutId, + layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, Box), paint: fn(&AnyView, &mut AnyBox, &mut WindowContext), } @@ -164,7 +163,6 @@ impl AnyView { pub fn downgrade(&self) -> AnyWeakView { AnyWeakView { model: self.model.downgrade(), - initialize: self.initialize, layout: self.layout, paint: self.paint, } @@ -175,7 +173,6 @@ impl AnyView { Ok(model) => Ok(View { model }), Err(model) => Err(Self { model, - initialize: self.initialize, layout: self.layout, paint: self.paint, }), @@ -186,13 +183,19 @@ impl AnyView { self.model.entity_type } - pub(crate) fn draw(&self, available_space: Size, cx: &mut WindowContext) { - let mut rendered_element = (self.initialize)(self, cx); - let layout_id = (self.layout)(self, &mut rendered_element, cx); - cx.window - .layout_engine - .compute_layout(layout_id, available_space); - (self.paint)(self, &mut rendered_element, cx); + pub(crate) fn draw( + &self, + origin: Point, + available_space: Size, + cx: &mut WindowContext, + ) { + cx.with_absolute_element_offset(origin, |cx| { + let (layout_id, mut rendered_element) = (self.layout)(self, cx); + cx.window + .layout_engine + .compute_layout(layout_id, available_space); + (self.paint)(self, &mut rendered_element, cx); + }) } } @@ -206,7 +209,6 @@ impl From> for AnyView { fn from(value: View) -> Self { AnyView { model: value.model.into_any(), - initialize: any_view::initialize::, layout: any_view::layout::, paint: any_view::paint::, } @@ -220,21 +222,12 @@ impl Element for AnyView { Some(self.model.entity_id.into()) } - fn initialize( - &mut self, - _view_state: &mut ParentViewState, - _element_state: Option, - cx: &mut ViewContext, - ) -> Self::ElementState { - (self.initialize)(self, cx) - } - fn layout( &mut self, _view_state: &mut ParentViewState, - rendered_element: &mut Self::ElementState, + rendered_element: Option, cx: &mut ViewContext, - ) -> LayoutId { + ) -> (LayoutId, Self::ElementState) { (self.layout)(self, rendered_element, cx) } @@ -251,8 +244,7 @@ impl Element for AnyView { pub struct AnyWeakView { model: AnyWeakModel, - initialize: fn(&AnyView, &mut WindowContext) -> AnyBox, - layout: fn(&AnyView, &mut AnyBox, &mut WindowContext) -> LayoutId, + layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, Box), paint: fn(&AnyView, &mut AnyBox, &mut WindowContext), } @@ -261,7 +253,6 @@ impl AnyWeakView { let model = self.model.upgrade()?; Some(AnyView { model, - initialize: self.initialize, layout: self.layout, paint: self.paint, }) @@ -272,7 +263,6 @@ impl From> for AnyWeakView { fn from(view: WeakView) -> Self { Self { model: view.model.into(), - initialize: any_view::initialize::, layout: any_view::layout::, paint: any_view::paint::, } @@ -319,28 +309,19 @@ where Some(self.view.entity_id().into()) } - fn initialize( + fn layout( &mut self, _: &mut ParentViewState, _: Option, cx: &mut ViewContext, - ) -> Self::ElementState { + ) -> (LayoutId, Self::ElementState) { self.view.update(cx, |view, cx| { let mut element = self.component.take().unwrap().render(); - element.initialize(view, cx); - element + let layout_id = element.layout(view, cx); + (layout_id, element) }) } - fn layout( - &mut self, - _: &mut ParentViewState, - element: &mut Self::ElementState, - cx: &mut ViewContext, - ) -> LayoutId { - self.view.update(cx, |view, cx| element.layout(view, cx)) - } - fn paint( &mut self, _: Bounds, @@ -356,27 +337,17 @@ mod any_view { use crate::{AnyElement, AnyView, BorrowWindow, LayoutId, Render, WindowContext}; use std::any::Any; - pub(crate) fn initialize(view: &AnyView, cx: &mut WindowContext) -> Box { - cx.with_element_id(Some(view.model.entity_id), |cx| { - let view = view.clone().downcast::().unwrap(); - let element = view.update(cx, |view, cx| { - let mut element = AnyElement::new(view.render(cx)); - element.initialize(view, cx); - element - }); - Box::new(element) - }) - } - pub(crate) fn layout( view: &AnyView, - element: &mut Box, cx: &mut WindowContext, - ) -> LayoutId { + ) -> (LayoutId, Box) { cx.with_element_id(Some(view.model.entity_id), |cx| { let view = view.clone().downcast::().unwrap(); - let element = element.downcast_mut::>().unwrap(); - view.update(cx, |view, cx| element.layout(view, cx)) + view.update(cx, |view, cx| { + let mut element = AnyElement::new(view.render(cx)); + let layout_id = element.layout(view, cx); + (layout_id, Box::new(element) as Box) + }) }) } diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index 0563c107c0b150fc8394acab0a4e3c2bbba4b2af..9c1951287124113c4b3934b314a5838dc2df2613 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -1633,8 +1633,8 @@ pub trait BorrowWindow: BorrowMut + BorrowMut { } } - /// Update the global element offset based on the given offset. This is used to implement - /// scrolling and position drag handles. + /// Update the global element offset relative to the current offset. This is used to implement + /// scrolling. fn with_element_offset( &mut self, offset: Point, @@ -1644,7 +1644,17 @@ pub trait BorrowWindow: BorrowMut + BorrowMut { return f(self); }; - let offset = self.element_offset() + offset; + let abs_offset = self.element_offset() + offset; + self.with_absolute_element_offset(abs_offset, f) + } + + /// Update the global element offset based on the given offset. This is used to implement + /// drag handles and other manual painting of elements. + fn with_absolute_element_offset( + &mut self, + offset: Point, + f: impl FnOnce(&mut Self) -> R, + ) -> R { self.window_mut() .current_frame .element_offset_stack