WIP: Create infrastructure for testing element layout

Antonio Scandurra and Nathan Sobo created

Co-Authored-By: Nathan Sobo <nathan@zed.dev>

Change summary

gpui/src/app.rs           | 34 ++++++++++++++----------------
gpui/src/elements/list.rs | 11 ++++++++++
gpui/src/presenter.rs     | 44 +++++++++++++++++++---------------------
3 files changed, 48 insertions(+), 41 deletions(-)

Detailed changes

gpui/src/app.rs 🔗

@@ -1067,15 +1067,9 @@ impl MutableAppContext {
             self.cx
                 .platform
                 .open_window(window_id, window_options, self.foreground.clone());
-        let text_layout_cache = TextLayoutCache::new(self.cx.platform.fonts());
-        let presenter = Rc::new(RefCell::new(Presenter::new(
-            window_id,
-            window.titlebar_height(),
-            self.cx.font_cache.clone(),
-            text_layout_cache,
-            self.assets.clone(),
-            self,
-        )));
+        let presenter = Rc::new(RefCell::new(
+            self.build_presenter(window_id, window.titlebar_height()),
+        ));
 
         {
             let mut app = self.upgrade();
@@ -1107,7 +1101,6 @@ impl MutableAppContext {
                 app.update(|cx| {
                     let scene = presenter.borrow_mut().build_scene(
                         window.size(),
-                        window.titlebar_height(),
                         window.scale_factor(),
                         cx,
                     );
@@ -1131,6 +1124,17 @@ impl MutableAppContext {
         });
     }
 
+    pub fn build_presenter(&self, window_id: usize, titlebar_height: f32) -> Presenter {
+        Presenter::new(
+            window_id,
+            titlebar_height,
+            self.cx.font_cache.clone(),
+            TextLayoutCache::new(self.cx.platform.fonts()),
+            self.assets.clone(),
+            self,
+        )
+    }
+
     pub fn add_view<T, F>(&mut self, window_id: usize, build_view: F) -> ViewHandle<T>
     where
         T: View,
@@ -1263,14 +1267,8 @@ impl MutableAppContext {
             {
                 {
                     let mut presenter = presenter.borrow_mut();
-                    let titlebar_height = window.titlebar_height();
-                    presenter.invalidate(invalidation, titlebar_height, self.as_ref());
-                    let scene = presenter.build_scene(
-                        window.size(),
-                        titlebar_height,
-                        window.scale_factor(),
-                        self,
-                    );
+                    presenter.invalidate(invalidation, self.as_ref());
+                    let scene = presenter.build_scene(window.size(), window.scale_factor(), self);
                     window.present_scene(scene);
                 }
                 self.presenters_and_platform_windows

gpui/src/elements/list.rs 🔗

@@ -192,3 +192,14 @@ impl<'a> sum_tree::Dimension<'a, ElementHeightSummary> for Height {
         self.0 += summary.height;
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[crate::test(self)]
+    fn test_layout(cx: &mut crate::MutableAppContext) {
+        let mut presenter = cx.build_presenter(0, 20.0);
+        let layout_cx = presenter.layout_cx(cx);
+    }
+}

gpui/src/presenter.rs 🔗

@@ -22,6 +22,7 @@ pub struct Presenter {
     text_layout_cache: TextLayoutCache,
     asset_cache: Arc<AssetCache>,
     last_mouse_moved_event: Option<Event>,
+    titlebar_height: f32,
 }
 
 impl Presenter {
@@ -41,6 +42,7 @@ impl Presenter {
             text_layout_cache,
             asset_cache,
             last_mouse_moved_event: None,
+            titlebar_height,
         }
     }
 
@@ -55,12 +57,7 @@ impl Presenter {
         path
     }
 
-    pub fn invalidate(
-        &mut self,
-        mut invalidation: WindowInvalidation,
-        titlebar_height: f32,
-        cx: &AppContext,
-    ) {
+    pub fn invalidate(&mut self, mut invalidation: WindowInvalidation, cx: &AppContext) {
         for view_id in invalidation.removed {
             invalidation.updated.remove(&view_id);
             self.rendered_views.remove(&view_id);
@@ -69,7 +66,7 @@ impl Presenter {
         for view_id in invalidation.updated {
             self.rendered_views.insert(
                 view_id,
-                cx.render_view(self.window_id, view_id, titlebar_height)
+                cx.render_view(self.window_id, view_id, self.titlebar_height)
                     .unwrap(),
             );
         }
@@ -78,14 +75,13 @@ impl Presenter {
     pub fn build_scene(
         &mut self,
         window_size: Vector2F,
-        titlebar_height: f32,
         scale_factor: f32,
         cx: &mut MutableAppContext,
     ) -> Scene {
         let mut scene = Scene::new(scale_factor);
 
         if let Some(root_view_id) = cx.root_view_id(self.window_id) {
-            self.layout(window_size, titlebar_height, cx);
+            self.layout(window_size, cx);
             self.after_layout(cx);
             let mut paint_cx = PaintContext {
                 scene: &mut scene,
@@ -107,19 +103,22 @@ impl Presenter {
         scene
     }
 
-    fn layout(&mut self, size: Vector2F, titlebar_height: f32, cx: &mut MutableAppContext) {
+    fn layout(&mut self, size: Vector2F, cx: &mut MutableAppContext) {
         if let Some(root_view_id) = cx.root_view_id(self.window_id) {
-            let mut layout_ctx = LayoutContext {
-                rendered_views: &mut self.rendered_views,
-                parents: &mut self.parents,
-                font_cache: &self.font_cache,
-                text_layout_cache: &self.text_layout_cache,
-                asset_cache: &self.asset_cache,
-                view_stack: Vec::new(),
-                app: cx,
-                titlebar_height,
-            };
-            layout_ctx.layout(root_view_id, SizeConstraint::strict(size));
+            self.layout_cx(cx)
+                .layout(root_view_id, SizeConstraint::strict(size));
+        }
+    }
+
+    pub fn layout_cx<'a>(&'a mut self, cx: &'a mut MutableAppContext) -> LayoutContext<'a> {
+        LayoutContext {
+            rendered_views: &mut self.rendered_views,
+            parents: &mut self.parents,
+            font_cache: &self.font_cache,
+            text_layout_cache: &self.text_layout_cache,
+            asset_cache: &self.asset_cache,
+            view_stack: Vec::new(),
+            app: cx,
         }
     }
 
@@ -185,12 +184,11 @@ pub struct DispatchDirective {
 pub struct LayoutContext<'a> {
     rendered_views: &'a mut HashMap<usize, ElementBox>,
     parents: &'a mut HashMap<usize, usize>,
+    view_stack: Vec<usize>,
     pub font_cache: &'a FontCache,
     pub text_layout_cache: &'a TextLayoutCache,
     pub asset_cache: &'a AssetCache,
     pub app: &'a mut MutableAppContext,
-    view_stack: Vec<usize>,
-    pub titlebar_height: f32,
 }
 
 impl<'a> LayoutContext<'a> {