diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 97fb82a5d6b7cbce8ab7373c9dcb78e6a7b8d3e9..0942c47910856a8c09102e7bfe7f2cf49b3518c4 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -14,8 +14,8 @@ use gpui::{ geometry::{rect::RectF, vector::vec2f, PathBuilder}, json::{self, ToJson}, platform::{CursorStyle, MouseButton}, - AppContext, Entity, ImageData, ModelHandle, SceneBuilder, Subscription, View, ViewContext, - ViewHandle, WeakViewHandle, + AppContext, Entity, ImageData, LayoutContext, ModelHandle, SceneBuilder, Subscription, View, + ViewContext, ViewHandle, WeakViewHandle, }; use project::Project; use settings::Settings; @@ -865,7 +865,7 @@ impl Element for AvatarRibbon { &mut self, constraint: gpui::SizeConstraint, _: &mut CollabTitlebarItem, - _: &mut ViewContext, + _: &mut LayoutContext, ) -> (gpui::geometry::vector::Vector2F, Self::LayoutState) { (constraint.max, ()) } diff --git a/crates/collab_ui/src/face_pile.rs b/crates/collab_ui/src/face_pile.rs index 839ea7c7353fd2b6d65bae5d58e9013b1f4cfc3a..1bbceee9af1bec406bf9b1398fde94dd230ac73d 100644 --- a/crates/collab_ui/src/face_pile.rs +++ b/crates/collab_ui/src/face_pile.rs @@ -7,7 +7,7 @@ use gpui::{ }, json::ToJson, serde_json::{self, json}, - AnyElement, Axis, Element, SceneBuilder, ViewContext, + AnyElement, Axis, Element, LayoutContext, SceneBuilder, ViewContext, }; use crate::CollabTitlebarItem; @@ -34,7 +34,7 @@ impl Element for FacePile { &mut self, constraint: gpui::SizeConstraint, view: &mut CollabTitlebarItem, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { debug_assert!(constraint.max_along(Axis::Horizontal) == f32::INFINITY); diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 7c43885763e09286c5916b0d89883491050bc086..d1ad1f26259da3874d46352e7033e5829026bd39 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -30,8 +30,8 @@ use gpui::{ json::{self, ToJson}, platform::{CursorStyle, Modifiers, MouseButton, MouseButtonEvent, MouseMovedEvent}, text_layout::{self, Line, RunStyle, TextLayoutCache}, - AnyElement, Axis, Border, CursorRegion, Element, EventContext, MouseRegion, Quad, SceneBuilder, - SizeConstraint, ViewContext, WindowContext, + AnyElement, Axis, Border, CursorRegion, Element, EventContext, LayoutContext, MouseRegion, + Quad, SceneBuilder, SizeConstraint, ViewContext, WindowContext, }; use itertools::Itertools; use json::json; @@ -1388,7 +1388,7 @@ impl EditorElement { line_layouts: &[text_layout::Line], include_root: bool, editor: &mut Editor, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> (f32, Vec) { let tooltip_style = cx.global::().theme.tooltip.clone(); let scroll_x = snapshot.scroll_anchor.offset.x(); @@ -1594,7 +1594,7 @@ impl Element for EditorElement { &mut self, constraint: SizeConstraint, editor: &mut Editor, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { let mut size = constraint.max; if size.x().is_infinite() { @@ -2565,10 +2565,18 @@ mod tests { let mut element = EditorElement::new(editor.read_with(cx, |editor, cx| editor.style(cx))); let (size, mut state) = editor.update(cx, |editor, cx| { + let mut new_parents = Default::default(); + let mut notify_views_if_parents_change = Default::default(); + let mut layout_cx = LayoutContext::new( + cx, + &mut new_parents, + &mut notify_views_if_parents_change, + false, + ); element.layout( SizeConstraint::new(vec2f(500., 500.), vec2f(500., 500.)), editor, - cx, + &mut layout_cx, ) }); diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 4d84f7c070fd179ec3220054b1f3fff2041ed3e5..f8d6459cf4fc1e6fca69d95ac86ab2b79681e8cc 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -1361,9 +1361,9 @@ impl AppContext { })); let mut window = Window::new(window_id, platform_window, self, build_root_view); - let scene = WindowContext::mutable(self, &mut window, window_id) - .build_scene() - .expect("initial scene should not error"); + let mut cx = WindowContext::mutable(self, &mut window, window_id); + cx.layout(false).expect("initial layout should not error"); + let scene = cx.paint().expect("initial paint should not error"); window.platform_window.present_scene(scene); window } @@ -1486,6 +1486,7 @@ impl AppContext { self.flushing_effects = true; let mut refreshing = false; + let mut updated_windows = HashSet::default(); loop { if let Some(effect) = self.pending_effects.pop_front() { match effect { @@ -1664,10 +1665,27 @@ impl AppContext { } else { self.remove_dropped_entities(); - if refreshing { - self.perform_window_refresh(); - } else { - self.update_windows(); + for window_id in self.windows.keys().cloned().collect::>() { + self.update_window(window_id, |cx| { + let invalidation = if refreshing { + let mut invalidation = + cx.window.invalidation.take().unwrap_or_default(); + invalidation + .updated + .extend(cx.window.rendered_views.keys().copied()); + Some(invalidation) + } else { + cx.window.invalidation.take() + }; + + if let Some(invalidation) = invalidation { + let appearance = cx.window.platform_window.appearance(); + cx.invalidate(invalidation, appearance); + if cx.layout(refreshing).log_err().is_some() { + updated_windows.insert(window_id); + } + } + }); } if self.pending_effects.is_empty() { @@ -1675,6 +1693,14 @@ impl AppContext { callback(self); } + for window_id in updated_windows.drain() { + self.update_window(window_id, |cx| { + if let Some(scene) = cx.paint().log_err() { + cx.window.platform_window.present_scene(scene); + } + }); + } + if self.pending_effects.is_empty() { self.flushing_effects = false; self.pending_notifications.clear(); @@ -1689,21 +1715,6 @@ impl AppContext { } } - fn update_windows(&mut self) { - let window_ids = self.windows.keys().cloned().collect::>(); - for window_id in window_ids { - self.update_window(window_id, |cx| { - if let Some(mut invalidation) = cx.window.invalidation.take() { - let appearance = cx.window.platform_window.appearance(); - cx.invalidate(&mut invalidation, appearance); - if let Some(scene) = cx.build_scene().log_err() { - cx.window.platform_window.present_scene(scene); - } - } - }); - } - } - fn window_was_resized(&mut self, window_id: usize) { self.pending_effects .push_back(Effect::ResizeWindow { window_id }); @@ -1747,23 +1758,6 @@ impl AppContext { self.pending_effects.push_back(Effect::RefreshWindows); } - fn perform_window_refresh(&mut self) { - let window_ids = self.windows.keys().cloned().collect::>(); - for window_id in window_ids { - self.update_window(window_id, |cx| { - let mut invalidation = cx.window.invalidation.take().unwrap_or_default(); - invalidation - .updated - .extend(cx.window.rendered_views.keys().copied()); - cx.invalidate(&mut invalidation, cx.window.platform_window.appearance()); - cx.refreshing = true; - if let Some(scene) = cx.build_scene().log_err() { - cx.window.platform_window.present_scene(scene); - } - }); - } - } - fn emit_global_event(&mut self, payload: Box) { let type_id = (&*payload).type_id(); @@ -3255,6 +3249,67 @@ impl BorrowWindowContext for ViewContext<'_, '_, V> { } } +pub struct LayoutContext<'a, 'b, 'c, V: View> { + view_context: &'c mut ViewContext<'a, 'b, V>, + new_parents: &'c mut HashMap, + views_to_notify_if_ancestors_change: &'c mut HashSet, + pub refreshing: bool, +} + +impl<'a, 'b, 'c, V: View> LayoutContext<'a, 'b, 'c, V> { + pub fn new( + view_context: &'c mut ViewContext<'a, 'b, V>, + new_parents: &'c mut HashMap, + views_to_notify_if_ancestors_change: &'c mut HashSet, + refreshing: bool, + ) -> Self { + Self { + view_context, + new_parents, + views_to_notify_if_ancestors_change, + refreshing, + } + } + + pub fn view_context(&mut self) -> &mut ViewContext<'a, 'b, V> { + self.view_context + } +} + +impl<'a, 'b, 'c, V: View> Deref for LayoutContext<'a, 'b, 'c, V> { + type Target = ViewContext<'a, 'b, V>; + + fn deref(&self) -> &Self::Target { + &self.view_context + } +} + +impl DerefMut for LayoutContext<'_, '_, '_, V> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.view_context + } +} + +impl BorrowAppContext for LayoutContext<'_, '_, '_, V> { + fn read_with T>(&self, f: F) -> T { + BorrowAppContext::read_with(&*self.view_context, f) + } + + fn update T>(&mut self, f: F) -> T { + BorrowAppContext::update(&mut *self.view_context, f) + } +} + +impl BorrowWindowContext for LayoutContext<'_, '_, '_, V> { + fn read_with T>(&self, window_id: usize, f: F) -> T { + BorrowWindowContext::read_with(&*self.view_context, window_id, f) + } + + fn update T>(&mut self, window_id: usize, f: F) -> T { + BorrowWindowContext::update(&mut *self.view_context, window_id, f) + } +} + pub struct EventContext<'a, 'b, 'c, V: View> { view_context: &'c mut ViewContext<'a, 'b, V>, pub(crate) handled: bool, diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index 49befafbec4bfca2fac1782f2d5c8d249b24a951..f9ccef7ae077268e5f17ae9ae09a8c8b1e53ef6e 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -14,8 +14,8 @@ use crate::{ text_layout::TextLayoutCache, util::post_inc, Action, AnyView, AnyViewHandle, AppContext, BorrowAppContext, BorrowWindowContext, Effect, - Element, Entity, Handle, MouseRegion, MouseRegionId, ParentId, SceneBuilder, Subscription, - View, ViewContext, ViewHandle, WindowInvalidation, + Element, Entity, Handle, LayoutContext, MouseRegion, MouseRegionId, ParentId, SceneBuilder, + Subscription, View, ViewContext, ViewHandle, WindowInvalidation, }; use anyhow::{anyhow, bail, Result}; use collections::{HashMap, HashSet}; @@ -93,8 +93,8 @@ impl Window { let root_view = window_context .build_and_insert_view(ParentId::Root, |cx| Some(build_view(cx))) .unwrap(); - if let Some(mut invalidation) = window_context.window.invalidation.take() { - window_context.invalidate(&mut invalidation, appearance); + if let Some(invalidation) = window_context.window.invalidation.take() { + window_context.invalidate(invalidation, appearance); } window.focused_view_id = Some(root_view.id()); window.root_view = Some(root_view.into_any()); @@ -113,7 +113,6 @@ pub struct WindowContext<'a> { pub(crate) app_context: Reference<'a, AppContext>, pub(crate) window: Reference<'a, Window>, pub(crate) window_id: usize, - pub(crate) refreshing: bool, pub(crate) removed: bool, } @@ -169,7 +168,6 @@ impl<'a> WindowContext<'a> { app_context: Reference::Mutable(app_context), window: Reference::Mutable(window), window_id, - refreshing: false, removed: false, } } @@ -179,7 +177,6 @@ impl<'a> WindowContext<'a> { app_context: Reference::Immutable(app_context), window: Reference::Immutable(window), window_id, - refreshing: false, removed: false, } } @@ -891,7 +888,7 @@ impl<'a> WindowContext<'a> { false } - pub fn invalidate(&mut self, invalidation: &mut WindowInvalidation, appearance: Appearance) { + pub fn invalidate(&mut self, mut invalidation: WindowInvalidation, appearance: Appearance) { self.start_frame(); self.window.appearance = appearance; for view_id in &invalidation.removed { @@ -932,13 +929,32 @@ impl<'a> WindowContext<'a> { Ok(element) } - pub fn build_scene(&mut self) -> Result { + pub(crate) fn layout(&mut self, refreshing: bool) -> Result<()> { + let window_size = self.window.platform_window.content_size(); + let root_view_id = self.window.root_view().id(); + let mut rendered_root = self.window.rendered_views.remove(&root_view_id).unwrap(); + let mut new_parents = HashMap::default(); + let mut views_to_notify_if_ancestors_change = HashSet::default(); + rendered_root.layout( + SizeConstraint::strict(window_size), + &mut new_parents, + &mut views_to_notify_if_ancestors_change, + refreshing, + self, + )?; + + self.window + .rendered_views + .insert(root_view_id, rendered_root); + Ok(()) + } + + pub(crate) fn paint(&mut self) -> Result { let window_size = self.window.platform_window.content_size(); let scale_factor = self.window.platform_window.scale_factor(); let root_view_id = self.window.root_view().id(); let mut rendered_root = self.window.rendered_views.remove(&root_view_id).unwrap(); - rendered_root.layout(SizeConstraint::strict(window_size), self)?; let mut scene_builder = SceneBuilder::new(scale_factor); rendered_root.paint( @@ -1366,11 +1382,17 @@ impl Element for ChildView { &mut self, constraint: SizeConstraint, _: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { if let Some(mut rendered_view) = cx.window.rendered_views.remove(&self.view_id) { let size = rendered_view - .layout(constraint, cx) + .layout( + constraint, + cx.new_parents, + cx.views_to_notify_if_ancestors_change, + cx.refreshing, + cx.view_context, + ) .log_err() .unwrap_or(Vector2F::zero()); cx.window.rendered_views.insert(self.view_id, rendered_view); diff --git a/crates/gpui/src/elements.rs b/crates/gpui/src/elements.rs index 7de0bc10f59ec0619b596b3a9a52d619a9104943..073d12c329255edba4bfc90921359094365f915a 100644 --- a/crates/gpui/src/elements.rs +++ b/crates/gpui/src/elements.rs @@ -33,9 +33,11 @@ use crate::{ rect::RectF, vector::{vec2f, Vector2F}, }, - json, Action, SceneBuilder, SizeConstraint, View, ViewContext, WeakViewHandle, WindowContext, + json, Action, LayoutContext, SceneBuilder, SizeConstraint, View, ViewContext, WeakViewHandle, + WindowContext, }; use anyhow::{anyhow, Result}; +use collections::{HashMap, HashSet}; use core::panic; use json::ToJson; use std::{ @@ -54,7 +56,7 @@ pub trait Element: 'static { &mut self, constraint: SizeConstraint, view: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState); fn paint( @@ -211,7 +213,7 @@ trait AnyElementState { &mut self, constraint: SizeConstraint, view: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> Vector2F; fn paint( @@ -263,7 +265,7 @@ impl> AnyElementState for ElementState { &mut self, constraint: SizeConstraint, view: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> Vector2F { let result; *self = match mem::take(self) { @@ -444,7 +446,7 @@ impl AnyElement { &mut self, constraint: SizeConstraint, view: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> Vector2F { self.state.layout(constraint, view, cx) } @@ -505,7 +507,7 @@ impl Element for AnyElement { &mut self, constraint: SizeConstraint, view: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { let size = self.layout(constraint, view, cx); (size, ()) @@ -597,7 +599,7 @@ impl> Element for ComponentHost { &mut self, constraint: SizeConstraint, view: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> (Vector2F, AnyElement) { let mut element = self.component.render(view, cx); let size = element.layout(constraint, view, cx); @@ -642,7 +644,14 @@ impl> Element for ComponentHost { } pub trait AnyRootElement { - fn layout(&mut self, constraint: SizeConstraint, cx: &mut WindowContext) -> Result; + fn layout( + &mut self, + constraint: SizeConstraint, + new_parents: &mut HashMap, + views_to_notify_if_ancestors_change: &mut HashSet, + refreshing: bool, + cx: &mut WindowContext, + ) -> Result; fn paint( &mut self, scene: &mut SceneBuilder, @@ -660,12 +669,27 @@ pub trait AnyRootElement { } impl AnyRootElement for RootElement { - fn layout(&mut self, constraint: SizeConstraint, cx: &mut WindowContext) -> Result { + fn layout( + &mut self, + constraint: SizeConstraint, + new_parents: &mut HashMap, + views_to_notify_if_ancestors_change: &mut HashSet, + refreshing: bool, + cx: &mut WindowContext, + ) -> Result { let view = self .view .upgrade(cx) .ok_or_else(|| anyhow!("layout called on a root element for a dropped view"))?; - view.update(cx, |view, cx| Ok(self.element.layout(constraint, view, cx))) + view.update(cx, |view, cx| { + let mut cx = LayoutContext::new( + cx, + new_parents, + views_to_notify_if_ancestors_change, + refreshing, + ); + Ok(self.element.layout(constraint, view, &mut cx)) + }) } fn paint( diff --git a/crates/gpui/src/elements/align.rs b/crates/gpui/src/elements/align.rs index b3724c923f0704c5ac9e15920e6db1e5f334d00e..165cfcf190c7d69304c424f0bbed34b048905c44 100644 --- a/crates/gpui/src/elements/align.rs +++ b/crates/gpui/src/elements/align.rs @@ -1,6 +1,6 @@ use crate::{ geometry::{rect::RectF, vector::Vector2F}, - json, AnyElement, Element, SceneBuilder, SizeConstraint, View, ViewContext, + json, AnyElement, Element, LayoutContext, SceneBuilder, SizeConstraint, View, ViewContext, }; use json::ToJson; @@ -48,7 +48,7 @@ impl Element for Align { &mut self, mut constraint: SizeConstraint, view: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { let mut size = constraint.max; constraint.min = Vector2F::zero(); diff --git a/crates/gpui/src/elements/canvas.rs b/crates/gpui/src/elements/canvas.rs index 36ff4e2cf409222de491694d88ccb3e4aabbe087..bbd8d0393cd038b3e1bde28aa4811280c0dcd768 100644 --- a/crates/gpui/src/elements/canvas.rs +++ b/crates/gpui/src/elements/canvas.rs @@ -34,7 +34,7 @@ where &mut self, constraint: crate::SizeConstraint, _: &mut V, - _: &mut crate::ViewContext, + _: &mut crate::LayoutContext, ) -> (Vector2F, Self::LayoutState) { let x = if constraint.max.x().is_finite() { constraint.max.x() diff --git a/crates/gpui/src/elements/clipped.rs b/crates/gpui/src/elements/clipped.rs index 85466972d39e4957bd12b81d1c0ad556b776b6ce..a87dc3e7735c181a8716a61acf8fc7720c62532c 100644 --- a/crates/gpui/src/elements/clipped.rs +++ b/crates/gpui/src/elements/clipped.rs @@ -3,7 +3,9 @@ use std::ops::Range; use pathfinder_geometry::{rect::RectF, vector::Vector2F}; use serde_json::json; -use crate::{json, AnyElement, Element, SceneBuilder, SizeConstraint, View, ViewContext}; +use crate::{ + json, AnyElement, Element, LayoutContext, SceneBuilder, SizeConstraint, View, ViewContext, +}; pub struct Clipped { child: AnyElement, @@ -23,7 +25,7 @@ impl Element for Clipped { &mut self, constraint: SizeConstraint, view: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { (self.child.layout(constraint, view, cx), ()) } diff --git a/crates/gpui/src/elements/constrained_box.rs b/crates/gpui/src/elements/constrained_box.rs index fc033c9b433360df8a8e958dd9f75e1b84c3317e..46916c74f1054d442e190a809d69a5fa945ad631 100644 --- a/crates/gpui/src/elements/constrained_box.rs +++ b/crates/gpui/src/elements/constrained_box.rs @@ -5,7 +5,7 @@ use serde_json::json; use crate::{ geometry::{rect::RectF, vector::Vector2F}, - json, AnyElement, Element, SceneBuilder, SizeConstraint, View, ViewContext, + json, AnyElement, Element, LayoutContext, SceneBuilder, SizeConstraint, View, ViewContext, }; pub struct ConstrainedBox { @@ -15,7 +15,7 @@ pub struct ConstrainedBox { pub enum Constraint { Static(SizeConstraint), - Dynamic(Box) -> SizeConstraint>), + Dynamic(Box) -> SizeConstraint>), } impl ToJson for Constraint { @@ -37,7 +37,8 @@ impl ConstrainedBox { pub fn dynamically( mut self, - constraint: impl 'static + FnMut(SizeConstraint, &mut V, &mut ViewContext) -> SizeConstraint, + constraint: impl 'static + + FnMut(SizeConstraint, &mut V, &mut LayoutContext) -> SizeConstraint, ) -> Self { self.constraint = Constraint::Dynamic(Box::new(constraint)); self @@ -119,7 +120,7 @@ impl ConstrainedBox { &mut self, input_constraint: SizeConstraint, view: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> SizeConstraint { match &mut self.constraint { Constraint::Static(constraint) => *constraint, @@ -138,7 +139,7 @@ impl Element for ConstrainedBox { &mut self, mut parent_constraint: SizeConstraint, view: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { let constraint = self.constraint(parent_constraint, view, cx); parent_constraint.min = parent_constraint.min.max(constraint.min); diff --git a/crates/gpui/src/elements/container.rs b/crates/gpui/src/elements/container.rs index 1cbef9a52e5319fbf1b5130e503e504bfc63bd03..3ce323db09775086ba1eb0897d71c6a51a0dd9ac 100644 --- a/crates/gpui/src/elements/container.rs +++ b/crates/gpui/src/elements/container.rs @@ -10,7 +10,7 @@ use crate::{ json::ToJson, platform::CursorStyle, scene::{self, Border, CursorRegion, Quad}, - AnyElement, Element, SceneBuilder, SizeConstraint, View, ViewContext, + AnyElement, Element, LayoutContext, SceneBuilder, SizeConstraint, View, ViewContext, }; use serde::Deserialize; use serde_json::json; @@ -192,7 +192,7 @@ impl Element for Container { &mut self, constraint: SizeConstraint, view: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { let mut size_buffer = self.margin_size() + self.padding_size(); if !self.style.border.overlay { diff --git a/crates/gpui/src/elements/empty.rs b/crates/gpui/src/elements/empty.rs index d1a3cbafdb1d7b6df56f249d9176219b5ef9e581..42a3824bfcb7f610b715424af6297363a469751b 100644 --- a/crates/gpui/src/elements/empty.rs +++ b/crates/gpui/src/elements/empty.rs @@ -6,7 +6,7 @@ use crate::{ vector::{vec2f, Vector2F}, }, json::{json, ToJson}, - SceneBuilder, View, ViewContext, + LayoutContext, SceneBuilder, View, ViewContext, }; use crate::{Element, SizeConstraint}; @@ -34,7 +34,7 @@ impl Element for Empty { &mut self, constraint: SizeConstraint, _: &mut V, - _: &mut ViewContext, + _: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { let x = if constraint.max.x().is_finite() && !self.collapsed { constraint.max.x() diff --git a/crates/gpui/src/elements/expanded.rs b/crates/gpui/src/elements/expanded.rs index 8a59191b7a541e0cc88d82d231bbf04b16b32e8b..1fb935b2b8fa272413698fb14d7cfa8ab9cdf51b 100644 --- a/crates/gpui/src/elements/expanded.rs +++ b/crates/gpui/src/elements/expanded.rs @@ -2,7 +2,7 @@ use std::ops::Range; use crate::{ geometry::{rect::RectF, vector::Vector2F}, - json, AnyElement, Element, SceneBuilder, SizeConstraint, View, ViewContext, + json, AnyElement, Element, LayoutContext, SceneBuilder, SizeConstraint, View, ViewContext, }; use serde_json::json; @@ -42,7 +42,7 @@ impl Element for Expanded { &mut self, mut constraint: SizeConstraint, view: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { if self.full_width { constraint.min.set_x(constraint.max.x()); diff --git a/crates/gpui/src/elements/flex.rs b/crates/gpui/src/elements/flex.rs index 7fee0006f7c3b4acdc2c97c674acfb39683704c7..e0e8dfc215069b892fbfc1cd25d640fbdb7f18e2 100644 --- a/crates/gpui/src/elements/flex.rs +++ b/crates/gpui/src/elements/flex.rs @@ -2,8 +2,8 @@ use std::{any::Any, cell::Cell, f32::INFINITY, ops::Range, rc::Rc}; use crate::{ json::{self, ToJson, Value}, - AnyElement, Axis, Element, ElementStateHandle, SceneBuilder, SizeConstraint, Vector2FExt, View, - ViewContext, + AnyElement, Axis, Element, ElementStateHandle, LayoutContext, SceneBuilder, SizeConstraint, + Vector2FExt, View, ViewContext, }; use pathfinder_geometry::{ rect::RectF, @@ -74,7 +74,7 @@ impl Flex { remaining_flex: &mut f32, cross_axis_max: &mut f32, view: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) { let cross_axis = self.axis.invert(); for child in &mut self.children { @@ -125,7 +125,7 @@ impl Element for Flex { &mut self, constraint: SizeConstraint, view: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { let mut total_flex = None; let mut fixed_space = 0.0; @@ -214,7 +214,7 @@ impl Element for Flex { } if let Some(scroll_state) = self.scroll_state.as_ref() { - scroll_state.0.update(cx, |scroll_state, _| { + scroll_state.0.update(cx.view_context(), |scroll_state, _| { if let Some(scroll_to) = scroll_state.scroll_to.take() { let visible_start = scroll_state.scroll_position.get(); let visible_end = visible_start + size.along(self.axis); @@ -432,7 +432,7 @@ impl Element for FlexItem { &mut self, constraint: SizeConstraint, view: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { let size = self.child.layout(constraint, view, cx); (size, ()) diff --git a/crates/gpui/src/elements/hook.rs b/crates/gpui/src/elements/hook.rs index cb22760285ef0a745657b48803490b7dc9f862ab..310b3c25ebeda1778daf3fd060bf24af6be10822 100644 --- a/crates/gpui/src/elements/hook.rs +++ b/crates/gpui/src/elements/hook.rs @@ -3,7 +3,7 @@ use std::ops::Range; use crate::{ geometry::{rect::RectF, vector::Vector2F}, json::json, - AnyElement, Element, SceneBuilder, SizeConstraint, View, ViewContext, + AnyElement, Element, LayoutContext, SceneBuilder, SizeConstraint, View, ViewContext, }; pub struct Hook { @@ -36,7 +36,7 @@ impl Element for Hook { &mut self, constraint: SizeConstraint, view: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { let size = self.child.layout(constraint, view, cx); if let Some(handler) = self.after_layout.as_mut() { diff --git a/crates/gpui/src/elements/image.rs b/crates/gpui/src/elements/image.rs index 162446c1f022added77887c8f69dc6dbb02196ce..98c5ae6226940946542313021e658243c843b6ea 100644 --- a/crates/gpui/src/elements/image.rs +++ b/crates/gpui/src/elements/image.rs @@ -5,7 +5,8 @@ use crate::{ vector::{vec2f, Vector2F}, }, json::{json, ToJson}, - scene, Border, Element, ImageData, SceneBuilder, SizeConstraint, View, ViewContext, + scene, Border, Element, ImageData, LayoutContext, SceneBuilder, SizeConstraint, View, + ViewContext, }; use serde::Deserialize; use std::{ops::Range, sync::Arc}; @@ -63,7 +64,7 @@ impl Element for Image { &mut self, constraint: SizeConstraint, _: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { let data = match &self.source { ImageSource::Path(path) => match cx.asset_cache.png(path) { diff --git a/crates/gpui/src/elements/keystroke_label.rs b/crates/gpui/src/elements/keystroke_label.rs index b179d781275542fcfc4e037a590859dc27876a64..c011649b2e946f980cd5b3eb2e7ab448bde8e2e1 100644 --- a/crates/gpui/src/elements/keystroke_label.rs +++ b/crates/gpui/src/elements/keystroke_label.rs @@ -39,7 +39,7 @@ impl Element for KeystrokeLabel { &mut self, constraint: SizeConstraint, view: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> (Vector2F, AnyElement) { let mut element = if let Some(keystrokes) = cx.keystrokes_for_action(self.view_id, self.action.as_ref()) diff --git a/crates/gpui/src/elements/label.rs b/crates/gpui/src/elements/label.rs index 2669f4d5f2f1ba058845cef44ce816feb28f8339..9499841b3d46a0d8c77da4e741bd1c623eeb0de4 100644 --- a/crates/gpui/src/elements/label.rs +++ b/crates/gpui/src/elements/label.rs @@ -8,7 +8,7 @@ use crate::{ }, json::{ToJson, Value}, text_layout::{Line, RunStyle}, - Element, SceneBuilder, SizeConstraint, View, ViewContext, + Element, LayoutContext, SceneBuilder, SizeConstraint, View, ViewContext, }; use serde::Deserialize; use serde_json::json; @@ -135,7 +135,7 @@ impl Element for Label { &mut self, constraint: SizeConstraint, _: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { let runs = self.compute_runs(); let line = cx.text_layout_cache().layout_str( diff --git a/crates/gpui/src/elements/list.rs b/crates/gpui/src/elements/list.rs index 84043f5e1ff135df9596ffe15029d700f96a6458..ca73196c8bb04a1e3dba879c23e667ecba1b7e22 100644 --- a/crates/gpui/src/elements/list.rs +++ b/crates/gpui/src/elements/list.rs @@ -4,7 +4,8 @@ use crate::{ vector::{vec2f, Vector2F}, }, json::json, - AnyElement, Element, MouseRegion, SceneBuilder, SizeConstraint, View, ViewContext, + AnyElement, Element, LayoutContext, MouseRegion, SceneBuilder, SizeConstraint, View, + ViewContext, }; use std::{cell::RefCell, collections::VecDeque, fmt::Debug, ops::Range, rc::Rc}; use sum_tree::{Bias, SumTree}; @@ -99,7 +100,7 @@ impl Element for List { &mut self, constraint: SizeConstraint, view: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { let state = &mut *self.state.0.borrow_mut(); let size = constraint.max; @@ -452,7 +453,7 @@ impl StateInner { existing_element: Option<&ListItem>, constraint: SizeConstraint, view: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> Option>>> { if let Some(ListItem::Rendered(element)) = existing_element { Some(element.clone()) @@ -665,7 +666,15 @@ mod tests { }); let mut list = List::new(state.clone()); - let (size, _) = list.layout(constraint, &mut view, cx); + let mut new_parents = Default::default(); + let mut notify_views_if_parents_change = Default::default(); + let mut layout_cx = LayoutContext::new( + cx, + &mut new_parents, + &mut notify_views_if_parents_change, + false, + ); + let (size, _) = list.layout(constraint, &mut view, &mut layout_cx); assert_eq!(size, vec2f(100., 40.)); assert_eq!( state.0.borrow().items.summary().clone(), @@ -689,7 +698,13 @@ mod tests { cx, ); - let (_, logical_scroll_top) = list.layout(constraint, &mut view, cx); + let mut layout_cx = LayoutContext::new( + cx, + &mut new_parents, + &mut notify_views_if_parents_change, + false, + ); + let (_, logical_scroll_top) = list.layout(constraint, &mut view, &mut layout_cx); assert_eq!( logical_scroll_top, ListOffset { @@ -713,7 +728,13 @@ mod tests { } ); - let (size, logical_scroll_top) = list.layout(constraint, &mut view, cx); + let mut layout_cx = LayoutContext::new( + cx, + &mut new_parents, + &mut notify_views_if_parents_change, + false, + ); + let (size, logical_scroll_top) = list.layout(constraint, &mut view, &mut layout_cx); assert_eq!(size, vec2f(100., 40.)); assert_eq!( state.0.borrow().items.summary().clone(), @@ -831,10 +852,18 @@ mod tests { let mut list = List::new(state.clone()); let window_size = vec2f(width, height); + let mut new_parents = Default::default(); + let mut notify_views_if_parents_change = Default::default(); + let mut layout_cx = LayoutContext::new( + cx, + &mut new_parents, + &mut notify_views_if_parents_change, + false, + ); let (size, logical_scroll_top) = list.layout( SizeConstraint::new(vec2f(0., 0.), window_size), &mut view, - cx, + &mut layout_cx, ); assert_eq!(size, window_size); last_logical_scroll_top = Some(logical_scroll_top); @@ -947,7 +976,7 @@ mod tests { &mut self, _: SizeConstraint, _: &mut V, - _: &mut ViewContext, + _: &mut LayoutContext, ) -> (Vector2F, ()) { (self.size, ()) } diff --git a/crates/gpui/src/elements/mouse_event_handler.rs b/crates/gpui/src/elements/mouse_event_handler.rs index 8abcf5f8354b4ef98d77492468146a6502cc13a0..ed624922d57362d0040a1d7e28a54ae9b3f28e9c 100644 --- a/crates/gpui/src/elements/mouse_event_handler.rs +++ b/crates/gpui/src/elements/mouse_event_handler.rs @@ -10,8 +10,8 @@ use crate::{ CursorRegion, HandlerSet, MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseHover, MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut, }, - AnyElement, Element, EventContext, MouseRegion, MouseState, SceneBuilder, SizeConstraint, View, - ViewContext, + AnyElement, Element, EventContext, LayoutContext, MouseRegion, MouseState, SceneBuilder, + SizeConstraint, View, ViewContext, }; use serde_json::json; use std::{marker::PhantomData, ops::Range}; @@ -220,7 +220,7 @@ impl Element for MouseEventHandler { &mut self, constraint: SizeConstraint, view: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { (self.child.layout(constraint, view, cx), ()) } diff --git a/crates/gpui/src/elements/overlay.rs b/crates/gpui/src/elements/overlay.rs index 0abd1231e2ec2dab8acf70017583fb12848b0df7..0f7e4a35c673ec78b5001420957670f5943ffe0f 100644 --- a/crates/gpui/src/elements/overlay.rs +++ b/crates/gpui/src/elements/overlay.rs @@ -3,7 +3,8 @@ use std::ops::Range; use crate::{ geometry::{rect::RectF, vector::Vector2F}, json::ToJson, - AnyElement, Axis, Element, MouseRegion, SceneBuilder, SizeConstraint, View, ViewContext, + AnyElement, Axis, Element, LayoutContext, MouseRegion, SceneBuilder, SizeConstraint, View, + ViewContext, }; use serde_json::json; @@ -124,7 +125,7 @@ impl Element for Overlay { &mut self, constraint: SizeConstraint, view: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { let constraint = if self.anchor_position.is_some() { SizeConstraint::new(Vector2F::zero(), cx.window_size()) diff --git a/crates/gpui/src/elements/resizable.rs b/crates/gpui/src/elements/resizable.rs index 37e15541f40ad565a23c14c68876fe6a3e8ad87f..0e78cc07fbce76fa73f6c5106ea218b774042281 100644 --- a/crates/gpui/src/elements/resizable.rs +++ b/crates/gpui/src/elements/resizable.rs @@ -7,7 +7,8 @@ use crate::{ geometry::rect::RectF, platform::{CursorStyle, MouseButton}, scene::MouseDrag, - AnyElement, Axis, Element, ElementStateHandle, MouseRegion, SceneBuilder, View, ViewContext, + AnyElement, Axis, Element, ElementStateHandle, LayoutContext, MouseRegion, SceneBuilder, View, + ViewContext, }; use super::{ConstrainedBox, Hook}; @@ -139,7 +140,7 @@ impl Element for Resizable { &mut self, constraint: crate::SizeConstraint, view: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { (self.child.layout(constraint, view, cx), ()) } diff --git a/crates/gpui/src/elements/stack.rs b/crates/gpui/src/elements/stack.rs index 348a9b4a3bbaa4ca859d9ef8e394543a4afe087a..196c04d2034a0efa796d9d0ac47dcda6c6f6ab51 100644 --- a/crates/gpui/src/elements/stack.rs +++ b/crates/gpui/src/elements/stack.rs @@ -3,7 +3,7 @@ use std::ops::Range; use crate::{ geometry::{rect::RectF, vector::Vector2F}, json::{self, json, ToJson}, - AnyElement, Element, SceneBuilder, SizeConstraint, View, ViewContext, + AnyElement, Element, LayoutContext, SceneBuilder, SizeConstraint, View, ViewContext, }; /// Element which renders it's children in a stack on top of each other. @@ -34,7 +34,7 @@ impl Element for Stack { &mut self, mut constraint: SizeConstraint, view: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { let mut size = constraint.min; let mut children = self.children.iter_mut(); diff --git a/crates/gpui/src/elements/svg.rs b/crates/gpui/src/elements/svg.rs index 0f75be82fd1e7894f4c9864d71edcfee1de80a8a..544422132298be738e97a29a0cd9f7e4a56eba38 100644 --- a/crates/gpui/src/elements/svg.rs +++ b/crates/gpui/src/elements/svg.rs @@ -8,7 +8,7 @@ use crate::{ rect::RectF, vector::{vec2f, Vector2F}, }, - scene, Element, SceneBuilder, SizeConstraint, View, ViewContext, + scene, Element, LayoutContext, SceneBuilder, SizeConstraint, View, ViewContext, }; pub struct Svg { @@ -38,7 +38,7 @@ impl Element for Svg { &mut self, constraint: SizeConstraint, _: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { match cx.asset_cache.svg(&self.path) { Ok(tree) => { diff --git a/crates/gpui/src/elements/text.rs b/crates/gpui/src/elements/text.rs index a92581f6c875e38a0acbf0854c683a0e5fb68a3c..829511c62f0978e58b9c1f8c9e5c5bc486a9a54e 100644 --- a/crates/gpui/src/elements/text.rs +++ b/crates/gpui/src/elements/text.rs @@ -7,8 +7,8 @@ use crate::{ }, json::{ToJson, Value}, text_layout::{Line, RunStyle, ShapedBoundary}, - AppContext, Element, FontCache, SceneBuilder, SizeConstraint, TextLayoutCache, View, - ViewContext, + AppContext, Element, FontCache, LayoutContext, SceneBuilder, SizeConstraint, TextLayoutCache, + View, ViewContext, }; use log::warn; use serde_json::json; @@ -78,7 +78,7 @@ impl Element for Text { &mut self, constraint: SizeConstraint, _: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { // Convert the string and highlight ranges into an iterator of highlighted chunks. @@ -411,10 +411,18 @@ mod tests { let mut view = TestView; fonts::with_font_cache(cx.font_cache().clone(), || { let mut text = Text::new("Hello\r\n", Default::default()).with_soft_wrap(true); + let mut new_parents = Default::default(); + let mut notify_views_if_parents_change = Default::default(); + let mut layout_cx = LayoutContext::new( + cx, + &mut new_parents, + &mut notify_views_if_parents_change, + false, + ); let (_, state) = text.layout( SizeConstraint::new(Default::default(), vec2f(f32::INFINITY, f32::INFINITY)), &mut view, - cx, + &mut layout_cx, ); assert_eq!(state.shaped_lines.len(), 2); assert_eq!(state.wrap_boundaries.len(), 2); diff --git a/crates/gpui/src/elements/tooltip.rs b/crates/gpui/src/elements/tooltip.rs index a879b996d5780f13555ae4e48a9af283c84e83b7..7b4892fc1c2f37012f0124113c5888c964d0232e 100644 --- a/crates/gpui/src/elements/tooltip.rs +++ b/crates/gpui/src/elements/tooltip.rs @@ -6,7 +6,8 @@ use crate::{ fonts::TextStyle, geometry::{rect::RectF, vector::Vector2F}, json::json, - Action, Axis, ElementStateHandle, SceneBuilder, SizeConstraint, Task, View, ViewContext, + Action, Axis, ElementStateHandle, LayoutContext, SceneBuilder, SizeConstraint, Task, View, + ViewContext, }; use serde::Deserialize; use std::{ @@ -172,7 +173,7 @@ impl Element for Tooltip { &mut self, constraint: SizeConstraint, view: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { let size = self.child.layout(constraint, view, cx); if let Some(tooltip) = self.tooltip.as_mut() { diff --git a/crates/gpui/src/elements/uniform_list.rs b/crates/gpui/src/elements/uniform_list.rs index e75425dc3f0b5b817762e0cc2bf268288c4433d0..9ccd57b2919727ec1c60e8af525d8b6de73e8f77 100644 --- a/crates/gpui/src/elements/uniform_list.rs +++ b/crates/gpui/src/elements/uniform_list.rs @@ -6,7 +6,7 @@ use crate::{ }, json::{self, json}, platform::ScrollWheelEvent, - AnyElement, MouseRegion, SceneBuilder, View, ViewContext, + AnyElement, LayoutContext, MouseRegion, SceneBuilder, View, ViewContext, }; use json::ToJson; use std::{cell::RefCell, cmp, ops::Range, rc::Rc}; @@ -159,7 +159,7 @@ impl Element for UniformList { &mut self, constraint: SizeConstraint, view: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { if constraint.max.y().is_infinite() { unimplemented!( diff --git a/crates/terminal_view/src/terminal_element.rs b/crates/terminal_view/src/terminal_element.rs index 392b050f434beb28316eb874fd2fee2c4f0a8c22..366db99622c7f0efe76169ce0d67d6ff6821ddc8 100644 --- a/crates/terminal_view/src/terminal_element.rs +++ b/crates/terminal_view/src/terminal_element.rs @@ -10,8 +10,8 @@ use gpui::{ platform::{CursorStyle, MouseButton}, serde_json::json, text_layout::{Line, RunStyle}, - AnyElement, Element, EventContext, FontCache, ModelContext, MouseRegion, Quad, SceneBuilder, - SizeConstraint, TextLayoutCache, ViewContext, WeakModelHandle, + AnyElement, Element, EventContext, FontCache, LayoutContext, ModelContext, MouseRegion, Quad, + SceneBuilder, SizeConstraint, TextLayoutCache, ViewContext, WeakModelHandle, }; use itertools::Itertools; use language::CursorShape; @@ -561,7 +561,7 @@ impl Element for TerminalElement { &mut self, constraint: gpui::SizeConstraint, view: &mut TerminalView, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> (gpui::geometry::vector::Vector2F, Self::LayoutState) { let settings = cx.global::(); let font_cache = cx.font_cache(); diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 8bd42fed045ec80f51ea7b9432f588dcef6ca2a6..599f04166a0bc03b6455173d747f83a00797fed0 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -24,8 +24,8 @@ use gpui::{ keymap_matcher::KeymapContext, platform::{CursorStyle, MouseButton, NavigationDirection, PromptLevel}, Action, AnyViewHandle, AnyWeakViewHandle, AppContext, AsyncAppContext, Entity, EventContext, - ModelHandle, MouseRegion, Quad, Task, View, ViewContext, ViewHandle, WeakViewHandle, - WindowContext, + LayoutContext, ModelHandle, MouseRegion, Quad, Task, View, ViewContext, ViewHandle, + WeakViewHandle, WindowContext, }; use project::{Project, ProjectEntryId, ProjectPath}; use serde::Deserialize; @@ -1999,7 +1999,7 @@ impl Element for PaneBackdrop { &mut self, constraint: gpui::SizeConstraint, view: &mut V, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { let size = self.child.layout(constraint, view, cx); (size, ()) diff --git a/crates/workspace/src/status_bar.rs b/crates/workspace/src/status_bar.rs index 60bc1f81f5a7470af06380c00be595c8bacfec57..c31acc2f999333e27ca3d1b2a388df91796edba8 100644 --- a/crates/workspace/src/status_bar.rs +++ b/crates/workspace/src/status_bar.rs @@ -8,8 +8,8 @@ use gpui::{ vector::{vec2f, Vector2F}, }, json::{json, ToJson}, - AnyElement, AnyViewHandle, Entity, SceneBuilder, SizeConstraint, Subscription, View, - ViewContext, ViewHandle, WindowContext, + AnyElement, AnyViewHandle, Entity, LayoutContext, SceneBuilder, SizeConstraint, Subscription, + View, ViewContext, ViewHandle, WindowContext, }; use settings::Settings; @@ -157,7 +157,7 @@ impl Element for StatusBarElement { &mut self, mut constraint: SizeConstraint, view: &mut StatusBar, - cx: &mut ViewContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { let max_width = constraint.max.x(); constraint.min = vec2f(0., constraint.min.y());