diff --git a/crates/assistant/src/assistant_panel.rs b/crates/assistant/src/assistant_panel.rs index 4e861c9d3e..86245621f8 100644 --- a/crates/assistant/src/assistant_panel.rs +++ b/crates/assistant/src/assistant_panel.rs @@ -1279,7 +1279,7 @@ impl Render for AssistantPanel { let conversation_count = self.saved_conversations.len(); canvas(move |bounds, cx| { uniform_list( - view, + view.clone(), "saved_conversations", conversation_count, |this, range, cx| { @@ -1288,7 +1288,7 @@ impl Render for AssistantPanel { .collect() }, ) - .track_scroll(scroll_handle) + .track_scroll(scroll_handle.clone()) .into_any_element() .draw( bounds.origin, diff --git a/crates/extensions_ui/src/extensions_ui.rs b/crates/extensions_ui/src/extensions_ui.rs index c062fbb01f..1ee58f46a4 100644 --- a/crates/extensions_ui/src/extensions_ui.rs +++ b/crates/extensions_ui/src/extensions_ui.rs @@ -414,13 +414,13 @@ impl Render for ExtensionsPage { let item_count = self.extensions_entries.len(); move |bounds, cx| { uniform_list::<_, Div, _>( - view, + view.clone(), "entries", item_count, Self::render_extensions, ) .size_full() - .track_scroll(scroll_handle) + .track_scroll(scroll_handle.clone()) .into_any_element() .draw( bounds.origin, diff --git a/crates/gpui/src/element.rs b/crates/gpui/src/element.rs index 4dbc7be652..d1d7a76924 100644 --- a/crates/gpui/src/element.rs +++ b/crates/gpui/src/element.rs @@ -103,13 +103,13 @@ pub trait IntoElement: Sized { { let element = self.into_element(); let element_id = element.element_id(); - let element = DrawableElement { + let mut element = DrawableElement { element: Some(element), phase: ElementDrawPhase::Start, }; let frame_state = - DrawableElement::draw(element, origin, available_space.map(Into::into), cx); + DrawableElement::draw(&mut element, origin, available_space.map(Into::into), cx); if let Some(mut frame_state) = frame_state { f(&mut frame_state, cx) @@ -301,8 +301,8 @@ impl DrawableElement { layout_id } - fn paint(mut self, cx: &mut ElementContext) -> Option { - match self.phase { + fn paint(&mut self, cx: &mut ElementContext) -> Option<&mut E::State> { + match &mut self.phase { ElementDrawPhase::LayoutRequested { layout_id, frame_state, @@ -312,13 +312,13 @@ impl DrawableElement { frame_state, .. } => { - let bounds = cx.layout_bounds(layout_id); + let bounds = cx.layout_bounds(*layout_id); - if let Some(mut frame_state) = frame_state { + if let Some(frame_state) = frame_state { self.element - .take() + .as_mut() .unwrap() - .paint(bounds, &mut frame_state, cx); + .paint(bounds, frame_state, cx); Some(frame_state) } else { let element_id = self @@ -330,7 +330,7 @@ impl DrawableElement { cx.with_element_state(element_id, |element_state, cx| { let mut element_state = element_state.unwrap(); self.element - .take() + .as_mut() .unwrap() .paint(bounds, &mut element_state, cx); ((), element_state) @@ -384,11 +384,11 @@ impl DrawableElement { } fn draw( - mut self, + &mut self, origin: Point, available_space: Size, cx: &mut ElementContext, - ) -> Option { + ) -> Option<&mut E::State> { self.measure(available_space, cx); cx.with_absolute_element_offset(origin, |cx| self.paint(cx)) } @@ -408,7 +408,7 @@ where } fn paint(&mut self, cx: &mut ElementContext) { - DrawableElement::paint(self.take().unwrap(), cx); + DrawableElement::paint(self.as_mut().unwrap(), cx); } fn measure( @@ -425,7 +425,7 @@ where available_space: Size, cx: &mut ElementContext, ) { - DrawableElement::draw(self.take().unwrap(), origin, available_space, cx); + DrawableElement::draw(self.as_mut().unwrap(), origin, available_space, cx); } } diff --git a/crates/gpui/src/elements/canvas.rs b/crates/gpui/src/elements/canvas.rs index 8011f51e0c..a661bdaa79 100644 --- a/crates/gpui/src/elements/canvas.rs +++ b/crates/gpui/src/elements/canvas.rs @@ -4,7 +4,7 @@ use crate::{Bounds, Element, ElementContext, IntoElement, Pixels, Style, StyleRe /// Construct a canvas element with the given paint callback. /// Useful for adding short term custom drawing to a view. -pub fn canvas(callback: impl 'static + FnOnce(&Bounds, &mut ElementContext)) -> Canvas { +pub fn canvas(callback: impl 'static + FnMut(&Bounds, &mut ElementContext)) -> Canvas { Canvas { paint_callback: Some(Box::new(callback)), style: StyleRefinement::default(), @@ -14,7 +14,7 @@ pub fn canvas(callback: impl 'static + FnOnce(&Bounds, &mut ElementConte /// A canvas element, meant for accessing the low level paint API without defining a whole /// custom element pub struct Canvas { - paint_callback: Option, &mut ElementContext)>>, + paint_callback: Option, &mut ElementContext)>>, style: StyleRefinement, } @@ -46,7 +46,7 @@ impl Element for Canvas { fn paint(&mut self, bounds: Bounds, style: &mut Style, cx: &mut ElementContext) { style.paint(bounds, cx, |cx| { - (self.paint_callback.take().unwrap())(&bounds, cx) + (self.paint_callback.as_mut().unwrap())(&bounds, cx) }); } } diff --git a/crates/gpui/src/view.rs b/crates/gpui/src/view.rs index d433e72e6a..621524a9c7 100644 --- a/crates/gpui/src/view.rs +++ b/crates/gpui/src/view.rs @@ -105,7 +105,7 @@ impl Element for View { } fn paint(&mut self, _: Bounds, element: &mut Self::State, cx: &mut ElementContext) { - cx.paint_view(self.entity_id(), |cx| element.take().unwrap().paint(cx)); + cx.paint_view(self.entity_id(), |cx| element.as_mut().unwrap().paint(cx)); } } @@ -247,22 +247,67 @@ impl AnyView { self.model.entity_id() } - pub(crate) fn draw( + pub(crate) fn layout( &self, origin: Point, available_space: Size, cx: &mut ElementContext, - ) { - cx.paint_view(self.entity_id(), |cx| { + ) -> AnyElement { + cx.in_layout(true); + let element = cx.paint_view(self.entity_id(), |cx| { cx.with_absolute_element_offset(origin, |cx| { let (layout_id, mut rendered_element) = (self.request_layout)(self, cx); cx.compute_layout(layout_id, available_space); - rendered_element.paint(cx) + rendered_element + }) + }); + cx.in_layout(false); + element + } + + pub(crate) fn paint( + &self, + origin: Point, + rendered_element: &mut AnyElement, + cx: &mut ElementContext, + ) { + cx.paint_view(self.entity_id(), |cx| { + cx.with_absolute_element_offset(origin, |cx| { + rendered_element.paint(cx); }); - }) + }); } } +// pub(crate) fn draw( +// &self, +// origin: Point, +// available_space: Size, +// cx: &mut ElementContext, +// ) { +// cx.paint_view(self.entity_id(), |cx| { +// cx.with_absolute_element_offset(origin, |cx| { +// cx.in_layout(true); +// let (layout_id, mut rendered_element) = (self.request_layout)(self, cx); +// assert_eq!( +// *cx.window.next_frame.next_stacking_order_ids.last().unwrap(), +// 0 +// ); +// // let prev_last_stacking_order_id = cx.window.next_frame.next_stacking_order_ids.last(); +// cx.compute_layout(layout_id, available_space); +// cx.in_layout(false); +// // assert_eq!(cx.window.next_frame.z_index_stack.len(), 0); +// *cx.window +// .next_frame +// .next_stacking_order_ids +// .last_mut() +// .unwrap() = 0; +// rendered_element.paint(cx) +// }); +// }) +// } +// } + impl From> for AnyView { fn from(value: View) -> Self { AnyView { @@ -307,7 +352,7 @@ impl Element for AnyView { fn paint(&mut self, bounds: Bounds, state: &mut Self::State, cx: &mut ElementContext) { cx.paint_view(self.entity_id(), |cx| { if !self.cache { - state.element.take().unwrap().paint(cx); + state.element.as_mut().unwrap().paint(cx); return; } diff --git a/crates/gpui/src/window.rs b/crates/gpui/src/window.rs index 0d1eb324e2..715f266162 100644 --- a/crates/gpui/src/window.rs +++ b/crates/gpui/src/window.rs @@ -960,55 +960,51 @@ impl<'a> WindowContext<'a> { requested_handler.handler = input_handler; } - // TODO: Restructure this let root_view = self.window.root_view.take().unwrap(); - self.with_element_context(true, |cx| { + let mut root_element = self.with_element_context(true, |cx| { cx.with_z_index(0, |cx| { cx.with_key_dispatch(Some(KeyContext::default()), None, |_, cx| { - // // We need to use cx.cx here so we can utilize borrow splitting - // for (action_type, action_listeners) in &cx.cx.app.global_action_listeners { - // for action_listener in action_listeners.iter().cloned() { - // cx.cx.window.next_frame.dispatch_tree.on_action( - // *action_type, - // Rc::new( - // move |action: &dyn Any, phase, cx: &mut WindowContext<'_>| { - // action_listener(action, phase, cx) - // }, - // ), - // ) - // } - // } - let available_space = cx.window.viewport_size.map(Into::into); - root_view.draw(Point::default(), available_space, cx); + let mut root_element = root_view.layout(Point::default(), available_space, cx); + root_view.paint(Point::default(), &mut root_element, cx); + root_element }) }) }); - if let Some(active_drag) = self.app.active_drag.take() { - self.with_element_context(true, |cx| { - cx.with_z_index(ACTIVE_DRAG_Z_INDEX, |cx| { + let mut drag_element = None; + let mut tooltip_element = None; + + self.with_element_context(true, |cx| { + cx.with_z_index(1, |cx| { + if let Some(active_drag) = cx.app.active_drag.take() { let offset = cx.mouse_position() - active_drag.cursor_offset; let available_space = size(AvailableSpace::MinContent, AvailableSpace::MinContent); - active_drag.view.draw(offset, available_space, cx); - }) - }); - self.active_drag = Some(active_drag); - } else if let Some(tooltip_request) = self.window.next_frame.tooltip_request.take() { - self.with_element_context(true, |cx| { - cx.with_z_index(1, |cx| { + let mut element = active_drag.view.layout(offset, available_space, cx); + active_drag.view.paint(offset, &mut element, cx); + drag_element = Some(element); + + cx.active_drag = Some(active_drag); + } else if let Some(tooltip_request) = cx.window.next_frame.tooltip_request.take() { let available_space = size(AvailableSpace::MinContent, AvailableSpace::MinContent); - tooltip_request.tooltip.view.draw( + let mut element = tooltip_request.tooltip.view.layout( tooltip_request.tooltip.cursor_offset, available_space, cx, ); - }) - }); - self.window.next_frame.tooltip_request = Some(tooltip_request); - } + tooltip_request.tooltip.view.paint( + tooltip_request.tooltip.cursor_offset, + &mut element, + cx, + ); + tooltip_element = Some(element); + + cx.window.next_frame.tooltip_request = Some(tooltip_request); + } + }) + }); assert_eq!(self.window.next_frame.z_index_stack.len(), 0); self.window.next_frame.next_stacking_order_ids = vec![0]; @@ -1030,36 +1026,33 @@ impl<'a> WindowContext<'a> { } } - let available_space = cx.window.viewport_size.map(Into::into); - root_view.draw(Point::default(), available_space, cx); + // let available_space = cx.window.viewport_size.map(Into::into); + // let mut root_element = root_view.layout(Point::default(), available_space, cx); + root_view.paint(Point::default(), &mut root_element, cx); }) }) }); - if let Some(active_drag) = self.app.active_drag.take() { - self.with_element_context(false, |cx| { - cx.with_z_index(ACTIVE_DRAG_Z_INDEX, |cx| { - let offset = cx.mouse_position() - active_drag.cursor_offset; - let available_space = - size(AvailableSpace::MinContent, AvailableSpace::MinContent); - active_drag.view.draw(offset, available_space, cx); - }) - }); - self.active_drag = Some(active_drag); - } else if let Some(tooltip_request) = self.window.next_frame.tooltip_request.take() { - self.with_element_context(false, |cx| { - cx.with_z_index(1, |cx| { - let available_space = - size(AvailableSpace::MinContent, AvailableSpace::MinContent); - tooltip_request.tooltip.view.draw( - tooltip_request.tooltip.cursor_offset, - available_space, - cx, - ); - }) - }); - self.window.next_frame.tooltip_request = Some(tooltip_request); - } + self.with_element_context(false, |cx| { + cx.with_z_index(1, |cx| { + if let Some(mut drag_element) = drag_element { + if let Some(active_drag) = cx.app.active_drag.take() { + let offset = cx.mouse_position() - active_drag.cursor_offset; + active_drag.view.paint(offset, &mut drag_element, cx); + } + } + + if let Some(mut tooltip_element) = tooltip_element { + if let Some(tooltip_request) = cx.window.next_frame.tooltip_request.take() { + tooltip_request.tooltip.view.paint( + tooltip_request.tooltip.cursor_offset, + &mut tooltip_element, + cx, + ); + } + } + }) + }); self.window.dirty_views.clear(); diff --git a/crates/gpui/src/window/element_cx.rs b/crates/gpui/src/window/element_cx.rs index 62bf1904b4..4eb9cd9811 100644 --- a/crates/gpui/src/window/element_cx.rs +++ b/crates/gpui/src/window/element_cx.rs @@ -168,6 +168,7 @@ pub struct ElementContext<'a> { #[deref_mut] pub(crate) cx: WindowContext<'a>, pub(crate) pre_paint_pass: bool, + pub(crate) in_layout: bool, } impl<'a> WindowContext<'a> { @@ -182,6 +183,7 @@ impl<'a> WindowContext<'a> { f(&mut ElementContext { cx: WindowContext::new(self.app, self.window), pre_paint_pass, + in_layout: false, }) } } @@ -318,6 +320,10 @@ impl<'a> VisualContext for ElementContext<'a> { } impl<'a> ElementContext<'a> { + pub(crate) fn in_layout(&mut self, in_layout: bool) { + self.in_layout = in_layout; + } + pub(crate) fn reuse_view(&mut self, next_stacking_order_id: u16) { let view_id = self.parent_view_id(); let grafted_view_ids = self @@ -483,6 +489,10 @@ impl<'a> ElementContext<'a> { /// Called during painting to invoke the given closure in a new stacking context. The given /// z-index is interpreted relative to the previous call to `stack`. pub fn with_z_index(&mut self, z_index: u16, f: impl FnOnce(&mut Self) -> R) -> R { + // if self.in_layout { + // panic!("Don't push z-index in layout"); + // } + let new_stacking_order_id = post_inc( self.window_mut() .next_frame @@ -1142,6 +1152,10 @@ impl<'a> ElementContext<'a> { return; } + // if self.in_layout { + // panic!("Don't add an opaque layer during layout"); + // } + let stacking_order = self.window.next_frame.z_index_stack.clone(); let view_id = self.parent_view_id(); let depth_map = &mut self.window.next_frame.depth_map; diff --git a/crates/language_tools/src/syntax_tree_view.rs b/crates/language_tools/src/syntax_tree_view.rs index 082e77fc36..9846d398c1 100644 --- a/crates/language_tools/src/syntax_tree_view.rs +++ b/crates/language_tools/src/syntax_tree_view.rs @@ -357,10 +357,12 @@ impl Render for SyntaxTreeView { .size_full() .track_scroll(self.list_scroll_handle.clone()) .text_bg(cx.theme().colors().background); + + let mut list_element = list.into_any_element(); rendered = rendered.child( canvas(move |bounds, cx| { - list.into_any_element().draw( + list_element.draw( bounds.origin, bounds.size.map(AvailableSpace::Definite), cx,