This commit is contained in:
Antonio Scandurra 2023-11-15 20:41:09 +01:00
parent 759ce7440c
commit 33a808a49b
8 changed files with 96 additions and 232 deletions

View file

@ -10,21 +10,12 @@ pub trait Element<V: 'static> {
fn element_id(&self) -> Option<ElementId>; fn element_id(&self) -> Option<ElementId>;
/// 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<Self::ElementState>,
cx: &mut ViewContext<V>,
) -> Self::ElementState;
fn layout( fn layout(
&mut self, &mut self,
view_state: &mut V, view_state: &mut V,
element_state: &mut Self::ElementState, previous_element_state: Option<Self::ElementState>,
cx: &mut ViewContext<V>, cx: &mut ViewContext<V>,
) -> LayoutId; ) -> (LayoutId, Self::ElementState);
fn paint( fn paint(
&mut self, &mut self,
@ -96,7 +87,6 @@ pub trait ParentComponent<V: 'static> {
} }
trait ElementObject<V> { trait ElementObject<V> {
fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId; fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId;
fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>); fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
fn measure( fn measure(
@ -123,9 +113,6 @@ struct RenderedElement<V: 'static, E: Element<V>> {
enum ElementRenderPhase<V> { enum ElementRenderPhase<V> {
#[default] #[default]
Start, Start,
Initialized {
frame_state: Option<V>,
},
LayoutRequested { LayoutRequested {
layout_id: LayoutId, layout_id: LayoutId,
frame_state: Option<V>, frame_state: Option<V>,
@ -157,42 +144,19 @@ where
E: Element<V>, E: Element<V>,
E::ElementState: 'static, E::ElementState: 'static,
{ {
fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
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<V>) -> LayoutId { fn layout(&mut self, state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
let layout_id; let (layout_id, frame_state) = match mem::take(&mut self.phase) {
let mut frame_state; ElementRenderPhase::Start => {
match mem::take(&mut self.phase) {
ElementRenderPhase::Initialized {
frame_state: initial_frame_state,
} => {
frame_state = initial_frame_state;
if let Some(id) = self.element.element_id() { if let Some(id) = self.element.element_id() {
layout_id = cx.with_element_state(id, |element_state, cx| { let layout_id = cx.with_element_state(id, |element_state, cx| {
let mut element_state = element_state.unwrap(); self.element.layout(state, element_state, cx)
let layout_id = self.element.layout(state, &mut element_state, cx);
(layout_id, element_state)
}); });
(layout_id, None)
} else { } else {
layout_id = self let (layout_id, frame_state) = self.element.layout(state, None, cx);
.element (layout_id, Some(frame_state))
.layout(state, frame_state.as_mut().unwrap(), cx);
} }
} }
ElementRenderPhase::Start => panic!("must call initialize before layout"),
ElementRenderPhase::LayoutRequested { .. } ElementRenderPhase::LayoutRequested { .. }
| ElementRenderPhase::LayoutComputed { .. } | ElementRenderPhase::LayoutComputed { .. }
| ElementRenderPhase::Painted { .. } => { | ElementRenderPhase::Painted { .. } => {
@ -244,10 +208,6 @@ where
cx: &mut ViewContext<V>, cx: &mut ViewContext<V>,
) -> Size<Pixels> { ) -> Size<Pixels> {
if matches!(&self.phase, ElementRenderPhase::Start) { if matches!(&self.phase, ElementRenderPhase::Start) {
self.initialize(view_state, cx);
}
if matches!(&self.phase, ElementRenderPhase::Initialized { .. }) {
self.layout(view_state, cx); self.layout(view_state, cx);
} }
@ -290,10 +250,7 @@ where
cx: &mut ViewContext<V>, cx: &mut ViewContext<V>,
) { ) {
self.measure(available_space, view_state, cx); self.measure(available_space, view_state, cx);
// Ignore the element offset when drawing this element, as the origin is already specified cx.with_absolute_element_offset(origin, |cx| self.paint(view_state, cx))
// in absolute terms.
origin -= cx.element_offset();
cx.with_element_offset(origin, |cx| self.paint(view_state, cx))
} }
} }
@ -309,10 +266,6 @@ impl<V> AnyElement<V> {
AnyElement(Box::new(RenderedElement::new(element))) AnyElement(Box::new(RenderedElement::new(element)))
} }
pub fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
self.0.initialize(view_state, cx);
}
pub fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId { pub fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
self.0.layout(view_state, cx) self.0.layout(view_state, cx)
} }
@ -393,25 +346,16 @@ where
None None
} }
fn initialize(
&mut self,
view_state: &mut V,
_rendered_element: Option<Self::ElementState>,
cx: &mut ViewContext<V>,
) -> 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( fn layout(
&mut self, &mut self,
view_state: &mut V, view_state: &mut V,
rendered_element: &mut Self::ElementState, _: Option<Self::ElementState>,
cx: &mut ViewContext<V>, cx: &mut ViewContext<V>,
) -> LayoutId { ) -> (LayoutId, Self::ElementState) {
rendered_element.layout(view_state, cx) let render = self.take().unwrap();
let mut rendered_element = (render)(view_state, cx).render();
let layout_id = rendered_element.layout(view_state, cx);
(layout_id, rendered_element)
} }
fn paint( fn paint(

View file

@ -617,46 +617,36 @@ impl<V: 'static> Element<V> for Div<V> {
self.interactivity.element_id.clone() self.interactivity.element_id.clone()
} }
fn initialize( fn layout(
&mut self, &mut self,
view_state: &mut V, view_state: &mut V,
element_state: Option<Self::ElementState>, element_state: Option<Self::ElementState>,
cx: &mut ViewContext<V>, cx: &mut ViewContext<V>,
) -> Self::ElementState { ) -> (LayoutId, Self::ElementState) {
let interactive_state = self let mut child_layout_ids = SmallVec::new();
.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,
cx: &mut ViewContext<V>,
) -> crate::LayoutId {
let mut interactivity = mem::take(&mut self.interactivity); let mut interactivity = mem::take(&mut self.interactivity);
let layout_id = let (layout_id, interactive_state) = interactivity.layout(
interactivity.layout(&mut element_state.interactive_state, cx, |style, cx| { element_state.map(|s| s.interactive_state),
cx,
|style, cx| {
cx.with_text_style(style.text_style().cloned(), |cx| { cx.with_text_style(style.text_style().cloned(), |cx| {
element_state.child_layout_ids = self child_layout_ids = self
.children .children
.iter_mut() .iter_mut()
.map(|child| child.layout(view_state, cx)) .map(|child| child.layout(view_state, cx))
.collect::<SmallVec<_>>(); .collect::<SmallVec<_>>();
cx.request_layout(&style, element_state.child_layout_ids.iter().copied()) cx.request_layout(&style, child_layout_ids.iter().copied())
}) })
}); },
);
self.interactivity = interactivity; self.interactivity = interactivity;
layout_id (
layout_id,
DivState {
interactive_state,
child_layout_ids,
},
)
} }
fn paint( fn paint(
@ -766,11 +756,12 @@ impl<V> Interactivity<V>
where where
V: 'static, V: 'static,
{ {
pub fn initialize( pub fn layout(
&mut self, &mut self,
element_state: Option<InteractiveElementState>, element_state: Option<InteractiveElementState>,
cx: &mut ViewContext<V>, cx: &mut ViewContext<V>,
) -> InteractiveElementState { f: impl FnOnce(Style, &mut ViewContext<V>) -> LayoutId,
) -> (LayoutId, InteractiveElementState) {
let mut element_state = element_state.unwrap_or_default(); let mut element_state = element_state.unwrap_or_default();
// Ensure we store a focus handle in our element state if we're focusable. // Ensure we store a focus handle in our element state if we're focusable.
@ -785,17 +776,9 @@ where
}); });
} }
element_state let style = self.compute_style(None, &mut element_state, cx);
} let layout_id = f(style, cx);
(layout_id, element_state)
pub fn layout(
&mut self,
element_state: &mut InteractiveElementState,
cx: &mut ViewContext<V>,
f: impl FnOnce(Style, &mut ViewContext<V>) -> LayoutId,
) -> LayoutId {
let style = self.compute_style(None, element_state, cx);
f(style, cx)
} }
pub fn paint( pub fn paint(
@ -1327,21 +1310,12 @@ where
self.element.element_id() self.element.element_id()
} }
fn initialize( fn layout(
&mut self, &mut self,
view_state: &mut V, view_state: &mut V,
element_state: Option<Self::ElementState>, element_state: Option<Self::ElementState>,
cx: &mut ViewContext<V>, cx: &mut ViewContext<V>,
) -> Self::ElementState { ) -> (LayoutId, Self::ElementState) {
self.element.initialize(view_state, element_state, cx)
}
fn layout(
&mut self,
view_state: &mut V,
element_state: &mut Self::ElementState,
cx: &mut ViewContext<V>,
) -> LayoutId {
self.element.layout(view_state, element_state, cx) self.element.layout(view_state, element_state, cx)
} }
@ -1422,21 +1396,12 @@ where
self.element.element_id() self.element.element_id()
} }
fn initialize( fn layout(
&mut self, &mut self,
view_state: &mut V, view_state: &mut V,
element_state: Option<Self::ElementState>, element_state: Option<Self::ElementState>,
cx: &mut ViewContext<V>, cx: &mut ViewContext<V>,
) -> Self::ElementState { ) -> (LayoutId, Self::ElementState) {
self.element.initialize(view_state, element_state, cx)
}
fn layout(
&mut self,
view_state: &mut V,
element_state: &mut Self::ElementState,
cx: &mut ViewContext<V>,
) -> LayoutId {
self.element.layout(view_state, element_state, cx) self.element.layout(view_state, element_state, cx)
} }

View file

@ -48,21 +48,12 @@ impl<V> Element<V> for Img<V> {
self.interactivity.element_id.clone() self.interactivity.element_id.clone()
} }
fn initialize( fn layout(
&mut self, &mut self,
_view_state: &mut V, _view_state: &mut V,
element_state: Option<Self::ElementState>, element_state: Option<Self::ElementState>,
cx: &mut ViewContext<V>, cx: &mut ViewContext<V>,
) -> Self::ElementState { ) -> (LayoutId, Self::ElementState) {
self.interactivity.initialize(element_state, cx)
}
fn layout(
&mut self,
_view_state: &mut V,
element_state: &mut Self::ElementState,
cx: &mut ViewContext<V>,
) -> LayoutId {
self.interactivity.layout(element_state, cx, |style, cx| { self.interactivity.layout(element_state, cx, |style, cx| {
cx.request_layout(&style, None) cx.request_layout(&style, None)
}) })

View file

@ -37,21 +37,12 @@ impl<V> Element<V> for Svg<V> {
self.interactivity.element_id.clone() self.interactivity.element_id.clone()
} }
fn initialize( fn layout(
&mut self, &mut self,
_view_state: &mut V, _view_state: &mut V,
element_state: Option<Self::ElementState>, element_state: Option<Self::ElementState>,
cx: &mut ViewContext<V>, cx: &mut ViewContext<V>,
) -> Self::ElementState { ) -> (LayoutId, Self::ElementState) {
self.interactivity.initialize(element_state, cx)
}
fn layout(
&mut self,
_view_state: &mut V,
element_state: &mut Self::ElementState,
cx: &mut ViewContext<V>,
) -> LayoutId {
self.interactivity.layout(element_state, cx, |style, cx| { self.interactivity.layout(element_state, cx, |style, cx| {
cx.request_layout(&style, None) cx.request_layout(&style, None)
}) })

View file

@ -76,21 +76,13 @@ impl<V: 'static> Element<V> for Text<V> {
None None
} }
fn initialize(
&mut self,
_view_state: &mut V,
element_state: Option<Self::ElementState>,
_cx: &mut ViewContext<V>,
) -> Self::ElementState {
element_state.unwrap_or_default()
}
fn layout( fn layout(
&mut self, &mut self,
_view: &mut V, _view: &mut V,
element_state: &mut Self::ElementState, element_state: Option<Self::ElementState>,
cx: &mut ViewContext<V>, cx: &mut ViewContext<V>,
) -> LayoutId { ) -> (LayoutId, Self::ElementState) {
let element_state = element_state.unwrap_or_default();
let text_system = cx.text_system().clone(); let text_system = cx.text_system().clone();
let text_style = cx.text_style(); let text_style = cx.text_style();
let font_size = text_style.font_size.to_pixels(cx.rem_size()); let font_size = text_style.font_size.to_pixels(cx.rem_size());
@ -148,7 +140,7 @@ impl<V: 'static> Element<V> for Text<V> {
} }
}); });
layout_id (layout_id, element_state)
} }
fn paint( fn paint(

View file

@ -131,9 +131,9 @@ impl<V: 'static> Element<V> for UniformList<V> {
fn layout( fn layout(
&mut self, &mut self,
_view_state: &mut V, _view_state: &mut V,
element_state: &mut Self::ElementState, element_state: Option<Self::ElementState>,
cx: &mut ViewContext<V>, cx: &mut ViewContext<V>,
) -> LayoutId { ) -> (LayoutId, Self::ElementState) {
let max_items = self.item_count; let max_items = self.item_count;
let item_size = element_state.item_size; let item_size = element_state.item_size;
let rem_size = cx.rem_size(); let rem_size = cx.rem_size();

View file

@ -1,7 +1,7 @@
use crate::{ use crate::{
private::Sealed, AnyBox, AnyElement, AnyModel, AnyWeakModel, AppContext, AvailableSpace, private::Sealed, AnyBox, AnyElement, AnyModel, AnyWeakModel, AppContext, AvailableSpace,
Bounds, Component, Element, ElementId, Entity, EntityId, Flatten, LayoutId, Model, Pixels, BorrowWindow, Bounds, Component, Element, ElementId, Entity, EntityId, Flatten, LayoutId,
Size, ViewContext, VisualContext, WeakModel, WindowContext, Model, Pixels, Point, Size, ViewContext, VisualContext, WeakModel, WindowContext,
}; };
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use std::{ use std::{
@ -155,8 +155,7 @@ impl<V> Eq for WeakView<V> {}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct AnyView { pub struct AnyView {
model: AnyModel, model: AnyModel,
initialize: fn(&AnyView, &mut WindowContext) -> AnyBox, layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, Box<dyn Any>),
layout: fn(&AnyView, &mut AnyBox, &mut WindowContext) -> LayoutId,
paint: fn(&AnyView, &mut AnyBox, &mut WindowContext), paint: fn(&AnyView, &mut AnyBox, &mut WindowContext),
} }
@ -164,7 +163,6 @@ impl AnyView {
pub fn downgrade(&self) -> AnyWeakView { pub fn downgrade(&self) -> AnyWeakView {
AnyWeakView { AnyWeakView {
model: self.model.downgrade(), model: self.model.downgrade(),
initialize: self.initialize,
layout: self.layout, layout: self.layout,
paint: self.paint, paint: self.paint,
} }
@ -175,7 +173,6 @@ impl AnyView {
Ok(model) => Ok(View { model }), Ok(model) => Ok(View { model }),
Err(model) => Err(Self { Err(model) => Err(Self {
model, model,
initialize: self.initialize,
layout: self.layout, layout: self.layout,
paint: self.paint, paint: self.paint,
}), }),
@ -186,13 +183,19 @@ impl AnyView {
self.model.entity_type self.model.entity_type
} }
pub(crate) fn draw(&self, available_space: Size<AvailableSpace>, cx: &mut WindowContext) { pub(crate) fn draw(
let mut rendered_element = (self.initialize)(self, cx); &self,
let layout_id = (self.layout)(self, &mut rendered_element, cx); origin: Point<Pixels>,
cx.window available_space: Size<AvailableSpace>,
.layout_engine cx: &mut WindowContext,
.compute_layout(layout_id, available_space); ) {
(self.paint)(self, &mut rendered_element, cx); 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<V: Render> From<View<V>> for AnyView {
fn from(value: View<V>) -> Self { fn from(value: View<V>) -> Self {
AnyView { AnyView {
model: value.model.into_any(), model: value.model.into_any(),
initialize: any_view::initialize::<V>,
layout: any_view::layout::<V>, layout: any_view::layout::<V>,
paint: any_view::paint::<V>, paint: any_view::paint::<V>,
} }
@ -220,21 +222,12 @@ impl<ParentViewState: 'static> Element<ParentViewState> for AnyView {
Some(self.model.entity_id.into()) Some(self.model.entity_id.into())
} }
fn initialize(
&mut self,
_view_state: &mut ParentViewState,
_element_state: Option<Self::ElementState>,
cx: &mut ViewContext<ParentViewState>,
) -> Self::ElementState {
(self.initialize)(self, cx)
}
fn layout( fn layout(
&mut self, &mut self,
_view_state: &mut ParentViewState, _view_state: &mut ParentViewState,
rendered_element: &mut Self::ElementState, rendered_element: Option<Self::ElementState>,
cx: &mut ViewContext<ParentViewState>, cx: &mut ViewContext<ParentViewState>,
) -> LayoutId { ) -> (LayoutId, Self::ElementState) {
(self.layout)(self, rendered_element, cx) (self.layout)(self, rendered_element, cx)
} }
@ -251,8 +244,7 @@ impl<ParentViewState: 'static> Element<ParentViewState> for AnyView {
pub struct AnyWeakView { pub struct AnyWeakView {
model: AnyWeakModel, model: AnyWeakModel,
initialize: fn(&AnyView, &mut WindowContext) -> AnyBox, layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, Box<dyn Any>),
layout: fn(&AnyView, &mut AnyBox, &mut WindowContext) -> LayoutId,
paint: fn(&AnyView, &mut AnyBox, &mut WindowContext), paint: fn(&AnyView, &mut AnyBox, &mut WindowContext),
} }
@ -261,7 +253,6 @@ impl AnyWeakView {
let model = self.model.upgrade()?; let model = self.model.upgrade()?;
Some(AnyView { Some(AnyView {
model, model,
initialize: self.initialize,
layout: self.layout, layout: self.layout,
paint: self.paint, paint: self.paint,
}) })
@ -272,7 +263,6 @@ impl<V: Render> From<WeakView<V>> for AnyWeakView {
fn from(view: WeakView<V>) -> Self { fn from(view: WeakView<V>) -> Self {
Self { Self {
model: view.model.into(), model: view.model.into(),
initialize: any_view::initialize::<V>,
layout: any_view::layout::<V>, layout: any_view::layout::<V>,
paint: any_view::paint::<V>, paint: any_view::paint::<V>,
} }
@ -319,28 +309,19 @@ where
Some(self.view.entity_id().into()) Some(self.view.entity_id().into())
} }
fn initialize( fn layout(
&mut self, &mut self,
_: &mut ParentViewState, _: &mut ParentViewState,
_: Option<Self::ElementState>, _: Option<Self::ElementState>,
cx: &mut ViewContext<ParentViewState>, cx: &mut ViewContext<ParentViewState>,
) -> Self::ElementState { ) -> (LayoutId, Self::ElementState) {
self.view.update(cx, |view, cx| { self.view.update(cx, |view, cx| {
let mut element = self.component.take().unwrap().render(); let mut element = self.component.take().unwrap().render();
element.initialize(view, cx); let layout_id = element.layout(view, cx);
element (layout_id, element)
}) })
} }
fn layout(
&mut self,
_: &mut ParentViewState,
element: &mut Self::ElementState,
cx: &mut ViewContext<ParentViewState>,
) -> LayoutId {
self.view.update(cx, |view, cx| element.layout(view, cx))
}
fn paint( fn paint(
&mut self, &mut self,
_: Bounds<Pixels>, _: Bounds<Pixels>,
@ -356,27 +337,17 @@ mod any_view {
use crate::{AnyElement, AnyView, BorrowWindow, LayoutId, Render, WindowContext}; use crate::{AnyElement, AnyView, BorrowWindow, LayoutId, Render, WindowContext};
use std::any::Any; use std::any::Any;
pub(crate) fn initialize<V: Render>(view: &AnyView, cx: &mut WindowContext) -> Box<dyn Any> {
cx.with_element_id(Some(view.model.entity_id), |cx| {
let view = view.clone().downcast::<V>().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<V: Render>( pub(crate) fn layout<V: Render>(
view: &AnyView, view: &AnyView,
element: &mut Box<dyn Any>,
cx: &mut WindowContext, cx: &mut WindowContext,
) -> LayoutId { ) -> (LayoutId, Box<dyn Any>) {
cx.with_element_id(Some(view.model.entity_id), |cx| { cx.with_element_id(Some(view.model.entity_id), |cx| {
let view = view.clone().downcast::<V>().unwrap(); let view = view.clone().downcast::<V>().unwrap();
let element = element.downcast_mut::<AnyElement<V>>().unwrap(); view.update(cx, |view, cx| {
view.update(cx, |view, cx| element.layout(view, cx)) let mut element = AnyElement::new(view.render(cx));
let layout_id = element.layout(view, cx);
(layout_id, Box::new(element) as Box<dyn Any>)
})
}) })
} }

View file

@ -1633,8 +1633,8 @@ pub trait BorrowWindow: BorrowMut<Window> + BorrowMut<AppContext> {
} }
} }
/// Update the global element offset based on the given offset. This is used to implement /// Update the global element offset relative to the current offset. This is used to implement
/// scrolling and position drag handles. /// scrolling.
fn with_element_offset<R>( fn with_element_offset<R>(
&mut self, &mut self,
offset: Point<Pixels>, offset: Point<Pixels>,
@ -1644,7 +1644,17 @@ pub trait BorrowWindow: BorrowMut<Window> + BorrowMut<AppContext> {
return f(self); 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<R>(
&mut self,
offset: Point<Pixels>,
f: impl FnOnce(&mut Self) -> R,
) -> R {
self.window_mut() self.window_mut()
.current_frame .current_frame
.element_offset_stack .element_offset_stack