diff --git a/crates/gpui/src/elements/deferred.rs b/crates/gpui/src/elements/deferred.rs new file mode 100644 index 0000000000000000000000000000000000000000..c1e3942ca86fc7d19da04b88dd91806129638a68 --- /dev/null +++ b/crates/gpui/src/elements/deferred.rs @@ -0,0 +1,63 @@ +use crate::{AnyElement, Bounds, Element, ElementContext, IntoElement, LayoutId, Pixels}; + +/// Builds a `Deferred` element, which delays the layout and paint of its child. +pub fn deferred(child: impl IntoElement) -> Deferred { + Deferred { + child: Some(child.into_any_element()), + priority: 0, + } +} + +/// An element which delays the painting of its child until after all of +/// its ancestors, while keeping its layout as part of the current element tree. +pub struct Deferred { + child: Option, + priority: usize, +} + +impl Element for Deferred { + type BeforeLayout = (); + type AfterLayout = (); + + fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, ()) { + let layout_id = self.child.as_mut().unwrap().before_layout(cx); + (layout_id, ()) + } + + fn after_layout( + &mut self, + _bounds: Bounds, + _before_layout: &mut Self::BeforeLayout, + cx: &mut ElementContext, + ) { + let child = self.child.take().unwrap(); + let element_offset = cx.element_offset(); + cx.defer_draw(child, element_offset, self.priority) + } + + fn paint( + &mut self, + _bounds: Bounds, + _before_layout: &mut Self::BeforeLayout, + _after_layout: &mut Self::AfterLayout, + _cx: &mut ElementContext, + ) { + } +} + +impl IntoElement for Deferred { + type Element = Self; + + fn into_element(self) -> Self::Element { + self + } +} + +impl Deferred { + /// Sets a priority for the element. A higher priority conceptually means painting the element + /// on top of deferred draws with a lower priority (i.e. closer to the viewer). + pub fn priority(mut self, priority: usize) -> Self { + self.priority = priority; + self + } +} diff --git a/crates/gpui/src/elements/mod.rs b/crates/gpui/src/elements/mod.rs index 30fe5d030604ebc768b94a88cf89995124a804b6..ee8f8964e16a191b5316d0a7e38a04f465518558 100644 --- a/crates/gpui/src/elements/mod.rs +++ b/crates/gpui/src/elements/mod.rs @@ -1,4 +1,5 @@ mod canvas; +mod deferred; mod div; mod img; mod list; @@ -8,6 +9,7 @@ mod text; mod uniform_list; pub use canvas::*; +pub use deferred::*; pub use div::*; pub use img::*; pub use list::*; diff --git a/crates/gpui/src/window/element_cx.rs b/crates/gpui/src/window/element_cx.rs index d04a903bdf49a6e22f72a7f43d94531f4dcd8588..8ed15f2f073105e0bab9e953d466288a2ee33a29 100644 --- a/crates/gpui/src/window/element_cx.rs +++ b/crates/gpui/src/window/element_cx.rs @@ -381,8 +381,7 @@ impl<'a> ElementContext<'a> { let mut sorted_deferred_draws = (0..self.window.next_frame.deferred_draws.len()).collect::>(); - sorted_deferred_draws - .sort_unstable_by_key(|ix| self.window.next_frame.deferred_draws[*ix].priority); + sorted_deferred_draws.sort_by_key(|ix| self.window.next_frame.deferred_draws[*ix].priority); self.layout_deferred_draws(&sorted_deferred_draws); self.window.mouse_hit_test = self.window.next_frame.hit_test(self.window.mouse_position); diff --git a/crates/workspace/src/dock.rs b/crates/workspace/src/dock.rs index 2947d26ddf235d91638c55603addf232e26ca2b1..ee79179dc801704a51af5e74c0b6808342088d26 100644 --- a/crates/workspace/src/dock.rs +++ b/crates/workspace/src/dock.rs @@ -2,10 +2,10 @@ use crate::persistence::model::DockData; use crate::DraggedDock; use crate::{status_bar::StatusItemView, Workspace}; use gpui::{ - div, px, Action, AnchorCorner, AnyView, AppContext, Axis, ClickEvent, Entity, EntityId, - EventEmitter, FocusHandle, FocusableView, IntoElement, KeyContext, MouseButton, ParentElement, - Render, SharedString, StyleRefinement, Styled, Subscription, View, ViewContext, VisualContext, - WeakView, WindowContext, + deferred, div, px, Action, AnchorCorner, AnyView, AppContext, Axis, ClickEvent, Entity, + EntityId, EventEmitter, FocusHandle, FocusableView, IntoElement, KeyContext, MouseButton, + ParentElement, Render, SharedString, StyleRefinement, Styled, Subscription, View, ViewContext, + VisualContext, WeakView, WindowContext, }; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -551,7 +551,7 @@ impl Render for Dock { let size = entry.panel.size(cx); let position = self.position; - let mut handle = div() + let handle = div() .id("resize-handle") .on_drag(DraggedDock(position), |dock, cx| { cx.stop_propagation(); @@ -564,36 +564,35 @@ impl Render for Dock { } })) .occlude(); - - match self.position() { - DockPosition::Left => { - handle = handle + let handle = match self.position() { + DockPosition::Left => deferred( + handle .absolute() - .right(px(0.)) + .right(-RESIZE_HANDLE_SIZE / 2.) .top(px(0.)) .h_full() .w(RESIZE_HANDLE_SIZE) - .cursor_col_resize(); - } - DockPosition::Bottom => { - handle = handle + .cursor_col_resize(), + ), + DockPosition::Bottom => deferred( + handle .absolute() - .top(px(0.)) + .top(-RESIZE_HANDLE_SIZE / 2.) .left(px(0.)) .w_full() .h(RESIZE_HANDLE_SIZE) - .cursor_row_resize(); - } - DockPosition::Right => { - handle = handle + .cursor_row_resize(), + ), + DockPosition::Right => deferred( + handle .absolute() .top(px(0.)) - .left(px(0.)) + .left(-RESIZE_HANDLE_SIZE / 2.) .h_full() .w(RESIZE_HANDLE_SIZE) - .cursor_col_resize(); - } - } + .cursor_col_resize(), + ), + }; div() .key_context(dispatch_context)